import { type Static } from '@sinclair/typebox'; /** * The common Notification Request envelope, schema_version 1. * * The public contract never exposes raw provider submission JSON. Provider-owned * routing keys, authorization, expiry syntax, and request identifiers remain * renderer/implementation concerns and are deliberately absent here. */ export declare const NOTIFICATION_SCHEMA_VERSION = 1; /** Cross-provider collapse identifiers are limited by encoded size, not JavaScript characters. */ export declare const COLLAPSE_KEY_MAX_BYTES = 64; /** Fixed identifiers registered by the iOS Companion App for inline replies. */ export declare const REPLY_CATEGORY_ID = "notifai.reply"; /** * Question sets carry their own category so the expanded notification is the * answering surface: the content extension renders choices and the secondary * typed-answer path. */ export declare const REPLY_CHOICE_CATEGORY_ID = "notifai.reply.choice"; export declare const REPLY_ACTION_ID = "notifai.reply.text"; export declare const REPLY_MAX_LENGTH = 4000; /** Companion image-attachment ceiling, shared by intake and capabilities. */ export declare const NOTIFICATION_IMAGE_MAX_BYTES: number; export declare const NOTIFICATION_MEDIA_TYPES: readonly ["image/jpeg", "image/png", "image/gif"]; export type NotificationMediaType = (typeof NOTIFICATION_MEDIA_TYPES)[number]; export declare const NotificationMediaTypeSchema: import("@sinclair/typebox").TUnion[]>; /** Device platforms known to the public contract. Delivery support is registry-owned. */ export declare const PLATFORMS: readonly ["ios", "macos", "android", "windows", "linux"]; export type Platform = (typeof PLATFORMS)[number]; export declare const PlatformSchema: import("@sinclair/typebox").TUnion[]>; /** Desktop Companion App platforms. They present requests in the app's own Edge. */ export declare const DESKTOP_PLATFORMS: readonly ["macos", "windows", "linux"]; export type DesktopPlatform = (typeof DESKTOP_PLATFORMS)[number]; export declare function isDesktopPlatform(platform: Platform): platform is DesktopPlatform; /** * Delivery providers known to the public contract. `stream` is the desktop * Companion App's own connection to the service: no third-party push service. */ export declare const PROVIDERS: readonly ["apns", "fcm", "stream"]; export type Provider = (typeof PROVIDERS)[number]; export declare const ProviderSchema: import("@sinclair/typebox").TUnion[]>; export declare const MediaItem: import("@sinclair/typebox").TObject<{ media_id: import("@sinclair/typebox").TString; /** Accessibility and fallback text; also the inline-render fallback. */ alt: import("@sinclair/typebox").TOptional; }>; export declare const MEDIA_MAX_ITEMS = 8; export declare const Presentation: import("@sinclair/typebox").TObject<{ title: import("@sinclair/typebox").TString; /** Purpose-written plain text for native banners and notification lists. */ summary: import("@sinclair/typebox").TString; /** Optional standalone focused content. Always interpreted as Markdown. */ body: import("@sinclair/typebox").TOptional; /** Ordered image attachments. Order is meaning: first is representative. */ media: import("@sinclair/typebox").TOptional; }>>>; }>; export declare const SESSION_LABEL_MAX_LENGTH = 64; export declare const SourceContext: import("@sinclair/typebox").TObject<{ /** Opaque Agent Session identity. Never rendered in User-facing text. */ session_id: import("@sinclair/typebox").TOptional; /** The only Agent Session string a User-facing surface may display. */ session_label: import("@sinclair/typebox").TOptional; /** Provenance used to upgrade a generated fallback when a semantic name arrives. */ session_label_source: import("@sinclair/typebox").TOptional, import("@sinclair/typebox").TLiteral<"semantic">]>>; /** Durable local proof that this machine's stored semantic label replaced a fallback. */ session_label_previous_source: import("@sinclair/typebox").TOptional>; /** Open harness slug, set only when authoritatively known. */ harness: import("@sinclair/typebox").TOptional; /** Git branch name; omitted on detached HEAD and outside Git. */ branch: import("@sinclair/typebox").TOptional; /** Privacy-safe linked-worktree basename, never a filesystem path. */ worktree: import("@sinclair/typebox").TOptional; }>; export declare const TargetSelector: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{ mode: import("@sinclair/typebox").TLiteral<"all">; }>, import("@sinclair/typebox").TObject<{ mode: import("@sinclair/typebox").TLiteral<"selected">; device_ids: import("@sinclair/typebox").TArray; }>]>; export declare const DeliveryPolicy: import("@sinclair/typebox").TObject<{ /** 24h default; 0 requests one immediate attempt with no retries. */ ttl_seconds: import("@sinclair/typebox").TInteger; /** No collapse by default; opting in requests replacement semantics. */ collapse_key: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>; }>; /** Longest choice label: it must fit a native notification action button. */ export declare const CHOICE_LABEL_MAX_LENGTH = 40; /** * Longest choice description, in Unicode code points: one or two short * sentences, two to four lines under the label on a phone. Measured against * real harness question forms, where the median option description is about * 100 characters. */ export declare const CHOICE_DESCRIPTION_MAX_LENGTH = 160; /** * One answer in a closed question. The id is the agent-facing token — stable, * machine-checkable, and never shown to the user; the label is the human text * rendered on the button. */ export declare const ReplyChoice: import("@sinclair/typebox").TObject<{ id: import("@sinclair/typebox").TString; label: import("@sinclair/typebox").TString; /** * What choosing this means, as one line of plain text. Companion Apps show * it under the label on the answer control; native notification action * buttons keep the label alone. */ description: import("@sinclair/typebox").TOptional; /** The asking agent recommends this answer. At most one choice per question. */ recommended: import("@sinclair/typebox").TOptional>; }>; export type ReplyChoiceT = Static; /** Upper bound on choices in one question. */ export declare const REPLY_MAX_CHOICES = 6; /** A reply window cannot outlive retained Notification Request content. */ export declare const REPLY_MAX_WINDOW_SECONDS: number; /** Upper bound on questions in one notification. */ export declare const REPLY_MAX_QUESTIONS = 10; /** * One question must be readable in full on the surface that offers the answers, * which is a notification the user reads at a glance. It shares the authored * Summary bound; longer explanation belongs in the optional Markdown Body. */ export declare const QUESTION_TEXT_MAX_LENGTH = 240; /** * One question in a reply request. With `choices` it is a closed question * answered by id; without, a free-text question. A typed answer remains possible * either way, so an agent must be prepared to receive text where it offered a * token. */ export declare const Question: import("@sinclair/typebox").TObject<{ /** Agent-facing token naming this question inside the set. */ id: import("@sinclair/typebox").TString; text: import("@sinclair/typebox").TString; choices: import("@sinclair/typebox").TOptional; /** The asking agent recommends this answer. At most one choice per question. */ recommended: import("@sinclair/typebox").TOptional>; }>>>; /** The user may select several choices. Only meaningful with `choices`. */ multi: import("@sinclair/typebox").TOptional; }>; export type QuestionT = Static; /** Opt-in reply channel. Presence enables the reply action. */ export declare const ReplyRequest: import("@sinclair/typebox").TObject<{ /** How long the server accepts a reply for this Notification Request. */ expires_in_seconds: import("@sinclair/typebox").TInteger; /** What is being asked, in order. */ questions: import("@sinclair/typebox").TArray; /** The asking agent recommends this answer. At most one choice per question. */ recommended: import("@sinclair/typebox").TOptional>; }>>>; /** The user may select several choices. Only meaningful with `choices`. */ multi: import("@sinclair/typebox").TOptional; }>>; }>; /** Product-owned semantic sound names shared by current Companion Apps. */ export declare const SEMANTIC_SOUNDS: readonly ["default", "update", "done", "attention", "alert"]; /** Semantic sound names shipped by the iOS Companion App. */ export declare const IOS_SOUNDS: readonly ["default", "update", "done", "attention", "alert"]; /** Semantic sound names shipped by the desktop Companion App. */ export declare const DESKTOP_SOUNDS: readonly ["default", "update", "done", "attention", "alert"]; /** Semantic sound names shipped by the Android Companion App. */ export declare const ANDROID_SOUNDS: readonly ["default", "update", "done", "attention", "alert"]; /** A semantic sound name a Companion App can play. */ export type IosSound = (typeof IOS_SOUNDS)[number]; export type DesktopSound = (typeof DESKTOP_SOUNDS)[number]; export type AndroidSound = (typeof ANDROID_SOUNDS)[number]; /** CLI spelling adds `none` for the contract's explicit silent (`null`) value. */ export declare const CLI_SOUNDS: readonly ["default", "update", "done", "attention", "alert", "none"]; /** User-given custom sound display names. */ export declare const SOUND_NAME_MAX_LENGTH = 64; /** Semantic name, custom sound id, or custom display name on a send. */ export declare const SOUND_REF_MAX_LENGTH = 128; /** Client-normalized upload ceiling for one custom sound. */ export declare const CUSTOM_SOUND_MAX_BYTES: number; /** Inclusive duration cap after client-side trim. */ export declare const CUSTOM_SOUND_MAX_DURATION_MS = 10000; /** Account-owned custom sound library size. */ export declare const CUSTOM_SOUND_LIBRARY_LIMIT = 50; /** Opaque custom sound ids minted by the service. */ export declare const CUSTOM_SOUND_ID_PATTERN = "^snd_[A-Za-z0-9_-]+$"; /** Client-normalized upload media type. */ export declare const NOTIFICATION_SOUND_MEDIA_TYPE = "audio/wav"; /** Silent background push that asks a Companion App to refresh custom sounds. */ export declare const SOUND_LIBRARY_SYNC: "sound_library"; /** * Silent background push that asks a Companion App advertising * `session_notes` to pull `GET /api/v1/session-messages`. */ export declare const SESSION_MESSAGES_SYNC: "session_messages"; export declare const INTERRUPTION_LEVELS: readonly ["passive", "active", "time_sensitive"]; export declare const IosOptions: import("@sinclair/typebox").TObject<{ /** A semantic sound, an Account custom sound id/name, or null (silent). */ sound: import("@sinclair/typebox").TOptional>; badge: import("@sinclair/typebox").TOptional>; thread_id: import("@sinclair/typebox").TOptional>; /** Caller-selected categories are unsupported; companions own their fixed reply categories. */ category: import("@sinclair/typebox").TOptional; interruption_level: import("@sinclair/typebox").TOptional[]>>; relevance_score: import("@sinclair/typebox").TOptional>; target_content_id: import("@sinclair/typebox").TOptional>; /** Namespaced, size-bounded custom data delivered under the `notifai` key. */ custom_data: import("@sinclair/typebox").TOptional>; }>; /** Desktop Companion App options: the Edge owns every other presentation choice. */ export declare const DesktopOptions: import("@sinclair/typebox").TObject<{ /** A semantic sound, an Account custom sound id/name, or null (silent). */ sound: import("@sinclair/typebox").TOptional>; }>; /** * macOS desktop options. Released CLIs send their iPhone options here too, so * the iPhone-only fields stay accepted; the desktop Companion App honors only * `sound` and its capability document marks the rest unsupported. */ export declare const MacosOptions: import("@sinclair/typebox").TObject<{ sound: import("@sinclair/typebox").TOptional>; badge: import("@sinclair/typebox").TOptional>; thread_id: import("@sinclair/typebox").TOptional>; category: import("@sinclair/typebox").TOptional; interruption_level: import("@sinclair/typebox").TOptional[]>>; relevance_score: import("@sinclair/typebox").TOptional>; target_content_id: import("@sinclair/typebox").TOptional>; custom_data: import("@sinclair/typebox").TOptional>; }>; /** Android options the first native Companion App actually honors. */ export declare const AndroidOptions: import("@sinclair/typebox").TObject<{ /** A semantic sound, an Account custom sound id/name, or null for the quiet channel. */ sound: import("@sinclair/typebox").TOptional>; /** Explicit notification group key; final grouping remains Android/OEM-owned. */ thread_id: import("@sinclair/typebox").TOptional>; /** Namespaced, size-bounded custom data inside the application-owned FCM envelope. */ custom_data: import("@sinclair/typebox").TOptional>; }>; /** Sender-chosen Project identifier slug. */ export declare const PROJECT_IDENTIFIER_PATTERN = "^[a-z0-9][a-z0-9._-]{0,63}$"; /** Sender-declared position on the lifecycle axis. */ export declare const Lifecycle: import("@sinclair/typebox").TObject<{ tier: import("@sinclair/typebox").TUnion[]>; state: import("@sinclair/typebox").TOptional[]>>; /** The request id of the question this `done` draft retires. */ retires_request_id: import("@sinclair/typebox").TOptional; }>; export type LifecycleT = Static; /** * What kind of thing this notification is. Kept closed so Companion Apps can * treat each value semantically rather than printing a sender-invented word. */ export declare const NOTIFICATION_KINDS: readonly ["update", "question", "done", "failed", "blocked"]; export type NotificationKind = (typeof NOTIFICATION_KINDS)[number]; /** Absent means `update`: a send that says nothing about itself is news. */ export declare const DEFAULT_NOTIFICATION_KIND: NotificationKind; /** A reply block is a question by construction, whatever kind was supplied. */ export declare function effectiveKind(draft: NotificationDraftT): NotificationKind; /** * The sound each kind arrives with when nobody chose one. * * Kind states what happened; this table turns that truth into the attention it * deserves, so an honest sender gets the right sound without reasoning about * audio. A caller's explicit sound and the user's saved preference both outrank * it — this is the floor, not a ceiling. * * It also closes the abuse this vocabulary used to invite: when kind drove * nothing, an agent could keep a failure quiet by calling it `done`. Now that * kind carries attention, the only rule an agent needs is to declare the kind * that is true. */ export declare const DEFAULT_SOUND_BY_KIND: Readonly>; /** The sound a kind arrives with absent an explicit choice. */ export declare function defaultSoundForKind(kind: NotificationKind): IosSound; export declare function isSemanticSound(value: string): value is IosSound; export declare function isCustomSoundId(value: string): boolean; /** * Sparse per-kind sound map. Missing keys inherit the next resolution layer. * Values are semantic names or custom sound ids. */ export declare const KindSoundMap: import("@sinclair/typebox").TObject<{ update: import("@sinclair/typebox").TOptional; question: import("@sinclair/typebox").TOptional; done: import("@sinclair/typebox").TOptional; failed: import("@sinclair/typebox").TOptional; blocked: import("@sinclair/typebox").TOptional; }>; export type KindSoundMapT = Static; /** Treat malformed keys as absent so a stored map cannot break delivery. */ export declare function normalizeKindSoundMap(value: unknown): KindSoundMapT; export declare const NotificationDraft: import("@sinclair/typebox").TObject<{ schema_version: import("@sinclair/typebox").TLiteral<1>; /** What this notification is. Absent means `update`. */ kind: import("@sinclair/typebox").TOptional[]>>; /** What this notification wants from the user. Absent means `new`. */ lifecycle: import("@sinclair/typebox").TOptional[]>; state: import("@sinclair/typebox").TOptional[]>>; /** The request id of the question this `done` draft retires. */ retires_request_id: import("@sinclair/typebox").TOptional; }>>; /** Optional Project identity; lazily recorded server-side. */ project: import("@sinclair/typebox").TOptional; /** Structured provenance; opaque ids remain machine-only. */ source: import("@sinclair/typebox").TOptional; /** The only Agent Session string a User-facing surface may display. */ session_label: import("@sinclair/typebox").TOptional; /** Provenance used to upgrade a generated fallback when a semantic name arrives. */ session_label_source: import("@sinclair/typebox").TOptional, import("@sinclair/typebox").TLiteral<"semantic">]>>; /** Durable local proof that this machine's stored semantic label replaced a fallback. */ session_label_previous_source: import("@sinclair/typebox").TOptional>; /** Open harness slug, set only when authoritatively known. */ harness: import("@sinclair/typebox").TOptional; /** Git branch name; omitted on detached HEAD and outside Git. */ branch: import("@sinclair/typebox").TOptional; /** Privacy-safe linked-worktree basename, never a filesystem path. */ worktree: import("@sinclair/typebox").TOptional; }>>; presentation: import("@sinclair/typebox").TObject<{ title: import("@sinclair/typebox").TString; /** Purpose-written plain text for native banners and notification lists. */ summary: import("@sinclair/typebox").TString; /** Optional standalone focused content. Always interpreted as Markdown. */ body: import("@sinclair/typebox").TOptional; /** Ordered image attachments. Order is meaning: first is representative. */ media: import("@sinclair/typebox").TOptional; }>>>; }>; targets: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{ mode: import("@sinclair/typebox").TLiteral<"all">; }>, import("@sinclair/typebox").TObject<{ mode: import("@sinclair/typebox").TLiteral<"selected">; device_ids: import("@sinclair/typebox").TArray; }>]>; delivery: import("@sinclair/typebox").TObject<{ /** 24h default; 0 requests one immediate attempt with no retries. */ ttl_seconds: import("@sinclair/typebox").TInteger; /** No collapse by default; opting in requests replacement semantics. */ collapse_key: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>; }>; reply: import("@sinclair/typebox").TOptional; /** The asking agent recommends this answer. At most one choice per question. */ recommended: import("@sinclair/typebox").TOptional>; }>>>; /** The user may select several choices. Only meaningful with `choices`. */ multi: import("@sinclair/typebox").TOptional; }>>; }>>; platform: import("@sinclair/typebox").TOptional>; badge: import("@sinclair/typebox").TOptional>; thread_id: import("@sinclair/typebox").TOptional>; /** Caller-selected categories are unsupported; companions own their fixed reply categories. */ category: import("@sinclair/typebox").TOptional; interruption_level: import("@sinclair/typebox").TOptional[]>>; relevance_score: import("@sinclair/typebox").TOptional>; target_content_id: import("@sinclair/typebox").TOptional>; /** Namespaced, size-bounded custom data delivered under the `notifai` key. */ custom_data: import("@sinclair/typebox").TOptional>; }>>; macos: import("@sinclair/typebox").TOptional>; badge: import("@sinclair/typebox").TOptional>; thread_id: import("@sinclair/typebox").TOptional>; category: import("@sinclair/typebox").TOptional; interruption_level: import("@sinclair/typebox").TOptional[]>>; relevance_score: import("@sinclair/typebox").TOptional>; target_content_id: import("@sinclair/typebox").TOptional>; custom_data: import("@sinclair/typebox").TOptional>; }>>; android: import("@sinclair/typebox").TOptional>; /** Explicit notification group key; final grouping remains Android/OEM-owned. */ thread_id: import("@sinclair/typebox").TOptional>; /** Namespaced, size-bounded custom data inside the application-owned FCM envelope. */ custom_data: import("@sinclair/typebox").TOptional>; }>>; windows: import("@sinclair/typebox").TOptional>; }>>; linux: import("@sinclair/typebox").TOptional>; }>>; }>>; }>; export type MediaItemT = Static; export type SourceContextT = Static; export type DeliveryPolicyT = Static; export type ReplyRequestT = Static; export type IosOptionsT = Static; export type DesktopOptionsT = Static; export type MacosOptionsT = Static; export type AndroidOptionsT = Static; export type NotificationDraftT = Static; export declare const NOTIFICATION_CONTRACT_FINGERPRINT: string; /** * Every fingerprint a service on this schema accepts: its own, then each * earlier schema whose every draft this one still accepts. A client sending * any other fingerprint is newer than the service and waits for it. */ export declare const ACCEPTED_NOTIFICATION_CONTRACT_FINGERPRINTS: readonly string[]; export declare function defaultDeliveryPolicy(): DeliveryPolicyT;