easy-ping 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -5
- package/dist/{adapter-D3lTy-4E.d.cts → adapter-BJ8Iejvs.d.cts} +1 -1
- package/dist/{adapter-D3lTy-4E.d.ts → adapter-BJ8Iejvs.d.ts} +1 -1
- package/dist/adapters/drizzle.d.cts +1 -1
- package/dist/adapters/drizzle.d.ts +1 -1
- package/dist/adapters/mongodb.d.cts +2 -2
- package/dist/adapters/mongodb.d.ts +2 -2
- package/dist/adapters/mysql.d.cts +2 -2
- package/dist/adapters/mysql.d.ts +2 -2
- package/dist/adapters/postgres.d.cts +2 -2
- package/dist/adapters/postgres.d.ts +2 -2
- package/dist/adapters/sqlite.d.cts +2 -2
- package/dist/adapters/sqlite.d.ts +2 -2
- package/dist/{chunk-USQ6CQTJ.js → chunk-JOVIZXO6.js} +105 -54
- package/dist/chunk-JOVIZXO6.js.map +1 -0
- package/dist/chunk-R3BE67L7.js +13 -0
- package/dist/chunk-R3BE67L7.js.map +1 -0
- package/dist/chunk-SSHVZHSJ.js +100 -0
- package/dist/chunk-SSHVZHSJ.js.map +1 -0
- package/dist/client.cjs +12 -3
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +6 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +12 -3
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +106 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +7 -14
- package/dist/index.js.map +1 -1
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +1 -1
- package/dist/{plugin-Cg9usuUi.d.ts → plugin-CSLKKgXT.d.ts} +1 -1
- package/dist/{plugin-CHd2ZiGC.d.cts → plugin-Wwp1nvo0.d.cts} +1 -1
- package/dist/plugins/digests.d.cts +2 -2
- package/dist/plugins/digests.d.ts +2 -2
- package/dist/plugins/preferences-client.d.cts +2 -2
- package/dist/plugins/preferences-client.d.ts +2 -2
- package/dist/plugins/preferences-react.d.cts +1 -1
- package/dist/plugins/preferences-react.d.ts +1 -1
- package/dist/plugins/preferences.cjs +3 -3
- package/dist/plugins/preferences.cjs.map +1 -1
- package/dist/plugins/preferences.d.cts +2 -2
- package/dist/plugins/preferences.d.ts +2 -2
- package/dist/plugins/preferences.js +2 -2
- package/dist/plugins/preferences.js.map +1 -1
- package/dist/plugins/push.cjs +2 -2
- package/dist/plugins/push.cjs.map +1 -1
- package/dist/plugins/push.d.cts +2 -2
- package/dist/plugins/push.d.ts +2 -2
- package/dist/plugins/push.js +1 -1
- package/dist/plugins/telegram.cjs +379 -0
- package/dist/plugins/telegram.cjs.map +1 -0
- package/dist/plugins/telegram.d.cts +153 -0
- package/dist/plugins/telegram.d.ts +153 -0
- package/dist/plugins/telegram.js +313 -0
- package/dist/plugins/telegram.js.map +1 -0
- package/dist/providers/telegram.cjs +103 -0
- package/dist/providers/telegram.cjs.map +1 -0
- package/dist/providers/telegram.d.cts +83 -0
- package/dist/providers/telegram.d.ts +83 -0
- package/dist/providers/telegram.js +3 -0
- package/dist/providers/telegram.js.map +1 -0
- package/dist/providers/web-push.d.cts +2 -2
- package/dist/providers/web-push.d.ts +2 -2
- package/dist/react.cjs +12 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -0
- package/dist/react.d.ts +6 -0
- package/dist/react.js +12 -3
- package/dist/react.js.map +1 -1
- package/dist/schema.d.cts +2 -2
- package/dist/schema.d.ts +2 -2
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +16 -4
- package/dist/chunk-USQ6CQTJ.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/base64url.ts","../src/core/config.ts","../src/core/definition.ts","../src/core/errors.ts","../src/core/signals.ts","../src/core/tokens.ts","../src/core/handler.ts","../src/core/html.ts","../src/core/rate-limit.ts","../src/core/backoff.ts","../src/core/runner.ts","../src/core/send.ts","../src/schema/declaration.ts","../src/core/store.ts","../src/core/instance.ts","../src/core/plugin.ts"],"names":["message","encoder","route","bucket","handler"],"mappings":"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","file":"index.cjs","sourcesContent":["// Web APIs, not Buffer: this runs on Workers and Vercel Edge.\n\nexport function encodeBase64Url(input: string | Uint8Array): string {\n const bytes = typeof input === \"string\" ? new TextEncoder().encode(input) : input;\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// Uint8Array<ArrayBuffer>: bare Uint8Array widens and is not a BufferSource.\nexport function decodeBase64UrlBytes(value: string): Uint8Array<ArrayBuffer> | null {\n try {\n const binary = atob(value.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n return Uint8Array.from(binary, (char) => char.charCodeAt(0));\n } catch {\n return null;\n }\n}\n\nexport function decodeBase64Url(value: string): string | null {\n const bytes = decodeBase64UrlBytes(value);\n return bytes ? new TextDecoder().decode(bytes) : null;\n}\n","import type { DatabaseAdapter } from \"./adapter\";\nimport type { NotificationDefinitions, PayloadOf } from \"./definition\";\nimport type { Logger } from \"./errors\";\nimport type { AnyPlugin, Promisable, RouteScope } from \"./plugin\";\nimport type { EmailProvider } from \"./provider\";\nimport type { RateLimitConfig } from \"./rate-limit\";\nimport type { Signals } from \"./signals\";\nimport type { Channel, DeliveryMode, DeliveryRecord, Recipient, SkipReason } from \"./types\";\n\nexport type SessionConfig = {\n /** null yields 401; throwing yields 500. Deliberately distinct. */\n getUserId: (request: Request) => string | null | Promise<string | null>;\n};\n\nexport type DeliveryConfig = {\n mode?: DeliveryMode;\n maxAttempts?: number;\n /** Must exceed the slowest provider timeout, or duplicates are systematic. */\n leaseMs?: number;\n batchSize?: number;\n /** inline mode only. */\n throwOnError?: boolean;\n backoff?: \"exponential\" | ((attempt: number) => number);\n /** Next.js `after` or Cloudflare `ctx.waitUntil`. Injected, not detected. */\n waitUntil?: (promise: Promise<unknown>) => void;\n /**\n * Run one small claim-and-deliver pass after any request the handler serves,\n * at most once per `everyMs` per process. Delivery then rides on your own\n * traffic and the cron becomes a backstop. Ignored in `inline` mode. RFC 0006 idea 5.\n */\n sweepOnRequest?: true | { everyMs?: number; limit?: number };\n};\n\nexport type EventsConfig = {\n /** Comment line keeping proxies from closing an idle stream. Default 25 s. */\n heartbeatMs?: number;\n /**\n * Without a cross-process signal source, each stream checks the database\n * for changes this often on its subscriber's behalf. Default 30 s; 0 disables.\n */\n probeIntervalMs?: number;\n /** Close the stream after this long; the client reconnects. 0 (default) leaves it open. */\n maxDurationMs?: number;\n};\n\nexport type ChannelsConfig = {\n inApp?: { enabled: boolean };\n email?: { provider: EmailProvider };\n};\n\nexport type EasyPingConfig<TDefs extends NotificationDefinitions> = {\n database: DatabaseAdapter;\n session: SessionConfig;\n /** Signs unsubscribe and other tokenised links. See RFC 0002 §5. */\n secret: string;\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n notifications: TDefs;\n channels: ChannelsConfig;\n delivery?: DeliveryConfig;\n /** Required by `cron` and `deferred` modes. See RFC 0002 §4. */\n cron?: {\n secret: string;\n /** Sweeps one POST /cron may run before returning. Defaults to 50. */\n maxSweeps?: number;\n };\n /** Bearer secret for plugin machine routes. Falls back to `cron.secret`. */\n machineSecret?: string;\n /** In-process fixed-window limiter, applied before routing. */\n rateLimit?: RateLimitConfig;\n /**\n * How \"something changed\" travels between the sender, the worker and open\n * event streams. Defaults to in-process. Supply a LISTEN/NOTIFY or change\n * stream implementation to cross replicas. RFC 0006 §4C.\n */\n signals?: Signals;\n /** `GET /events`, a Server-Sent Events stream per user. `false` unmounts it. */\n events?: EventsConfig | false;\n plugins?: readonly AnyPlugin[];\n /** Where the handler is mounted, used to strip the prefix off incoming URLs. */\n basePath?: string;\n /** Origins other than the request host that may POST. `\"*.example.com\"` matches subdomains. */\n trustedOrigins?: readonly string[];\n /** Runs before routing. Return a Response to short-circuit — a rate limiter's 429, say. */\n // biome-ignore lint/suspicious/noConfusingVoidType: a hook that returns nothing is the common case\n onRequest?: (request: Request) => Promisable<Response | undefined | void>;\n /** Defaults to 64 KiB. */\n maxBodyBytes?: number;\n /** Table-name prefix; must match the one given to the adapter. */\n tablePrefix?: string;\n logger?: Logger;\n};\n\nexport type SendArgs<TDefs extends NotificationDefinitions, TKey extends keyof TDefs> = {\n to: string | readonly string[];\n payload: PayloadOf<TDefs[TKey]>;\n actorId?: string;\n dedupeKey?: string;\n overrides?: { channels?: readonly Channel[] };\n};\n\nexport type SendResult = {\n notifications: readonly {\n id: string;\n userId: string;\n deliveries: readonly { id: string; channel: Channel }[];\n }[];\n skipped: readonly { userId: string; reason: SkipReason }[];\n};\n\nexport type Worker = {\n stop: () => Promise<void>;\n};\n\nexport type MountedRoute = {\n method: \"GET\" | \"POST\";\n path: string;\n scope: RouteScope;\n /** \"core\" for the built-in routes, otherwise the plugin id. */\n owner: string;\n};\n\nexport type HealthReport = {\n mode: DeliveryMode;\n cronMounted: boolean;\n /** True when the chosen mode relies on a cron sweep that is not wired up. */\n cronRequiredButMissing: boolean;\n warnings: readonly string[];\n};\n\n/** Response header carrying a per-user inbox version, so app traffic can replace polling. */\nexport const INBOX_VERSION_HEADER = \"x-easy-ping-inbox\";\n\nexport type EasyPing<TDefs extends NotificationDefinitions> = {\n send<TKey extends keyof TDefs & string>(\n type: TKey,\n args: SendArgs<TDefs, TKey>,\n ): Promise<SendResult>;\n\n handler: {\n /** Method-agnostic entry, for toNodeHandler and single-dispatch frameworks. */\n handle: (request: Request) => Promise<Response>;\n GET: (request: Request) => Promise<Response>;\n POST: (request: Request) => Promise<Response>;\n };\n\n /** Idle interval defaults to 10 s; a send in this process wakes the loop at once. */\n startWorker(options?: { intervalMs?: number; batchSize?: number }): Worker;\n healthCheck(): Promise<HealthReport>;\n\n /** Every mounted route with its auth scope, so `custom`-scoped ones stay visible. RFC 0002 §3. */\n listRoutes(): readonly MountedRoute[];\n\n /**\n * Headers to attach to any response your app sends this user. The client's\n * `instrument(fetch)` reads them and refreshes only when the version moved,\n * so an active user never needs a dedicated poll. RFC 0006 idea 1.\n */\n inboxHeaders(userId: string): Record<string, string>;\n\n /** Deliveries that exhausted their attempts, newest first. Wire it to an admin page or an alert. */\n getFailedDeliveries(options?: {\n /** Defaults to the last 24 hours. */\n since?: Date;\n /** Defaults to 100. */\n limit?: number;\n }): Promise<readonly DeliveryRecord[]>;\n};\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { Channel } from \"./types\";\n\nexport type PayloadFromSchema<TSchema> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : Record<string, unknown>;\n\nexport type EmailTemplate<TPayload> = {\n subject: (payload: TPayload) => string;\n /** Rendered HTML. react-email users wrap: `(p) => render(<Email {...p} />)`. */\n template: (payload: TPayload) => string | Promise<string>;\n};\n\nexport type NotificationDefinition<\n TSchema extends StandardSchemaV1 | undefined = StandardSchemaV1 | undefined,\n> = {\n schema?: TSchema;\n channels: readonly Channel[];\n maxAttempts?: number;\n email?: EmailTemplate<PayloadFromSchema<TSchema>>;\n};\n\n/** Binds TSchema so email callbacks infer the payload; TS cannot infer from a sibling property. */\nexport function defineNotification<TSchema extends StandardSchemaV1 | undefined = undefined>(\n definition: NotificationDefinition<TSchema>,\n): NotificationDefinition<TSchema> {\n return definition;\n}\n\n/** Erased form. `EmailTemplate<never>` because callbacks are contravariant. */\nexport type AnyNotificationDefinition = {\n schema?: StandardSchemaV1 | undefined;\n channels: readonly Channel[];\n maxAttempts?: number | undefined;\n email?: EmailTemplate<never> | undefined;\n};\n\nexport type NotificationDefinitions = Record<string, AnyNotificationDefinition>;\n\nexport type PayloadOf<TDef> = TDef extends { schema: infer TSchema extends StandardSchemaV1 }\n ? StandardSchemaV1.InferOutput<TSchema>\n : Record<string, unknown>;\n","export class EasyPingError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EasyPingError\";\n }\n}\n\n/** Thrown when a payload fails its Standard Schema. Developer error. */\nexport class ValidationError extends EasyPingError {\n readonly issues: readonly { message: string; path?: string }[];\n\n constructor(type: string, issues: readonly { message: string; path?: string }[]) {\n super(`Payload for \"${type}\" failed validation: ${issues.map((i) => i.message).join(\"; \")}`);\n this.name = \"ValidationError\";\n this.issues = issues;\n }\n}\n\n/** Thrown at startup for a malformed config. Never at send time. */\nexport class ConfigError extends EasyPingError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n\nexport type Logger = {\n warn: (message: string, meta?: Record<string, unknown>) => void;\n error: (message: string, meta?: Record<string, unknown>) => void;\n};\n\nexport const consoleLogger: Logger = {\n warn: (message, meta) => console.warn(`[easy-ping] ${message}`, meta ?? \"\"),\n error: (message, meta) => console.error(`[easy-ping] ${message}`, meta ?? \"\"),\n};\n","/**\n * The wake-up seam. A publish carries no payload: it says \"something changed\n * on this channel, go look\", so losing one costs latency, never data.\n * RFC 0006 §4C.\n */\nexport type Signals = {\n /** True when a publish in one process reaches subscribers in another. */\n readonly crossProcess: boolean;\n publish(channel: string): void;\n subscribe(channel: string, handler: () => void): () => void;\n close?(): Promise<void> | void;\n};\n\nexport const DELIVERIES_CHANNEL = \"deliveries\";\nexport const inboxChannel = (userId: string) => `inbox:${userId}`;\n\n/** In-process only. The default, and exactly right on SQLite or a single replica. */\nexport function createMemorySignals(): Signals {\n const handlers = new Map<string, Set<() => void>>();\n\n return {\n crossProcess: false,\n publish(channel) {\n const set = handlers.get(channel);\n if (!set) return;\n for (const handler of [...set]) {\n queueMicrotask(() => {\n try {\n handler();\n } catch {\n // a subscriber's failure is its own problem\n }\n });\n }\n },\n subscribe(channel, handler) {\n let set = handlers.get(channel);\n if (!set) {\n set = new Set();\n handlers.set(channel, set);\n }\n set.add(handler);\n return () => {\n set?.delete(handler);\n if (set?.size === 0) handlers.delete(channel);\n };\n },\n };\n}\n\n/**\n * Wraps a cross-process transport (LISTEN/NOTIFY, a change stream) so local\n * subscribers still hear local publishes even if the transport drops them,\n * and a transport failure degrades to in-process rather than to silence.\n */\nexport function createBridgedSignals(\n transport: {\n publish(channel: string): Promise<void> | void;\n subscribe(channel: string, handler: () => void): Promise<() => void> | (() => void);\n },\n onError: (error: unknown) => void,\n): Signals {\n const local = createMemorySignals();\n const remoteUnsubscribes = new Map<string, Promise<() => void>>();\n const counts = new Map<string, number>();\n\n return {\n crossProcess: true,\n publish(channel) {\n local.publish(channel);\n Promise.resolve()\n .then(() => transport.publish(channel))\n .catch(onError);\n },\n subscribe(channel, handler) {\n const unsubscribeLocal = local.subscribe(channel, handler);\n counts.set(channel, (counts.get(channel) ?? 0) + 1);\n\n if (!remoteUnsubscribes.has(channel)) {\n remoteUnsubscribes.set(\n channel,\n Promise.resolve()\n .then(() => transport.subscribe(channel, () => local.publish(channel)))\n .catch((error) => {\n onError(error);\n return () => {};\n }),\n );\n }\n\n return () => {\n unsubscribeLocal();\n const remaining = (counts.get(channel) ?? 1) - 1;\n if (remaining > 0) {\n counts.set(channel, remaining);\n return;\n }\n counts.delete(channel);\n const pending = remoteUnsubscribes.get(channel);\n remoteUnsubscribes.delete(channel);\n pending?.then((unsubscribe) => unsubscribe()).catch(onError);\n };\n },\n };\n}\n","import { decodeBase64Url, decodeBase64UrlBytes, encodeBase64Url } from \"./base64url\";\n\nexport type TokenClaims = {\n /** Subject — the user the token acts for. */\n uid: string;\n /** What the token is allowed to do. Verification requires an exact match. */\n purpose: string;\n /** Expiry, epoch seconds. */\n exp: number;\n /** Issued at, epoch seconds. Set by signToken; lets a route refuse a token older than a later change. */\n iat?: number;\n /** Free-form, purpose-specific. */\n data?: Record<string, string>;\n};\n\nconst encoder = new TextEncoder();\n\n// Changing this invalidates every outstanding token. Bump it on purpose only.\nconst KEY_SALT = encoder.encode(\"easy-ping/tokens/v1\");\n\n/** One HMAC key per purpose, derived with HKDF, so an unsubscribe key signs nothing else. */\nasync function hmacKey(secret: string, purpose: string): Promise<CryptoKey> {\n const master = await crypto.subtle.importKey(\"raw\", encoder.encode(secret), \"HKDF\", false, [\n \"deriveKey\",\n ]);\n return crypto.subtle.deriveKey(\n { name: \"HKDF\", hash: \"SHA-256\", salt: KEY_SALT, info: encoder.encode(purpose) },\n master,\n { name: \"HMAC\", hash: \"SHA-256\", length: 256 },\n false,\n [\"sign\", \"verify\"],\n );\n}\n\nexport async function signToken(\n secret: string,\n claims: TokenClaims,\n now: Date = new Date(),\n): Promise<string> {\n const stamped: TokenClaims = { ...claims, iat: claims.iat ?? Math.floor(now.getTime() / 1000) };\n const body = encodeBase64Url(JSON.stringify(stamped));\n const signature = await crypto.subtle.sign(\n \"HMAC\",\n await hmacKey(secret, claims.purpose),\n encoder.encode(body),\n );\n return `${body}.${encodeBase64Url(new Uint8Array(signature))}`;\n}\n\n/** null for every failure mode. Distinguishing them tells an attacker which part to fix. */\nexport async function verifyToken(\n secret: string,\n token: string,\n purpose: string,\n now: Date = new Date(),\n): Promise<TokenClaims | null> {\n const separator = token.lastIndexOf(\".\");\n if (separator <= 0) return null;\n\n const body = token.slice(0, separator);\n const signature = decodeBase64UrlBytes(token.slice(separator + 1));\n if (!signature) return null;\n\n // Verified under the expected purpose's key before the body is parsed. subtle.verify is constant-time.\n const valid = await crypto.subtle.verify(\n \"HMAC\",\n await hmacKey(secret, purpose),\n signature,\n encoder.encode(body),\n );\n if (!valid) return null;\n\n const decoded = decodeBase64Url(body);\n if (!decoded) return null;\n\n let claims: TokenClaims;\n try {\n claims = JSON.parse(decoded) as TokenClaims;\n } catch {\n return null;\n }\n\n if (typeof claims?.uid !== \"string\" || typeof claims.exp !== \"number\") return null;\n if (claims.purpose !== purpose) return null;\n if (claims.exp * 1000 <= now.getTime()) return null;\n if (claims.iat !== undefined && typeof claims.iat !== \"number\") return null;\n\n if (claims.data !== undefined) {\n if (typeof claims.data !== \"object\" || claims.data === null || Array.isArray(claims.data)) {\n return null;\n }\n for (const value of Object.values(claims.data)) {\n if (typeof value !== \"string\") return null;\n }\n }\n\n return claims;\n}\n\nexport const DEFAULT_TOKEN_TTL_SECONDS = 30 * 24 * 60 * 60;\n/** Ninety days. A link that must outlive this should be re-issued, not made immortal. */\nexport const MAX_TOKEN_TTL_SECONDS = 90 * 24 * 60 * 60;\n\nexport const expiresIn = (seconds: number, now: Date = new Date()): number =>\n Math.floor(now.getTime() / 1000) + Math.min(Math.max(seconds, 0), MAX_TOKEN_TTL_SECONDS);\n\nexport type SignRequest = {\n uid: string;\n purpose: string;\n data?: Record<string, string>;\n /** Defaults to 30 days, capped at 90. */\n ttlSeconds?: number;\n};\n\n/** What a plugin gets instead of the secret: signs only its own declared purposes. */\nexport function createScopedSigner(\n secret: string,\n pluginId: string,\n purposes: ReadonlySet<string>,\n onViolation: (message: string) => Error,\n): (request: SignRequest) => Promise<string> {\n return (request) => {\n if (!purposes.has(request.purpose)) {\n throw onViolation(\n `plugin \"${pluginId}\" tried to sign a token for purpose \"${request.purpose}\", ` +\n \"which none of its signed routes declare.\",\n );\n }\n return signToken(secret, {\n uid: request.uid,\n purpose: request.purpose,\n exp: expiresIn(request.ttlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS),\n ...(request.data ? { data: request.data } : {}),\n });\n };\n}\n","import type { DatabaseAdapter } from \"./adapter\";\nimport type { SessionConfig } from \"./config\";\nimport type { Logger } from \"./errors\";\nimport type { Promisable, RouteDefinition } from \"./plugin\";\nimport type { Runner } from \"./runner\";\nimport { inboxChannel, type Signals } from \"./signals\";\nimport { verifyToken } from \"./tokens\";\n\nexport type EventsSettings = {\n heartbeatMs: number;\n probeIntervalMs: number;\n maxDurationMs: number;\n};\n\nexport type HandlerDeps = {\n adapter: DatabaseAdapter;\n session: SessionConfig;\n runner: Runner;\n logger: Logger;\n basePath: string;\n secret: string;\n signals: Signals;\n /** `false` unmounts GET /events. */\n events: EventsSettings | false;\n /** Fire-and-forget delivery pass after a request. Rate-limited by the instance. */\n sweepOnRequest?: (() => void) | undefined;\n cronSecret?: string | undefined;\n /** Guards plugin machine routes. The instance defaults it to cronSecret. */\n machineSecret?: string | undefined;\n cronMaxSweeps?: number | undefined;\n pluginRoutes?: readonly RouteDefinition[] | undefined;\n /** Returns a 429 to send, or null to proceed. Runs after onRequest, before routing. */\n rateLimit?: ((request: Request) => Response | null) | undefined;\n /** Origins other than the request's own host that may POST. `*.example.com` allowed. */\n trustedOrigins?: readonly string[] | undefined;\n /** Runs before routing. Returning a Response short-circuits; use it for rate limiting. */\n // biome-ignore lint/suspicious/noConfusingVoidType: a hook that returns nothing is the common case\n onRequest?: ((request: Request) => Promisable<Response | undefined | void>) | undefined;\n maxBodyBytes?: number | undefined;\n};\n\n/** Every JSON body is capped here. Nothing legitimate the routes accept is bigger. */\nexport const MAX_BODY_BYTES = 64 * 1024;\n\nconst MAX_READ_IDS = 200;\n\n// Per-user data: no shared caching, no sniffing.\nconst PRIVATE_HEADERS: Record<string, string> = {\n \"cache-control\": \"private, no-store\",\n \"x-content-type-options\": \"nosniff\",\n};\n\nconst json = (body: unknown, status = 200) =>\n new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json\", ...PRIVATE_HEADERS },\n });\n\nconst empty = (status: number) => new Response(null, { status, headers: PRIVATE_HEADERS });\n\n/** Plugin responses get the same headers, without touching their body. */\nfunction harden(response: Response): Response {\n const headers = new Headers(response.headers);\n for (const [name, value] of Object.entries(PRIVATE_HEADERS)) {\n if (!headers.has(name)) headers.set(name, value);\n }\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nconst encoder = new TextEncoder();\n\n/** Constant time over SHA-256 digests, so neither content nor length leaks. Works on edge runtimes. */\nasync function timingSafeEqual(a: string, b: string): Promise<boolean> {\n const [left, right] = await Promise.all(\n [a, b].map(\n async (value) => new Uint8Array(await crypto.subtle.digest(\"SHA-256\", encoder.encode(value))),\n ),\n );\n let diff = 0;\n for (let i = 0; i < 32; i += 1) diff |= (left?.[i] ?? 0) ^ (right?.[i] ?? 0);\n return diff === 0;\n}\n\n/** Anchored at a segment boundary: `/foo/api/notifications/cron` is not a cron request. */\nfunction routePath(url: URL, basePath: string): string {\n const { pathname } = url;\n if (pathname === basePath) return \"/\";\n if (pathname.startsWith(`${basePath}/`)) return pathname.slice(basePath.length);\n return pathname;\n}\n\nexport type JsonBody = { body: Record<string, unknown> } | { error: Response };\n\n/** Reads a JSON object body with a streaming byte cap. Malformed JSON is 400; an empty body is `{}`. */\nexport async function readJsonBody(\n request: Request,\n maxBytes: number = MAX_BODY_BYTES,\n): Promise<JsonBody> {\n const tooLarge = () => ({ error: json({ error: `body exceeds ${maxBytes} bytes` }, 413) });\n\n const declared = Number(request.headers.get(\"content-length\"));\n if (Number.isFinite(declared) && declared > maxBytes) return tooLarge();\n if (!request.body) return { body: {} };\n\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel();\n return tooLarge();\n }\n chunks.push(value);\n }\n\n const bytes = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n const text = new TextDecoder().decode(bytes);\n if (text.trim() === \"\") return { body: {} };\n\n try {\n const parsed: unknown = JSON.parse(text);\n return {\n body:\n parsed && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {},\n };\n } catch {\n return { error: json({ error: \"body must be a JSON object\" }, 400) };\n }\n}\n\nconst isJsonContentType = (request: Request) =>\n /^application\\/json\\s*(;|$)/i.test((request.headers.get(\"content-type\") ?? \"\").trim());\n\nfunction originAllowed(origin: string, url: URL, request: Request, trusted: readonly string[]) {\n let host: string;\n try {\n host = new URL(origin).host;\n } catch {\n return false;\n }\n\n if (host === url.host) return true;\n // Behind a proxy that rewrites Host, the public host arrives here instead.\n const forwarded = request.headers.get(\"x-forwarded-host\")?.split(\",\")[0]?.trim();\n if (forwarded && host === forwarded) return true;\n\n return trusted.some((entry) =>\n entry.startsWith(\"*.\") ? host.endsWith(entry.slice(1)) : entry === origin,\n );\n}\n\n/** CSRF: a cross-site form can neither send `application/json` without a preflight nor forge `Origin`. */\nfunction csrfCheck(request: Request, url: URL, trusted: readonly string[]): Response | null {\n if (!isJsonContentType(request)) {\n return json({ error: \"content-type must be application/json\" }, 415);\n }\n\n const origin = request.headers.get(\"origin\");\n if (origin === null) return null;\n if (origin === \"null\" || !originAllowed(origin, url, request, trusted)) return empty(403);\n\n return null;\n}\n\nexport function createHandler(deps: HandlerDeps) {\n const trustedOrigins = deps.trustedOrigins ?? [];\n const maxBodyBytes = deps.maxBodyBytes ?? MAX_BODY_BYTES;\n\n async function resolveUserId(request: Request): Promise<string | null | \"error\"> {\n try {\n return await deps.session.getUserId(request);\n } catch (error) {\n // A broken session lookup is a 500, never a 401. RFC 0002 §1.\n deps.logger.error(\"session.getUserId threw\", { error });\n return \"error\";\n }\n }\n\n async function bearerMatches(request: Request, secret: string | undefined): Promise<boolean> {\n if (!secret) return false;\n const header = request.headers.get(\"authorization\") ?? \"\";\n const presented = header.startsWith(\"Bearer \") ? header.slice(7) : header;\n return timingSafeEqual(presented, secret);\n }\n\n async function handleCron(request: Request): Promise<Response> {\n if (!deps.cronSecret) return empty(404);\n if (!(await bearerMatches(request, deps.cronSecret))) return empty(401);\n\n // Bounded so an overlapping scheduler does not hold a request open for the whole backlog.\n const result = await deps.runner.drain(\n deps.cronMaxSweeps === undefined ? {} : { maxSweeps: deps.cronMaxSweeps },\n );\n return json(result);\n }\n\n /** Plugin routes first; auth is enforced here so a plugin cannot forget it. */\n async function handlePluginRoute(\n route: RouteDefinition,\n request: Request,\n url: URL,\n ): Promise<Response> {\n if (route.scope.type === \"user\") {\n if (request.method === \"POST\") {\n const rejected = csrfCheck(request, url, trustedOrigins);\n if (rejected) return rejected;\n }\n\n const userId = await resolveUserId(request);\n if (userId === \"error\") return empty(500);\n if (userId === null) return empty(401);\n return harden(await route.handler({ request, userId, claims: null, params: {} }));\n }\n\n if (route.scope.type === \"machine\") {\n if (!deps.machineSecret) return empty(404);\n if (!(await bearerMatches(request, deps.machineSecret))) return empty(401);\n return harden(await route.handler({ request, userId: null, claims: null, params: {} }));\n }\n\n if (route.scope.type === \"signed\") {\n const token =\n url.searchParams.get(\"token\") ??\n (request.headers.get(\"authorization\") ?? \"\").replace(/^Bearer /, \"\");\n\n const claims = await verifyToken(deps.secret, token, route.scope.purpose);\n // One response for every failure mode. RFC 0002 §5.\n if (!claims) return empty(400);\n\n return harden(await route.handler({ request, userId: claims.uid, claims, params: {} }));\n }\n\n return harden(await route.handler({ request, userId: null, claims: null, params: {} }));\n }\n\n async function route(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const path = routePath(url, deps.basePath);\n\n if (deps.onRequest) {\n const early = await deps.onRequest(request);\n if (early instanceof Response) return early;\n }\n\n if (deps.rateLimit) {\n const limited = deps.rateLimit(request);\n if (limited) return limited;\n }\n\n if (path === \"/cron\") {\n if (request.method !== \"POST\") return empty(405);\n return handleCron(request);\n }\n\n const pluginRoute = deps.pluginRoutes?.find(\n (candidate) => candidate.path === path && candidate.method === request.method,\n );\n if (pluginRoute) return handlePluginRoute(pluginRoute, request, url);\n\n if (request.method === \"POST\") {\n const rejected = csrfCheck(request, url, trustedOrigins);\n if (rejected) return rejected;\n }\n\n const userId = await resolveUserId(request);\n if (userId === \"error\") return empty(500);\n if (userId === null) return empty(401);\n\n if (request.method === \"GET\" && path === \"/events\") {\n return deps.events ? events(request, userId, deps.events) : empty(404);\n }\n\n if (request.method === \"GET\" && path === \"/\") {\n const limitParam = Number(url.searchParams.get(\"limit\") ?? 20);\n const limit = Number.isFinite(limitParam) ? Math.min(Math.max(limitParam, 1), 100) : 20;\n const cursor = url.searchParams.get(\"cursor\");\n\n // unseenCount rides on the first page only: a cursor request is scrollback, not a poll.\n const [page, unseenCount] = await Promise.all([\n deps.adapter.listNotifications({\n userId,\n limit,\n ...(cursor ? { cursor } : {}),\n ...(url.searchParams.get(\"unreadOnly\") === \"true\" ? { unreadOnly: true } : {}),\n }),\n cursor ? Promise.resolve(null) : deps.adapter.countUnseen(userId),\n ]);\n\n return json(unseenCount === null ? page : { ...page, unseenCount });\n }\n\n if (request.method === \"GET\" && path === \"/count\") {\n return json({ unseen: await deps.adapter.countUnseen(userId) });\n }\n\n if (request.method === \"POST\" && path === \"/seen\") {\n const parsed = await readJsonBody(request, maxBodyBytes);\n if (\"error\" in parsed) return parsed.error;\n const before = typeof parsed.body.before === \"string\" ? new Date(parsed.body.before) : null;\n\n // +1ms: Postgres keeps microseconds, an ISO string milliseconds; without it markSeen misses the newest row.\n const cutoff =\n before && !Number.isNaN(before.getTime()) ? new Date(before.getTime() + 1) : new Date();\n\n await deps.adapter.markSeen(userId, cutoff);\n deps.signals.publish(inboxChannel(userId));\n return json({ ok: true });\n }\n\n if (request.method === \"POST\" && path === \"/read\") {\n const parsed = await readJsonBody(request, maxBodyBytes);\n if (\"error\" in parsed) return parsed.error;\n const ids = Array.isArray(parsed.body.ids)\n ? parsed.body.ids.filter((id): id is string => typeof id === \"string\")\n : [];\n if (ids.length === 0) return json({ error: \"ids must be a non-empty string array\" }, 400);\n\n if (ids.length > MAX_READ_IDS) {\n return json({ error: `at most ${MAX_READ_IDS} ids per request` }, 400);\n }\n\n // 404, not 403: a 403 confirms the row exists. RFC 0002 §2.\n const updated = await deps.adapter.markRead(userId, ids);\n if (updated > 0) deps.signals.publish(inboxChannel(userId));\n return updated === 0 ? empty(404) : json({ updated });\n }\n\n if (request.method === \"POST\" && path === \"/read-all\") {\n const updated = await deps.adapter.markAllRead(userId);\n if (updated > 0) deps.signals.publish(inboxChannel(userId));\n return json({ updated });\n }\n\n return empty(404);\n }\n\n /** A change fingerprint cheap enough to take every probe interval. */\n async function fingerprint(userId: string): Promise<string> {\n const [page, unseen] = await Promise.all([\n deps.adapter.listNotifications({ userId, limit: 1 }),\n deps.adapter.countUnseen(userId),\n ]);\n const newest = page.notifications[0];\n return `${newest?.id ?? \"\"}|${newest?.readAt ? 1 : 0}|${unseen}`;\n }\n\n /**\n * Server-Sent Events: `ready` once, `changed` whenever this user's inbox\n * moves, comments as keepalive. No payload ever travels on the stream; the\n * client fetches the feed on `changed`. RFC 0006 §4D.\n */\n function events(request: Request, userId: string, settings: EventsSettings): Response {\n const encoder = new TextEncoder();\n const timers: ReturnType<typeof setInterval>[] = [];\n let unsubscribe: (() => void) | undefined;\n let closed = false;\n let cleanup = () => {};\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n const write = (text: string) => {\n if (closed) return;\n try {\n controller.enqueue(encoder.encode(text));\n } catch {\n cleanup();\n }\n };\n cleanup = () => {\n if (closed) return;\n closed = true;\n unsubscribe?.();\n for (const timer of timers) clearInterval(timer);\n try {\n controller.close();\n } catch {\n // already closed by the consumer\n }\n };\n const changed = () => write(\"event: changed\\ndata: {}\\n\\n\");\n\n write(\"retry: 3000\\n\\nevent: ready\\ndata: {}\\n\\n\");\n unsubscribe = deps.signals.subscribe(inboxChannel(userId), changed);\n timers.push(setInterval(() => write(\": keepalive\\n\\n\"), settings.heartbeatMs));\n\n if (!deps.signals.crossProcess && settings.probeIntervalMs > 0) {\n let last: string | undefined;\n fingerprint(userId)\n .then((value) => {\n last = value;\n })\n .catch(() => {});\n timers.push(\n setInterval(() => {\n fingerprint(userId)\n .then((value) => {\n if (last !== undefined && value !== last) changed();\n last = value;\n })\n .catch((error) => deps.logger.error(\"events probe failed\", { error }));\n }, settings.probeIntervalMs),\n );\n }\n\n if (settings.maxDurationMs > 0) {\n timers.push(\n setTimeout(cleanup, settings.maxDurationMs) as ReturnType<typeof setInterval>,\n );\n }\n request.signal?.addEventListener(\"abort\", cleanup, { once: true });\n },\n cancel() {\n cleanup();\n },\n });\n\n return new Response(stream, {\n headers: {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache, no-store\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n \"x-content-type-options\": \"nosniff\",\n },\n });\n }\n\n async function handle(request: Request): Promise<Response> {\n try {\n return await route(request);\n } catch (error) {\n // A thrown driver error must not escape: unhandled rejection on Node, stack trace elsewhere.\n deps.logger.error(\"request failed\", { url: request.url, error });\n return empty(500);\n } finally {\n deps.sweepOnRequest?.();\n }\n }\n\n return {\n handle,\n GET: handle,\n POST: handle,\n };\n}\n","const ESCAPES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n};\n\n/** For template literals: anything a user typed goes through this, or their HTML ships from your domain. */\nexport const escapeHtml = (value: unknown): string =>\n String(value ?? \"\").replace(/[&<>\"']/g, (char) => ESCAPES[char] ?? char);\n","export type RateLimitConfig = {\n /** Requests allowed per key per window. */\n max: number;\n windowMs: number;\n /** Bucket key. Defaults to the client address from proxy headers; null exempts the request. */\n key?: (request: Request) => string | null;\n};\n\nconst clientAddress = (request: Request): string | null => {\n const headers = request.headers;\n return (\n headers.get(\"cf-connecting-ip\") ??\n headers.get(\"x-real-ip\") ??\n headers.get(\"x-forwarded-for\")?.split(\",\")[0]?.trim() ??\n null\n );\n};\n\n/** Fixed window in process memory: per isolate or replica, so a bound rather than a quota. */\nexport function createRateLimiter(config: RateLimitConfig): (request: Request) => Response | null {\n const keyOf = config.key ?? clientAddress;\n const buckets = new Map<string, { count: number; resetAt: number }>();\n let lastSweep = 0;\n\n return (request) => {\n const key = keyOf(request);\n if (key === null) return null;\n\n const now = Date.now();\n\n // Sweep expired buckets at most once per window.\n if (now - lastSweep > config.windowMs) {\n for (const [id, bucket] of buckets) if (bucket.resetAt <= now) buckets.delete(id);\n lastSweep = now;\n }\n\n let bucket = buckets.get(key);\n if (!bucket || bucket.resetAt <= now) {\n bucket = { count: 0, resetAt: now + config.windowMs };\n buckets.set(key, bucket);\n }\n\n bucket.count += 1;\n if (bucket.count <= config.max) return null;\n\n return new Response(null, {\n status: 429,\n headers: {\n \"retry-after\": String(Math.max(1, Math.ceil((bucket.resetAt - now) / 1000))),\n \"cache-control\": \"private, no-store\",\n },\n });\n };\n}\n","/** Exponential backoff with ±20% jitter, floored by the sweep interval. RFC 0001 §4. */\nconst SCHEDULE_MS = [30_000, 120_000, 480_000, 1_920_000] as const;\n\nexport type Backoff = \"exponential\" | ((attempt: number) => number);\n\nexport function backoffMs(attempt: number, strategy: Backoff = \"exponential\"): number {\n if (typeof strategy === \"function\") return Math.max(0, strategy(attempt));\n\n const index = Math.min(Math.max(attempt, 1), SCHEDULE_MS.length) - 1;\n const base = SCHEDULE_MS[index] ?? SCHEDULE_MS[SCHEDULE_MS.length - 1] ?? 30_000;\n return Math.round(base * (0.8 + Math.random() * 0.4));\n}\n\nexport const nextAttemptAt = (attempt: number, strategy?: Backoff, now = new Date()): Date =>\n new Date(now.getTime() + backoffMs(attempt, strategy));\n","import type { ClaimedDelivery, DatabaseAdapter, DeliveryOutcome, DeliveryRelease } from \"./adapter\";\nimport { type Backoff, nextAttemptAt } from \"./backoff\";\nimport type { ChannelsConfig, Worker } from \"./config\";\nimport type { NotificationDefinitions } from \"./definition\";\nimport type { Logger } from \"./errors\";\nimport type { AnyPlugin } from \"./plugin\";\nimport { DELIVERIES_CHANNEL, type Signals } from \"./signals\";\nimport type { Channel, Recipient } from \"./types\";\n\nexport type RunnerDeps = {\n adapter: DatabaseAdapter;\n definitions: NotificationDefinitions;\n channels: ChannelsConfig;\n plugins: readonly AnyPlugin[];\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n logger: Logger;\n leaseMs: number;\n batchSize: number;\n backoff: Backoff;\n /** Wakes an idle worker the moment a send commits, so the idle interval can be long. */\n signals?: Signals | undefined;\n};\n\n/** Long on purpose: a send in this process wakes the loop, and the cron sweep backstops the rest. */\nexport const DEFAULT_WORKER_IDLE_MS = 10_000;\n\nexport type SweepResult = {\n claimed: number;\n sent: number;\n failed: number;\n /** Deliveries that had nothing to do. Not errors; see DeliveryOutcome. */\n skipped: number;\n};\n\nasync function withTimeout<T>(\n run: (signal: AbortSignal) => Promise<T>,\n ms: number,\n label: string,\n): Promise<T> {\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n // Abort first: racing a promise leaves the original request running.\n controller.abort();\n reject(new Error(`${label} timed out after ${ms}ms`));\n }, ms);\n });\n\n try {\n return await Promise.race([run(controller.signal), timeout]);\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** Persisted to `last_error`, which admin tooling reads: addresses do not go in. */\nexport const redactErrorMessage = (text: string) =>\n text.replace(/[^\\s\"'<>()[\\]{},;]+@[^\\s\"'<>()[\\]{},;]+/g, \"[redacted-email]\");\n\nconst message = (error: unknown) =>\n redactErrorMessage(error instanceof Error ? error.message : String(error));\n\nexport function createRunner(deps: RunnerDeps) {\n async function deliverOne(\n delivery: ClaimedDelivery,\n recipient: Recipient | undefined,\n ): Promise<DeliveryOutcome> {\n if (!recipient) {\n return { result: \"failed\", error: \"recipient could not be resolved\", retryable: false };\n }\n\n if (delivery.channel === \"inApp\") {\n // The notification row is the delivery. Nothing to transmit.\n return { result: \"sent\" };\n }\n\n if (delivery.channel === \"email\") {\n const provider = deps.channels.email?.provider;\n if (!provider) {\n return { result: \"failed\", error: \"no email provider configured\", retryable: false };\n }\n // Captured before the closure below: narrowing does not survive into it.\n const to = recipient.email;\n if (!to) {\n return { result: \"failed\", error: \"recipient has no email address\", retryable: false };\n }\n\n const email = deps.definitions[delivery.notification.type]?.email;\n if (!email) {\n return {\n result: \"failed\",\n error: `notification type \"${delivery.notification.type}\" has no email template`,\n retryable: false,\n };\n }\n\n try {\n const payload = delivery.notification.payload as never;\n const html = await email.template(payload);\n\n await withTimeout(\n (signal) =>\n provider.send({\n to,\n subject: email.subject(payload),\n html,\n // Delivery is at-least-once; the provider dedupes on this.\n idempotencyKey: delivery.id,\n signal,\n }),\n provider.timeoutMs ?? 30_000,\n `${provider.name} send`,\n );\n\n return { result: \"sent\" };\n } catch (error) {\n return {\n result: \"failed\",\n error: message(error),\n retryable: provider.isRetryable(error),\n };\n }\n }\n\n const owner = deps.plugins.find(\n (plugin) => plugin.channels?.includes(delivery.channel) && plugin.hooks?.deliver,\n );\n if (!owner?.hooks?.deliver) {\n return {\n result: \"failed\",\n error: `no plugin delivers channel \"${delivery.channel}\"`,\n retryable: false,\n };\n }\n\n try {\n return await withTimeout(\n (signal) =>\n Promise.resolve(\n // biome-ignore lint/style/noNonNullAssertion: guarded directly above\n owner.hooks!.deliver!({\n channel: delivery.channel,\n deliveryId: delivery.id,\n attempt: delivery.attempts + 1,\n recipient,\n notification: {\n id: delivery.notificationId,\n userId: delivery.notification.userId,\n type: delivery.notification.type,\n payload: delivery.notification.payload,\n },\n signal,\n }),\n ),\n 30_000,\n `plugin \"${owner.id}\" deliver`,\n );\n } catch (error) {\n return { result: \"failed\", error: message(error), retryable: true };\n }\n }\n\n async function notifyAfterDeliver(delivery: ClaimedDelivery, outcome: DeliveryOutcome) {\n const isTerminal =\n outcome.result !== \"failed\" ||\n !outcome.retryable ||\n delivery.attempts + 1 >= delivery.maxAttempts;\n\n for (const plugin of deps.plugins) {\n const hook = plugin.hooks?.afterDeliver;\n if (!hook) continue;\n try {\n await hook({\n deliveryId: delivery.id,\n notificationId: delivery.notificationId,\n userId: delivery.notification.userId,\n channel: delivery.channel,\n outcome,\n attempt: delivery.attempts + 1,\n isTerminal,\n });\n } catch (error) {\n // Fail open: the message is already sent. RFC 0004 §5.\n deps.logger.error(`plugin \"${plugin.id}\" afterDeliver threw; ignoring`, {\n deliveryId: delivery.id,\n error,\n });\n }\n }\n }\n\n async function runOnce(\n options: { limit?: number; channels?: readonly Channel[]; ids?: readonly string[] } = {},\n ): Promise<SweepResult> {\n const claimToken = crypto.randomUUID();\n\n const claimed = await deps.adapter.claimPendingDeliveries({\n limit: options.limit ?? deps.batchSize,\n leaseMs: deps.leaseMs,\n claimToken,\n ...(options.channels ? { channels: options.channels } : {}),\n ...(options.ids ? { ids: options.ids } : {}),\n });\n\n if (claimed.length === 0) return { claimed: 0, sent: 0, failed: 0, skipped: 0 };\n\n const userIds = [...new Set(claimed.map((row) => row.notification.userId))];\n const recipients = await deps.getRecipients(userIds);\n const byUserId = new Map(recipients.map((recipient) => [recipient.userId, recipient]));\n\n const releases: DeliveryRelease[] = [];\n let sent = 0;\n let failed = 0;\n let skipped = 0;\n\n for (const delivery of claimed) {\n const outcome = await deliverOne(delivery, byUserId.get(delivery.notification.userId));\n\n if (outcome.result === \"sent\") sent += 1;\n else if (outcome.result === \"skipped\") skipped += 1;\n else failed += 1;\n\n releases.push({\n id: delivery.id,\n claimToken,\n outcome,\n ...(outcome.result === \"failed\" && outcome.retryable\n ? { nextAttemptAt: nextAttemptAt(delivery.attempts + 1, deps.backoff) }\n : {}),\n });\n\n await notifyAfterDeliver(delivery, outcome);\n }\n\n await deps.adapter.releaseDeliveries(releases);\n return { claimed: claimed.length, sent, failed, skipped };\n }\n\n /** Drains until empty. Pass `ids` to bound it to one send. */\n async function drain(\n options: { maxSweeps?: number; ids?: readonly string[] } = {},\n ): Promise<SweepResult> {\n const maxSweeps = options.maxSweeps ?? 50;\n const total: SweepResult = { claimed: 0, sent: 0, failed: 0, skipped: 0 };\n\n for (let sweep = 0; sweep < maxSweeps; sweep += 1) {\n const result = await runOnce(options.ids ? { ids: options.ids } : {});\n total.claimed += result.claimed;\n total.sent += result.sent;\n total.failed += result.failed;\n total.skipped += result.skipped;\n if (result.claimed === 0) break;\n }\n\n return total;\n }\n\n let warnedMissingWaitUntil = false;\n\n function scheduleDeferred(\n waitUntil?: (promise: Promise<unknown>) => void,\n ids?: readonly string[],\n ): void {\n if (waitUntil) {\n waitUntil(\n drain({ maxSweeps: 10, ...(ids ? { ids } : {}) }).catch((error) =>\n deps.logger.error(\"deferred sweep failed\", { error }),\n ),\n );\n return;\n }\n\n if (!warnedMissingWaitUntil) {\n warnedMissingWaitUntil = true;\n deps.logger.warn(\n \"delivery.mode is 'deferred' but no delivery.waitUntil was supplied — \" +\n \"falling back to the cron sweep. Notifications are not lost, but they \" +\n \"will not be delivered until POST /cron runs.\",\n );\n }\n }\n\n function startWorker(options: { intervalMs?: number; batchSize?: number } = {}): Worker {\n const intervalMs = options.intervalMs ?? DEFAULT_WORKER_IDLE_MS;\n let stopped = false;\n let wake: (() => void) | undefined;\n let pending = false;\n\n const unsubscribe = deps.signals?.subscribe(DELIVERIES_CHANNEL, () => {\n pending = true;\n wake?.();\n });\n\n // Sleeps for the interval, or until a send publishes, whichever is first.\n const idle = (ms: number) =>\n new Promise<void>((resolve) => {\n if (pending) {\n pending = false;\n resolve();\n return;\n }\n const timer = setTimeout(done, ms);\n function done() {\n clearTimeout(timer);\n wake = undefined;\n pending = false;\n resolve();\n }\n wake = done;\n });\n\n const loop = (async () => {\n while (!stopped) {\n try {\n const result = await runOnce({ limit: options.batchSize ?? deps.batchSize });\n // Only idle when there was nothing to do; otherwise keep draining.\n if (result.claimed === 0 && !stopped) await idle(intervalMs);\n } catch (error) {\n deps.logger.error(\"worker sweep failed\", { error });\n if (!stopped) await idle(intervalMs);\n }\n }\n })();\n\n return {\n stop: async () => {\n stopped = true;\n unsubscribe?.();\n wake?.();\n // Let the in-flight sweep finish and release its leases.\n await loop;\n },\n };\n }\n\n return { runOnce, drain, scheduleDeferred, startWorker };\n}\n\nexport type Runner = ReturnType<typeof createRunner>;\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { DatabaseAdapter, InsertDelivery, InsertNotification } from \"./adapter\";\nimport type { ChannelsConfig, SendResult } from \"./config\";\nimport type { NotificationDefinitions } from \"./definition\";\nimport { type Logger, ValidationError } from \"./errors\";\nimport type { AnyPlugin, BeforeSendResult, ChannelDecision } from \"./plugin\";\nimport type { Channel, Recipient, SkipReason } from \"./types\";\n\nexport type SendPipelineDeps = {\n adapter: DatabaseAdapter;\n definitions: NotificationDefinitions;\n channels: ChannelsConfig;\n plugins: readonly AnyPlugin[];\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n maxAttempts: number;\n logger: Logger;\n generateId?: () => string;\n};\n\nexport type SendInput = {\n to: string | readonly string[];\n payload: unknown;\n actorId?: string | undefined;\n dedupeKey?: string | undefined;\n overrides?: { channels?: readonly Channel[] } | undefined;\n};\n\nasync function validatePayload(type: string, schema: StandardSchemaV1, payload: unknown) {\n const result = await schema[\"~standard\"].validate(payload);\n if (result.issues) {\n throw new ValidationError(\n type,\n result.issues.map((issue) => ({\n message: issue.message,\n ...(issue.path ? { path: issue.path.map(String).join(\".\") } : {}),\n })),\n );\n }\n return result.value;\n}\n\n/** inApp is on unless disabled; every other channel needs a provider or a plugin that delivers it. */\nexport function isChannelUsable(\n channel: Channel,\n channels: ChannelsConfig,\n plugins: readonly AnyPlugin[] = [],\n): boolean {\n if (channel === \"inApp\") return channels.inApp?.enabled !== false;\n if (channel === \"email\") return Boolean(channels.email?.provider);\n // Anything else is usable only if a plugin claims it and can deliver it.\n return plugins.some((plugin) => plugin.channels?.includes(channel) && plugin.hooks?.deliver);\n}\n\n/** One prepare() per plugin per send, keyed by plugin id. */\nasync function runPrepare(\n plugins: readonly AnyPlugin[],\n ctx: { type: string; recipients: readonly Recipient[] },\n logger: Logger,\n): Promise<Map<string, unknown>> {\n const prepared = new Map<string, unknown>();\n\n for (const plugin of plugins) {\n const hook = plugin.hooks?.prepare;\n if (!hook) continue;\n try {\n prepared.set(plugin.id, await hook(ctx));\n } catch (error) {\n // Fail closed: a failed bulk load must not decide with stale assumptions.\n logger.error(`plugin \"${plugin.id}\" prepare threw; its hooks will see undefined`, {\n type: ctx.type,\n error,\n });\n prepared.set(plugin.id, undefined);\n }\n }\n\n return prepared;\n}\n\nasync function runBeforeSend(\n plugins: readonly AnyPlugin[],\n base: { type: string; recipient: Recipient; actorId: string | null },\n payload: unknown,\n dedupeKey: string | null,\n prepared: Map<string, unknown>,\n logger: Logger,\n): Promise<BeforeSendResult> {\n let currentPayload = payload;\n let currentDedupeKey = dedupeKey;\n\n for (const plugin of plugins) {\n const hook = plugin.hooks?.beforeSend;\n if (!hook) continue;\n\n let result: BeforeSendResult;\n try {\n result = await hook({\n ...base,\n payload: currentPayload,\n dedupeKey: currentDedupeKey,\n prepared: prepared.get(plugin.id),\n });\n } catch (error) {\n // Fail closed: failing open would email people who opted out. RFC 0004 §5.\n logger.error(`plugin \"${plugin.id}\" beforeSend threw; cancelling send`, {\n type: base.type,\n userId: base.recipient.userId,\n error,\n });\n return { action: \"cancel\", reason: `plugin \"${plugin.id}\" beforeSend threw` };\n }\n\n if (result.action === \"cancel\") return result;\n if (result.payload !== undefined) currentPayload = result.payload;\n if (result.dedupeKey !== undefined) currentDedupeKey = result.dedupeKey;\n }\n\n return {\n action: \"continue\",\n payload: currentPayload,\n ...(currentDedupeKey === null ? {} : { dedupeKey: currentDedupeKey }),\n };\n}\n\nasync function runResolveChannels(\n plugins: readonly AnyPlugin[],\n base: { type: string; recipient: Recipient; payload: unknown },\n initial: readonly ChannelDecision[],\n prepared: Map<string, unknown>,\n logger: Logger,\n): Promise<readonly ChannelDecision[]> {\n let decisions = initial;\n\n for (const plugin of plugins) {\n const hook = plugin.hooks?.resolveChannels;\n if (!hook) continue;\n\n try {\n decisions = [...(await hook({ ...base, decisions, prepared: prepared.get(plugin.id) }))];\n } catch (error) {\n // Fail closed: keep the decisions already made. RFC 0004 §5.\n logger.error(`plugin \"${plugin.id}\" resolveChannels threw; keeping prior decisions`, {\n type: base.type,\n userId: base.recipient.userId,\n error,\n });\n return decisions;\n }\n }\n\n return decisions;\n}\n\nexport async function runSend(\n type: string,\n input: SendInput,\n deps: SendPipelineDeps,\n): Promise<SendResult> {\n const definition = deps.definitions[type];\n if (!definition) {\n throw new ValidationError(type, [{ message: `unknown notification type \"${type}\"` }]);\n }\n\n const payload = definition.schema\n ? await validatePayload(type, definition.schema, input.payload)\n : input.payload;\n\n const userIds = [...new Set(Array.isArray(input.to) ? input.to : [input.to as string])];\n const recipients = await deps.getRecipients(userIds);\n const byUserId = new Map(recipients.map((recipient) => [recipient.userId, recipient]));\n\n const newId = deps.generateId ?? (() => crypto.randomUUID());\n const skipped: { userId: string; reason: SkipReason }[] = [];\n const rows: InsertNotification[] = [];\n const actorId = input.actorId ?? null;\n\n const declared = input.overrides?.channels ?? definition.channels;\n const requested = declared.filter((channel) =>\n isChannelUsable(channel, deps.channels, deps.plugins),\n );\n\n // Distinct from \"no-channels\": a missing provider is not an opt-out.\n if (declared.length > 0 && requested.length === 0) {\n return {\n notifications: [],\n skipped: userIds.map((userId) => ({ userId, reason: \"channel-unavailable\" as const })),\n };\n }\n\n const prepared = await runPrepare(deps.plugins, { type, recipients }, deps.logger);\n\n for (const userId of userIds) {\n const recipient = byUserId.get(userId);\n if (!recipient) {\n skipped.push({ userId, reason: \"no-recipient\" });\n continue;\n }\n\n const before = await runBeforeSend(\n deps.plugins,\n { type, recipient, actorId },\n payload,\n input.dedupeKey ?? null,\n prepared,\n deps.logger,\n );\n\n if (before.action === \"cancel\") {\n skipped.push({ userId, reason: \"no-channels\" });\n continue;\n }\n\n const resolved = await runResolveChannels(\n deps.plugins,\n { type, recipient, payload: before.payload ?? payload },\n requested.map((channel) => ({ channel, action: \"send\" as const })),\n prepared,\n deps.logger,\n );\n\n const now = new Date();\n const deliveries: InsertDelivery[] = resolved\n .filter((decision) => decision.action !== \"skip\")\n .filter((decision) => isChannelUsable(decision.channel, deps.channels, deps.plugins))\n .map((decision) => ({\n id: newId(),\n channel: decision.channel,\n maxAttempts: definition.maxAttempts ?? deps.maxAttempts,\n // defer is just not_before; the claim query refuses rows whose time has not come. RFC 0004 §4.2.\n notBefore: decision.action === \"defer\" && decision.notBefore ? decision.notBefore : now,\n }));\n\n if (deliveries.length === 0) {\n skipped.push({ userId, reason: \"no-channels\" });\n continue;\n }\n\n const dedupeKey = before.action === \"continue\" ? before.dedupeKey : undefined;\n\n rows.push({\n id: newId(),\n userId,\n type,\n payload: before.payload ?? payload,\n ...(actorId ? { actorId } : {}),\n ...(dedupeKey ? { dedupeKey } : {}),\n deliveries,\n });\n }\n\n if (rows.length === 0) return { notifications: [], skipped };\n\n const { created, deduped } = await deps.adapter.createNotifications(rows);\n const createdSet = new Set(created);\n\n for (const row of rows) {\n if (deduped.includes(row.id)) skipped.push({ userId: row.userId, reason: \"deduped\" });\n }\n\n const notifications = rows\n .filter((row) => createdSet.has(row.id))\n .map((row) => ({\n id: row.id,\n userId: row.userId,\n deliveries: row.deliveries.map((delivery) => ({\n id: delivery.id,\n channel: delivery.channel,\n })),\n }));\n\n for (const plugin of deps.plugins) {\n const hook = plugin.hooks?.afterSend;\n if (!hook) continue;\n try {\n await hook({\n type,\n payload,\n notifications: notifications.map(({ id, userId }) => ({ id, userId })),\n prepared: prepared.get(plugin.id),\n });\n } catch (error) {\n // Fails open: the rows are committed.\n deps.logger.error(`plugin \"${plugin.id}\" afterSend threw; ignoring`, { type, error });\n }\n }\n\n return { notifications, skipped };\n}\n","import type { SchemaDeclaration } from \"../core/plugin\";\n\nexport const toSnakeCase = (value: string) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n\n/** Core tables in the plugin format. A drift test asserts it agrees with the Drizzle schema. */\nexport const coreSchema = {\n notification: {\n tableName: \"notification\",\n fields: {\n id: { type: \"string\", required: true },\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n payload: { type: \"json\", required: true },\n actorId: { type: \"string\" },\n groupKey: { type: \"string\" },\n dedupeKey: { type: \"string\" },\n seenAt: { type: \"date\" },\n readAt: { type: \"date\" },\n archivedAt: { type: \"date\" },\n createdAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"userId\", \"createdAt\"], name: \"notification_feed_idx\" },\n { on: [\"userId\", \"groupKey\"], name: \"notification_group_idx\" },\n { on: [\"userId\", \"dedupeKey\"], unique: true, name: \"notification_dedupe_idx\" },\n ],\n },\n\n notificationDelivery: {\n tableName: \"notification_delivery\",\n fields: {\n id: { type: \"string\", required: true },\n notificationId: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n status: { type: \"string\", required: true, default: \"pending\" },\n attempts: { type: \"number\", required: true, default: 0 },\n maxAttempts: { type: \"number\", required: true, default: 5 },\n notBefore: { type: \"date\", required: true, defaultNow: true },\n claimedAt: { type: \"date\" },\n claimedBy: { type: \"string\" },\n lastError: { type: \"string\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"status\", \"notBefore\"], name: \"delivery_claim_idx\" },\n { on: [\"notificationId\"], name: \"delivery_notification_idx\" },\n ],\n },\n\n notificationPreference: {\n tableName: \"notification_preference\",\n fields: {\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n enabled: { type: \"boolean\", required: true, default: true },\n frequency: { type: \"string\", required: true, default: \"instant\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"userId\", \"type\", \"channel\"],\n },\n} satisfies SchemaDeclaration;\n","import { toSnakeCase } from \"../schema/declaration\";\nimport { ConfigError } from \"./errors\";\nimport type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"./plugin\";\n\nexport type Scalar = string | number | boolean | Date | null;\n\n/** Operators are tagged objects so a bare value is always equality; json columns cannot be filtered. */\nexport type WhereCondition =\n | Scalar\n | { in: readonly (string | number)[] }\n | { lt: Date | number }\n | { lte: Date | number }\n | { gt: Date | number }\n | { gte: Date | number }\n | { not: Scalar };\n\nexport type WhereClause = Record<string, WhereCondition>;\n\nexport type QueryOptions = {\n limit?: number;\n orderBy?: { field: string; direction: \"asc\" | \"desc\" };\n};\n\nexport type UpsertOptions = { onConflict: readonly string[] };\n\n/** Table access for plugins, scoped to the tables the plugin declared. */\nexport type PluginStore = {\n find<T = Record<string, unknown>>(\n table: string,\n where?: WhereClause,\n options?: QueryOptions,\n ): Promise<T[]>;\n insert(table: string, rows: readonly Record<string, unknown>[]): Promise<number>;\n upsert(\n table: string,\n rows: readonly Record<string, unknown>[],\n options: UpsertOptions,\n ): Promise<number>;\n update(table: string, where: WhereClause, set: Record<string, unknown>): Promise<number>;\n remove(table: string, where: WhereClause): Promise<number>;\n};\n\nexport type TableStorage = {\n readonly naming?: \"snake_case\" | \"preserve\";\n readonly serializesJson?: boolean;\n\n queryTable(\n table: string,\n where: WhereClause,\n options: QueryOptions,\n ): Promise<Record<string, unknown>[]>;\n insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ): Promise<number>;\n updateRows(table: string, where: WhereClause, set: Record<string, unknown>): Promise<number>;\n deleteRows(table: string, where: WhereClause): Promise<number>;\n};\n\nconst OPERATORS = [\"in\", \"lt\", \"lte\", \"gt\", \"gte\", \"not\"] as const;\n\nexport const isOperator = (value: unknown): boolean =>\n typeof value === \"object\" &&\n value !== null &&\n !(value instanceof Date) &&\n OPERATORS.some((op) => Object.hasOwn(value, op));\n\nconst isScalar = (value: unknown): value is Scalar =>\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value instanceof Date;\n\n/** A forwarded JSON body can carry `{ $ne: … }`; refuse anything that is not a scalar or a known operator. */\nfunction assertCondition(pluginId: string, field: string, condition: unknown): void {\n if (isScalar(condition)) return;\n\n if (isOperator(condition)) {\n const operator = condition as Record<string, unknown>;\n const keys = Object.keys(operator);\n const [op] = keys;\n if (keys.length !== 1 || op === undefined) {\n throw new ConfigError(`plugin \"${pluginId}\" gave field \"${field}\" more than one operator.`);\n }\n const payload = operator[op];\n const valid =\n op === \"in\"\n ? Array.isArray(payload) &&\n payload.every((item) => typeof item === \"string\" || typeof item === \"number\")\n : isScalar(payload);\n if (valid) return;\n }\n\n throw new ConfigError(\n `plugin \"${pluginId}\" passed a non-scalar value for field \"${field}\"; ` +\n \"validate request bodies before querying with them.\",\n );\n}\n\nfunction assertValue(pluginId: string, field: string, spec: FieldDeclaration, value: unknown) {\n if (value === undefined || isScalar(value)) return;\n if (spec.type === \"json\" && typeof value === \"object\") return;\n throw new ConfigError(\n `plugin \"${pluginId}\" passed a non-scalar value for ${spec.type} field \"${field}\".`,\n );\n}\n\n/** Every table and column is checked against the plugin's own declaration. */\nexport function createPluginStore(\n pluginId: string,\n schema: SchemaDeclaration | undefined,\n storage: TableStorage,\n prefix: string,\n): PluginStore {\n const byTableName = new Map<string, TableDeclaration>();\n for (const declaration of Object.values(schema ?? {})) {\n byTableName.set(declaration.tableName, declaration);\n }\n\n function resolve(table: string): TableDeclaration {\n const declaration = byTableName.get(table);\n if (!declaration) {\n throw new ConfigError(\n `plugin \"${pluginId}\" accessed table \"${table}\", which it does not declare in schema().`,\n );\n }\n return declaration;\n }\n\n function checkFields(table: TableDeclaration, fields: Iterable<string>, context: string) {\n for (const field of fields) {\n // hasOwn, not a lookup: `constructor` and `__proto__` are not columns.\n const spec = Object.hasOwn(table.fields, field) ? table.fields[field] : undefined;\n if (!spec) {\n throw new ConfigError(\n `plugin \"${pluginId}\" used unknown field \"${field}\" on \"${table.tableName}\" (${context}).`,\n );\n }\n if (context === \"where\" && spec.type === \"json\") {\n throw new ConfigError(\n `plugin \"${pluginId}\" cannot filter on json field \"${field}\"; ` +\n \"a bare object value is indistinguishable from an operator.\",\n );\n }\n }\n }\n\n function checkWhere(table: TableDeclaration, where: WhereClause) {\n checkFields(table, Object.keys(where), \"where\");\n for (const [field, condition] of Object.entries(where)) {\n assertCondition(pluginId, field, condition);\n }\n }\n\n function checkRow(table: TableDeclaration, row: Record<string, unknown>, context: string) {\n checkFields(table, Object.keys(row), context);\n for (const [field, value] of Object.entries(row)) {\n const spec = table.fields[field];\n if (spec) assertValue(pluginId, field, spec, value);\n }\n }\n\n const qualified = (table: TableDeclaration) => prefix + table.tableName;\n\n // A document store keeps the declared names; a SQL adapter wants columns.\n const column = (field: string) => (storage.naming === \"preserve\" ? field : toSnakeCase(field));\n\n // json must reach postgres-js as text.\n const serialize = (table: TableDeclaration, row: Record<string, unknown>) => {\n if (storage.serializesJson === false) return row;\n\n const out: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(row)) {\n out[field] =\n table.fields[field]?.type === \"json\" && value !== null && value !== undefined\n ? JSON.stringify(value)\n : value;\n }\n return out;\n };\n\n return {\n async find(table, where = {}, options = {}) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n if (options.orderBy) checkFields(declaration, [options.orderBy.field], \"orderBy\");\n\n const rows = await storage.queryTable(qualified(declaration), where, options);\n\n // SELECT * returns snake_case; plugins read camelCase.\n return rows.map((row) => {\n const mapped: Record<string, unknown> = {};\n for (const field of Object.keys(declaration.fields)) {\n const value = row[column(field)];\n const type = declaration.fields[field]?.type;\n // Drivers differ on jsonb (parsed or text) and timestamptz (Date or text).\n if (type === \"json\" && typeof value === \"string\") mapped[field] = JSON.parse(value);\n else if (type === \"date\" && typeof value === \"string\") mapped[field] = new Date(value);\n // MySQL and SQLite have no boolean column; they hand back 0 and 1.\n else if (type === \"boolean\" && typeof value === \"number\") mapped[field] = value !== 0;\n else mapped[field] = value;\n }\n return mapped;\n }) as never;\n },\n\n async insert(table, rows) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"insert\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n );\n },\n\n async upsert(table, rows, options) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"upsert\");\n checkFields(declaration, options.onConflict, \"onConflict\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n options.onConflict,\n );\n },\n\n async update(table, where, set) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n checkRow(declaration, set, \"update\");\n return storage.updateRows(qualified(declaration), where, serialize(declaration, set));\n },\n\n async remove(table, where) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n return storage.deleteRows(qualified(declaration), where);\n },\n };\n}\n","import type { Backoff } from \"./backoff\";\nimport {\n type EasyPing,\n type EasyPingConfig,\n type HealthReport,\n INBOX_VERSION_HEADER,\n type MountedRoute,\n type SendArgs,\n type SendResult,\n} from \"./config\";\nimport type { NotificationDefinitions } from \"./definition\";\nimport { ConfigError, consoleLogger } from \"./errors\";\nimport { createHandler } from \"./handler\";\nimport type { AnyPlugin } from \"./plugin\";\nimport { createRateLimiter } from \"./rate-limit\";\nimport { createRunner } from \"./runner\";\nimport { isChannelUsable, runSend } from \"./send\";\nimport { createMemorySignals, DELIVERIES_CHANNEL, inboxChannel, type Signals } from \"./signals\";\nimport { createPluginStore } from \"./store\";\nimport { createScopedSigner } from \"./tokens\";\nimport type { DeliveryMode } from \"./types\";\n\nconst CORE_ROUTES: readonly MountedRoute[] = [\n { method: \"GET\", path: \"/\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"GET\", path: \"/count\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/seen\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/read\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/read-all\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"GET\", path: \"/events\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/cron\", scope: { type: \"machine\" }, owner: \"core\" },\n];\n\nconst DEFAULTS = {\n maxAttempts: 5,\n leaseMs: 60_000,\n batchSize: 20,\n basePath: \"/api/notifications\",\n mode: \"cron\" as DeliveryMode,\n};\n\nexport const MIN_SECRET_LENGTH = 16;\n\nconst PLACEHOLDER_SECRETS = new Set([\n \"secret\",\n \"changeme\",\n \"change-me\",\n \"replace-me\",\n \"replace-me-too\",\n \"password\",\n \"demo-signing-secret\",\n \"demo-cron-secret\",\n]);\n\nfunction checkSecretStrength(name: string, value: string) {\n if (value.length < MIN_SECRET_LENGTH || PLACEHOLDER_SECRETS.has(value.toLowerCase())) {\n throw new ConfigError(\n `\\`${name}\\` must be at least ${MIN_SECRET_LENGTH} characters and not a placeholder. ` +\n \"Generate one with `openssl rand -base64 32`.\",\n );\n }\n}\n\nfunction validate(config: EasyPingConfig<NotificationDefinitions>, plugins: readonly AnyPlugin[]) {\n if (!config.database) throw new ConfigError(\"`database` is required.\");\n if (!config.notifications) throw new ConfigError(\"`notifications` is required.\");\n\n // No default resolver and no dev bypass: an insecure default ships, a crash does not.\n if (typeof config.session?.getUserId !== \"function\") {\n throw new ConfigError(\n \"`session.getUserId` is required — the mounted endpoints serve a user's private inbox \" +\n \"and must resolve the caller. See RFC 0002.\",\n );\n }\n\n if (!config.secret) {\n throw new ConfigError(\n \"`secret` is required — it signs unsubscribe and other session-less links. \" +\n \"Adding it later is a breaking change, so it is mandatory from the start.\",\n );\n }\n checkSecretStrength(\"secret\", config.secret);\n if (config.cron?.secret) checkSecretStrength(\"cron.secret\", config.cron.secret);\n if (config.machineSecret) checkSecretStrength(\"machineSecret\", config.machineSecret);\n\n if (config.rateLimit && (config.rateLimit.max < 1 || config.rateLimit.windowMs < 1)) {\n throw new ConfigError(\"`rateLimit.max` and `rateLimit.windowMs` must both be positive.\");\n }\n\n if (typeof config.getRecipients !== \"function\") {\n throw new ConfigError(\"`getRecipients` is required to resolve emails and timezones.\");\n }\n\n const seen = new Set<string>();\n for (const plugin of plugins) {\n if (seen.has(plugin.id)) {\n throw new ConfigError(`duplicate plugin id \"${plugin.id}\" — ids must be unique.`);\n }\n seen.add(plugin.id);\n }\n\n for (const plugin of plugins) {\n for (const dependency of plugin.dependsOn ?? []) {\n if (!seen.has(dependency)) {\n throw new ConfigError(\n `plugin \"${plugin.id}\" requires \"${dependency}\", which is not registered.`,\n );\n }\n }\n }\n\n const routes = new Set<string>();\n for (const plugin of plugins) {\n for (const route of plugin.routes ?? []) {\n const signature = `${route.method} ${route.path}`;\n if (routes.has(signature)) {\n throw new ConfigError(`route collision: two plugins both registered \"${signature}\".`);\n }\n routes.add(signature);\n }\n }\n\n const mode = config.delivery?.mode ?? DEFAULTS.mode;\n if ((mode === \"cron\" || mode === \"deferred\") && !config.cron?.secret) {\n throw new ConfigError(\n `delivery.mode \"${mode}\" relies on the cron sweep, so \\`cron.secret\\` is required. ` +\n \"Left unset the endpoint would be unauthenticated — a free flush-everything trigger \" +\n \"against your email provider. See RFC 0002 §4.\",\n );\n }\n}\n\nexport function easyPing<TDefs extends NotificationDefinitions>(\n config: EasyPingConfig<TDefs>,\n): EasyPing<TDefs> {\n const plugins = config.plugins ?? [];\n validate(config as EasyPingConfig<NotificationDefinitions>, plugins);\n\n const logger = config.logger ?? consoleLogger;\n const tablePrefix = config.tablePrefix ?? \"\";\n const mode = config.delivery?.mode ?? DEFAULTS.mode;\n const leaseMs = config.delivery?.leaseMs ?? DEFAULTS.leaseMs;\n const warnings: string[] = [];\n\n // Below this ratio a slow send is re-claimed mid-flight. RFC 0003 §7.\n const providerTimeout = config.channels.email?.provider?.timeoutMs;\n if (providerTimeout !== undefined && providerTimeout >= leaseMs / 2) {\n warnings.push(\n `email provider timeout (${providerTimeout}ms) is at least half of delivery.leaseMs ` +\n `(${leaseMs}ms); raise leaseMs or duplicate sends become systematic.`,\n );\n }\n\n const unusable = new Map<string, string[]>();\n for (const [type, definition] of Object.entries(config.notifications)) {\n const missing = definition.channels.filter(\n (channel) => !isChannelUsable(channel, config.channels, plugins),\n );\n if (missing.length > 0) unusable.set(type, [...missing]);\n }\n\n for (const [type, channels] of unusable) {\n const dead = channels.length === config.notifications[type]?.channels.length;\n warnings.push(\n `notification \"${type}\" declares ${channels.map((c) => `\"${c}\"`).join(\", \")} ` +\n `but no provider is configured for ${channels.length > 1 ? \"them\" : \"it\"}` +\n (dead ? \" — this type can never be delivered.\" : \"; those channels will be skipped.\"),\n );\n }\n\n if (mode === \"deferred\" && !config.delivery?.waitUntil) {\n warnings.push(\n \"delivery.mode is 'deferred' but no delivery.waitUntil was supplied; \" +\n \"delivery will wait for the cron sweep.\",\n );\n }\n\n // Custom-scoped routes are named at startup with their justification. RFC 0002 §3.\n for (const plugin of plugins) {\n for (const route of plugin.routes ?? []) {\n if (route.scope.type === \"custom\") {\n warnings.push(\n `plugin \"${plugin.id}\" mounts ${route.method} ${route.path} with custom auth: ` +\n route.scope.justification,\n );\n }\n }\n }\n\n for (const warning of warnings) logger.warn(warning);\n\n const baseSignals = config.signals ?? createMemorySignals();\n\n // Per-user inbox versions for the piggyback header. In-process counters, so\n // another replica's number differs; the client treats any change as \"look\",\n // which costs a spurious refresh, never a missed one.\n const inboxVersions = new Map<string, number>();\n const signals: Signals = {\n crossProcess: baseSignals.crossProcess,\n publish(channel) {\n if (channel.startsWith(\"inbox:\")) {\n if (inboxVersions.size > 50_000) inboxVersions.clear();\n const userId = channel.slice(\"inbox:\".length);\n inboxVersions.set(userId, (inboxVersions.get(userId) ?? 0) + 1);\n }\n baseSignals.publish(channel);\n },\n subscribe: (channel, handler) => baseSignals.subscribe(channel, handler),\n };\n\n const runner = createRunner({\n adapter: config.database,\n definitions: config.notifications,\n channels: config.channels,\n plugins,\n getRecipients: config.getRecipients,\n logger,\n leaseMs,\n batchSize: config.delivery?.batchSize ?? DEFAULTS.batchSize,\n backoff: (config.delivery?.backoff ?? \"exponential\") as Backoff,\n signals,\n });\n\n const pluginRoutes = plugins.flatMap((plugin) => plugin.routes ?? []);\n\n const events =\n config.events === false\n ? false\n : {\n heartbeatMs: config.events?.heartbeatMs ?? 25_000,\n probeIntervalMs: config.events?.probeIntervalMs ?? 30_000,\n maxDurationMs: config.events?.maxDurationMs ?? 0,\n };\n\n const sweepConfig = config.delivery?.sweepOnRequest;\n let lastRequestSweep = 0;\n const sweepOnRequest =\n sweepConfig && mode !== \"inline\"\n ? () => {\n const settings = sweepConfig === true ? {} : sweepConfig;\n const now = Date.now();\n if (now - lastRequestSweep < (settings.everyMs ?? 5_000)) return;\n lastRequestSweep = now;\n const pass = runner\n .runOnce({ limit: settings.limit ?? 5 })\n .catch((error) => logger.error(\"request-driven sweep failed\", { error }));\n config.delivery?.waitUntil?.(pass);\n }\n : undefined;\n\n const handler = createHandler({\n adapter: config.database,\n session: config.session,\n runner,\n logger,\n secret: config.secret,\n signals,\n events,\n sweepOnRequest,\n basePath: config.basePath ?? DEFAULTS.basePath,\n pluginRoutes,\n trustedOrigins: config.trustedOrigins,\n onRequest: config.onRequest,\n maxBodyBytes: config.maxBodyBytes,\n rateLimit: config.rateLimit ? createRateLimiter(config.rateLimit) : undefined,\n cronMaxSweeps: config.cron?.maxSweeps,\n ...(config.cron?.secret ? { cronSecret: config.cron.secret } : {}),\n ...((config.machineSecret ?? config.cron?.secret)\n ? { machineSecret: config.machineSecret ?? config.cron?.secret }\n : {}),\n });\n\n async function send<TKey extends keyof TDefs & string>(\n type: TKey,\n args: SendArgs<TDefs, TKey>,\n ): Promise<SendResult> {\n const result = await runSend(\n type,\n {\n to: args.to,\n payload: args.payload,\n actorId: args.actorId,\n dedupeKey: args.dedupeKey,\n overrides: args.overrides,\n },\n {\n adapter: config.database,\n definitions: config.notifications,\n channels: config.channels,\n plugins,\n getRecipients: config.getRecipients,\n maxAttempts: config.delivery?.maxAttempts ?? DEFAULTS.maxAttempts,\n logger,\n },\n );\n\n // Rows are committed; everything below only affects latency. RFC 0001 §8.1.\n if (result.notifications.length > 0) {\n for (const notification of result.notifications) {\n signals.publish(inboxChannel(notification.userId));\n }\n signals.publish(DELIVERIES_CHANNEL);\n\n // Scoped to this send, or an inline send flushes the whole backlog.\n const ids = result.notifications.flatMap((notification) =>\n notification.deliveries.map((delivery) => delivery.id),\n );\n\n if (mode === \"inline\") await runner.drain({ ids });\n else if (mode === \"deferred\") runner.scheduleDeferred(config.delivery?.waitUntil, ids);\n }\n\n return result;\n }\n\n // After send() exists, before any hook or route can run.\n for (const plugin of plugins) {\n const purposes = new Set(\n (plugin.routes ?? []).flatMap((route) =>\n route.scope.type === \"signed\" ? [route.scope.purpose] : [],\n ),\n );\n plugin.init?.({\n store: createPluginStore(plugin.id, plugin.schema, config.database, tablePrefix),\n sign: createScopedSigner(\n config.secret,\n plugin.id,\n purposes,\n (message) => new ConfigError(message),\n ),\n logger,\n notificationTypes: Object.keys(config.notifications),\n getRecipients: config.getRecipients,\n send: (type, args) => send(type as keyof TDefs & string, args as never) as Promise<unknown>,\n });\n }\n\n return {\n send,\n handler,\n\n startWorker: (options) => runner.startWorker(options ?? {}),\n\n inboxHeaders: (userId) => ({\n [INBOX_VERSION_HEADER]: String(inboxVersions.get(userId) ?? 0),\n }),\n\n listRoutes: () => [\n ...CORE_ROUTES.filter(\n (route) =>\n (route.path !== \"/cron\" || Boolean(config.cron?.secret)) &&\n (route.path !== \"/events\" || events !== false),\n ),\n ...plugins.flatMap((plugin) =>\n (plugin.routes ?? []).map((route) => ({\n method: route.method,\n path: route.path,\n scope: route.scope,\n owner: plugin.id,\n })),\n ),\n ],\n\n getFailedDeliveries: (options = {}) =>\n config.database.getFailedDeliveries({\n since: options.since ?? new Date(Date.now() - 24 * 3600_000),\n limit: Math.min(options.limit ?? 100, 1000),\n }),\n\n healthCheck: async (): Promise<HealthReport> => {\n const cronMounted = Boolean(config.cron?.secret);\n return {\n mode,\n cronMounted,\n cronRequiredButMissing:\n !cronMounted && (mode === \"cron\" || mode === \"deferred\" || mode === \"inline\"),\n warnings,\n };\n },\n };\n}\n","import type { DeliveryOutcome } from \"./adapter\";\nimport type { Logger } from \"./errors\";\nimport type { PluginStore } from \"./store\";\nimport type { SignRequest, TokenClaims } from \"./tokens\";\nimport type { Channel, Recipient } from \"./types\";\n\nexport type Promisable<T> = T | Promise<T>;\n\nexport type PrepareContext = {\n type: string;\n recipients: readonly Recipient[];\n};\n\nexport type BeforeSendContext = {\n type: string;\n recipient: Recipient;\n payload: unknown;\n actorId: string | null;\n dedupeKey: string | null;\n /** Whatever this plugin's own prepare() returned for this send. */\n prepared: unknown;\n};\n\nexport type BeforeSendResult =\n | { action: \"continue\"; payload?: unknown; dedupeKey?: string }\n | { action: \"cancel\"; reason: string };\n\nexport type ChannelDecision = {\n channel: Channel;\n action: \"send\" | \"skip\" | \"defer\";\n /** defer only. Written to notification_delivery.not_before. */\n notBefore?: Date | undefined;\n};\n\nexport type ResolveChannelsContext = {\n type: string;\n recipient: Recipient;\n payload: unknown;\n decisions: readonly ChannelDecision[];\n /** Whatever this plugin's own prepare() returned for this send. */\n prepared: unknown;\n};\n\nexport type DeliverContext = {\n channel: Channel;\n deliveryId: string;\n attempt: number;\n recipient: Recipient;\n notification: { id: string; userId: string; type: string; payload: unknown };\n /** Aborted on the runner's timeout. */\n signal: AbortSignal;\n};\n\nexport type AfterSendContext = {\n type: string;\n payload: unknown;\n /** Committed rows. Ids exist only at this point. */\n notifications: readonly { id: string; userId: string }[];\n /** Whatever this plugin's own prepare() returned for this send. */\n prepared: unknown;\n};\n\nexport type AfterDeliverContext = {\n deliveryId: string;\n notificationId: string;\n userId: string;\n channel: Channel;\n outcome: DeliveryOutcome;\n attempt: number;\n isTerminal: boolean;\n};\n\n/** beforeSend and resolveChannels fail closed; afterDeliver fails open. */\nexport type PluginHooks = {\n /** Once per send, for bulk loading — the per-recipient hooks would be an N+1. */\n prepare?: (ctx: PrepareContext) => Promisable<unknown>;\n beforeSend?: (ctx: BeforeSendContext) => Promisable<BeforeSendResult>;\n resolveChannels?: (ctx: ResolveChannelsContext) => Promisable<readonly ChannelDecision[]>;\n /** Once per send, after commit. The only hook that sees notification ids. Fails open. */\n afterSend?: (ctx: AfterSendContext) => Promisable<void>;\n /** Delivers one of the plugin's declared `channels`. Core carries inApp and email. */\n deliver?: (ctx: DeliverContext) => Promisable<DeliveryOutcome>;\n afterDeliver?: (ctx: AfterDeliverContext) => Promisable<void>;\n};\n\nexport type FieldType = \"string\" | \"number\" | \"boolean\" | \"date\" | \"json\";\n\nexport type FieldDeclaration = {\n type: FieldType;\n required?: boolean;\n default?: string | number | boolean;\n /** date fields only. Renders as defaultNow() / CURRENT_TIMESTAMP. */\n defaultNow?: boolean;\n};\n\nexport type IndexDeclaration = {\n on: readonly string[];\n unique?: boolean;\n name?: string;\n};\n\nexport type TableDeclaration = {\n tableName: string;\n fields: Record<string, FieldDeclaration>;\n primaryKey?: readonly string[];\n indexes?: readonly IndexDeclaration[];\n};\n\nexport type SchemaDeclaration = Record<string, TableDeclaration>;\n\nexport type RouteScope =\n | { type: \"user\" }\n | { type: \"machine\" }\n | { type: \"signed\"; purpose: string }\n | { type: \"custom\"; justification: string };\n\nexport type RouteContext = {\n request: Request;\n /** Resolved for user-scoped routes, so a handler cannot forget to scope. */\n userId: string | null;\n /** Verified before dispatch, so a handler cannot forget to check. */\n claims: TokenClaims | null;\n params: Record<string, string>;\n};\n\nexport type RouteDefinition = {\n path: string;\n method: \"GET\" | \"POST\";\n scope: RouteScope;\n handler: (ctx: RouteContext) => Promise<Response>;\n};\n\n/** Handed to a plugin at startup so it need not be given the database twice. */\nexport type PluginInitContext = {\n /** Scoped to the tables this plugin declares in schema(). */\n store: PluginStore;\n /** Mints tokens for this plugin's own `signed` routes only. The secret itself is never handed out. */\n sign: (request: SignRequest) => Promise<string>;\n logger: Logger;\n /** Configured notification names, so a route can refuse to store rows for types that do not exist. */\n notificationTypes: readonly string[];\n /** The app's resolver, for plugins that need timezones or addresses. */\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n /** The instance's own send(), so a composed message inherits retry, backoff and idempotency. */\n send: (\n type: string,\n args: { to: string | readonly string[]; payload: unknown; dedupeKey?: string },\n ) => Promise<unknown>;\n};\n\nexport type EasyPingPlugin<\n TId extends string = string,\n TSchema extends SchemaDeclaration = SchemaDeclaration,\n> = {\n id: TId;\n dependsOn?: readonly string[];\n schema?: TSchema;\n routes?: readonly RouteDefinition[];\n hooks?: PluginHooks;\n /** Channels this plugin delivers. Makes them usable in a notification. */\n channels?: readonly Channel[];\n /** Called once by easyPing() before any hook or route can run. */\n init?: (ctx: PluginInitContext) => void;\n};\n\nexport type AnyPlugin = EasyPingPlugin<string, SchemaDeclaration>;\n\nexport function definePlugin<TId extends string, TSchema extends SchemaDeclaration>(\n plugin: EasyPingPlugin<TId, TSchema>,\n): EasyPingPlugin<TId, TSchema> {\n return plugin;\n}\n\nexport type ClientFetch = (path: string, init?: RequestInit) => Promise<unknown>;\n\nexport type ClientPlugin<\n TId extends string = string,\n TActions extends Record<string, unknown> = Record<string, unknown>,\n> = {\n id: TId;\n /** Phantom. Links client types to the server plugin so a mismatch is a type error. */\n $InferServerPlugin?: AnyPlugin;\n actions: (fetch: ClientFetch) => TActions;\n};\n\nexport type AnyClientPlugin = ClientPlugin<string, Record<string, unknown>>;\n\nexport function defineClientPlugin<TId extends string, TActions extends Record<string, unknown>>(\n plugin: ClientPlugin<TId, TActions>,\n): ClientPlugin<TId, TActions> {\n return plugin;\n}\n\nexport type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n/** Naked type parameter, so the conditional distributes over the union. */\ntype ExtractActions<TPlugin> = TPlugin extends { actions: (fetch: never) => infer TActions }\n ? TActions\n : never;\n\n/** Indexes the tuple rather than recursing: a fold blows the instantiation depth limit. */\nexport type ActionsOf<TPlugins extends readonly AnyClientPlugin[]> = UnionToIntersection<\n ExtractActions<TPlugins[number]>\n>;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/base64url.ts","../src/core/config.ts","../src/core/definition.ts","../src/core/errors.ts","../src/core/signals.ts","../src/core/tokens.ts","../src/core/handler.ts","../src/core/html.ts","../src/core/rate-limit.ts","../src/core/backoff.ts","../src/core/runner.ts","../src/core/send.ts","../src/schema/declaration.ts","../src/core/store.ts","../src/core/instance.ts","../src/core/plugin.ts"],"names":["message","encoder","route","bucket","handler"],"mappings":"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","file":"index.cjs","sourcesContent":["// Web APIs, not Buffer: this runs on Workers and Vercel Edge.\n\nexport function encodeBase64Url(input: string | Uint8Array): string {\n const bytes = typeof input === \"string\" ? new TextEncoder().encode(input) : input;\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// Uint8Array<ArrayBuffer>: bare Uint8Array widens and is not a BufferSource.\nexport function decodeBase64UrlBytes(value: string): Uint8Array<ArrayBuffer> | null {\n try {\n const binary = atob(value.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n return Uint8Array.from(binary, (char) => char.charCodeAt(0));\n } catch {\n return null;\n }\n}\n\nexport function decodeBase64Url(value: string): string | null {\n const bytes = decodeBase64UrlBytes(value);\n return bytes ? new TextDecoder().decode(bytes) : null;\n}\n","import type { DatabaseAdapter } from \"./adapter\";\nimport type { NotificationDefinitions, PayloadOf } from \"./definition\";\nimport type { Logger } from \"./errors\";\nimport type { AnyPlugin, Promisable, RouteScope } from \"./plugin\";\nimport type { EmailProvider } from \"./provider\";\nimport type { RateLimitConfig } from \"./rate-limit\";\nimport type { Signals } from \"./signals\";\nimport type { Channel, DeliveryMode, DeliveryRecord, Recipient, SkipReason } from \"./types\";\n\nexport type SessionConfig = {\n /** null yields 401; throwing yields 500. Deliberately distinct. */\n getUserId: (request: Request) => string | null | Promise<string | null>;\n};\n\nexport type DeliveryConfig = {\n mode?: DeliveryMode;\n maxAttempts?: number;\n /** Must exceed the slowest provider timeout, or duplicates are systematic. */\n leaseMs?: number;\n batchSize?: number;\n /** inline mode only. */\n throwOnError?: boolean;\n backoff?: \"exponential\" | ((attempt: number) => number);\n /** Next.js `after` or Cloudflare `ctx.waitUntil`. Injected, not detected. */\n waitUntil?: (promise: Promise<unknown>) => void;\n /**\n * Run one small claim-and-deliver pass after any request the handler serves,\n * at most once per `everyMs` per process. Delivery then rides on your own\n * traffic and the cron becomes a backstop. Ignored in `inline` mode. RFC 0006 idea 5.\n */\n sweepOnRequest?: true | { everyMs?: number; limit?: number };\n};\n\nexport type EventsConfig = {\n /** Comment line keeping proxies from closing an idle stream. Default 25 s. */\n heartbeatMs?: number;\n /**\n * Without a cross-process signal source, each stream checks the database\n * for changes this often on its subscriber's behalf. Default 30 s; 0 disables.\n */\n probeIntervalMs?: number;\n /** Concurrent streams one user may hold in this process before a 429. Default 10. */\n maxStreamsPerUser?: number;\n /** Concurrent streams this process holds in total before a 503. Default 5000. */\n maxStreams?: number;\n /** Close the stream after this long; the client reconnects. 0 (default) leaves it open. */\n maxDurationMs?: number;\n};\n\nexport type ChannelsConfig = {\n inApp?: { enabled: boolean };\n email?: { provider: EmailProvider };\n};\n\nexport type EasyPingConfig<TDefs extends NotificationDefinitions> = {\n database: DatabaseAdapter;\n session: SessionConfig;\n /** Signs unsubscribe and other tokenised links. See RFC 0002 §5. */\n secret: string;\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n notifications: TDefs;\n channels: ChannelsConfig;\n delivery?: DeliveryConfig;\n /** Required by `cron` and `deferred` modes. See RFC 0002 §4. */\n cron?: {\n secret: string;\n /** Sweeps one POST /cron may run before returning. Defaults to 50. */\n maxSweeps?: number;\n };\n /** Bearer secret for plugin machine routes. Falls back to `cron.secret`. */\n machineSecret?: string;\n /** In-process fixed-window limiter, applied before routing. */\n rateLimit?: RateLimitConfig;\n /**\n * How \"something changed\" travels between the sender, the worker and open\n * event streams. Defaults to in-process. Supply a LISTEN/NOTIFY or change\n * stream implementation to cross replicas. RFC 0006 §4C.\n */\n signals?: Signals;\n /** `GET /events`, a Server-Sent Events stream per user. `false` unmounts it. */\n events?: EventsConfig | false;\n plugins?: readonly AnyPlugin[];\n /** Where the handler is mounted, used to strip the prefix off incoming URLs. */\n basePath?: string;\n /** Origins other than the request host that may POST. `\"*.example.com\"` matches subdomains. */\n trustedOrigins?: readonly string[];\n /** Runs before routing. Return a Response to short-circuit — a rate limiter's 429, say. */\n // biome-ignore lint/suspicious/noConfusingVoidType: a hook that returns nothing is the common case\n onRequest?: (request: Request) => Promisable<Response | undefined | void>;\n /** Defaults to 64 KiB. */\n maxBodyBytes?: number;\n /** Table-name prefix; must match the one given to the adapter. */\n tablePrefix?: string;\n logger?: Logger;\n};\n\nexport type SendArgs<TDefs extends NotificationDefinitions, TKey extends keyof TDefs> = {\n to: string | readonly string[];\n payload: PayloadOf<TDefs[TKey]>;\n actorId?: string;\n dedupeKey?: string;\n overrides?: { channels?: readonly Channel[] };\n};\n\nexport type SendResult = {\n notifications: readonly {\n id: string;\n userId: string;\n deliveries: readonly { id: string; channel: Channel }[];\n }[];\n skipped: readonly { userId: string; reason: SkipReason }[];\n};\n\nexport type Worker = {\n stop: () => Promise<void>;\n};\n\nexport type MountedRoute = {\n method: \"GET\" | \"POST\";\n path: string;\n scope: RouteScope;\n /** \"core\" for the built-in routes, otherwise the plugin id. */\n owner: string;\n};\n\nexport type HealthReport = {\n mode: DeliveryMode;\n cronMounted: boolean;\n /** True when the chosen mode relies on a cron sweep that is not wired up. */\n cronRequiredButMissing: boolean;\n warnings: readonly string[];\n};\n\n/** Response header carrying a per-user inbox version, so app traffic can replace polling. */\nexport const INBOX_VERSION_HEADER = \"x-easy-ping-inbox\";\n\nexport type EasyPing<TDefs extends NotificationDefinitions> = {\n send<TKey extends keyof TDefs & string>(\n type: TKey,\n args: SendArgs<TDefs, TKey>,\n ): Promise<SendResult>;\n\n handler: {\n /** Method-agnostic entry, for toNodeHandler and single-dispatch frameworks. */\n handle: (request: Request) => Promise<Response>;\n GET: (request: Request) => Promise<Response>;\n POST: (request: Request) => Promise<Response>;\n };\n\n /** Idle interval defaults to 10 s; a send in this process wakes the loop at once. */\n startWorker(options?: { intervalMs?: number; batchSize?: number }): Worker;\n healthCheck(): Promise<HealthReport>;\n\n /** Every mounted route with its auth scope, so `custom`-scoped ones stay visible. RFC 0002 §3. */\n listRoutes(): readonly MountedRoute[];\n\n /**\n * Headers to attach to any response your app sends this user. The client's\n * `instrument(fetch)` reads them and refreshes only when the version moved,\n * so an active user never needs a dedicated poll. RFC 0006 idea 1.\n */\n inboxHeaders(userId: string): Record<string, string>;\n\n /** Deliveries that exhausted their attempts, newest first. Wire it to an admin page or an alert. */\n getFailedDeliveries(options?: {\n /** Defaults to the last 24 hours. */\n since?: Date;\n /** Defaults to 100. */\n limit?: number;\n }): Promise<readonly DeliveryRecord[]>;\n};\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { Channel } from \"./types\";\n\nexport type PayloadFromSchema<TSchema> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : Record<string, unknown>;\n\nexport type EmailTemplate<TPayload> = {\n subject: (payload: TPayload) => string;\n /** Rendered HTML. react-email users wrap: `(p) => render(<Email {...p} />)`. */\n template: (payload: TPayload) => string | Promise<string>;\n};\n\nexport type NotificationDefinition<\n TSchema extends StandardSchemaV1 | undefined = StandardSchemaV1 | undefined,\n> = {\n schema?: TSchema;\n channels: readonly Channel[];\n maxAttempts?: number;\n email?: EmailTemplate<PayloadFromSchema<TSchema>>;\n};\n\n/** Binds TSchema so email callbacks infer the payload; TS cannot infer from a sibling property. */\nexport function defineNotification<TSchema extends StandardSchemaV1 | undefined = undefined>(\n definition: NotificationDefinition<TSchema>,\n): NotificationDefinition<TSchema> {\n return definition;\n}\n\n/** Erased form. `EmailTemplate<never>` because callbacks are contravariant. */\nexport type AnyNotificationDefinition = {\n schema?: StandardSchemaV1 | undefined;\n channels: readonly Channel[];\n maxAttempts?: number | undefined;\n email?: EmailTemplate<never> | undefined;\n};\n\nexport type NotificationDefinitions = Record<string, AnyNotificationDefinition>;\n\nexport type PayloadOf<TDef> = TDef extends { schema: infer TSchema extends StandardSchemaV1 }\n ? StandardSchemaV1.InferOutput<TSchema>\n : Record<string, unknown>;\n","export class EasyPingError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EasyPingError\";\n }\n}\n\n/** Thrown when a payload fails its Standard Schema. Developer error. */\nexport class ValidationError extends EasyPingError {\n readonly issues: readonly { message: string; path?: string }[];\n\n constructor(type: string, issues: readonly { message: string; path?: string }[]) {\n super(`Payload for \"${type}\" failed validation: ${issues.map((i) => i.message).join(\"; \")}`);\n this.name = \"ValidationError\";\n this.issues = issues;\n }\n}\n\n/** Thrown at startup for a malformed config. Never at send time. */\nexport class ConfigError extends EasyPingError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n\nexport type Logger = {\n warn: (message: string, meta?: Record<string, unknown>) => void;\n error: (message: string, meta?: Record<string, unknown>) => void;\n};\n\nexport const consoleLogger: Logger = {\n warn: (message, meta) => console.warn(`[easy-ping] ${message}`, meta ?? \"\"),\n error: (message, meta) => console.error(`[easy-ping] ${message}`, meta ?? \"\"),\n};\n","/**\n * The wake-up seam. A publish carries no payload: it says \"something changed\n * on this channel, go look\", so losing one costs latency, never data.\n * RFC 0006 §4C.\n */\nexport type Signals = {\n /** True when a publish in one process reaches subscribers in another. */\n readonly crossProcess: boolean;\n publish(channel: string): void;\n subscribe(channel: string, handler: () => void): () => void;\n close?(): Promise<void> | void;\n};\n\nexport const DELIVERIES_CHANNEL = \"deliveries\";\nexport const inboxChannel = (userId: string) => `inbox:${userId}`;\n\n/** In-process only. The default, and exactly right on SQLite or a single replica. */\nexport function createMemorySignals(): Signals {\n const handlers = new Map<string, Set<() => void>>();\n\n return {\n crossProcess: false,\n publish(channel) {\n const set = handlers.get(channel);\n if (!set) return;\n for (const handler of [...set]) {\n queueMicrotask(() => {\n try {\n handler();\n } catch {\n // a subscriber's failure is its own problem\n }\n });\n }\n },\n subscribe(channel, handler) {\n let set = handlers.get(channel);\n if (!set) {\n set = new Set();\n handlers.set(channel, set);\n }\n set.add(handler);\n return () => {\n set?.delete(handler);\n if (set?.size === 0) handlers.delete(channel);\n };\n },\n };\n}\n\n/**\n * Wraps a cross-process transport (LISTEN/NOTIFY, a change stream) so local\n * subscribers still hear local publishes even if the transport drops them,\n * and a transport failure degrades to in-process rather than to silence.\n */\nexport function createBridgedSignals(\n transport: {\n publish(channel: string): Promise<void> | void;\n subscribe(channel: string, handler: () => void): Promise<() => void> | (() => void);\n },\n onError: (error: unknown) => void,\n): Signals {\n const local = createMemorySignals();\n const remoteUnsubscribes = new Map<string, Promise<() => void>>();\n const counts = new Map<string, number>();\n\n return {\n crossProcess: true,\n publish(channel) {\n local.publish(channel);\n Promise.resolve()\n .then(() => transport.publish(channel))\n .catch(onError);\n },\n subscribe(channel, handler) {\n const unsubscribeLocal = local.subscribe(channel, handler);\n counts.set(channel, (counts.get(channel) ?? 0) + 1);\n\n if (!remoteUnsubscribes.has(channel)) {\n remoteUnsubscribes.set(\n channel,\n Promise.resolve()\n .then(() => transport.subscribe(channel, () => local.publish(channel)))\n .catch((error) => {\n onError(error);\n return () => {};\n }),\n );\n }\n\n return () => {\n unsubscribeLocal();\n const remaining = (counts.get(channel) ?? 1) - 1;\n if (remaining > 0) {\n counts.set(channel, remaining);\n return;\n }\n counts.delete(channel);\n const pending = remoteUnsubscribes.get(channel);\n remoteUnsubscribes.delete(channel);\n pending?.then((unsubscribe) => unsubscribe()).catch(onError);\n };\n },\n };\n}\n","import { decodeBase64Url, decodeBase64UrlBytes, encodeBase64Url } from \"./base64url\";\n\nexport type TokenClaims = {\n /** Subject — the user the token acts for. */\n uid: string;\n /** What the token is allowed to do. Verification requires an exact match. */\n purpose: string;\n /** Expiry, epoch seconds. */\n exp: number;\n /** Issued at, epoch seconds. Set by signToken; lets a route refuse a token older than a later change. */\n iat?: number;\n /** Free-form, purpose-specific. */\n data?: Record<string, string>;\n};\n\nconst encoder = new TextEncoder();\n\n// Changing this invalidates every outstanding token. Bump it on purpose only.\nconst KEY_SALT = encoder.encode(\"easy-ping/tokens/v1\");\n\n/** One HMAC key per purpose, derived with HKDF, so an unsubscribe key signs nothing else. */\nasync function hmacKey(secret: string, purpose: string): Promise<CryptoKey> {\n const master = await crypto.subtle.importKey(\"raw\", encoder.encode(secret), \"HKDF\", false, [\n \"deriveKey\",\n ]);\n return crypto.subtle.deriveKey(\n { name: \"HKDF\", hash: \"SHA-256\", salt: KEY_SALT, info: encoder.encode(purpose) },\n master,\n { name: \"HMAC\", hash: \"SHA-256\", length: 256 },\n false,\n [\"sign\", \"verify\"],\n );\n}\n\nexport async function signToken(\n secret: string,\n claims: TokenClaims,\n now: Date = new Date(),\n): Promise<string> {\n const stamped: TokenClaims = { ...claims, iat: claims.iat ?? Math.floor(now.getTime() / 1000) };\n const body = encodeBase64Url(JSON.stringify(stamped));\n const signature = await crypto.subtle.sign(\n \"HMAC\",\n await hmacKey(secret, claims.purpose),\n encoder.encode(body),\n );\n return `${body}.${encodeBase64Url(new Uint8Array(signature))}`;\n}\n\n/** null for every failure mode. Distinguishing them tells an attacker which part to fix. */\nexport async function verifyToken(\n secret: string,\n token: string,\n purpose: string,\n now: Date = new Date(),\n): Promise<TokenClaims | null> {\n const separator = token.lastIndexOf(\".\");\n if (separator <= 0) return null;\n\n const body = token.slice(0, separator);\n const signature = decodeBase64UrlBytes(token.slice(separator + 1));\n if (!signature) return null;\n\n // Verified under the expected purpose's key before the body is parsed. subtle.verify is constant-time.\n const valid = await crypto.subtle.verify(\n \"HMAC\",\n await hmacKey(secret, purpose),\n signature,\n encoder.encode(body),\n );\n if (!valid) return null;\n\n const decoded = decodeBase64Url(body);\n if (!decoded) return null;\n\n let claims: TokenClaims;\n try {\n claims = JSON.parse(decoded) as TokenClaims;\n } catch {\n return null;\n }\n\n if (typeof claims?.uid !== \"string\" || typeof claims.exp !== \"number\") return null;\n if (claims.purpose !== purpose) return null;\n if (claims.exp * 1000 <= now.getTime()) return null;\n if (claims.iat !== undefined && typeof claims.iat !== \"number\") return null;\n\n if (claims.data !== undefined) {\n if (typeof claims.data !== \"object\" || claims.data === null || Array.isArray(claims.data)) {\n return null;\n }\n for (const value of Object.values(claims.data)) {\n if (typeof value !== \"string\") return null;\n }\n }\n\n return claims;\n}\n\nexport const DEFAULT_TOKEN_TTL_SECONDS = 30 * 24 * 60 * 60;\n/** Ninety days. A link that must outlive this should be re-issued, not made immortal. */\nexport const MAX_TOKEN_TTL_SECONDS = 90 * 24 * 60 * 60;\n\nexport const expiresIn = (seconds: number, now: Date = new Date()): number =>\n Math.floor(now.getTime() / 1000) + Math.min(Math.max(seconds, 0), MAX_TOKEN_TTL_SECONDS);\n\nexport type SignRequest = {\n uid: string;\n purpose: string;\n data?: Record<string, string>;\n /** Defaults to 30 days, capped at 90. */\n ttlSeconds?: number;\n};\n\n/** What a plugin gets instead of the secret: signs only its own declared purposes. */\nexport function createScopedSigner(\n secret: string,\n pluginId: string,\n purposes: ReadonlySet<string>,\n onViolation: (message: string) => Error,\n): (request: SignRequest) => Promise<string> {\n return (request) => {\n if (!purposes.has(request.purpose)) {\n throw onViolation(\n `plugin \"${pluginId}\" tried to sign a token for purpose \"${request.purpose}\", ` +\n \"which none of its signed routes declare.\",\n );\n }\n return signToken(secret, {\n uid: request.uid,\n purpose: request.purpose,\n exp: expiresIn(request.ttlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS),\n ...(request.data ? { data: request.data } : {}),\n });\n };\n}\n","import type { DatabaseAdapter } from \"./adapter\";\nimport type { SessionConfig } from \"./config\";\nimport type { Logger } from \"./errors\";\nimport type { Promisable, RouteDefinition } from \"./plugin\";\nimport type { Runner } from \"./runner\";\nimport { inboxChannel, type Signals } from \"./signals\";\nimport { verifyToken } from \"./tokens\";\n\nexport type EventsSettings = {\n heartbeatMs: number;\n probeIntervalMs: number;\n maxDurationMs: number;\n maxStreamsPerUser: number;\n maxStreams: number;\n};\n\n/** Unread chunks a stream may hold before it is closed on a consumer that stopped reading. */\nconst STREAM_HIGH_WATER_MARK = 256;\n\nexport type HandlerDeps = {\n adapter: DatabaseAdapter;\n session: SessionConfig;\n runner: Runner;\n logger: Logger;\n basePath: string;\n secret: string;\n signals: Signals;\n /** `false` unmounts GET /events. */\n events: EventsSettings | false;\n /** Fire-and-forget delivery pass after a request. Rate-limited by the instance. */\n sweepOnRequest?: (() => void) | undefined;\n cronSecret?: string | undefined;\n /** Guards plugin machine routes. The instance defaults it to cronSecret. */\n machineSecret?: string | undefined;\n cronMaxSweeps?: number | undefined;\n pluginRoutes?: readonly RouteDefinition[] | undefined;\n /** Returns a 429 to send, or null to proceed. Runs after onRequest, before routing. */\n rateLimit?: ((request: Request) => Response | null) | undefined;\n /** Origins other than the request's own host that may POST. `*.example.com` allowed. */\n trustedOrigins?: readonly string[] | undefined;\n /** Runs before routing. Returning a Response short-circuits; use it for rate limiting. */\n // biome-ignore lint/suspicious/noConfusingVoidType: a hook that returns nothing is the common case\n onRequest?: ((request: Request) => Promisable<Response | undefined | void>) | undefined;\n maxBodyBytes?: number | undefined;\n};\n\n/** Every JSON body is capped here. Nothing legitimate the routes accept is bigger. */\nexport const MAX_BODY_BYTES = 64 * 1024;\n\nconst MAX_READ_IDS = 200;\n\n// Per-user data: no shared caching, no sniffing.\nconst PRIVATE_HEADERS: Record<string, string> = {\n \"cache-control\": \"private, no-store\",\n \"x-content-type-options\": \"nosniff\",\n};\n\nconst json = (body: unknown, status = 200, headers: Record<string, string> = {}) =>\n new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json\", ...PRIVATE_HEADERS, ...headers },\n });\n\nconst empty = (status: number) => new Response(null, { status, headers: PRIVATE_HEADERS });\n\n/** Plugin responses get the same headers, without touching their body. */\nfunction harden(response: Response): Response {\n const headers = new Headers(response.headers);\n for (const [name, value] of Object.entries(PRIVATE_HEADERS)) {\n if (!headers.has(name)) headers.set(name, value);\n }\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nconst encoder = new TextEncoder();\n\n/** Constant time over SHA-256 digests, so neither content nor length leaks. Works on edge runtimes. */\nasync function timingSafeEqual(a: string, b: string): Promise<boolean> {\n const [left, right] = await Promise.all(\n [a, b].map(\n async (value) => new Uint8Array(await crypto.subtle.digest(\"SHA-256\", encoder.encode(value))),\n ),\n );\n let diff = 0;\n for (let i = 0; i < 32; i += 1) diff |= (left?.[i] ?? 0) ^ (right?.[i] ?? 0);\n return diff === 0;\n}\n\n/** Anchored at a segment boundary: `/foo/api/notifications/cron` is not a cron request. */\nfunction routePath(url: URL, basePath: string): string {\n const { pathname } = url;\n if (pathname === basePath) return \"/\";\n if (pathname.startsWith(`${basePath}/`)) return pathname.slice(basePath.length);\n return pathname;\n}\n\nexport type JsonBody = { body: Record<string, unknown> } | { error: Response };\n\n/** Reads a JSON object body with a streaming byte cap. Malformed JSON is 400; an empty body is `{}`. */\nexport async function readJsonBody(\n request: Request,\n maxBytes: number = MAX_BODY_BYTES,\n): Promise<JsonBody> {\n const tooLarge = () => ({ error: json({ error: `body exceeds ${maxBytes} bytes` }, 413) });\n\n const declared = Number(request.headers.get(\"content-length\"));\n if (Number.isFinite(declared) && declared > maxBytes) return tooLarge();\n if (!request.body) return { body: {} };\n\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel();\n return tooLarge();\n }\n chunks.push(value);\n }\n\n const bytes = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n const text = new TextDecoder().decode(bytes);\n if (text.trim() === \"\") return { body: {} };\n\n try {\n const parsed: unknown = JSON.parse(text);\n return {\n body:\n parsed && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {},\n };\n } catch {\n return { error: json({ error: \"body must be a JSON object\" }, 400) };\n }\n}\n\nconst isJsonContentType = (request: Request) =>\n /^application\\/json\\s*(;|$)/i.test((request.headers.get(\"content-type\") ?? \"\").trim());\n\nfunction originAllowed(origin: string, url: URL, request: Request, trusted: readonly string[]) {\n let host: string;\n try {\n host = new URL(origin).host;\n } catch {\n return false;\n }\n\n if (host === url.host) return true;\n // Behind a proxy that rewrites Host, the public host arrives here instead.\n const forwarded = request.headers.get(\"x-forwarded-host\")?.split(\",\")[0]?.trim();\n if (forwarded && host === forwarded) return true;\n\n return trusted.some((entry) =>\n entry.startsWith(\"*.\") ? host.endsWith(entry.slice(1)) : entry === origin,\n );\n}\n\n/** CSRF: a cross-site form can neither send `application/json` without a preflight nor forge `Origin`. */\nfunction csrfCheck(request: Request, url: URL, trusted: readonly string[]): Response | null {\n if (!isJsonContentType(request)) {\n return json({ error: \"content-type must be application/json\" }, 415);\n }\n\n const origin = request.headers.get(\"origin\");\n if (origin === null) return null;\n if (origin === \"null\" || !originAllowed(origin, url, request, trusted)) return empty(403);\n\n return null;\n}\n\nexport function createHandler(deps: HandlerDeps) {\n const trustedOrigins = deps.trustedOrigins ?? [];\n const maxBodyBytes = deps.maxBodyBytes ?? MAX_BODY_BYTES;\n\n async function resolveUserId(request: Request): Promise<string | null | \"error\"> {\n try {\n return await deps.session.getUserId(request);\n } catch (error) {\n // A broken session lookup is a 500, never a 401. RFC 0002 §1.\n deps.logger.error(\"session.getUserId threw\", { error });\n return \"error\";\n }\n }\n\n async function bearerMatches(request: Request, secret: string | undefined): Promise<boolean> {\n if (!secret) return false;\n const header = request.headers.get(\"authorization\") ?? \"\";\n const presented = header.startsWith(\"Bearer \") ? header.slice(7) : header;\n return timingSafeEqual(presented, secret);\n }\n\n async function handleCron(request: Request): Promise<Response> {\n if (!deps.cronSecret) return empty(404);\n if (!(await bearerMatches(request, deps.cronSecret))) return empty(401);\n\n // Bounded so an overlapping scheduler does not hold a request open for the whole backlog.\n const result = await deps.runner.drain(\n deps.cronMaxSweeps === undefined ? {} : { maxSweeps: deps.cronMaxSweeps },\n );\n return json(result);\n }\n\n /** Plugin routes first; auth is enforced here so a plugin cannot forget it. */\n async function handlePluginRoute(\n route: RouteDefinition,\n request: Request,\n url: URL,\n ): Promise<Response> {\n if (route.scope.type === \"user\") {\n if (request.method === \"POST\") {\n const rejected = csrfCheck(request, url, trustedOrigins);\n if (rejected) return rejected;\n }\n\n const userId = await resolveUserId(request);\n if (userId === \"error\") return empty(500);\n if (userId === null) return empty(401);\n return harden(await route.handler({ request, userId, claims: null, params: {} }));\n }\n\n if (route.scope.type === \"machine\") {\n if (!deps.machineSecret) return empty(404);\n if (!(await bearerMatches(request, deps.machineSecret))) return empty(401);\n return harden(await route.handler({ request, userId: null, claims: null, params: {} }));\n }\n\n if (route.scope.type === \"signed\") {\n const token =\n url.searchParams.get(\"token\") ??\n (request.headers.get(\"authorization\") ?? \"\").replace(/^Bearer /, \"\");\n\n const claims = await verifyToken(deps.secret, token, route.scope.purpose);\n // One response for every failure mode. RFC 0002 §5.\n if (!claims) return empty(400);\n\n return harden(await route.handler({ request, userId: claims.uid, claims, params: {} }));\n }\n\n return harden(await route.handler({ request, userId: null, claims: null, params: {} }));\n }\n\n async function route(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const path = routePath(url, deps.basePath);\n\n if (deps.onRequest) {\n const early = await deps.onRequest(request);\n if (early instanceof Response) return early;\n }\n\n if (deps.rateLimit) {\n const limited = deps.rateLimit(request);\n if (limited) return limited;\n }\n\n if (path === \"/cron\") {\n if (request.method !== \"POST\") return empty(405);\n return handleCron(request);\n }\n\n const pluginRoute = deps.pluginRoutes?.find(\n (candidate) => candidate.path === path && candidate.method === request.method,\n );\n if (pluginRoute) return handlePluginRoute(pluginRoute, request, url);\n\n if (request.method === \"POST\") {\n const rejected = csrfCheck(request, url, trustedOrigins);\n if (rejected) return rejected;\n }\n\n const userId = await resolveUserId(request);\n if (userId === \"error\") return empty(500);\n if (userId === null) return empty(401);\n\n if (request.method === \"GET\" && path === \"/events\") {\n if (!deps.events) return empty(404);\n // A session can open streams for free; without a cap one account can hold every socket.\n if ((openStreams.get(userId) ?? 0) >= deps.events.maxStreamsPerUser) {\n return json({ error: \"too many open event streams\" }, 429, { \"retry-after\": \"30\" });\n }\n if (totalStreams >= deps.events.maxStreams) {\n return json({ error: \"event streams unavailable\" }, 503, { \"retry-after\": \"30\" });\n }\n return events(request, userId, deps.events);\n }\n\n if (request.method === \"GET\" && path === \"/\") {\n const limitParam = Number(url.searchParams.get(\"limit\") ?? 20);\n const limit = Number.isFinite(limitParam) ? Math.min(Math.max(limitParam, 1), 100) : 20;\n const cursor = url.searchParams.get(\"cursor\");\n\n // unseenCount rides on the first page only: a cursor request is scrollback, not a poll.\n const [page, unseenCount] = await Promise.all([\n deps.adapter.listNotifications({\n userId,\n limit,\n ...(cursor ? { cursor } : {}),\n ...(url.searchParams.get(\"unreadOnly\") === \"true\" ? { unreadOnly: true } : {}),\n }),\n cursor ? Promise.resolve(null) : deps.adapter.countUnseen(userId),\n ]);\n\n return json(unseenCount === null ? page : { ...page, unseenCount });\n }\n\n if (request.method === \"GET\" && path === \"/count\") {\n return json({ unseen: await deps.adapter.countUnseen(userId) });\n }\n\n if (request.method === \"POST\" && path === \"/seen\") {\n const parsed = await readJsonBody(request, maxBodyBytes);\n if (\"error\" in parsed) return parsed.error;\n const before = typeof parsed.body.before === \"string\" ? new Date(parsed.body.before) : null;\n\n // +1ms: Postgres keeps microseconds, an ISO string milliseconds; without it markSeen misses the newest row.\n const cutoff =\n before && !Number.isNaN(before.getTime()) ? new Date(before.getTime() + 1) : new Date();\n\n await deps.adapter.markSeen(userId, cutoff);\n deps.signals.publish(inboxChannel(userId));\n return json({ ok: true });\n }\n\n if (request.method === \"POST\" && path === \"/read\") {\n const parsed = await readJsonBody(request, maxBodyBytes);\n if (\"error\" in parsed) return parsed.error;\n const ids = Array.isArray(parsed.body.ids)\n ? parsed.body.ids.filter((id): id is string => typeof id === \"string\")\n : [];\n if (ids.length === 0) return json({ error: \"ids must be a non-empty string array\" }, 400);\n\n if (ids.length > MAX_READ_IDS) {\n return json({ error: `at most ${MAX_READ_IDS} ids per request` }, 400);\n }\n\n // 404, not 403: a 403 confirms the row exists. RFC 0002 §2.\n const updated = await deps.adapter.markRead(userId, ids);\n if (updated > 0) deps.signals.publish(inboxChannel(userId));\n return updated === 0 ? empty(404) : json({ updated });\n }\n\n if (request.method === \"POST\" && path === \"/read-all\") {\n const updated = await deps.adapter.markAllRead(userId);\n if (updated > 0) deps.signals.publish(inboxChannel(userId));\n return json({ updated });\n }\n\n return empty(404);\n }\n\n const openStreams = new Map<string, number>();\n let totalStreams = 0;\n\n const trackStream = (userId: string) => {\n openStreams.set(userId, (openStreams.get(userId) ?? 0) + 1);\n totalStreams += 1;\n return () => {\n const remaining = (openStreams.get(userId) ?? 1) - 1;\n if (remaining > 0) openStreams.set(userId, remaining);\n else openStreams.delete(userId);\n totalStreams -= 1;\n };\n };\n\n /** A change fingerprint cheap enough to take every probe interval. */\n async function fingerprint(userId: string): Promise<string> {\n const [page, unseen] = await Promise.all([\n deps.adapter.listNotifications({ userId, limit: 1 }),\n deps.adapter.countUnseen(userId),\n ]);\n const newest = page.notifications[0];\n return `${newest?.id ?? \"\"}|${newest?.readAt ? 1 : 0}|${unseen}`;\n }\n\n // One probe per user, however many streams that user holds: N tabs must not mean N queries.\n type Probe = { listeners: Set<() => void>; timer: ReturnType<typeof setInterval>; last?: string };\n const probes = new Map<string, Probe>();\n\n function subscribeProbe(userId: string, onChanged: () => void, intervalMs: number) {\n let probe = probes.get(userId);\n if (!probe) {\n const created: Probe = {\n listeners: new Set(),\n timer: setInterval(() => {\n fingerprint(userId)\n .then((value) => {\n if (created.last !== undefined && value !== created.last) {\n for (const listener of created.listeners) listener();\n }\n created.last = value;\n })\n .catch((error) => deps.logger.error(\"events probe failed\", { error }));\n }, intervalMs),\n };\n probe = created;\n probes.set(userId, created);\n fingerprint(userId)\n .then((value) => {\n if (created.last === undefined) created.last = value;\n })\n .catch(() => {});\n }\n probe.listeners.add(onChanged);\n return () => {\n const current = probes.get(userId);\n if (!current) return;\n current.listeners.delete(onChanged);\n if (current.listeners.size === 0) {\n clearInterval(current.timer);\n probes.delete(userId);\n }\n };\n }\n\n /**\n * Server-Sent Events: `ready` once, `changed` whenever this user's inbox\n * moves, comments as keepalive. No payload ever travels on the stream; the\n * client fetches the feed on `changed`. RFC 0006 §4D.\n */\n function events(request: Request, userId: string, settings: EventsSettings): Response {\n const encoder = new TextEncoder();\n const timers: ReturnType<typeof setInterval>[] = [];\n const unsubscribes: (() => void)[] = [];\n let closed = false;\n let cleanup = () => {};\n\n const stream = new ReadableStream<Uint8Array>(\n {\n start(controller) {\n const write = (text: string) => {\n if (closed) return;\n // A consumer that stopped reading would make this queue grow without bound.\n if (controller.desiredSize !== null && controller.desiredSize <= 0) {\n cleanup();\n return;\n }\n try {\n controller.enqueue(encoder.encode(text));\n } catch {\n cleanup();\n }\n };\n cleanup = () => {\n if (closed) return;\n closed = true;\n for (const unsubscribe of unsubscribes) unsubscribe();\n for (const timer of timers) clearInterval(timer);\n try {\n controller.close();\n } catch {\n // already closed by the consumer\n }\n };\n const changed = () => write(\"event: changed\\ndata: {}\\n\\n\");\n\n unsubscribes.push(trackStream(userId));\n write(\"retry: 3000\\n\\nevent: ready\\ndata: {}\\n\\n\");\n unsubscribes.push(deps.signals.subscribe(inboxChannel(userId), changed));\n timers.push(setInterval(() => write(\": keepalive\\n\\n\"), settings.heartbeatMs));\n\n if (!deps.signals.crossProcess && settings.probeIntervalMs > 0) {\n unsubscribes.push(subscribeProbe(userId, changed, settings.probeIntervalMs));\n }\n\n if (settings.maxDurationMs > 0) {\n timers.push(\n setTimeout(cleanup, settings.maxDurationMs) as ReturnType<typeof setInterval>,\n );\n }\n request.signal?.addEventListener(\"abort\", cleanup, { once: true });\n },\n cancel() {\n cleanup();\n },\n },\n { highWaterMark: STREAM_HIGH_WATER_MARK },\n );\n\n return new Response(stream, {\n headers: {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-cache, no-store\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\",\n \"x-content-type-options\": \"nosniff\",\n },\n });\n }\n\n async function handle(request: Request): Promise<Response> {\n let response: Response | undefined;\n try {\n response = await route(request);\n return response;\n } catch (error) {\n // A thrown driver error must not escape: unhandled rejection on Node, stack trace elsewhere.\n deps.logger.error(\"request failed\", { url: request.url, error });\n return empty(500);\n } finally {\n // Only a served request earns a sweep; anonymous 401s must not drive database work.\n if (response && response.status < 400) deps.sweepOnRequest?.();\n }\n }\n\n return {\n handle,\n GET: handle,\n POST: handle,\n };\n}\n","const ESCAPES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n};\n\n/** For template literals: anything a user typed goes through this, or their HTML ships from your domain. */\nexport const escapeHtml = (value: unknown): string =>\n String(value ?? \"\").replace(/[&<>\"']/g, (char) => ESCAPES[char] ?? char);\n","export type RateLimitConfig = {\n /** Requests allowed per key per window. */\n max: number;\n windowMs: number;\n /** Bucket key. Defaults to the client address from proxy headers; null exempts the request. */\n key?: (request: Request) => string | null;\n};\n\nconst clientAddress = (request: Request): string | null => {\n const headers = request.headers;\n return (\n headers.get(\"cf-connecting-ip\") ??\n headers.get(\"x-real-ip\") ??\n headers.get(\"x-forwarded-for\")?.split(\",\")[0]?.trim() ??\n null\n );\n};\n\n/** Fixed window in process memory: per isolate or replica, so a bound rather than a quota. */\nexport function createRateLimiter(config: RateLimitConfig): (request: Request) => Response | null {\n const keyOf = config.key ?? clientAddress;\n const buckets = new Map<string, { count: number; resetAt: number }>();\n let lastSweep = 0;\n\n return (request) => {\n const key = keyOf(request);\n if (key === null) return null;\n\n const now = Date.now();\n\n // Sweep expired buckets at most once per window.\n if (now - lastSweep > config.windowMs) {\n for (const [id, bucket] of buckets) if (bucket.resetAt <= now) buckets.delete(id);\n lastSweep = now;\n }\n\n let bucket = buckets.get(key);\n if (!bucket || bucket.resetAt <= now) {\n bucket = { count: 0, resetAt: now + config.windowMs };\n buckets.set(key, bucket);\n }\n\n bucket.count += 1;\n if (bucket.count <= config.max) return null;\n\n return new Response(null, {\n status: 429,\n headers: {\n \"retry-after\": String(Math.max(1, Math.ceil((bucket.resetAt - now) / 1000))),\n \"cache-control\": \"private, no-store\",\n },\n });\n };\n}\n","/** Exponential backoff with ±20% jitter, floored by the sweep interval. RFC 0001 §4. */\nconst SCHEDULE_MS = [30_000, 120_000, 480_000, 1_920_000] as const;\n\nexport type Backoff = \"exponential\" | ((attempt: number) => number);\n\nexport function backoffMs(attempt: number, strategy: Backoff = \"exponential\"): number {\n if (typeof strategy === \"function\") return Math.max(0, strategy(attempt));\n\n const index = Math.min(Math.max(attempt, 1), SCHEDULE_MS.length) - 1;\n const base = SCHEDULE_MS[index] ?? SCHEDULE_MS[SCHEDULE_MS.length - 1] ?? 30_000;\n return Math.round(base * (0.8 + Math.random() * 0.4));\n}\n\nexport const nextAttemptAt = (attempt: number, strategy?: Backoff, now = new Date()): Date =>\n new Date(now.getTime() + backoffMs(attempt, strategy));\n","import type { ClaimedDelivery, DatabaseAdapter, DeliveryOutcome, DeliveryRelease } from \"./adapter\";\nimport { type Backoff, nextAttemptAt } from \"./backoff\";\nimport type { ChannelsConfig, Worker } from \"./config\";\nimport type { NotificationDefinitions } from \"./definition\";\nimport type { Logger } from \"./errors\";\nimport type { AnyPlugin } from \"./plugin\";\nimport { DELIVERIES_CHANNEL, type Signals } from \"./signals\";\nimport type { Channel, Recipient } from \"./types\";\n\nexport type RunnerDeps = {\n adapter: DatabaseAdapter;\n definitions: NotificationDefinitions;\n channels: ChannelsConfig;\n plugins: readonly AnyPlugin[];\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n logger: Logger;\n leaseMs: number;\n batchSize: number;\n backoff: Backoff;\n /** Wakes an idle worker the moment a send commits, so the idle interval can be long. */\n signals?: Signals | undefined;\n};\n\n/** Long on purpose: a send in this process wakes the loop, and the cron sweep backstops the rest. */\nexport const DEFAULT_WORKER_IDLE_MS = 10_000;\n\nexport type SweepResult = {\n claimed: number;\n sent: number;\n failed: number;\n /** Deliveries that had nothing to do. Not errors; see DeliveryOutcome. */\n skipped: number;\n};\n\nasync function withTimeout<T>(\n run: (signal: AbortSignal) => Promise<T>,\n ms: number,\n label: string,\n): Promise<T> {\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n // Abort first: racing a promise leaves the original request running.\n controller.abort();\n reject(new Error(`${label} timed out after ${ms}ms`));\n }, ms);\n });\n\n try {\n return await Promise.race([run(controller.signal), timeout]);\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** Persisted to `last_error`, which admin tooling reads: addresses do not go in. */\nexport const redactErrorMessage = (text: string) =>\n text.replace(/[^\\s\"'<>()[\\]{},;]+@[^\\s\"'<>()[\\]{},;]+/g, \"[redacted-email]\");\n\nconst message = (error: unknown) =>\n redactErrorMessage(error instanceof Error ? error.message : String(error));\n\nexport function createRunner(deps: RunnerDeps) {\n async function deliverOne(\n delivery: ClaimedDelivery,\n recipient: Recipient | undefined,\n ): Promise<DeliveryOutcome> {\n if (!recipient) {\n return { result: \"failed\", error: \"recipient could not be resolved\", retryable: false };\n }\n\n if (delivery.channel === \"inApp\") {\n // The notification row is the delivery. Nothing to transmit.\n return { result: \"sent\" };\n }\n\n if (delivery.channel === \"email\") {\n const provider = deps.channels.email?.provider;\n if (!provider) {\n return { result: \"failed\", error: \"no email provider configured\", retryable: false };\n }\n // Captured before the closure below: narrowing does not survive into it.\n const to = recipient.email;\n if (!to) {\n return { result: \"failed\", error: \"recipient has no email address\", retryable: false };\n }\n\n const email = deps.definitions[delivery.notification.type]?.email;\n if (!email) {\n return {\n result: \"failed\",\n error: `notification type \"${delivery.notification.type}\" has no email template`,\n retryable: false,\n };\n }\n\n try {\n const payload = delivery.notification.payload as never;\n const html = await email.template(payload);\n\n await withTimeout(\n (signal) =>\n provider.send({\n to,\n subject: email.subject(payload),\n html,\n // Delivery is at-least-once; the provider dedupes on this.\n idempotencyKey: delivery.id,\n signal,\n }),\n provider.timeoutMs ?? 30_000,\n `${provider.name} send`,\n );\n\n return { result: \"sent\" };\n } catch (error) {\n return {\n result: \"failed\",\n error: message(error),\n retryable: provider.isRetryable(error),\n };\n }\n }\n\n const owner = deps.plugins.find(\n (plugin) => plugin.channels?.includes(delivery.channel) && plugin.hooks?.deliver,\n );\n if (!owner?.hooks?.deliver) {\n return {\n result: \"failed\",\n error: `no plugin delivers channel \"${delivery.channel}\"`,\n retryable: false,\n };\n }\n\n try {\n return await withTimeout(\n (signal) =>\n Promise.resolve(\n // biome-ignore lint/style/noNonNullAssertion: guarded directly above\n owner.hooks!.deliver!({\n channel: delivery.channel,\n deliveryId: delivery.id,\n attempt: delivery.attempts + 1,\n recipient,\n notification: {\n id: delivery.notificationId,\n userId: delivery.notification.userId,\n type: delivery.notification.type,\n payload: delivery.notification.payload,\n },\n signal,\n }),\n ),\n 30_000,\n `plugin \"${owner.id}\" deliver`,\n );\n } catch (error) {\n return { result: \"failed\", error: message(error), retryable: true };\n }\n }\n\n async function notifyAfterDeliver(delivery: ClaimedDelivery, outcome: DeliveryOutcome) {\n const isTerminal =\n outcome.result !== \"failed\" ||\n !outcome.retryable ||\n delivery.attempts + 1 >= delivery.maxAttempts;\n\n for (const plugin of deps.plugins) {\n const hook = plugin.hooks?.afterDeliver;\n if (!hook) continue;\n try {\n await hook({\n deliveryId: delivery.id,\n notificationId: delivery.notificationId,\n userId: delivery.notification.userId,\n channel: delivery.channel,\n outcome,\n attempt: delivery.attempts + 1,\n isTerminal,\n });\n } catch (error) {\n // Fail open: the message is already sent. RFC 0004 §5.\n deps.logger.error(`plugin \"${plugin.id}\" afterDeliver threw; ignoring`, {\n deliveryId: delivery.id,\n error,\n });\n }\n }\n }\n\n async function runOnce(\n options: { limit?: number; channels?: readonly Channel[]; ids?: readonly string[] } = {},\n ): Promise<SweepResult> {\n const claimToken = crypto.randomUUID();\n\n const claimed = await deps.adapter.claimPendingDeliveries({\n limit: options.limit ?? deps.batchSize,\n leaseMs: deps.leaseMs,\n claimToken,\n ...(options.channels ? { channels: options.channels } : {}),\n ...(options.ids ? { ids: options.ids } : {}),\n });\n\n if (claimed.length === 0) return { claimed: 0, sent: 0, failed: 0, skipped: 0 };\n\n const userIds = [...new Set(claimed.map((row) => row.notification.userId))];\n const recipients = await deps.getRecipients(userIds);\n const byUserId = new Map(recipients.map((recipient) => [recipient.userId, recipient]));\n\n const releases: DeliveryRelease[] = [];\n let sent = 0;\n let failed = 0;\n let skipped = 0;\n\n for (const delivery of claimed) {\n const outcome = await deliverOne(delivery, byUserId.get(delivery.notification.userId));\n\n if (outcome.result === \"sent\") sent += 1;\n else if (outcome.result === \"skipped\") skipped += 1;\n else failed += 1;\n\n releases.push({\n id: delivery.id,\n claimToken,\n outcome,\n ...(outcome.result === \"failed\" && outcome.retryable\n ? { nextAttemptAt: nextAttemptAt(delivery.attempts + 1, deps.backoff) }\n : {}),\n });\n\n await notifyAfterDeliver(delivery, outcome);\n }\n\n await deps.adapter.releaseDeliveries(releases);\n return { claimed: claimed.length, sent, failed, skipped };\n }\n\n /** Drains until empty. Pass `ids` to bound it to one send. */\n async function drain(\n options: { maxSweeps?: number; ids?: readonly string[] } = {},\n ): Promise<SweepResult> {\n const maxSweeps = options.maxSweeps ?? 50;\n const total: SweepResult = { claimed: 0, sent: 0, failed: 0, skipped: 0 };\n\n for (let sweep = 0; sweep < maxSweeps; sweep += 1) {\n const result = await runOnce(options.ids ? { ids: options.ids } : {});\n total.claimed += result.claimed;\n total.sent += result.sent;\n total.failed += result.failed;\n total.skipped += result.skipped;\n if (result.claimed === 0) break;\n }\n\n return total;\n }\n\n let warnedMissingWaitUntil = false;\n\n function scheduleDeferred(\n waitUntil?: (promise: Promise<unknown>) => void,\n ids?: readonly string[],\n ): void {\n if (waitUntil) {\n waitUntil(\n drain({ maxSweeps: 10, ...(ids ? { ids } : {}) }).catch((error) =>\n deps.logger.error(\"deferred sweep failed\", { error }),\n ),\n );\n return;\n }\n\n if (!warnedMissingWaitUntil) {\n warnedMissingWaitUntil = true;\n deps.logger.warn(\n \"delivery.mode is 'deferred' but no delivery.waitUntil was supplied — \" +\n \"falling back to the cron sweep. Notifications are not lost, but they \" +\n \"will not be delivered until POST /cron runs.\",\n );\n }\n }\n\n function startWorker(options: { intervalMs?: number; batchSize?: number } = {}): Worker {\n const intervalMs = options.intervalMs ?? DEFAULT_WORKER_IDLE_MS;\n let stopped = false;\n let wake: (() => void) | undefined;\n let pending = false;\n\n const unsubscribe = deps.signals?.subscribe(DELIVERIES_CHANNEL, () => {\n pending = true;\n wake?.();\n });\n\n // Sleeps for the interval, or until a send publishes, whichever is first.\n const idle = (ms: number) =>\n new Promise<void>((resolve) => {\n if (pending) {\n pending = false;\n resolve();\n return;\n }\n const timer = setTimeout(done, ms);\n function done() {\n clearTimeout(timer);\n wake = undefined;\n pending = false;\n resolve();\n }\n wake = done;\n });\n\n const loop = (async () => {\n while (!stopped) {\n try {\n const result = await runOnce({ limit: options.batchSize ?? deps.batchSize });\n // Only idle when there was nothing to do; otherwise keep draining.\n if (result.claimed === 0 && !stopped) await idle(intervalMs);\n } catch (error) {\n deps.logger.error(\"worker sweep failed\", { error });\n if (!stopped) await idle(intervalMs);\n }\n }\n })();\n\n return {\n stop: async () => {\n stopped = true;\n unsubscribe?.();\n wake?.();\n // Let the in-flight sweep finish and release its leases.\n await loop;\n },\n };\n }\n\n return { runOnce, drain, scheduleDeferred, startWorker };\n}\n\nexport type Runner = ReturnType<typeof createRunner>;\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { DatabaseAdapter, InsertDelivery, InsertNotification } from \"./adapter\";\nimport type { ChannelsConfig, SendResult } from \"./config\";\nimport type { NotificationDefinitions } from \"./definition\";\nimport { type Logger, ValidationError } from \"./errors\";\nimport type { AnyPlugin, BeforeSendResult, ChannelDecision } from \"./plugin\";\nimport type { Channel, Recipient, SkipReason } from \"./types\";\n\nexport type SendPipelineDeps = {\n adapter: DatabaseAdapter;\n definitions: NotificationDefinitions;\n channels: ChannelsConfig;\n plugins: readonly AnyPlugin[];\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n maxAttempts: number;\n logger: Logger;\n generateId?: () => string;\n};\n\nexport type SendInput = {\n to: string | readonly string[];\n payload: unknown;\n actorId?: string | undefined;\n dedupeKey?: string | undefined;\n overrides?: { channels?: readonly Channel[] } | undefined;\n};\n\nasync function validatePayload(type: string, schema: StandardSchemaV1, payload: unknown) {\n const result = await schema[\"~standard\"].validate(payload);\n if (result.issues) {\n throw new ValidationError(\n type,\n result.issues.map((issue) => ({\n message: issue.message,\n ...(issue.path ? { path: issue.path.map(String).join(\".\") } : {}),\n })),\n );\n }\n return result.value;\n}\n\n/** inApp is on unless disabled; every other channel needs a provider or a plugin that delivers it. */\nexport function isChannelUsable(\n channel: Channel,\n channels: ChannelsConfig,\n plugins: readonly AnyPlugin[] = [],\n): boolean {\n if (channel === \"inApp\") return channels.inApp?.enabled !== false;\n if (channel === \"email\") return Boolean(channels.email?.provider);\n // Anything else is usable only if a plugin claims it and can deliver it.\n return plugins.some((plugin) => plugin.channels?.includes(channel) && plugin.hooks?.deliver);\n}\n\n/** One prepare() per plugin per send, keyed by plugin id. */\nasync function runPrepare(\n plugins: readonly AnyPlugin[],\n ctx: { type: string; recipients: readonly Recipient[] },\n logger: Logger,\n): Promise<Map<string, unknown>> {\n const prepared = new Map<string, unknown>();\n\n for (const plugin of plugins) {\n const hook = plugin.hooks?.prepare;\n if (!hook) continue;\n try {\n prepared.set(plugin.id, await hook(ctx));\n } catch (error) {\n // Fail closed: a failed bulk load must not decide with stale assumptions.\n logger.error(`plugin \"${plugin.id}\" prepare threw; its hooks will see undefined`, {\n type: ctx.type,\n error,\n });\n prepared.set(plugin.id, undefined);\n }\n }\n\n return prepared;\n}\n\nasync function runBeforeSend(\n plugins: readonly AnyPlugin[],\n base: { type: string; recipient: Recipient; actorId: string | null },\n payload: unknown,\n dedupeKey: string | null,\n prepared: Map<string, unknown>,\n logger: Logger,\n): Promise<BeforeSendResult> {\n let currentPayload = payload;\n let currentDedupeKey = dedupeKey;\n\n for (const plugin of plugins) {\n const hook = plugin.hooks?.beforeSend;\n if (!hook) continue;\n\n let result: BeforeSendResult;\n try {\n result = await hook({\n ...base,\n payload: currentPayload,\n dedupeKey: currentDedupeKey,\n prepared: prepared.get(plugin.id),\n });\n } catch (error) {\n // Fail closed: failing open would email people who opted out. RFC 0004 §5.\n logger.error(`plugin \"${plugin.id}\" beforeSend threw; cancelling send`, {\n type: base.type,\n userId: base.recipient.userId,\n error,\n });\n return { action: \"cancel\", reason: `plugin \"${plugin.id}\" beforeSend threw` };\n }\n\n if (result.action === \"cancel\") return result;\n if (result.payload !== undefined) currentPayload = result.payload;\n if (result.dedupeKey !== undefined) currentDedupeKey = result.dedupeKey;\n }\n\n return {\n action: \"continue\",\n payload: currentPayload,\n ...(currentDedupeKey === null ? {} : { dedupeKey: currentDedupeKey }),\n };\n}\n\nasync function runResolveChannels(\n plugins: readonly AnyPlugin[],\n base: { type: string; recipient: Recipient; payload: unknown },\n initial: readonly ChannelDecision[],\n prepared: Map<string, unknown>,\n logger: Logger,\n): Promise<readonly ChannelDecision[]> {\n let decisions = initial;\n\n for (const plugin of plugins) {\n const hook = plugin.hooks?.resolveChannels;\n if (!hook) continue;\n\n try {\n decisions = [...(await hook({ ...base, decisions, prepared: prepared.get(plugin.id) }))];\n } catch (error) {\n // Fail closed: keep the decisions already made. RFC 0004 §5.\n logger.error(`plugin \"${plugin.id}\" resolveChannels threw; keeping prior decisions`, {\n type: base.type,\n userId: base.recipient.userId,\n error,\n });\n return decisions;\n }\n }\n\n return decisions;\n}\n\nexport async function runSend(\n type: string,\n input: SendInput,\n deps: SendPipelineDeps,\n): Promise<SendResult> {\n const definition = deps.definitions[type];\n if (!definition) {\n throw new ValidationError(type, [{ message: `unknown notification type \"${type}\"` }]);\n }\n\n const payload = definition.schema\n ? await validatePayload(type, definition.schema, input.payload)\n : input.payload;\n\n const userIds = [...new Set(Array.isArray(input.to) ? input.to : [input.to as string])];\n const recipients = await deps.getRecipients(userIds);\n const byUserId = new Map(recipients.map((recipient) => [recipient.userId, recipient]));\n\n const newId = deps.generateId ?? (() => crypto.randomUUID());\n const skipped: { userId: string; reason: SkipReason }[] = [];\n const rows: InsertNotification[] = [];\n const actorId = input.actorId ?? null;\n\n const declared = input.overrides?.channels ?? definition.channels;\n const requested = declared.filter((channel) =>\n isChannelUsable(channel, deps.channels, deps.plugins),\n );\n\n // Distinct from \"no-channels\": a missing provider is not an opt-out.\n if (declared.length > 0 && requested.length === 0) {\n return {\n notifications: [],\n skipped: userIds.map((userId) => ({ userId, reason: \"channel-unavailable\" as const })),\n };\n }\n\n const prepared = await runPrepare(deps.plugins, { type, recipients }, deps.logger);\n\n for (const userId of userIds) {\n const recipient = byUserId.get(userId);\n if (!recipient) {\n skipped.push({ userId, reason: \"no-recipient\" });\n continue;\n }\n\n const before = await runBeforeSend(\n deps.plugins,\n { type, recipient, actorId },\n payload,\n input.dedupeKey ?? null,\n prepared,\n deps.logger,\n );\n\n if (before.action === \"cancel\") {\n skipped.push({ userId, reason: \"no-channels\" });\n continue;\n }\n\n const resolved = await runResolveChannels(\n deps.plugins,\n { type, recipient, payload: before.payload ?? payload },\n requested.map((channel) => ({ channel, action: \"send\" as const })),\n prepared,\n deps.logger,\n );\n\n const now = new Date();\n const deliveries: InsertDelivery[] = resolved\n .filter((decision) => decision.action !== \"skip\")\n .filter((decision) => isChannelUsable(decision.channel, deps.channels, deps.plugins))\n .map((decision) => ({\n id: newId(),\n channel: decision.channel,\n maxAttempts: definition.maxAttempts ?? deps.maxAttempts,\n // defer is just not_before; the claim query refuses rows whose time has not come. RFC 0004 §4.2.\n notBefore: decision.action === \"defer\" && decision.notBefore ? decision.notBefore : now,\n }));\n\n if (deliveries.length === 0) {\n skipped.push({ userId, reason: \"no-channels\" });\n continue;\n }\n\n const dedupeKey = before.action === \"continue\" ? before.dedupeKey : undefined;\n\n rows.push({\n id: newId(),\n userId,\n type,\n payload: before.payload ?? payload,\n ...(actorId ? { actorId } : {}),\n ...(dedupeKey ? { dedupeKey } : {}),\n deliveries,\n });\n }\n\n if (rows.length === 0) return { notifications: [], skipped };\n\n const { created, deduped } = await deps.adapter.createNotifications(rows);\n const createdSet = new Set(created);\n\n for (const row of rows) {\n if (deduped.includes(row.id)) skipped.push({ userId: row.userId, reason: \"deduped\" });\n }\n\n const notifications = rows\n .filter((row) => createdSet.has(row.id))\n .map((row) => ({\n id: row.id,\n userId: row.userId,\n deliveries: row.deliveries.map((delivery) => ({\n id: delivery.id,\n channel: delivery.channel,\n })),\n }));\n\n for (const plugin of deps.plugins) {\n const hook = plugin.hooks?.afterSend;\n if (!hook) continue;\n try {\n await hook({\n type,\n payload,\n notifications: notifications.map(({ id, userId }) => ({ id, userId })),\n prepared: prepared.get(plugin.id),\n });\n } catch (error) {\n // Fails open: the rows are committed.\n deps.logger.error(`plugin \"${plugin.id}\" afterSend threw; ignoring`, { type, error });\n }\n }\n\n return { notifications, skipped };\n}\n","import type { SchemaDeclaration } from \"../core/plugin\";\n\nexport const toSnakeCase = (value: string) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n\n/** Core tables in the plugin format. A drift test asserts it agrees with the Drizzle schema. */\nexport const coreSchema = {\n notification: {\n tableName: \"notification\",\n fields: {\n id: { type: \"string\", required: true },\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n payload: { type: \"json\", required: true },\n actorId: { type: \"string\" },\n groupKey: { type: \"string\" },\n dedupeKey: { type: \"string\" },\n seenAt: { type: \"date\" },\n readAt: { type: \"date\" },\n archivedAt: { type: \"date\" },\n createdAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"userId\", \"createdAt\"], name: \"notification_feed_idx\" },\n { on: [\"userId\", \"groupKey\"], name: \"notification_group_idx\" },\n { on: [\"userId\", \"dedupeKey\"], unique: true, name: \"notification_dedupe_idx\" },\n ],\n },\n\n notificationDelivery: {\n tableName: \"notification_delivery\",\n fields: {\n id: { type: \"string\", required: true },\n notificationId: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n status: { type: \"string\", required: true, default: \"pending\" },\n attempts: { type: \"number\", required: true, default: 0 },\n maxAttempts: { type: \"number\", required: true, default: 5 },\n notBefore: { type: \"date\", required: true, defaultNow: true },\n claimedAt: { type: \"date\" },\n claimedBy: { type: \"string\" },\n lastError: { type: \"string\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"status\", \"notBefore\"], name: \"delivery_claim_idx\" },\n { on: [\"notificationId\"], name: \"delivery_notification_idx\" },\n ],\n },\n\n notificationPreference: {\n tableName: \"notification_preference\",\n fields: {\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n enabled: { type: \"boolean\", required: true, default: true },\n frequency: { type: \"string\", required: true, default: \"instant\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"userId\", \"type\", \"channel\"],\n },\n} satisfies SchemaDeclaration;\n","import { toSnakeCase } from \"../schema/declaration\";\nimport { ConfigError } from \"./errors\";\nimport type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"./plugin\";\n\nexport type Scalar = string | number | boolean | Date | null;\n\n/** Operators are tagged objects so a bare value is always equality; json columns cannot be filtered. */\nexport type WhereCondition =\n | Scalar\n | { in: readonly (string | number)[] }\n | { lt: Date | number }\n | { lte: Date | number }\n | { gt: Date | number }\n | { gte: Date | number }\n | { not: Scalar };\n\nexport type WhereClause = Record<string, WhereCondition>;\n\nexport type QueryOptions = {\n limit?: number;\n orderBy?: { field: string; direction: \"asc\" | \"desc\" };\n};\n\nexport type UpsertOptions = { onConflict: readonly string[] };\n\n/** Table access for plugins, scoped to the tables the plugin declared. */\nexport type PluginStore = {\n find<T = Record<string, unknown>>(\n table: string,\n where?: WhereClause,\n options?: QueryOptions,\n ): Promise<T[]>;\n insert(table: string, rows: readonly Record<string, unknown>[]): Promise<number>;\n upsert(\n table: string,\n rows: readonly Record<string, unknown>[],\n options: UpsertOptions,\n ): Promise<number>;\n update(table: string, where: WhereClause, set: Record<string, unknown>): Promise<number>;\n remove(table: string, where: WhereClause): Promise<number>;\n};\n\nexport type TableStorage = {\n readonly naming?: \"snake_case\" | \"preserve\";\n readonly serializesJson?: boolean;\n\n queryTable(\n table: string,\n where: WhereClause,\n options: QueryOptions,\n ): Promise<Record<string, unknown>[]>;\n insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ): Promise<number>;\n updateRows(table: string, where: WhereClause, set: Record<string, unknown>): Promise<number>;\n deleteRows(table: string, where: WhereClause): Promise<number>;\n};\n\nconst OPERATORS = [\"in\", \"lt\", \"lte\", \"gt\", \"gte\", \"not\"] as const;\n\nexport const isOperator = (value: unknown): boolean =>\n typeof value === \"object\" &&\n value !== null &&\n !(value instanceof Date) &&\n OPERATORS.some((op) => Object.hasOwn(value, op));\n\nconst isScalar = (value: unknown): value is Scalar =>\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value instanceof Date;\n\n/** A forwarded JSON body can carry `{ $ne: … }`; refuse anything that is not a scalar or a known operator. */\nfunction assertCondition(pluginId: string, field: string, condition: unknown): void {\n if (isScalar(condition)) return;\n\n if (isOperator(condition)) {\n const operator = condition as Record<string, unknown>;\n const keys = Object.keys(operator);\n const [op] = keys;\n if (keys.length !== 1 || op === undefined) {\n throw new ConfigError(`plugin \"${pluginId}\" gave field \"${field}\" more than one operator.`);\n }\n const payload = operator[op];\n const valid =\n op === \"in\"\n ? Array.isArray(payload) &&\n payload.every((item) => typeof item === \"string\" || typeof item === \"number\")\n : isScalar(payload);\n if (valid) return;\n }\n\n throw new ConfigError(\n `plugin \"${pluginId}\" passed a non-scalar value for field \"${field}\"; ` +\n \"validate request bodies before querying with them.\",\n );\n}\n\nfunction assertValue(pluginId: string, field: string, spec: FieldDeclaration, value: unknown) {\n if (value === undefined || isScalar(value)) return;\n if (spec.type === \"json\" && typeof value === \"object\") return;\n throw new ConfigError(\n `plugin \"${pluginId}\" passed a non-scalar value for ${spec.type} field \"${field}\".`,\n );\n}\n\n/** Every table and column is checked against the plugin's own declaration. */\nexport function createPluginStore(\n pluginId: string,\n schema: SchemaDeclaration | undefined,\n storage: TableStorage,\n prefix: string,\n): PluginStore {\n const byTableName = new Map<string, TableDeclaration>();\n for (const declaration of Object.values(schema ?? {})) {\n byTableName.set(declaration.tableName, declaration);\n }\n\n function resolve(table: string): TableDeclaration {\n const declaration = byTableName.get(table);\n if (!declaration) {\n throw new ConfigError(\n `plugin \"${pluginId}\" accessed table \"${table}\", which it does not declare in schema().`,\n );\n }\n return declaration;\n }\n\n function checkFields(table: TableDeclaration, fields: Iterable<string>, context: string) {\n for (const field of fields) {\n // hasOwn, not a lookup: `constructor` and `__proto__` are not columns.\n const spec = Object.hasOwn(table.fields, field) ? table.fields[field] : undefined;\n if (!spec) {\n throw new ConfigError(\n `plugin \"${pluginId}\" used unknown field \"${field}\" on \"${table.tableName}\" (${context}).`,\n );\n }\n if (context === \"where\" && spec.type === \"json\") {\n throw new ConfigError(\n `plugin \"${pluginId}\" cannot filter on json field \"${field}\"; ` +\n \"a bare object value is indistinguishable from an operator.\",\n );\n }\n }\n }\n\n function checkWhere(table: TableDeclaration, where: WhereClause) {\n checkFields(table, Object.keys(where), \"where\");\n for (const [field, condition] of Object.entries(where)) {\n assertCondition(pluginId, field, condition);\n }\n }\n\n function checkRow(table: TableDeclaration, row: Record<string, unknown>, context: string) {\n checkFields(table, Object.keys(row), context);\n for (const [field, value] of Object.entries(row)) {\n const spec = table.fields[field];\n if (spec) assertValue(pluginId, field, spec, value);\n }\n }\n\n const qualified = (table: TableDeclaration) => prefix + table.tableName;\n\n // A document store keeps the declared names; a SQL adapter wants columns.\n const column = (field: string) => (storage.naming === \"preserve\" ? field : toSnakeCase(field));\n\n // json must reach postgres-js as text.\n const serialize = (table: TableDeclaration, row: Record<string, unknown>) => {\n if (storage.serializesJson === false) return row;\n\n const out: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(row)) {\n out[field] =\n table.fields[field]?.type === \"json\" && value !== null && value !== undefined\n ? JSON.stringify(value)\n : value;\n }\n return out;\n };\n\n return {\n async find(table, where = {}, options = {}) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n if (options.orderBy) checkFields(declaration, [options.orderBy.field], \"orderBy\");\n\n const rows = await storage.queryTable(qualified(declaration), where, options);\n\n // SELECT * returns snake_case; plugins read camelCase.\n return rows.map((row) => {\n const mapped: Record<string, unknown> = {};\n for (const field of Object.keys(declaration.fields)) {\n const value = row[column(field)];\n const type = declaration.fields[field]?.type;\n // Drivers differ on jsonb (parsed or text) and timestamptz (Date or text).\n if (type === \"json\" && typeof value === \"string\") mapped[field] = JSON.parse(value);\n else if (type === \"date\" && typeof value === \"string\") mapped[field] = new Date(value);\n // MySQL and SQLite have no boolean column; they hand back 0 and 1.\n else if (type === \"boolean\" && typeof value === \"number\") mapped[field] = value !== 0;\n else mapped[field] = value;\n }\n return mapped;\n }) as never;\n },\n\n async insert(table, rows) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"insert\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n );\n },\n\n async upsert(table, rows, options) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"upsert\");\n checkFields(declaration, options.onConflict, \"onConflict\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n options.onConflict,\n );\n },\n\n async update(table, where, set) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n checkRow(declaration, set, \"update\");\n return storage.updateRows(qualified(declaration), where, serialize(declaration, set));\n },\n\n async remove(table, where) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n return storage.deleteRows(qualified(declaration), where);\n },\n };\n}\n","import type { Backoff } from \"./backoff\";\nimport {\n type EasyPing,\n type EasyPingConfig,\n type HealthReport,\n INBOX_VERSION_HEADER,\n type MountedRoute,\n type SendArgs,\n type SendResult,\n} from \"./config\";\nimport type { NotificationDefinitions } from \"./definition\";\nimport { ConfigError, consoleLogger } from \"./errors\";\nimport { createHandler } from \"./handler\";\nimport type { AnyPlugin } from \"./plugin\";\nimport { createRateLimiter } from \"./rate-limit\";\nimport { createRunner } from \"./runner\";\nimport { isChannelUsable, runSend } from \"./send\";\nimport { createMemorySignals, DELIVERIES_CHANNEL, inboxChannel, type Signals } from \"./signals\";\nimport { createPluginStore } from \"./store\";\nimport { createScopedSigner } from \"./tokens\";\nimport type { DeliveryMode } from \"./types\";\n\nconst CORE_ROUTES: readonly MountedRoute[] = [\n { method: \"GET\", path: \"/\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"GET\", path: \"/count\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/seen\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/read\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/read-all\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"GET\", path: \"/events\", scope: { type: \"user\" }, owner: \"core\" },\n { method: \"POST\", path: \"/cron\", scope: { type: \"machine\" }, owner: \"core\" },\n];\n\nconst DEFAULTS = {\n maxAttempts: 5,\n leaseMs: 60_000,\n batchSize: 20,\n basePath: \"/api/notifications\",\n mode: \"cron\" as DeliveryMode,\n};\n\nexport const MIN_SECRET_LENGTH = 16;\n\nconst PLACEHOLDER_SECRETS = new Set([\n \"secret\",\n \"changeme\",\n \"change-me\",\n \"replace-me\",\n \"replace-me-too\",\n \"password\",\n \"demo-signing-secret\",\n \"demo-cron-secret\",\n]);\n\nfunction checkSecretStrength(name: string, value: string) {\n if (value.length < MIN_SECRET_LENGTH || PLACEHOLDER_SECRETS.has(value.toLowerCase())) {\n throw new ConfigError(\n `\\`${name}\\` must be at least ${MIN_SECRET_LENGTH} characters and not a placeholder. ` +\n \"Generate one with `openssl rand -base64 32`.\",\n );\n }\n}\n\nfunction validate(config: EasyPingConfig<NotificationDefinitions>, plugins: readonly AnyPlugin[]) {\n if (!config.database) throw new ConfigError(\"`database` is required.\");\n if (!config.notifications) throw new ConfigError(\"`notifications` is required.\");\n\n // No default resolver and no dev bypass: an insecure default ships, a crash does not.\n if (typeof config.session?.getUserId !== \"function\") {\n throw new ConfigError(\n \"`session.getUserId` is required — the mounted endpoints serve a user's private inbox \" +\n \"and must resolve the caller. See RFC 0002.\",\n );\n }\n\n if (!config.secret) {\n throw new ConfigError(\n \"`secret` is required — it signs unsubscribe and other session-less links. \" +\n \"Adding it later is a breaking change, so it is mandatory from the start.\",\n );\n }\n checkSecretStrength(\"secret\", config.secret);\n if (config.cron?.secret) checkSecretStrength(\"cron.secret\", config.cron.secret);\n if (config.machineSecret) checkSecretStrength(\"machineSecret\", config.machineSecret);\n\n if (config.rateLimit && (config.rateLimit.max < 1 || config.rateLimit.windowMs < 1)) {\n throw new ConfigError(\"`rateLimit.max` and `rateLimit.windowMs` must both be positive.\");\n }\n\n if (typeof config.getRecipients !== \"function\") {\n throw new ConfigError(\"`getRecipients` is required to resolve emails and timezones.\");\n }\n\n const seen = new Set<string>();\n for (const plugin of plugins) {\n if (seen.has(plugin.id)) {\n throw new ConfigError(`duplicate plugin id \"${plugin.id}\" — ids must be unique.`);\n }\n seen.add(plugin.id);\n }\n\n for (const plugin of plugins) {\n for (const dependency of plugin.dependsOn ?? []) {\n if (!seen.has(dependency)) {\n throw new ConfigError(\n `plugin \"${plugin.id}\" requires \"${dependency}\", which is not registered.`,\n );\n }\n }\n }\n\n const routes = new Set<string>();\n for (const plugin of plugins) {\n for (const route of plugin.routes ?? []) {\n const signature = `${route.method} ${route.path}`;\n if (routes.has(signature)) {\n throw new ConfigError(`route collision: two plugins both registered \"${signature}\".`);\n }\n routes.add(signature);\n }\n }\n\n const mode = config.delivery?.mode ?? DEFAULTS.mode;\n if ((mode === \"cron\" || mode === \"deferred\") && !config.cron?.secret) {\n throw new ConfigError(\n `delivery.mode \"${mode}\" relies on the cron sweep, so \\`cron.secret\\` is required. ` +\n \"Left unset the endpoint would be unauthenticated — a free flush-everything trigger \" +\n \"against your email provider. See RFC 0002 §4.\",\n );\n }\n}\n\nexport function easyPing<TDefs extends NotificationDefinitions>(\n config: EasyPingConfig<TDefs>,\n): EasyPing<TDefs> {\n const plugins = config.plugins ?? [];\n validate(config as EasyPingConfig<NotificationDefinitions>, plugins);\n\n const logger = config.logger ?? consoleLogger;\n const tablePrefix = config.tablePrefix ?? \"\";\n const mode = config.delivery?.mode ?? DEFAULTS.mode;\n const leaseMs = config.delivery?.leaseMs ?? DEFAULTS.leaseMs;\n const warnings: string[] = [];\n\n // Below this ratio a slow send is re-claimed mid-flight. RFC 0003 §7.\n const providerTimeout = config.channels.email?.provider?.timeoutMs;\n if (providerTimeout !== undefined && providerTimeout >= leaseMs / 2) {\n warnings.push(\n `email provider timeout (${providerTimeout}ms) is at least half of delivery.leaseMs ` +\n `(${leaseMs}ms); raise leaseMs or duplicate sends become systematic.`,\n );\n }\n\n const unusable = new Map<string, string[]>();\n for (const [type, definition] of Object.entries(config.notifications)) {\n const missing = definition.channels.filter(\n (channel) => !isChannelUsable(channel, config.channels, plugins),\n );\n if (missing.length > 0) unusable.set(type, [...missing]);\n }\n\n for (const [type, channels] of unusable) {\n const dead = channels.length === config.notifications[type]?.channels.length;\n warnings.push(\n `notification \"${type}\" declares ${channels.map((c) => `\"${c}\"`).join(\", \")} ` +\n `but no provider is configured for ${channels.length > 1 ? \"them\" : \"it\"}` +\n (dead ? \" — this type can never be delivered.\" : \"; those channels will be skipped.\"),\n );\n }\n\n if (mode === \"deferred\" && !config.delivery?.waitUntil) {\n warnings.push(\n \"delivery.mode is 'deferred' but no delivery.waitUntil was supplied; \" +\n \"delivery will wait for the cron sweep.\",\n );\n }\n\n // Custom-scoped routes are named at startup with their justification. RFC 0002 §3.\n for (const plugin of plugins) {\n for (const route of plugin.routes ?? []) {\n if (route.scope.type === \"custom\") {\n warnings.push(\n `plugin \"${plugin.id}\" mounts ${route.method} ${route.path} with custom auth: ` +\n route.scope.justification,\n );\n }\n }\n }\n\n for (const warning of warnings) logger.warn(warning);\n\n const baseSignals = config.signals ?? createMemorySignals();\n\n // Per-user inbox versions for the piggyback header. In-process counters, so\n // another replica's number differs; the client treats any change as \"look\",\n // which costs a spurious refresh, never a missed one.\n const inboxVersions = new Map<string, number>();\n const signals: Signals = {\n crossProcess: baseSignals.crossProcess,\n publish(channel) {\n if (channel.startsWith(\"inbox:\")) {\n if (inboxVersions.size > 50_000) inboxVersions.clear();\n const userId = channel.slice(\"inbox:\".length);\n inboxVersions.set(userId, (inboxVersions.get(userId) ?? 0) + 1);\n }\n baseSignals.publish(channel);\n },\n subscribe: (channel, handler) => baseSignals.subscribe(channel, handler),\n };\n\n const runner = createRunner({\n adapter: config.database,\n definitions: config.notifications,\n channels: config.channels,\n plugins,\n getRecipients: config.getRecipients,\n logger,\n leaseMs,\n batchSize: config.delivery?.batchSize ?? DEFAULTS.batchSize,\n backoff: (config.delivery?.backoff ?? \"exponential\") as Backoff,\n signals,\n });\n\n const pluginRoutes = plugins.flatMap((plugin) => plugin.routes ?? []);\n\n const events =\n config.events === false\n ? false\n : {\n heartbeatMs: config.events?.heartbeatMs ?? 25_000,\n probeIntervalMs: config.events?.probeIntervalMs ?? 30_000,\n maxDurationMs: config.events?.maxDurationMs ?? 0,\n maxStreamsPerUser: config.events?.maxStreamsPerUser ?? 10,\n maxStreams: config.events?.maxStreams ?? 5_000,\n };\n\n const sweepConfig = config.delivery?.sweepOnRequest;\n let lastRequestSweep = 0;\n const sweepOnRequest =\n sweepConfig && mode !== \"inline\"\n ? () => {\n const settings = sweepConfig === true ? {} : sweepConfig;\n const now = Date.now();\n if (now - lastRequestSweep < (settings.everyMs ?? 5_000)) return;\n lastRequestSweep = now;\n const pass = runner\n .runOnce({ limit: settings.limit ?? 5 })\n .catch((error) => logger.error(\"request-driven sweep failed\", { error }));\n config.delivery?.waitUntil?.(pass);\n }\n : undefined;\n\n const handler = createHandler({\n adapter: config.database,\n session: config.session,\n runner,\n logger,\n secret: config.secret,\n signals,\n events,\n sweepOnRequest,\n basePath: config.basePath ?? DEFAULTS.basePath,\n pluginRoutes,\n trustedOrigins: config.trustedOrigins,\n onRequest: config.onRequest,\n maxBodyBytes: config.maxBodyBytes,\n rateLimit: config.rateLimit ? createRateLimiter(config.rateLimit) : undefined,\n cronMaxSweeps: config.cron?.maxSweeps,\n ...(config.cron?.secret ? { cronSecret: config.cron.secret } : {}),\n ...((config.machineSecret ?? config.cron?.secret)\n ? { machineSecret: config.machineSecret ?? config.cron?.secret }\n : {}),\n });\n\n async function send<TKey extends keyof TDefs & string>(\n type: TKey,\n args: SendArgs<TDefs, TKey>,\n ): Promise<SendResult> {\n const result = await runSend(\n type,\n {\n to: args.to,\n payload: args.payload,\n actorId: args.actorId,\n dedupeKey: args.dedupeKey,\n overrides: args.overrides,\n },\n {\n adapter: config.database,\n definitions: config.notifications,\n channels: config.channels,\n plugins,\n getRecipients: config.getRecipients,\n maxAttempts: config.delivery?.maxAttempts ?? DEFAULTS.maxAttempts,\n logger,\n },\n );\n\n // Rows are committed; everything below only affects latency. RFC 0001 §8.1.\n if (result.notifications.length > 0) {\n for (const notification of result.notifications) {\n signals.publish(inboxChannel(notification.userId));\n }\n signals.publish(DELIVERIES_CHANNEL);\n\n // Scoped to this send, or an inline send flushes the whole backlog.\n const ids = result.notifications.flatMap((notification) =>\n notification.deliveries.map((delivery) => delivery.id),\n );\n\n if (mode === \"inline\") await runner.drain({ ids });\n else if (mode === \"deferred\") runner.scheduleDeferred(config.delivery?.waitUntil, ids);\n }\n\n return result;\n }\n\n // After send() exists, before any hook or route can run.\n for (const plugin of plugins) {\n const purposes = new Set(\n (plugin.routes ?? []).flatMap((route) =>\n route.scope.type === \"signed\" ? [route.scope.purpose] : [],\n ),\n );\n plugin.init?.({\n store: createPluginStore(plugin.id, plugin.schema, config.database, tablePrefix),\n sign: createScopedSigner(\n config.secret,\n plugin.id,\n purposes,\n (message) => new ConfigError(message),\n ),\n logger,\n notificationTypes: Object.keys(config.notifications),\n getRecipients: config.getRecipients,\n send: (type, args) => send(type as keyof TDefs & string, args as never) as Promise<unknown>,\n });\n }\n\n return {\n send,\n handler,\n\n startWorker: (options) => runner.startWorker(options ?? {}),\n\n inboxHeaders: (userId) => ({\n [INBOX_VERSION_HEADER]: String(inboxVersions.get(userId) ?? 0),\n }),\n\n listRoutes: () => [\n ...CORE_ROUTES.filter(\n (route) =>\n (route.path !== \"/cron\" || Boolean(config.cron?.secret)) &&\n (route.path !== \"/events\" || events !== false),\n ),\n ...plugins.flatMap((plugin) =>\n (plugin.routes ?? []).map((route) => ({\n method: route.method,\n path: route.path,\n scope: route.scope,\n owner: plugin.id,\n })),\n ),\n ],\n\n getFailedDeliveries: (options = {}) =>\n config.database.getFailedDeliveries({\n since: options.since ?? new Date(Date.now() - 24 * 3600_000),\n limit: Math.min(options.limit ?? 100, 1000),\n }),\n\n healthCheck: async (): Promise<HealthReport> => {\n const cronMounted = Boolean(config.cron?.secret);\n return {\n mode,\n cronMounted,\n cronRequiredButMissing:\n !cronMounted && (mode === \"cron\" || mode === \"deferred\" || mode === \"inline\"),\n warnings,\n };\n },\n };\n}\n","import type { DeliveryOutcome } from \"./adapter\";\nimport type { Logger } from \"./errors\";\nimport type { PluginStore } from \"./store\";\nimport type { SignRequest, TokenClaims } from \"./tokens\";\nimport type { Channel, Recipient } from \"./types\";\n\nexport type Promisable<T> = T | Promise<T>;\n\nexport type PrepareContext = {\n type: string;\n recipients: readonly Recipient[];\n};\n\nexport type BeforeSendContext = {\n type: string;\n recipient: Recipient;\n payload: unknown;\n actorId: string | null;\n dedupeKey: string | null;\n /** Whatever this plugin's own prepare() returned for this send. */\n prepared: unknown;\n};\n\nexport type BeforeSendResult =\n | { action: \"continue\"; payload?: unknown; dedupeKey?: string }\n | { action: \"cancel\"; reason: string };\n\nexport type ChannelDecision = {\n channel: Channel;\n action: \"send\" | \"skip\" | \"defer\";\n /** defer only. Written to notification_delivery.not_before. */\n notBefore?: Date | undefined;\n};\n\nexport type ResolveChannelsContext = {\n type: string;\n recipient: Recipient;\n payload: unknown;\n decisions: readonly ChannelDecision[];\n /** Whatever this plugin's own prepare() returned for this send. */\n prepared: unknown;\n};\n\nexport type DeliverContext = {\n channel: Channel;\n deliveryId: string;\n attempt: number;\n recipient: Recipient;\n notification: { id: string; userId: string; type: string; payload: unknown };\n /** Aborted on the runner's timeout. */\n signal: AbortSignal;\n};\n\nexport type AfterSendContext = {\n type: string;\n payload: unknown;\n /** Committed rows. Ids exist only at this point. */\n notifications: readonly { id: string; userId: string }[];\n /** Whatever this plugin's own prepare() returned for this send. */\n prepared: unknown;\n};\n\nexport type AfterDeliverContext = {\n deliveryId: string;\n notificationId: string;\n userId: string;\n channel: Channel;\n outcome: DeliveryOutcome;\n attempt: number;\n isTerminal: boolean;\n};\n\n/** beforeSend and resolveChannels fail closed; afterDeliver fails open. */\nexport type PluginHooks = {\n /** Once per send, for bulk loading — the per-recipient hooks would be an N+1. */\n prepare?: (ctx: PrepareContext) => Promisable<unknown>;\n beforeSend?: (ctx: BeforeSendContext) => Promisable<BeforeSendResult>;\n resolveChannels?: (ctx: ResolveChannelsContext) => Promisable<readonly ChannelDecision[]>;\n /** Once per send, after commit. The only hook that sees notification ids. Fails open. */\n afterSend?: (ctx: AfterSendContext) => Promisable<void>;\n /** Delivers one of the plugin's declared `channels`. Core carries inApp and email. */\n deliver?: (ctx: DeliverContext) => Promisable<DeliveryOutcome>;\n afterDeliver?: (ctx: AfterDeliverContext) => Promisable<void>;\n};\n\nexport type FieldType = \"string\" | \"number\" | \"boolean\" | \"date\" | \"json\";\n\nexport type FieldDeclaration = {\n type: FieldType;\n required?: boolean;\n default?: string | number | boolean;\n /** date fields only. Renders as defaultNow() / CURRENT_TIMESTAMP. */\n defaultNow?: boolean;\n};\n\nexport type IndexDeclaration = {\n on: readonly string[];\n unique?: boolean;\n name?: string;\n};\n\nexport type TableDeclaration = {\n tableName: string;\n fields: Record<string, FieldDeclaration>;\n primaryKey?: readonly string[];\n indexes?: readonly IndexDeclaration[];\n};\n\nexport type SchemaDeclaration = Record<string, TableDeclaration>;\n\nexport type RouteScope =\n | { type: \"user\" }\n | { type: \"machine\" }\n | { type: \"signed\"; purpose: string }\n | { type: \"custom\"; justification: string };\n\nexport type RouteContext = {\n request: Request;\n /** Resolved for user-scoped routes, so a handler cannot forget to scope. */\n userId: string | null;\n /** Verified before dispatch, so a handler cannot forget to check. */\n claims: TokenClaims | null;\n params: Record<string, string>;\n};\n\nexport type RouteDefinition = {\n path: string;\n method: \"GET\" | \"POST\";\n scope: RouteScope;\n handler: (ctx: RouteContext) => Promise<Response>;\n};\n\n/** Handed to a plugin at startup so it need not be given the database twice. */\nexport type PluginInitContext = {\n /** Scoped to the tables this plugin declares in schema(). */\n store: PluginStore;\n /** Mints tokens for this plugin's own `signed` routes only. The secret itself is never handed out. */\n sign: (request: SignRequest) => Promise<string>;\n logger: Logger;\n /** Configured notification names, so a route can refuse to store rows for types that do not exist. */\n notificationTypes: readonly string[];\n /** The app's resolver, for plugins that need timezones or addresses. */\n getRecipients: (userIds: readonly string[]) => Promise<readonly Recipient[]>;\n /** The instance's own send(), so a composed message inherits retry, backoff and idempotency. */\n send: (\n type: string,\n args: { to: string | readonly string[]; payload: unknown; dedupeKey?: string },\n ) => Promise<unknown>;\n};\n\nexport type EasyPingPlugin<\n TId extends string = string,\n TSchema extends SchemaDeclaration = SchemaDeclaration,\n> = {\n id: TId;\n dependsOn?: readonly string[];\n schema?: TSchema;\n routes?: readonly RouteDefinition[];\n hooks?: PluginHooks;\n /** Channels this plugin delivers. Makes them usable in a notification. */\n channels?: readonly Channel[];\n /** Called once by easyPing() before any hook or route can run. */\n init?: (ctx: PluginInitContext) => void;\n};\n\nexport type AnyPlugin = EasyPingPlugin<string, SchemaDeclaration>;\n\nexport function definePlugin<TId extends string, TSchema extends SchemaDeclaration>(\n plugin: EasyPingPlugin<TId, TSchema>,\n): EasyPingPlugin<TId, TSchema> {\n return plugin;\n}\n\nexport type ClientFetch = (path: string, init?: RequestInit) => Promise<unknown>;\n\nexport type ClientPlugin<\n TId extends string = string,\n TActions extends Record<string, unknown> = Record<string, unknown>,\n> = {\n id: TId;\n /** Phantom. Links client types to the server plugin so a mismatch is a type error. */\n $InferServerPlugin?: AnyPlugin;\n actions: (fetch: ClientFetch) => TActions;\n};\n\nexport type AnyClientPlugin = ClientPlugin<string, Record<string, unknown>>;\n\nexport function defineClientPlugin<TId extends string, TActions extends Record<string, unknown>>(\n plugin: ClientPlugin<TId, TActions>,\n): ClientPlugin<TId, TActions> {\n return plugin;\n}\n\nexport type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n/** Naked type parameter, so the conditional distributes over the union. */\ntype ExtractActions<TPlugin> = TPlugin extends { actions: (fetch: never) => infer TActions }\n ? TActions\n : never;\n\n/** Indexes the tuple rather than recursing: a fold blows the instantiation depth limit. */\nexport type ActionsOf<TPlugins extends readonly AnyClientPlugin[]> = UnionToIntersection<\n ExtractActions<TPlugins[number]>\n>;\n"]}
|