easy-ping 0.3.0 → 0.5.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.
Files changed (127) hide show
  1. package/README.md +174 -82
  2. package/dist/adapter-B7R4rXtJ.d.cts +17 -0
  3. package/dist/adapter-B7R4rXtJ.d.ts +17 -0
  4. package/dist/{adapter-BfLe2J0t.d.cts → adapter-D3lTy-4E.d.cts} +6 -32
  5. package/dist/{adapter-BfLe2J0t.d.ts → adapter-D3lTy-4E.d.ts} +6 -32
  6. package/dist/adapters/drizzle.cjs +4 -4
  7. package/dist/adapters/drizzle.cjs.map +1 -1
  8. package/dist/adapters/drizzle.d.cts +35 -1
  9. package/dist/adapters/drizzle.d.ts +35 -1
  10. package/dist/adapters/drizzle.js +5 -5
  11. package/dist/adapters/drizzle.js.map +1 -1
  12. package/dist/adapters/mongodb.cjs +8 -7
  13. package/dist/adapters/mongodb.cjs.map +1 -1
  14. package/dist/adapters/mongodb.d.cts +4 -17
  15. package/dist/adapters/mongodb.d.ts +4 -17
  16. package/dist/adapters/mongodb.js +7 -7
  17. package/dist/adapters/mongodb.js.map +1 -1
  18. package/dist/adapters/mysql.cjs +605 -0
  19. package/dist/adapters/mysql.cjs.map +1 -0
  20. package/dist/adapters/mysql.d.cts +38 -0
  21. package/dist/adapters/mysql.d.ts +38 -0
  22. package/dist/adapters/mysql.js +51 -0
  23. package/dist/adapters/mysql.js.map +1 -0
  24. package/dist/adapters/postgres.cjs +19 -11
  25. package/dist/adapters/postgres.cjs.map +1 -1
  26. package/dist/adapters/postgres.d.cts +9 -54
  27. package/dist/adapters/postgres.d.ts +9 -54
  28. package/dist/adapters/postgres.js +6 -41
  29. package/dist/adapters/postgres.js.map +1 -1
  30. package/dist/adapters/sqlite.cjs +593 -0
  31. package/dist/adapters/sqlite.cjs.map +1 -0
  32. package/dist/adapters/sqlite.d.cts +37 -0
  33. package/dist/adapters/sqlite.d.ts +37 -0
  34. package/dist/adapters/sqlite.js +53 -0
  35. package/dist/adapters/sqlite.js.map +1 -0
  36. package/dist/browser.cjs.map +1 -1
  37. package/dist/browser.d.cts +2 -14
  38. package/dist/browser.d.ts +2 -14
  39. package/dist/browser.js.map +1 -1
  40. package/dist/chunk-2EYKPF5A.js +393 -0
  41. package/dist/chunk-2EYKPF5A.js.map +1 -0
  42. package/dist/{chunk-OZSOIX23.js → chunk-3VOQOGDR.js} +54 -12
  43. package/dist/chunk-3VOQOGDR.js.map +1 -0
  44. package/dist/{chunk-NYDVNMKG.js → chunk-AEYYTE5I.js} +4 -3
  45. package/dist/chunk-AEYYTE5I.js.map +1 -0
  46. package/dist/chunk-BECMTNK7.js +315 -0
  47. package/dist/chunk-BECMTNK7.js.map +1 -0
  48. package/dist/chunk-CK5UPVYP.js +48 -0
  49. package/dist/chunk-CK5UPVYP.js.map +1 -0
  50. package/dist/{chunk-BV3U542P.js → chunk-E4IZ2CQC.js} +2 -2
  51. package/dist/chunk-E4IZ2CQC.js.map +1 -0
  52. package/dist/chunk-GJNLOQJS.js +226 -0
  53. package/dist/chunk-GJNLOQJS.js.map +1 -0
  54. package/dist/chunk-HY47TQMY.js +52 -0
  55. package/dist/chunk-HY47TQMY.js.map +1 -0
  56. package/dist/chunk-M4R77BJD.js +64 -0
  57. package/dist/chunk-M4R77BJD.js.map +1 -0
  58. package/dist/{chunk-RBDW4S6F.js → chunk-XIDVLYNQ.js} +14 -4
  59. package/dist/chunk-XIDVLYNQ.js.map +1 -0
  60. package/dist/client.cjs.map +1 -1
  61. package/dist/client.js.map +1 -1
  62. package/dist/index.cjs +362 -64
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +56 -37
  65. package/dist/index.d.ts +56 -37
  66. package/dist/index.js +120 -359
  67. package/dist/index.js.map +1 -1
  68. package/dist/node.cjs +27 -6
  69. package/dist/node.cjs.map +1 -1
  70. package/dist/node.d.cts +8 -2
  71. package/dist/node.d.ts +8 -2
  72. package/dist/node.js +26 -6
  73. package/dist/node.js.map +1 -1
  74. package/dist/{plugin-CmPOFVmn.d.ts → plugin-CHd2ZiGC.d.cts} +37 -25
  75. package/dist/{plugin-f5KaFWSN.d.cts → plugin-Cg9usuUi.d.ts} +37 -25
  76. package/dist/plugins/digests.cjs +1 -4
  77. package/dist/plugins/digests.cjs.map +1 -1
  78. package/dist/plugins/digests.d.cts +6 -31
  79. package/dist/plugins/digests.d.ts +6 -31
  80. package/dist/plugins/digests.js +1 -4
  81. package/dist/plugins/digests.js.map +1 -1
  82. package/dist/plugins/preferences-client.cjs.map +1 -1
  83. package/dist/plugins/preferences-client.d.cts +2 -2
  84. package/dist/plugins/preferences-client.d.ts +2 -2
  85. package/dist/plugins/preferences-client.js +1 -1
  86. package/dist/plugins/preferences-react.cjs.map +1 -1
  87. package/dist/plugins/preferences-react.js.map +1 -1
  88. package/dist/plugins/preferences.cjs +101 -17
  89. package/dist/plugins/preferences.cjs.map +1 -1
  90. package/dist/plugins/preferences.d.cts +4 -2
  91. package/dist/plugins/preferences.d.ts +4 -2
  92. package/dist/plugins/preferences.js +36 -9
  93. package/dist/plugins/preferences.js.map +1 -1
  94. package/dist/plugins/push.cjs +198 -40
  95. package/dist/plugins/push.cjs.map +1 -1
  96. package/dist/plugins/push.d.cts +20 -18
  97. package/dist/plugins/push.d.ts +20 -18
  98. package/dist/plugins/push.js +141 -41
  99. package/dist/plugins/push.js.map +1 -1
  100. package/dist/providers/web-push.cjs +37 -11
  101. package/dist/providers/web-push.cjs.map +1 -1
  102. package/dist/providers/web-push.d.cts +10 -11
  103. package/dist/providers/web-push.d.ts +10 -11
  104. package/dist/providers/web-push.js +37 -12
  105. package/dist/providers/web-push.js.map +1 -1
  106. package/dist/react.cjs.map +1 -1
  107. package/dist/react.d.cts +1 -4
  108. package/dist/react.d.ts +1 -4
  109. package/dist/react.js.map +1 -1
  110. package/dist/schema.cjs +121 -2
  111. package/dist/schema.cjs.map +1 -1
  112. package/dist/schema.d.cts +25 -14
  113. package/dist/schema.d.ts +25 -14
  114. package/dist/schema.js +4 -2
  115. package/dist/testing.cjs +3 -19
  116. package/dist/testing.cjs.map +1 -1
  117. package/dist/testing.d.cts +4 -22
  118. package/dist/testing.d.ts +4 -22
  119. package/dist/testing.js +3 -19
  120. package/dist/testing.js.map +1 -1
  121. package/package.json +12 -1
  122. package/dist/chunk-BV3U542P.js.map +0 -1
  123. package/dist/chunk-NYDVNMKG.js.map +0 -1
  124. package/dist/chunk-OZSOIX23.js.map +0 -1
  125. package/dist/chunk-RBDW4S6F.js.map +0 -1
  126. package/dist/chunk-W3BMEPPQ.js +0 -50
  127. package/dist/chunk-W3BMEPPQ.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/base64url.ts","../../src/schema/declaration.ts","../../src/core/store.ts","../../src/adapters/sql/statement.ts","../../src/adapters/sql/adapter.ts","../../src/adapters/sql/dialect.ts","../../src/adapters/sqlite/adapter.ts","../../src/schema/render-sqlite.ts","../../src/adapters/sqlite/helpers.ts"],"names":["quote"],"mappings":"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","file":"sqlite.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 { 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","export type Placeholder = \"dollar\" | \"question\";\n\nexport type StatementOptions = {\n /** `$1, $2` for Postgres; `?` for MySQL and SQLite. */\n placeholder?: Placeholder;\n /** What the driver is handed for a JS value. Dates become ISO strings by default. */\n bind?: (value: unknown) => unknown;\n};\n\nconst defaultBind = (value: unknown) => (value instanceof Date ? value.toISOString() : value);\n\n/** SQL text plus bound values. Values are never interpolated; identifiers arrive pre-validated. */\nexport class Statement {\n #text = \"\";\n readonly params: unknown[] = [];\n readonly #placeholder: Placeholder;\n readonly #bind: (value: unknown) => unknown;\n\n constructor(options: StatementOptions = {}) {\n this.#placeholder = options.placeholder ?? \"dollar\";\n this.#bind = options.bind ?? defaultBind;\n }\n\n /** Raw SQL. Never user input; use `value`. */\n raw(fragment: string): this {\n this.#text += fragment;\n return this;\n }\n\n value(value: unknown): this {\n this.params.push(this.#bind(value));\n this.#text += this.#placeholder === \"dollar\" ? `$${this.params.length}` : \"?\";\n return this;\n }\n\n list(values: readonly unknown[], separator = \", \"): this {\n values.forEach((value, index) => {\n if (index > 0) this.raw(separator);\n this.value(value);\n });\n return this;\n }\n\n /** `($1::text, $2::timestamptz)`. Casts are Postgres-only and dropped elsewhere. */\n tuple(cells: readonly (readonly [unknown, string])[]): this {\n this.raw(\"(\");\n cells.forEach(([value, cast], index) => {\n if (index > 0) this.raw(\", \");\n this.value(value);\n if (this.#placeholder === \"dollar\") this.raw(`::${cast}`);\n });\n return this.raw(\")\");\n }\n\n get text(): string {\n return this.#text;\n }\n}\n\nexport const quoteWith =\n (quoteChar: '\"' | \"`\") =>\n (identifier: string): string =>\n `${quoteChar}${identifier.split(quoteChar).join(quoteChar + quoteChar)}${quoteChar}`;\n\n/** Double-quoted: Postgres and SQLite. */\nexport const quote = quoteWith('\"');\n","import type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\nimport { toSnakeCase } from \"../../schema/declaration\";\nimport type { Dialect, Row, SqlExec, SqlResult } from \"./dialect\";\nimport { Statement } from \"./statement\";\n\nexport type SqlAdapterOptions = {\n /** Table-name prefix. Must match the instance's `tablePrefix`. */\n prefix?: string;\n /** Makes createNotifications atomic and, on MySQL, lets a claim use FOR UPDATE SKIP LOCKED. */\n transaction?: <T>(fn: (exec: SqlExec) => Promise<T>) => Promise<T>;\n};\n\nconst str = (value: unknown): string => String(value);\nconst nullableStr = (value: unknown): string | null => (value == null ? null : String(value));\nconst num = (value: unknown): number => Number(value);\n\nconst encodeCursor = (createdAt: Date, id: string) =>\n encodeBase64Url(`${createdAt.toISOString()}|${id}`);\n\nfunction decodeCursor(cursor: string): { createdAt: Date; id: string } | null {\n const decoded = decodeBase64Url(cursor);\n if (!decoded) return null;\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nconst NONE: SqlResult = { rows: [], affectedRows: 0 };\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** InnoDB rolls back the loser of a deadlock and asks for a retry; bounded and jittered. */\nasync function retryingLocks<T>(dialect: Dialect, attempt: () => Promise<T>): Promise<T> {\n for (let tries = 0; ; tries += 1) {\n try {\n return await attempt();\n } catch (error) {\n if (tries >= 5 || !dialect.isRetryableLock(error)) throw error;\n await sleep(5 + Math.random() * 20 * (tries + 1));\n }\n }\n}\n\n/**\n * Every SQL engine that is not Postgres, behind one dialect: the same queries\n * minus RETURNING, casts and IS DISTINCT FROM. RFC 0005.\n */\nexport function createSqlAdapter(\n dialect: Dialect,\n exec: SqlExec,\n options: SqlAdapterOptions = {},\n): DatabaseAdapter {\n const prefix = options.prefix ?? \"\";\n const q = dialect.quote;\n const NOTIFICATION = q(`${prefix}notification`);\n const DELIVERY = q(`${prefix}notification_delivery`);\n\n const stmt = () => new Statement({ placeholder: dialect.placeholder, bind: dialect.bind });\n const run = (statement: Statement, on: SqlExec = exec) => on(statement.text, statement.params);\n const atomically = <T>(fn: (on: SqlExec) => Promise<T>): Promise<T> =>\n options.transaction ? options.transaction(fn) : fn(exec);\n\n const toNotification = (row: Row): NotificationRecord => ({\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: dialect.readJson(row.payload),\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: dialect.readNullableDate(row.seen_at),\n readAt: dialect.readNullableDate(row.read_at),\n archivedAt: dialect.readNullableDate(row.archived_at),\n createdAt: dialect.readDate(row.created_at),\n });\n\n const toDelivery = (row: Row): DeliveryRecord => ({\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n status: str(row.status) as DeliveryStatus,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notBefore: dialect.readDate(row.not_before),\n claimedAt: dialect.readNullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: dialect.readDate(row.updated_at),\n });\n\n function appendWhere(statement: Statement, where: WhereClause): void {\n const entries = Object.entries(where);\n if (entries.length === 0) return;\n\n statement.raw(\" WHERE \");\n\n entries.forEach(([field, condition], index) => {\n if (index > 0) statement.raw(\" AND \");\n const column = q(toSnakeCase(field));\n\n if (condition === null) {\n statement.raw(`${column} IS NULL`);\n return;\n }\n if (!isOperator(condition)) {\n statement.raw(`${column} = `).value(condition);\n return;\n }\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) {\n const list = operator.in as readonly (string | number)[];\n if (list.length === 0) statement.raw(\"1 = 0\");\n else statement.raw(`${column} IN (`).list(list).raw(\")\");\n return;\n }\n if (\"lt\" in operator) statement.raw(`${column} < `).value(operator.lt);\n else if (\"lte\" in operator) statement.raw(`${column} <= `).value(operator.lte);\n else if (\"gt\" in operator) statement.raw(`${column} > `).value(operator.gt);\n else if (\"gte\" in operator) statement.raw(`${column} >= `).value(operator.gte);\n else if (\"not\" in operator) {\n if (operator.not === null) statement.raw(`${column} IS NOT NULL`);\n else dialect.distinctFrom(statement, column, operator.not);\n } else statement.raw(\"1 = 1\");\n });\n }\n\n function eligible(statement: Statement, args: ClaimArgs, now: Date, staleBefore: Date): void {\n statement\n .raw(\"(status = 'pending' OR (status = 'claimed' AND claimed_at < \")\n .value(staleBefore)\n .raw(\")) AND not_before <= \")\n .value(now)\n .raw(\" AND attempts < max_attempts\");\n if (args.channels && args.channels.length > 0) {\n statement.raw(\" AND channel IN (\").list(args.channels).raw(\")\");\n }\n if (args.ids && args.ids.length > 0) {\n statement.raw(\" AND id IN (\").list(args.ids).raw(\")\");\n }\n }\n\n /** The token is unique per call, so this is exactly what the call just claimed. */\n const readClaimed = (token: string, on: SqlExec) =>\n run(\n stmt()\n .raw(\n \"SELECT c.id, c.notification_id, c.channel, c.attempts, c.max_attempts,\" +\n ` n.user_id, n.type, n.payload, n.actor_id FROM ${DELIVERY} c` +\n ` JOIN ${NOTIFICATION} n ON n.id = c.notification_id WHERE c.claimed_by = `,\n )\n .value(token)\n .raw(\" AND c.status = 'claimed' ORDER BY c.not_before ASC, c.id ASC\"),\n on,\n );\n\n return {\n name: dialect.name,\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n const now = new Date();\n\n return atomically(async (on) => {\n const created: string[] = [];\n const deduped: string[] = [];\n\n // No RETURNING on MySQL and INSERT IGNORE hides real errors: look, insert, treat a race as dedupe.\n for (const row of input) {\n if (row.dedupeKey) {\n const existing = await run(\n stmt()\n .raw(`SELECT id FROM ${NOTIFICATION} WHERE user_id = `)\n .value(row.userId)\n .raw(\" AND dedupe_key = \")\n .value(row.dedupeKey),\n on,\n );\n if (existing.rows.length > 0) {\n deduped.push(row.id);\n continue;\n }\n }\n\n try {\n await run(\n stmt()\n .raw(\n `INSERT INTO ${NOTIFICATION} ` +\n \"(id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at) VALUES (\",\n )\n .list([\n row.id,\n row.userId,\n row.type,\n JSON.stringify(row.payload ?? null),\n row.actorId ?? null,\n row.groupKey ?? null,\n row.dedupeKey ?? null,\n now,\n ])\n .raw(\")\"),\n on,\n );\n } catch (error) {\n if (row.dedupeKey && dialect.isDuplicateKey(error)) {\n deduped.push(row.id);\n continue;\n }\n throw error;\n }\n created.push(row.id);\n }\n\n const createdSet = new Set(created);\n const deliveries = input\n .filter((row) => createdSet.has(row.id))\n .flatMap((row) => row.deliveries.map((delivery) => ({ row, delivery })));\n\n if (deliveries.length > 0) {\n const insert = stmt().raw(\n `INSERT INTO ${DELIVERY} ` +\n \"(id, notification_id, channel, max_attempts, not_before, updated_at) VALUES \",\n );\n deliveries.forEach(({ row, delivery }, index) => {\n if (index > 0) insert.raw(\", \");\n insert\n .raw(\"(\")\n .list([\n delivery.id,\n row.id,\n delivery.channel,\n delivery.maxAttempts,\n delivery.notBefore,\n now,\n ])\n .raw(\")\");\n });\n await run(insert, on);\n }\n\n return { created, deduped };\n });\n },\n\n async claimPendingDeliveries(args: ClaimArgs): Promise<readonly ClaimedDelivery[]> {\n const now = args.now ?? new Date();\n const staleBefore = new Date(now.getTime() - args.leaseMs);\n const strategy = options.transaction\n ? dialect.claim.withTransaction\n : dialect.claim.withoutTransaction;\n\n const claimSet = (statement: Statement) =>\n statement\n .raw(\"status = 'claimed', claimed_at = \")\n .value(now)\n .raw(\", claimed_by = \")\n .value(args.claimToken);\n\n let result: SqlResult;\n\n if (strategy === \"skip-locked\") {\n result = await atomically(async (on) => {\n const pick = stmt().raw(`SELECT id FROM ${DELIVERY} WHERE `);\n eligible(pick, args, now, staleBefore);\n pick\n .raw(\" ORDER BY not_before ASC, id ASC LIMIT \")\n .value(args.limit)\n .raw(\" FOR UPDATE SKIP LOCKED\");\n const ids = (await run(pick, on)).rows.map((row) => str(row.id));\n if (ids.length === 0) return NONE;\n\n const update = stmt().raw(`UPDATE ${DELIVERY} SET `);\n claimSet(update).raw(\" WHERE id IN (\").list(ids).raw(\")\");\n await run(update, on);\n return readClaimed(args.claimToken, on);\n });\n } else {\n const update = stmt();\n if (strategy === \"derived-update\") {\n // The derived table is materialised, which is what lets MySQL update the table it\n // selects from; the outer predicate is re-evaluated on the locked row.\n update.raw(`UPDATE ${DELIVERY} d JOIN (SELECT id FROM ${DELIVERY} WHERE `);\n eligible(update, args, now, staleBefore);\n update\n .raw(\" ORDER BY not_before ASC, id ASC LIMIT \")\n .value(args.limit)\n .raw(\") s ON s.id = d.id SET d.status = 'claimed', d.claimed_at = \")\n .value(now)\n .raw(\", d.claimed_by = \")\n .value(args.claimToken)\n .raw(\" WHERE d.status = 'pending' OR (d.status = 'claimed' AND d.claimed_at < \")\n .value(staleBefore)\n .raw(\")\");\n } else {\n update.raw(`UPDATE ${DELIVERY} SET `);\n claimSet(update).raw(` WHERE id IN (SELECT id FROM ${DELIVERY} WHERE `);\n eligible(update, args, now, staleBefore);\n update.raw(\" ORDER BY not_before ASC, id ASC LIMIT \").value(args.limit).raw(\")\");\n }\n const updated = await retryingLocks(dialect, () => run(update));\n result = updated.affectedRows > 0 ? await readClaimed(args.claimToken, exec) : NONE;\n }\n\n return result.rows.map((row) => ({\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notification: {\n userId: str(row.user_id),\n type: str(row.type),\n payload: dialect.readJson(row.payload),\n actorId: nullableStr(row.actor_id),\n },\n }));\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n // No claimed_by predicate (RFC 0003 §6). `status` before `attempts`: MySQL evaluates SET\n // left to right with updated values, and the CASE needs the old count.\n await atomically(async (on) => {\n for (const { id, outcome, nextAttemptAt } of releases) {\n const result = outcome.result;\n const retryable = outcome.result === \"failed\" && outcome.retryable;\n const error =\n outcome.result === \"failed\"\n ? outcome.error.slice(0, 2000)\n : outcome.result === \"skipped\"\n ? outcome.reason.slice(0, 2000)\n : null;\n\n await run(\n stmt()\n .raw(`UPDATE ${DELIVERY} SET status = CASE WHEN `)\n .value(result)\n .raw(\" = 'sent' THEN 'sent' WHEN \")\n .value(result)\n .raw(\" = 'skipped' THEN 'skipped' WHEN \")\n .value(retryable)\n .raw(\" = 1 AND attempts + 1 < max_attempts THEN 'pending' ELSE 'failed' END\")\n .raw(\", attempts = CASE WHEN \")\n .value(result)\n .raw(\" IN ('sent', 'skipped') THEN attempts ELSE attempts + 1 END\")\n .raw(\", last_error = \")\n .value(error)\n .raw(\", not_before = COALESCE(\")\n .value(nextAttemptAt ?? null)\n .raw(\", not_before), claimed_at = NULL, claimed_by = NULL, updated_at = \")\n .value(now)\n .raw(\" WHERE id = \")\n .value(id),\n on,\n );\n }\n });\n },\n\n async listNotifications(feed: FeedQuery): Promise<FeedPage> {\n const cursor = feed.cursor ? decodeCursor(feed.cursor) : null;\n\n const statement = stmt()\n .raw(`SELECT * FROM ${NOTIFICATION} WHERE user_id = `)\n .value(feed.userId)\n .raw(\" AND archived_at IS NULL\");\n if (feed.unreadOnly) statement.raw(\" AND read_at IS NULL\");\n if (cursor) {\n statement\n .raw(\" AND (created_at, id) < (\")\n .value(cursor.createdAt)\n .raw(\", \")\n .value(cursor.id)\n .raw(\")\");\n }\n statement.raw(\" ORDER BY created_at DESC, id DESC LIMIT \").value(feed.limit + 1);\n\n const { rows } = await run(statement);\n const page = rows.slice(0, feed.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor: rows.length > feed.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const { rows } = await run(\n stmt()\n .raw(`SELECT COUNT(*) AS count FROM ${NOTIFICATION} WHERE user_id = `)\n .value(userId)\n .raw(\" AND seen_at IS NULL AND archived_at IS NULL\"),\n );\n return num(rows[0]?.count ?? 0);\n },\n\n async markSeen(userId: string, before: Date) {\n await run(\n stmt()\n .raw(`UPDATE ${NOTIFICATION} SET seen_at = `)\n .value(new Date())\n .raw(\" WHERE user_id = \")\n .value(userId)\n .raw(\" AND seen_at IS NULL AND created_at <= \")\n .value(before),\n );\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Idempotent, so the answer is rows matched; MySQL's affectedRows reports rows changed.\n await run(\n stmt()\n .raw(`UPDATE ${NOTIFICATION} SET read_at = COALESCE(read_at, `)\n .value(new Date())\n .raw(\") WHERE user_id = \")\n .value(userId)\n .raw(\" AND id IN (\")\n .list(notificationIds)\n .raw(\")\"),\n );\n const { rows } = await run(\n stmt()\n .raw(`SELECT COUNT(*) AS count FROM ${NOTIFICATION} WHERE user_id = `)\n .value(userId)\n .raw(\" AND id IN (\")\n .list(notificationIds)\n .raw(\")\"),\n );\n return num(rows[0]?.count ?? 0);\n },\n\n async markAllRead(userId: string) {\n const { affectedRows } = await run(\n stmt()\n .raw(`UPDATE ${NOTIFICATION} SET read_at = `)\n .value(new Date())\n .raw(\" WHERE user_id = \")\n .value(userId)\n .raw(\" AND read_at IS NULL\"),\n );\n return affectedRows;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const { rows } = await run(\n stmt()\n .raw(`SELECT * FROM ${DELIVERY} WHERE status = 'failed' AND updated_at >= `)\n .value(args.since)\n .raw(\" ORDER BY updated_at DESC LIMIT \")\n .value(args.limit),\n );\n return rows.map(toDelivery);\n },\n\n async queryTable(table: string, where: WhereClause, queryOptions: QueryOptions) {\n const statement = stmt().raw(`SELECT * FROM ${q(table)}`);\n appendWhere(statement, where);\n if (queryOptions.orderBy) {\n const direction = queryOptions.orderBy.direction === \"desc\" ? \"DESC\" : \"ASC\";\n statement.raw(` ORDER BY ${q(toSnakeCase(queryOptions.orderBy.field))} ${direction}`);\n }\n if (queryOptions.limit) statement.raw(\" LIMIT \").value(queryOptions.limit);\n return [...(await run(statement)).rows];\n },\n\n async insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ) {\n if (rows.length === 0) return 0;\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const statement = stmt().raw(\n `INSERT INTO ${q(table)} (${columns.map((c) => q(toSnakeCase(c))).join(\", \")}) VALUES `,\n );\n rows.forEach((row, index) => {\n if (index > 0) statement.raw(\", \");\n statement\n .raw(\"(\")\n .list(columns.map((column) => row[column]))\n .raw(\")\");\n });\n\n if (onConflict && onConflict.length > 0) {\n statement.raw(\n dialect.upsertClause(\n onConflict.map((f) => q(toSnakeCase(f))),\n columns.filter((c) => !onConflict.includes(c)).map((c) => q(toSnakeCase(c))),\n ),\n );\n await run(statement);\n // MySQL reports 2 for an updated row; the rows handed in is the honest count.\n return rows.length;\n }\n\n return (await run(statement)).affectedRows;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set);\n if (assignments.length === 0) return 0;\n\n const statement = stmt().raw(`UPDATE ${q(table)} SET `);\n assignments.forEach(([field, value], index) => {\n if (index > 0) statement.raw(\", \");\n statement.raw(`${q(toSnakeCase(field))} = `).value(value);\n });\n appendWhere(statement, where);\n return (await run(statement)).affectedRows;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const statement = stmt().raw(`DELETE FROM ${q(table)}`);\n appendWhere(statement, where);\n return (await run(statement)).affectedRows;\n },\n };\n}\n","import type { Placeholder, Statement } from \"./statement\";\nimport { quoteWith } from \"./statement\";\n\nexport type Row = Record<string, unknown>;\n\nexport type SqlResult = {\n rows: readonly Row[];\n /** Rows an INSERT/UPDATE/DELETE touched; drivers without RETURNING report through this. */\n affectedRows: number;\n};\n\n/** The whole driver contract for the MySQL and SQLite adapters. */\nexport type SqlExec = (text: string, params: readonly unknown[]) => Promise<SqlResult>;\n\n/** How a claim takes its rows. RFC 0005 §3. */\nexport type ClaimStrategy = \"skip-locked\" | \"derived-update\" | \"subquery-update\";\n\nexport type Dialect = {\n name: string;\n placeholder: Placeholder;\n quote: (identifier: string) => string;\n bind: (value: unknown) => unknown;\n readDate: (value: unknown) => Date;\n readNullableDate: (value: unknown) => Date | null;\n readJson: (value: unknown) => unknown;\n /** Appends `column IS DISTINCT FROM value` in the engine's spelling. */\n distinctFrom: (statement: Statement, column: string, value: unknown) => void;\n /** The clause after a multi-row INSERT that makes it an upsert. Columns arrive quoted. */\n upsertClause: (conflict: readonly string[], update: readonly string[]) => string;\n isDuplicateKey: (error: unknown) => boolean;\n /** A deadlock or busy lock the engine asks the caller to retry; the statement was rolled back. */\n isRetryableLock: (error: unknown) => boolean;\n claim: { withTransaction: ClaimStrategy; withoutTransaction: ClaimStrategy };\n};\n\nconst parseUtc = (value: unknown): Date => {\n if (value instanceof Date) return value;\n const text = String(value).trim();\n // \"2026-09-23 10:11:12.345\" from a dateStrings driver carries no zone; it was written as UTC.\n return new Date(/^\\d{4}-\\d{2}-\\d{2} /.test(text) ? `${text.replace(\" \", \"T\")}Z` : text);\n};\n\nconst readJson = (value: unknown) => (typeof value === \"string\" ? JSON.parse(value) : value);\n\nconst bindCommon = (value: unknown) => {\n if (typeof value === \"boolean\") return value ? 1 : 0;\n if (value === undefined) return null;\n return value;\n};\n\nconst code = (error: unknown) => (error as { code?: unknown } | null)?.code;\nconst errno = (error: unknown) => (error as { errno?: unknown } | null)?.errno;\n\nexport const mysqlDialect: Dialect = {\n name: \"mysql\",\n placeholder: \"question\",\n quote: quoteWith(\"`\"),\n bind: (value) =>\n value instanceof Date ? value.toISOString().slice(0, 23).replace(\"T\", \" \") : bindCommon(value),\n readDate: parseUtc,\n readNullableDate: (value) => (value == null ? null : parseUtc(value)),\n readJson,\n distinctFrom: (statement, column, value) => {\n statement.raw(`NOT (${column} <=> `).value(value).raw(\")\");\n },\n // VALUES() rather than the 8.0.19 `AS new` alias: it also works on MariaDB.\n upsertClause: (conflict, update) =>\n ` ON DUPLICATE KEY UPDATE ${(\n update.length === 0\n ? [`${conflict[0]} = ${conflict[0]}`]\n : update.map((column) => `${column} = VALUES(${column})`)\n ).join(\", \")}`,\n isDuplicateKey: (error) => code(error) === \"ER_DUP_ENTRY\" || errno(error) === 1062,\n isRetryableLock: (error) =>\n code(error) === \"ER_LOCK_DEADLOCK\" ||\n errno(error) === 1213 ||\n code(error) === \"ER_LOCK_WAIT_TIMEOUT\" ||\n errno(error) === 1205,\n claim: { withTransaction: \"skip-locked\", withoutTransaction: \"derived-update\" },\n};\n\nexport const sqliteDialect: Dialect = {\n name: \"sqlite\",\n placeholder: \"question\",\n quote: quoteWith('\"'),\n bind: (value) => (value instanceof Date ? value.toISOString() : bindCommon(value)),\n readDate: parseUtc,\n readNullableDate: (value) => (value == null ? null : parseUtc(value)),\n readJson,\n distinctFrom: (statement, column, value) => {\n statement.raw(`${column} IS NOT `).value(value);\n },\n upsertClause: (conflict, update) =>\n ` ON CONFLICT (${conflict.join(\", \")}) DO ${\n update.length === 0\n ? \"NOTHING\"\n : `UPDATE SET ${update.map((column) => `${column} = excluded.${column}`).join(\", \")}`\n }`,\n isDuplicateKey: (error) =>\n code(error) === \"SQLITE_CONSTRAINT_UNIQUE\" ||\n /UNIQUE constraint failed/i.test(String((error as Error | null)?.message ?? \"\")),\n isRetryableLock: (error) =>\n code(error) === \"SQLITE_BUSY\" ||\n /database is locked/i.test(String((error as Error | null)?.message ?? \"\")),\n claim: { withTransaction: \"subquery-update\", withoutTransaction: \"subquery-update\" },\n};\n","import type { DatabaseAdapter } from \"../../core/adapter\";\nimport { createSqlAdapter, type SqlAdapterOptions } from \"../sql/adapter\";\nimport { type SqlExec, sqliteDialect } from \"../sql/dialect\";\n\nexport type SqliteAdapterOptions = SqlAdapterOptions;\n\n/**\n * SQLite through any driver. One writer at a time, so the claim is a plain\n * UPDATE … WHERE id IN (SELECT … LIMIT ?). Dates are ISO text, booleans 0/1, JSON text. RFC 0005 §3.\n */\nexport function sqliteAdapter(query: SqlExec, options: SqliteAdapterOptions = {}): DatabaseAdapter {\n return createSqlAdapter(sqliteDialect, query, options);\n}\n","import type { FieldDeclaration, SchemaDeclaration } from \"../core/plugin\";\nimport { toSnakeCase } from \"./declaration\";\n\nconst SQL_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"TEXT\",\n number: \"INTEGER\",\n boolean: \"INTEGER\",\n // ISO-8601 with milliseconds and a trailing Z, the same 24 characters\n // `Date#toISOString` writes, so `<=` on the text is `<=` on the instant.\n date: \"TEXT\",\n json: \"TEXT\",\n};\n\nconst quote = (value: string) => `\"${value.split('\"').join('\"\"')}\"`;\n\nconst defaultClause = (spec: FieldDeclaration): string => {\n if (spec.defaultNow) return \" DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\";\n if (spec.default === undefined) return \"\";\n if (typeof spec.default === \"string\") return ` DEFAULT '${spec.default.replace(/'/g, \"''\")}'`;\n if (typeof spec.default === \"boolean\") return ` DEFAULT ${spec.default ? 1 : 0}`;\n return ` DEFAULT ${spec.default}`;\n};\n\n/** SchemaDeclaration to SQLite DDL. Every statement is `IF NOT EXISTS`. */\nexport function renderSqliteDdl(schema: SchemaDeclaration, prefix = \"\"): string[] {\n const statements: string[] = [];\n\n for (const table of Object.values(schema)) {\n const name = quote(prefix + table.tableName);\n\n const columns = Object.entries(table.fields).map(([field, spec]) => {\n const nullability = spec.required ? \" NOT NULL\" : \"\";\n return ` ${quote(toSnakeCase(field))} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`;\n });\n\n if (table.primaryKey?.length) {\n columns.push(\n ` PRIMARY KEY (${table.primaryKey.map((f) => quote(toSnakeCase(f))).join(\", \")})`,\n );\n }\n\n statements.push(`CREATE TABLE IF NOT EXISTS ${name} (\\n${columns.join(\",\\n\")}\\n)`);\n\n for (const index of table.indexes ?? []) {\n const indexName = quote(\n prefix + (index.name ?? `${table.tableName}_${index.on.join(\"_\")}_idx`),\n );\n const cols = index.on.map((f) => quote(toSnakeCase(f))).join(\", \");\n statements.push(\n `CREATE ${index.unique ? \"UNIQUE \" : \"\"}INDEX IF NOT EXISTS ${indexName} ON ${name} (${cols})`,\n );\n }\n }\n\n return statements;\n}\n","import type { SchemaDeclaration } from \"../../core/plugin\";\nimport { coreSchema } from \"../../schema/declaration\";\nimport { renderSqliteDdl } from \"../../schema/render-sqlite\";\nimport type { Row, SqlExec } from \"../sql/dialect\";\n\n/** node:sqlite's DatabaseSync and better-sqlite3's Database, structurally, so neither is a dependency. */\nexport type SqliteDatabaseLike = {\n prepare(sql: string): {\n all(...params: unknown[]): unknown;\n run(...params: unknown[]): { changes: number | bigint };\n };\n exec(sql: string): unknown;\n};\n\nconst returnsRows = (text: string) =>\n /^\\s*(select|with|pragma)\\b/i.test(text) || /\\breturning\\b/i.test(text);\n\n/** The SqlExec for a synchronous SQLite driver. */\nexport const sqliteQuery =\n (db: SqliteDatabaseLike): SqlExec =>\n async (text, params) => {\n const statement = db.prepare(text);\n if (returnsRows(text)) return { rows: statement.all(...params) as Row[], affectedRows: 0 };\n const { changes } = statement.run(...params);\n return { rows: [], affectedRows: Number(changes) };\n };\n\n/**\n * The `transaction` option for a synchronous driver. Queued one behind another: the adapter\n * awaits between statements, and SQLite refuses a BEGIN inside an open transaction.\n */\nexport function sqliteTransaction(db: SqliteDatabaseLike) {\n const exec = sqliteQuery(db);\n let tail: Promise<unknown> = Promise.resolve();\n\n return <T>(fn: (exec: SqlExec) => Promise<T>): Promise<T> => {\n const run = tail.then(async () => {\n db.exec(\"BEGIN\");\n try {\n const result = await fn(exec);\n db.exec(\"COMMIT\");\n return result;\n } catch (error) {\n db.exec(\"ROLLBACK\");\n throw error;\n }\n });\n tail = run.catch(() => undefined);\n return run;\n };\n}\n\nexport type CreateSqliteTablesOptions = {\n prefix?: string;\n plugins?: readonly SchemaDeclaration[];\n};\n\n/** Creates core and plugin tables, IF NOT EXISTS. Bootstrap, not migration. */\nexport async function createSqliteTables(\n query: SqlExec,\n options: CreateSqliteTablesOptions = {},\n): Promise<number> {\n let count = 0;\n for (const schema of [coreSchema, ...(options.plugins ?? [])]) {\n for (const statement of renderSqliteDdl(schema, options.prefix)) {\n await query(statement, []);\n count += 1;\n }\n }\n return count;\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import { S as SqlAdapterOptions, a as SqlExec } from '../adapter-B7R4rXtJ.cjs';
2
+ export { b as SqliteResult } from '../adapter-B7R4rXtJ.cjs';
3
+ import { D as DatabaseAdapter } from '../adapter-D3lTy-4E.cjs';
4
+ import { S as SchemaDeclaration } from '../plugin-CHd2ZiGC.cjs';
5
+
6
+ type SqliteAdapterOptions = SqlAdapterOptions;
7
+ /**
8
+ * SQLite through any driver. One writer at a time, so the claim is a plain
9
+ * UPDATE … WHERE id IN (SELECT … LIMIT ?). Dates are ISO text, booleans 0/1, JSON text. RFC 0005 §3.
10
+ */
11
+ declare function sqliteAdapter(query: SqlExec, options?: SqliteAdapterOptions): DatabaseAdapter;
12
+
13
+ /** node:sqlite's DatabaseSync and better-sqlite3's Database, structurally, so neither is a dependency. */
14
+ type SqliteDatabaseLike = {
15
+ prepare(sql: string): {
16
+ all(...params: unknown[]): unknown;
17
+ run(...params: unknown[]): {
18
+ changes: number | bigint;
19
+ };
20
+ };
21
+ exec(sql: string): unknown;
22
+ };
23
+ /** The SqlExec for a synchronous SQLite driver. */
24
+ declare const sqliteQuery: (db: SqliteDatabaseLike) => SqlExec;
25
+ /**
26
+ * The `transaction` option for a synchronous driver. Queued one behind another: the adapter
27
+ * awaits between statements, and SQLite refuses a BEGIN inside an open transaction.
28
+ */
29
+ declare function sqliteTransaction(db: SqliteDatabaseLike): <T>(fn: (exec: SqlExec) => Promise<T>) => Promise<T>;
30
+ type CreateSqliteTablesOptions = {
31
+ prefix?: string;
32
+ plugins?: readonly SchemaDeclaration[];
33
+ };
34
+ /** Creates core and plugin tables, IF NOT EXISTS. Bootstrap, not migration. */
35
+ declare function createSqliteTables(query: SqlExec, options?: CreateSqliteTablesOptions): Promise<number>;
36
+
37
+ export { type CreateSqliteTablesOptions, type SqliteAdapterOptions, type SqliteDatabaseLike, SqlExec as SqliteQuery, createSqliteTables, sqliteAdapter, sqliteQuery, sqliteTransaction };
@@ -0,0 +1,37 @@
1
+ import { S as SqlAdapterOptions, a as SqlExec } from '../adapter-B7R4rXtJ.js';
2
+ export { b as SqliteResult } from '../adapter-B7R4rXtJ.js';
3
+ import { D as DatabaseAdapter } from '../adapter-D3lTy-4E.js';
4
+ import { S as SchemaDeclaration } from '../plugin-Cg9usuUi.js';
5
+
6
+ type SqliteAdapterOptions = SqlAdapterOptions;
7
+ /**
8
+ * SQLite through any driver. One writer at a time, so the claim is a plain
9
+ * UPDATE … WHERE id IN (SELECT … LIMIT ?). Dates are ISO text, booleans 0/1, JSON text. RFC 0005 §3.
10
+ */
11
+ declare function sqliteAdapter(query: SqlExec, options?: SqliteAdapterOptions): DatabaseAdapter;
12
+
13
+ /** node:sqlite's DatabaseSync and better-sqlite3's Database, structurally, so neither is a dependency. */
14
+ type SqliteDatabaseLike = {
15
+ prepare(sql: string): {
16
+ all(...params: unknown[]): unknown;
17
+ run(...params: unknown[]): {
18
+ changes: number | bigint;
19
+ };
20
+ };
21
+ exec(sql: string): unknown;
22
+ };
23
+ /** The SqlExec for a synchronous SQLite driver. */
24
+ declare const sqliteQuery: (db: SqliteDatabaseLike) => SqlExec;
25
+ /**
26
+ * The `transaction` option for a synchronous driver. Queued one behind another: the adapter
27
+ * awaits between statements, and SQLite refuses a BEGIN inside an open transaction.
28
+ */
29
+ declare function sqliteTransaction(db: SqliteDatabaseLike): <T>(fn: (exec: SqlExec) => Promise<T>) => Promise<T>;
30
+ type CreateSqliteTablesOptions = {
31
+ prefix?: string;
32
+ plugins?: readonly SchemaDeclaration[];
33
+ };
34
+ /** Creates core and plugin tables, IF NOT EXISTS. Bootstrap, not migration. */
35
+ declare function createSqliteTables(query: SqlExec, options?: CreateSqliteTablesOptions): Promise<number>;
36
+
37
+ export { type CreateSqliteTablesOptions, type SqliteAdapterOptions, type SqliteDatabaseLike, SqlExec as SqliteQuery, createSqliteTables, sqliteAdapter, sqliteQuery, sqliteTransaction };
@@ -0,0 +1,53 @@
1
+ import { renderSqliteDdl } from '../chunk-HY47TQMY.js';
2
+ import { createSqlAdapter, sqliteDialect } from '../chunk-2EYKPF5A.js';
3
+ import '../chunk-CK5UPVYP.js';
4
+ import '../chunk-3VOQOGDR.js';
5
+ import { coreSchema } from '../chunk-AEYYTE5I.js';
6
+ import '../chunk-PTGHMCCG.js';
7
+
8
+ // src/adapters/sqlite/adapter.ts
9
+ function sqliteAdapter(query, options = {}) {
10
+ return createSqlAdapter(sqliteDialect, query, options);
11
+ }
12
+
13
+ // src/adapters/sqlite/helpers.ts
14
+ var returnsRows = (text) => /^\s*(select|with|pragma)\b/i.test(text) || /\breturning\b/i.test(text);
15
+ var sqliteQuery = (db) => async (text, params) => {
16
+ const statement = db.prepare(text);
17
+ if (returnsRows(text)) return { rows: statement.all(...params), affectedRows: 0 };
18
+ const { changes } = statement.run(...params);
19
+ return { rows: [], affectedRows: Number(changes) };
20
+ };
21
+ function sqliteTransaction(db) {
22
+ const exec = sqliteQuery(db);
23
+ let tail = Promise.resolve();
24
+ return (fn) => {
25
+ const run = tail.then(async () => {
26
+ db.exec("BEGIN");
27
+ try {
28
+ const result = await fn(exec);
29
+ db.exec("COMMIT");
30
+ return result;
31
+ } catch (error) {
32
+ db.exec("ROLLBACK");
33
+ throw error;
34
+ }
35
+ });
36
+ tail = run.catch(() => void 0);
37
+ return run;
38
+ };
39
+ }
40
+ async function createSqliteTables(query, options = {}) {
41
+ let count = 0;
42
+ for (const schema of [coreSchema, ...options.plugins ?? []]) {
43
+ for (const statement of renderSqliteDdl(schema, options.prefix)) {
44
+ await query(statement, []);
45
+ count += 1;
46
+ }
47
+ }
48
+ return count;
49
+ }
50
+
51
+ export { createSqliteTables, sqliteAdapter, sqliteQuery, sqliteTransaction };
52
+ //# sourceMappingURL=sqlite.js.map
53
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/sqlite/adapter.ts","../../src/adapters/sqlite/helpers.ts"],"names":[],"mappings":";;;;;;;;AAUO,SAAS,aAAA,CAAc,KAAA,EAAgB,OAAA,GAAgC,EAAC,EAAoB;AACjG,EAAA,OAAO,gBAAA,CAAiB,aAAA,EAAe,KAAA,EAAO,OAAO,CAAA;AACvD;;;ACEA,IAAM,WAAA,GAAc,CAAC,IAAA,KACnB,6BAAA,CAA8B,KAAK,IAAI,CAAA,IAAK,gBAAA,CAAiB,IAAA,CAAK,IAAI,CAAA;AAGjE,IAAM,WAAA,GACX,CAAC,EAAA,KACD,OAAO,MAAM,MAAA,KAAW;AACtB,EAAA,MAAM,SAAA,GAAY,EAAA,CAAG,OAAA,CAAQ,IAAI,CAAA;AACjC,EAAA,IAAI,WAAA,CAAY,IAAI,CAAA,EAAG,OAAO,EAAE,IAAA,EAAM,SAAA,CAAU,GAAA,CAAI,GAAG,MAAM,CAAA,EAAY,YAAA,EAAc,CAAA,EAAE;AACzF,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,SAAA,CAAU,GAAA,CAAI,GAAG,MAAM,CAAA;AAC3C,EAAA,OAAO,EAAE,IAAA,EAAM,IAAI,YAAA,EAAc,MAAA,CAAO,OAAO,CAAA,EAAE;AACnD;AAMK,SAAS,kBAAkB,EAAA,EAAwB;AACxD,EAAA,MAAM,IAAA,GAAO,YAAY,EAAE,CAAA;AAC3B,EAAA,IAAI,IAAA,GAAyB,QAAQ,OAAA,EAAQ;AAE7C,EAAA,OAAO,CAAI,EAAA,KAAkD;AAC3D,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,YAAY;AAChC,MAAA,EAAA,CAAG,KAAK,OAAO,CAAA;AACf,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,IAAI,CAAA;AAC5B,QAAA,EAAA,CAAG,KAAK,QAAQ,CAAA;AAChB,QAAA,OAAO,MAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,EAAA,CAAG,KAAK,UAAU,CAAA;AAClB,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,CAAC,CAAA;AACD,IAAA,IAAA,GAAO,GAAA,CAAI,KAAA,CAAM,MAAM,MAAS,CAAA;AAChC,IAAA,OAAO,GAAA;AAAA,EACT,CAAA;AACF;AAQA,eAAsB,kBAAA,CACpB,KAAA,EACA,OAAA,GAAqC,EAAC,EACrB;AACjB,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,MAAW,MAAA,IAAU,CAAC,UAAA,EAAY,GAAI,QAAQ,OAAA,IAAW,EAAG,CAAA,EAAG;AAC7D,IAAA,KAAA,MAAW,SAAA,IAAa,eAAA,CAAgB,MAAA,EAAQ,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC/D,MAAA,MAAM,KAAA,CAAM,SAAA,EAAW,EAAE,CAAA;AACzB,MAAA,KAAA,IAAS,CAAA;AAAA,IACX;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT","file":"sqlite.js","sourcesContent":["import type { DatabaseAdapter } from \"../../core/adapter\";\nimport { createSqlAdapter, type SqlAdapterOptions } from \"../sql/adapter\";\nimport { type SqlExec, sqliteDialect } from \"../sql/dialect\";\n\nexport type SqliteAdapterOptions = SqlAdapterOptions;\n\n/**\n * SQLite through any driver. One writer at a time, so the claim is a plain\n * UPDATE … WHERE id IN (SELECT … LIMIT ?). Dates are ISO text, booleans 0/1, JSON text. RFC 0005 §3.\n */\nexport function sqliteAdapter(query: SqlExec, options: SqliteAdapterOptions = {}): DatabaseAdapter {\n return createSqlAdapter(sqliteDialect, query, options);\n}\n","import type { SchemaDeclaration } from \"../../core/plugin\";\nimport { coreSchema } from \"../../schema/declaration\";\nimport { renderSqliteDdl } from \"../../schema/render-sqlite\";\nimport type { Row, SqlExec } from \"../sql/dialect\";\n\n/** node:sqlite's DatabaseSync and better-sqlite3's Database, structurally, so neither is a dependency. */\nexport type SqliteDatabaseLike = {\n prepare(sql: string): {\n all(...params: unknown[]): unknown;\n run(...params: unknown[]): { changes: number | bigint };\n };\n exec(sql: string): unknown;\n};\n\nconst returnsRows = (text: string) =>\n /^\\s*(select|with|pragma)\\b/i.test(text) || /\\breturning\\b/i.test(text);\n\n/** The SqlExec for a synchronous SQLite driver. */\nexport const sqliteQuery =\n (db: SqliteDatabaseLike): SqlExec =>\n async (text, params) => {\n const statement = db.prepare(text);\n if (returnsRows(text)) return { rows: statement.all(...params) as Row[], affectedRows: 0 };\n const { changes } = statement.run(...params);\n return { rows: [], affectedRows: Number(changes) };\n };\n\n/**\n * The `transaction` option for a synchronous driver. Queued one behind another: the adapter\n * awaits between statements, and SQLite refuses a BEGIN inside an open transaction.\n */\nexport function sqliteTransaction(db: SqliteDatabaseLike) {\n const exec = sqliteQuery(db);\n let tail: Promise<unknown> = Promise.resolve();\n\n return <T>(fn: (exec: SqlExec) => Promise<T>): Promise<T> => {\n const run = tail.then(async () => {\n db.exec(\"BEGIN\");\n try {\n const result = await fn(exec);\n db.exec(\"COMMIT\");\n return result;\n } catch (error) {\n db.exec(\"ROLLBACK\");\n throw error;\n }\n });\n tail = run.catch(() => undefined);\n return run;\n };\n}\n\nexport type CreateSqliteTablesOptions = {\n prefix?: string;\n plugins?: readonly SchemaDeclaration[];\n};\n\n/** Creates core and plugin tables, IF NOT EXISTS. Bootstrap, not migration. */\nexport async function createSqliteTables(\n query: SqlExec,\n options: CreateSqliteTablesOptions = {},\n): Promise<number> {\n let count = 0;\n for (const schema of [coreSchema, ...(options.plugins ?? [])]) {\n for (const statement of renderSqliteDdl(schema, options.prefix)) {\n await query(statement, []);\n count += 1;\n }\n }\n return count;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.cjs","sourcesContent":["/**\n * The browser half of web push.\n *\n * Everything here is injectable so it can be tested in Node: the real\n * navigator, Notification and fetch are only reached through the defaults.\n */\n\nexport type PushSubscriptionPayload = {\n endpoint: string;\n keys: { p256dh: string; auth: string };\n};\n\nexport type SubscribeOptions = {\n /** VAPID public key, base64url — the same one the server signs with. */\n publicKey: string;\n baseUrl?: string;\n serviceWorkerPath?: string;\n scope?: string;\n fetch?: typeof globalThis.fetch;\n /** Pre-resolved registration, so tests need no service worker. */\n registration?: ServiceWorkerRegistration;\n};\n\nexport class PushUnsupportedError extends Error {\n constructor(reason: string) {\n super(`web push is unavailable: ${reason}`);\n this.name = \"PushUnsupportedError\";\n }\n}\n\nexport class PushPermissionError extends Error {\n constructor(readonly permission: NotificationPermission) {\n super(`notification permission was ${permission}`);\n this.name = \"PushPermissionError\";\n }\n}\n\nexport function isPushSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n typeof PushManager !== \"undefined\" &&\n typeof Notification !== \"undefined\"\n );\n}\n\n/**\n * applicationServerKey must be raw bytes; handing the browser the base64url\n * string it came in as fails with an opaque InvalidCharacterError.\n */\nexport function decodeVapidKey(publicKey: string): Uint8Array<ArrayBuffer> {\n const padded = publicKey.padEnd(publicKey.length + ((4 - (publicKey.length % 4)) % 4), \"=\");\n\n let binary: string;\n try {\n binary = atob(padded.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n } catch {\n // atob throws a bare \"Invalid character\", which says nothing about which\n // of the several keys in a push setup is wrong.\n throw new Error(\"VAPID publicKey is not valid base64url\");\n }\n\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n if (bytes.length !== 65 || bytes[0] !== 0x04) {\n throw new Error(\n `VAPID publicKey must be a 65-byte uncompressed EC point, got ${bytes.length} bytes`,\n );\n }\n return bytes;\n}\n\nasync function resolveRegistration(options: SubscribeOptions): Promise<ServiceWorkerRegistration> {\n if (options.registration) return options.registration;\n if (!isPushSupported()) throw new PushUnsupportedError(\"this browser has no PushManager\");\n\n const path = options.serviceWorkerPath ?? \"/sw.js\";\n const registration = await navigator.serviceWorker.register(\n path,\n options.scope ? { scope: options.scope } : undefined,\n );\n\n // subscribe() before the worker is active rejects.\n await navigator.serviceWorker.ready;\n return registration;\n}\n\n/**\n * Registers the worker, asks permission, subscribes, and hands the\n * subscription to the server. Returns what was registered.\n */\nexport async function subscribeToPush(options: SubscribeOptions): Promise<PushSubscriptionPayload> {\n const registration = await resolveRegistration(options);\n\n if (typeof Notification !== \"undefined\") {\n const permission =\n Notification.permission === \"default\"\n ? await Notification.requestPermission()\n : Notification.permission;\n\n if (permission !== \"granted\") throw new PushPermissionError(permission);\n }\n\n const existing = await registration.pushManager.getSubscription();\n const subscription =\n existing ??\n (await registration.pushManager.subscribe({\n // Required by Chrome; a silent push is rejected outright.\n userVisibleOnly: true,\n applicationServerKey: decodeVapidKey(options.publicKey),\n }));\n\n const payload = subscription.toJSON() as PushSubscriptionPayload;\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n const response = await doFetch(`${baseUrl}/push/devices`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: payload.endpoint, keys: payload.keys }),\n });\n\n if (!response.ok) {\n throw new Error(`registering the push device failed: ${response.status}`);\n }\n\n return payload;\n}\n\n/** Tells the server first: a browser-only unsubscribe leaves a dead row behind. */\nexport async function unsubscribeFromPush(\n options: Omit<SubscribeOptions, \"publicKey\">,\n): Promise<boolean> {\n const registration = await resolveRegistration({ ...options, publicKey: \"\" });\n const subscription = await registration.pushManager.getSubscription();\n if (!subscription) return false;\n\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n await doFetch(`${baseUrl}/push/devices/remove`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: subscription.endpoint }),\n }).catch(() => undefined);\n\n return subscription.unsubscribe();\n}\n"]}
1
+ {"version":3,"sources":["../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.cjs","sourcesContent":["// Everything here is injectable so it can be tested in Node.\n\nexport type PushSubscriptionPayload = {\n endpoint: string;\n keys: { p256dh: string; auth: string };\n};\n\nexport type SubscribeOptions = {\n /** VAPID public key, base64url — the same one the server signs with. */\n publicKey: string;\n baseUrl?: string;\n serviceWorkerPath?: string;\n scope?: string;\n fetch?: typeof globalThis.fetch;\n /** Pre-resolved registration, so tests need no service worker. */\n registration?: ServiceWorkerRegistration;\n};\n\nexport class PushUnsupportedError extends Error {\n constructor(reason: string) {\n super(`web push is unavailable: ${reason}`);\n this.name = \"PushUnsupportedError\";\n }\n}\n\nexport class PushPermissionError extends Error {\n constructor(readonly permission: NotificationPermission) {\n super(`notification permission was ${permission}`);\n this.name = \"PushPermissionError\";\n }\n}\n\nexport function isPushSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n typeof PushManager !== \"undefined\" &&\n typeof Notification !== \"undefined\"\n );\n}\n\n/** applicationServerKey must be raw bytes, not the base64url string. */\nexport function decodeVapidKey(publicKey: string): Uint8Array<ArrayBuffer> {\n const padded = publicKey.padEnd(publicKey.length + ((4 - (publicKey.length % 4)) % 4), \"=\");\n\n let binary: string;\n try {\n binary = atob(padded.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n } catch {\n throw new Error(\"VAPID publicKey is not valid base64url\");\n }\n\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n if (bytes.length !== 65 || bytes[0] !== 0x04) {\n throw new Error(\n `VAPID publicKey must be a 65-byte uncompressed EC point, got ${bytes.length} bytes`,\n );\n }\n return bytes;\n}\n\nasync function resolveRegistration(options: SubscribeOptions): Promise<ServiceWorkerRegistration> {\n if (options.registration) return options.registration;\n if (!isPushSupported()) throw new PushUnsupportedError(\"this browser has no PushManager\");\n\n const path = options.serviceWorkerPath ?? \"/sw.js\";\n const registration = await navigator.serviceWorker.register(\n path,\n options.scope ? { scope: options.scope } : undefined,\n );\n\n // subscribe() before the worker is active rejects.\n await navigator.serviceWorker.ready;\n return registration;\n}\n\n/** Registers the worker, asks permission, subscribes, and registers the subscription with the server. */\nexport async function subscribeToPush(options: SubscribeOptions): Promise<PushSubscriptionPayload> {\n const registration = await resolveRegistration(options);\n\n if (typeof Notification !== \"undefined\") {\n const permission =\n Notification.permission === \"default\"\n ? await Notification.requestPermission()\n : Notification.permission;\n\n if (permission !== \"granted\") throw new PushPermissionError(permission);\n }\n\n const existing = await registration.pushManager.getSubscription();\n const subscription =\n existing ??\n (await registration.pushManager.subscribe({\n // Required by Chrome; a silent push is rejected outright.\n userVisibleOnly: true,\n applicationServerKey: decodeVapidKey(options.publicKey),\n }));\n\n const payload = subscription.toJSON() as PushSubscriptionPayload;\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n const response = await doFetch(`${baseUrl}/push/devices`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: payload.endpoint, keys: payload.keys }),\n });\n\n if (!response.ok) {\n throw new Error(`registering the push device failed: ${response.status}`);\n }\n\n return payload;\n}\n\n/** Tells the server first: a browser-only unsubscribe leaves a dead row behind. */\nexport async function unsubscribeFromPush(\n options: Omit<SubscribeOptions, \"publicKey\">,\n): Promise<boolean> {\n const registration = await resolveRegistration({ ...options, publicKey: \"\" });\n const subscription = await registration.pushManager.getSubscription();\n if (!subscription) return false;\n\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n await doFetch(`${baseUrl}/push/devices/remove`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: subscription.endpoint }),\n }).catch(() => undefined);\n\n return subscription.unsubscribe();\n}\n"]}
@@ -1,9 +1,3 @@
1
- /**
2
- * The browser half of web push.
3
- *
4
- * Everything here is injectable so it can be tested in Node: the real
5
- * navigator, Notification and fetch are only reached through the defaults.
6
- */
7
1
  type PushSubscriptionPayload = {
8
2
  endpoint: string;
9
3
  keys: {
@@ -29,15 +23,9 @@ declare class PushPermissionError extends Error {
29
23
  constructor(permission: NotificationPermission);
30
24
  }
31
25
  declare function isPushSupported(): boolean;
32
- /**
33
- * applicationServerKey must be raw bytes; handing the browser the base64url
34
- * string it came in as fails with an opaque InvalidCharacterError.
35
- */
26
+ /** applicationServerKey must be raw bytes, not the base64url string. */
36
27
  declare function decodeVapidKey(publicKey: string): Uint8Array<ArrayBuffer>;
37
- /**
38
- * Registers the worker, asks permission, subscribes, and hands the
39
- * subscription to the server. Returns what was registered.
40
- */
28
+ /** Registers the worker, asks permission, subscribes, and registers the subscription with the server. */
41
29
  declare function subscribeToPush(options: SubscribeOptions): Promise<PushSubscriptionPayload>;
42
30
  /** Tells the server first: a browser-only unsubscribe leaves a dead row behind. */
43
31
  declare function unsubscribeFromPush(options: Omit<SubscribeOptions, "publicKey">): Promise<boolean>;
package/dist/browser.d.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * The browser half of web push.
3
- *
4
- * Everything here is injectable so it can be tested in Node: the real
5
- * navigator, Notification and fetch are only reached through the defaults.
6
- */
7
1
  type PushSubscriptionPayload = {
8
2
  endpoint: string;
9
3
  keys: {
@@ -29,15 +23,9 @@ declare class PushPermissionError extends Error {
29
23
  constructor(permission: NotificationPermission);
30
24
  }
31
25
  declare function isPushSupported(): boolean;
32
- /**
33
- * applicationServerKey must be raw bytes; handing the browser the base64url
34
- * string it came in as fails with an opaque InvalidCharacterError.
35
- */
26
+ /** applicationServerKey must be raw bytes, not the base64url string. */
36
27
  declare function decodeVapidKey(publicKey: string): Uint8Array<ArrayBuffer>;
37
- /**
38
- * Registers the worker, asks permission, subscribes, and hands the
39
- * subscription to the server. Returns what was registered.
40
- */
28
+ /** Registers the worker, asks permission, subscribes, and registers the subscription with the server. */
41
29
  declare function subscribeToPush(options: SubscribeOptions): Promise<PushSubscriptionPayload>;
42
30
  /** Tells the server first: a browser-only unsubscribe leaves a dead row behind. */
43
31
  declare function unsubscribeFromPush(options: Omit<SubscribeOptions, "publicKey">): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.js","sourcesContent":["/**\n * The browser half of web push.\n *\n * Everything here is injectable so it can be tested in Node: the real\n * navigator, Notification and fetch are only reached through the defaults.\n */\n\nexport type PushSubscriptionPayload = {\n endpoint: string;\n keys: { p256dh: string; auth: string };\n};\n\nexport type SubscribeOptions = {\n /** VAPID public key, base64url — the same one the server signs with. */\n publicKey: string;\n baseUrl?: string;\n serviceWorkerPath?: string;\n scope?: string;\n fetch?: typeof globalThis.fetch;\n /** Pre-resolved registration, so tests need no service worker. */\n registration?: ServiceWorkerRegistration;\n};\n\nexport class PushUnsupportedError extends Error {\n constructor(reason: string) {\n super(`web push is unavailable: ${reason}`);\n this.name = \"PushUnsupportedError\";\n }\n}\n\nexport class PushPermissionError extends Error {\n constructor(readonly permission: NotificationPermission) {\n super(`notification permission was ${permission}`);\n this.name = \"PushPermissionError\";\n }\n}\n\nexport function isPushSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n typeof PushManager !== \"undefined\" &&\n typeof Notification !== \"undefined\"\n );\n}\n\n/**\n * applicationServerKey must be raw bytes; handing the browser the base64url\n * string it came in as fails with an opaque InvalidCharacterError.\n */\nexport function decodeVapidKey(publicKey: string): Uint8Array<ArrayBuffer> {\n const padded = publicKey.padEnd(publicKey.length + ((4 - (publicKey.length % 4)) % 4), \"=\");\n\n let binary: string;\n try {\n binary = atob(padded.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n } catch {\n // atob throws a bare \"Invalid character\", which says nothing about which\n // of the several keys in a push setup is wrong.\n throw new Error(\"VAPID publicKey is not valid base64url\");\n }\n\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n if (bytes.length !== 65 || bytes[0] !== 0x04) {\n throw new Error(\n `VAPID publicKey must be a 65-byte uncompressed EC point, got ${bytes.length} bytes`,\n );\n }\n return bytes;\n}\n\nasync function resolveRegistration(options: SubscribeOptions): Promise<ServiceWorkerRegistration> {\n if (options.registration) return options.registration;\n if (!isPushSupported()) throw new PushUnsupportedError(\"this browser has no PushManager\");\n\n const path = options.serviceWorkerPath ?? \"/sw.js\";\n const registration = await navigator.serviceWorker.register(\n path,\n options.scope ? { scope: options.scope } : undefined,\n );\n\n // subscribe() before the worker is active rejects.\n await navigator.serviceWorker.ready;\n return registration;\n}\n\n/**\n * Registers the worker, asks permission, subscribes, and hands the\n * subscription to the server. Returns what was registered.\n */\nexport async function subscribeToPush(options: SubscribeOptions): Promise<PushSubscriptionPayload> {\n const registration = await resolveRegistration(options);\n\n if (typeof Notification !== \"undefined\") {\n const permission =\n Notification.permission === \"default\"\n ? await Notification.requestPermission()\n : Notification.permission;\n\n if (permission !== \"granted\") throw new PushPermissionError(permission);\n }\n\n const existing = await registration.pushManager.getSubscription();\n const subscription =\n existing ??\n (await registration.pushManager.subscribe({\n // Required by Chrome; a silent push is rejected outright.\n userVisibleOnly: true,\n applicationServerKey: decodeVapidKey(options.publicKey),\n }));\n\n const payload = subscription.toJSON() as PushSubscriptionPayload;\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n const response = await doFetch(`${baseUrl}/push/devices`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: payload.endpoint, keys: payload.keys }),\n });\n\n if (!response.ok) {\n throw new Error(`registering the push device failed: ${response.status}`);\n }\n\n return payload;\n}\n\n/** Tells the server first: a browser-only unsubscribe leaves a dead row behind. */\nexport async function unsubscribeFromPush(\n options: Omit<SubscribeOptions, \"publicKey\">,\n): Promise<boolean> {\n const registration = await resolveRegistration({ ...options, publicKey: \"\" });\n const subscription = await registration.pushManager.getSubscription();\n if (!subscription) return false;\n\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n await doFetch(`${baseUrl}/push/devices/remove`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: subscription.endpoint }),\n }).catch(() => undefined);\n\n return subscription.unsubscribe();\n}\n"]}
1
+ {"version":3,"sources":["../src/browser/index.ts"],"names":[],"mappings":"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","file":"browser.js","sourcesContent":["// Everything here is injectable so it can be tested in Node.\n\nexport type PushSubscriptionPayload = {\n endpoint: string;\n keys: { p256dh: string; auth: string };\n};\n\nexport type SubscribeOptions = {\n /** VAPID public key, base64url — the same one the server signs with. */\n publicKey: string;\n baseUrl?: string;\n serviceWorkerPath?: string;\n scope?: string;\n fetch?: typeof globalThis.fetch;\n /** Pre-resolved registration, so tests need no service worker. */\n registration?: ServiceWorkerRegistration;\n};\n\nexport class PushUnsupportedError extends Error {\n constructor(reason: string) {\n super(`web push is unavailable: ${reason}`);\n this.name = \"PushUnsupportedError\";\n }\n}\n\nexport class PushPermissionError extends Error {\n constructor(readonly permission: NotificationPermission) {\n super(`notification permission was ${permission}`);\n this.name = \"PushPermissionError\";\n }\n}\n\nexport function isPushSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n \"serviceWorker\" in navigator &&\n typeof PushManager !== \"undefined\" &&\n typeof Notification !== \"undefined\"\n );\n}\n\n/** applicationServerKey must be raw bytes, not the base64url string. */\nexport function decodeVapidKey(publicKey: string): Uint8Array<ArrayBuffer> {\n const padded = publicKey.padEnd(publicKey.length + ((4 - (publicKey.length % 4)) % 4), \"=\");\n\n let binary: string;\n try {\n binary = atob(padded.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n } catch {\n throw new Error(\"VAPID publicKey is not valid base64url\");\n }\n\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n if (bytes.length !== 65 || bytes[0] !== 0x04) {\n throw new Error(\n `VAPID publicKey must be a 65-byte uncompressed EC point, got ${bytes.length} bytes`,\n );\n }\n return bytes;\n}\n\nasync function resolveRegistration(options: SubscribeOptions): Promise<ServiceWorkerRegistration> {\n if (options.registration) return options.registration;\n if (!isPushSupported()) throw new PushUnsupportedError(\"this browser has no PushManager\");\n\n const path = options.serviceWorkerPath ?? \"/sw.js\";\n const registration = await navigator.serviceWorker.register(\n path,\n options.scope ? { scope: options.scope } : undefined,\n );\n\n // subscribe() before the worker is active rejects.\n await navigator.serviceWorker.ready;\n return registration;\n}\n\n/** Registers the worker, asks permission, subscribes, and registers the subscription with the server. */\nexport async function subscribeToPush(options: SubscribeOptions): Promise<PushSubscriptionPayload> {\n const registration = await resolveRegistration(options);\n\n if (typeof Notification !== \"undefined\") {\n const permission =\n Notification.permission === \"default\"\n ? await Notification.requestPermission()\n : Notification.permission;\n\n if (permission !== \"granted\") throw new PushPermissionError(permission);\n }\n\n const existing = await registration.pushManager.getSubscription();\n const subscription =\n existing ??\n (await registration.pushManager.subscribe({\n // Required by Chrome; a silent push is rejected outright.\n userVisibleOnly: true,\n applicationServerKey: decodeVapidKey(options.publicKey),\n }));\n\n const payload = subscription.toJSON() as PushSubscriptionPayload;\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n const response = await doFetch(`${baseUrl}/push/devices`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: payload.endpoint, keys: payload.keys }),\n });\n\n if (!response.ok) {\n throw new Error(`registering the push device failed: ${response.status}`);\n }\n\n return payload;\n}\n\n/** Tells the server first: a browser-only unsubscribe leaves a dead row behind. */\nexport async function unsubscribeFromPush(\n options: Omit<SubscribeOptions, \"publicKey\">,\n): Promise<boolean> {\n const registration = await resolveRegistration({ ...options, publicKey: \"\" });\n const subscription = await registration.pushManager.getSubscription();\n if (!subscription) return false;\n\n const doFetch = options.fetch ?? globalThis.fetch;\n const baseUrl = (options.baseUrl ?? \"/api/notifications\").replace(/\\/$/, \"\");\n\n await doFetch(`${baseUrl}/push/devices/remove`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ endpoint: subscription.endpoint }),\n }).catch(() => undefined);\n\n return subscription.unsubscribe();\n}\n"]}