import { GroupInfo } from './table.js'; export interface NotificationRecord { api?: string; app_id?: string; enabled?: boolean; id?: string; model?: string; name?: string; v2?: boolean; } export type ParsedNotificationKey = { id: string; kind: 'hex'; } | { id: string; kind: 'system_id'; } | { kind: 'app_full'; model: string; name: string; slug: string; } | { kind: 'app_short'; name: string; slug: string; } | { kind: 'bare'; name: string; } | { input: string; kind: 'invalid'; }; /** * Translate a stored model path into its display form. * * apps// (own-app prefix is implicit in the slug) * apps// → apps// * apps// → unchanged (preserve a paste-back form) * → unchanged * * Stripping `apps//` keeps the common case readable; the rare collision * with a same-named built-in (e.g. an app model literally named * `subscriptions`) is recovered by `expandModelCandidates` at lookup time. */ export declare function normalizeModelForDisplay(model: string, ownAppId: string | undefined, appSlugById: Record): string; /** * Produce the column-1 paste-back key for a notification. * * System (no app_id): record.id verbatim — already in `com..` form. * App with model+name: `app...` * Anything else: record.id (degenerate, no meaningful slug) * * Notification identity is `(api, model, name, app_id?)`; collapsing on * `(app_id, name)` alone caused two `notify_me.back-in-stock` rows * (different `model`) to render identically. */ export declare function formatNotificationKey(record: NotificationRecord, appSlugById: Record): string; /** * Group a notification record. System rows (no app_id) are not store data — * they belong to the platform and render under a `system` divider at the top. */ export declare function groupNotificationRecord(record: NotificationRecord, appSlugById: Record): GroupInfo; /** * Classify a notification identifier. The base `classifyIdentifier` collapses * every dot-segment after `app..` into `name`, which loses the model. * Notifications need a model-aware split, so they bypass the base classifier. * * Recognised shapes: * - 24-char hex → hex (delegate to base GET-by-id) * - com. → system_id (canonical platform id) * - app... → app_full (triplet lookup) * - app.. → app_short (3-part legacy; ambiguous) * - bare → bare (requires --app= scope; ambiguous) * - anything else → invalid * * Multi-segment names (e.g. `unpaid.v2`) only appear in system notifications, * which arrive via the `com.*` form and never go through `app.*` parsing. */ export declare function parseNotificationKey(input: string): ParsedNotificationKey; /** * Render the disambiguation error body when a `(app_id, name)` query returns * multiple notifications. Caller fetches with `limit = displayLimit + 1` so * we can detect overflow without paging through the whole result set; if * `results.length > displayLimit`, the surplus rows are dropped and a hint * line is appended directing the user to the full key form. */ export declare function formatDisambiguationError(results: NotificationRecord[], appSlugById: Record, identifier: string, displayLimit?: number): string; /** * Build the `template` value used on send records at `/notifications` from a * manifest record's fields. Three shapes: * * System (no app_id): . * App on a standard model: app_.. * App on a custom (apps//x) model: app_.apps__. * * The custom-model branch transforms slashes to underscores in the model * segment. * * V2 system notifications have `name` literally ending in `.v2` (mirroring the * `id` and the `v2: true` flag), but the send-record `template` strips that * suffix. App notifications carry `v2: true` without the suffix in `name`, so * they pass through unchanged. * * Returns undefined when `model` or `name` is missing. */ export declare function buildNotificationTemplate(record: NotificationRecord): string | undefined; /** * Expand a display-form model into the candidate stored values to try at * lookup time. A bare display token can mean either: * - the literal built-in model (e.g. `subscriptions`) * - an own-app model whose `apps//` prefix was stripped for display * so we try both. `apps//x` is resolved to `apps//x`; an already-hex * `apps//x` passes through unchanged. */ export declare function expandModelCandidates(modelDisplay: string, appId: string, resolveAppId: (slug: string) => Promise): Promise;