easy-ping 0.9.0 → 0.10.1

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 (103) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/drizzle.cjs +6 -4
  3. package/dist/adapters/drizzle.cjs.map +1 -1
  4. package/dist/adapters/drizzle.js +7 -5
  5. package/dist/adapters/drizzle.js.map +1 -1
  6. package/dist/adapters/mongodb.cjs.map +1 -1
  7. package/dist/adapters/mongodb.d.cts +1 -1
  8. package/dist/adapters/mongodb.d.ts +1 -1
  9. package/dist/adapters/mongodb.js +1 -1
  10. package/dist/adapters/mysql.cjs.map +1 -1
  11. package/dist/adapters/mysql.d.cts +1 -1
  12. package/dist/adapters/mysql.d.ts +1 -1
  13. package/dist/adapters/mysql.js +2 -2
  14. package/dist/adapters/postgres.cjs +3 -3
  15. package/dist/adapters/postgres.cjs.map +1 -1
  16. package/dist/adapters/postgres.d.cts +2 -2
  17. package/dist/adapters/postgres.d.ts +2 -2
  18. package/dist/adapters/postgres.js +5 -5
  19. package/dist/adapters/postgres.js.map +1 -1
  20. package/dist/adapters/sqlite.cjs.map +1 -1
  21. package/dist/adapters/sqlite.d.cts +1 -1
  22. package/dist/adapters/sqlite.d.ts +1 -1
  23. package/dist/adapters/sqlite.js +2 -2
  24. package/dist/{chunk-EROWLUL4.js → chunk-A4HX5YTG.js} +5 -3
  25. package/dist/chunk-A4HX5YTG.js.map +1 -0
  26. package/dist/{chunk-JOVIZXO6.js → chunk-CFLVAF2R.js} +20 -6
  27. package/dist/chunk-CFLVAF2R.js.map +1 -0
  28. package/dist/{chunk-2EYKPF5A.js → chunk-CMWOIYVQ.js} +3 -3
  29. package/dist/{chunk-2EYKPF5A.js.map → chunk-CMWOIYVQ.js.map} +1 -1
  30. package/dist/{chunk-E4IZ2CQC.js → chunk-JN3UCQBP.js} +2 -2
  31. package/dist/chunk-JN3UCQBP.js.map +1 -0
  32. package/dist/{chunk-3VOQOGDR.js → chunk-O2PBBL5X.js} +24 -6
  33. package/dist/chunk-O2PBBL5X.js.map +1 -0
  34. package/dist/index.cjs +74 -10
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +4 -2
  37. package/dist/index.d.ts +4 -2
  38. package/dist/index.js +39 -7
  39. package/dist/index.js.map +1 -1
  40. package/dist/node.cjs +14 -2
  41. package/dist/node.cjs.map +1 -1
  42. package/dist/node.js +15 -3
  43. package/dist/node.js.map +1 -1
  44. package/dist/{plugin-C4fikLl7.d.ts → plugin-Bp68CCnd.d.ts} +1 -0
  45. package/dist/{plugin-6S8tpH0n.d.cts → plugin-p4HS8yjS.d.cts} +1 -0
  46. package/dist/plugins/digests.cjs +1 -1
  47. package/dist/plugins/digests.cjs.map +1 -1
  48. package/dist/plugins/digests.d.cts +1 -1
  49. package/dist/plugins/digests.d.ts +1 -1
  50. package/dist/plugins/digests.js +1 -1
  51. package/dist/plugins/digests.js.map +1 -1
  52. package/dist/plugins/mobile-push.cjs +2 -1
  53. package/dist/plugins/mobile-push.cjs.map +1 -1
  54. package/dist/plugins/mobile-push.d.cts +1 -1
  55. package/dist/plugins/mobile-push.d.ts +1 -1
  56. package/dist/plugins/mobile-push.js +3 -2
  57. package/dist/plugins/mobile-push.js.map +1 -1
  58. package/dist/plugins/preferences-client.cjs.map +1 -1
  59. package/dist/plugins/preferences-client.d.cts +1 -1
  60. package/dist/plugins/preferences-client.d.ts +1 -1
  61. package/dist/plugins/preferences-client.js +1 -1
  62. package/dist/plugins/preferences.cjs.map +1 -1
  63. package/dist/plugins/preferences.d.cts +1 -1
  64. package/dist/plugins/preferences.d.ts +1 -1
  65. package/dist/plugins/preferences.js +1 -1
  66. package/dist/plugins/push.cjs.map +1 -1
  67. package/dist/plugins/push.d.cts +1 -1
  68. package/dist/plugins/push.d.ts +1 -1
  69. package/dist/plugins/push.js +1 -1
  70. package/dist/plugins/telegram.cjs +22 -1
  71. package/dist/plugins/telegram.cjs.map +1 -1
  72. package/dist/plugins/telegram.d.cts +1 -1
  73. package/dist/plugins/telegram.d.ts +1 -1
  74. package/dist/plugins/telegram.js +23 -2
  75. package/dist/plugins/telegram.js.map +1 -1
  76. package/dist/providers/expo-push.cjs +1 -1
  77. package/dist/providers/expo-push.cjs.map +1 -1
  78. package/dist/providers/expo-push.js +1 -1
  79. package/dist/providers/expo-push.js.map +1 -1
  80. package/dist/providers/web-push.cjs +3 -7
  81. package/dist/providers/web-push.cjs.map +1 -1
  82. package/dist/providers/web-push.d.cts +1 -1
  83. package/dist/providers/web-push.d.ts +1 -1
  84. package/dist/providers/web-push.js +3 -7
  85. package/dist/providers/web-push.js.map +1 -1
  86. package/dist/react-native.cjs +20 -2
  87. package/dist/react-native.cjs.map +1 -1
  88. package/dist/react-native.js +20 -2
  89. package/dist/react-native.js.map +1 -1
  90. package/dist/react.cjs +20 -2
  91. package/dist/react.cjs.map +1 -1
  92. package/dist/react.js +20 -2
  93. package/dist/react.js.map +1 -1
  94. package/dist/schema.cjs +3 -1
  95. package/dist/schema.cjs.map +1 -1
  96. package/dist/schema.d.cts +2 -1
  97. package/dist/schema.d.ts +2 -1
  98. package/dist/schema.js +1 -1
  99. package/package.json +8 -3
  100. package/dist/chunk-3VOQOGDR.js.map +0 -1
  101. package/dist/chunk-E4IZ2CQC.js.map +0 -1
  102. package/dist/chunk-EROWLUL4.js.map +0 -1
  103. package/dist/chunk-JOVIZXO6.js.map +0 -1
package/README.md CHANGED
@@ -11,7 +11,7 @@ database, with no per-notification bill.
11
11
  [![node](https://img.shields.io/node/v/easy-ping)](https://www.npmjs.com/package/easy-ping)
12
12
  [![license](https://img.shields.io/npm/l/easy-ping?color=blue)](./LICENSE)
13
13
 
14
- [Documentation](https://easy-ping.teklumoges.dev) · [Quickstart](https://easy-ping.teklumoges.dev/docs/quickstart) · [Changelog](https://easy-ping.teklumoges.dev/docs/changelog) · [AI context](https://easy-ping.teklumoges.dev/docs/ai-assistant)
14
+ [Documentation](https://easy-pings.com) · [Quickstart](https://easy-pings.com/docs/quickstart) · [Changelog](https://easy-pings.com/docs/changelog) · [AI context](https://easy-pings.com/docs/ai-assistant)
15
15
 
16
16
  </div>
17
17
 
@@ -61,7 +61,7 @@ Every "no queue required" decision below follows from that.
61
61
  > `http_ece`; email is verified against Resend's live API, including idempotent retries and a full
62
62
  > send-to-delivered pass. The bell updates over a server-sent event stream with polling as the
63
63
  > fallback; batching is not built yet. Minor
64
- > versions may still move APIs before 1.0; [what is stable and how changes are announced](https://easy-ping.teklumoges.dev/docs/stability).
64
+ > versions may still move APIs before 1.0; [what is stable and how changes are announced](https://easy-pings.com/docs/stability).
65
65
 
66
66
  ---
67
67
 
@@ -326,17 +326,19 @@ function drizzleAdapter(client, options = {}) {
326
326
  drizzleOrm.sql`, `
327
327
  )})`
328
328
  );
329
- const conflict = onConflict && onConflict.length > 0 ? drizzleOrm.sql` ON CONFLICT (${drizzleOrm.sql.join(
329
+ const updated = (onConflict ?? []).length ? columns.filter((column) => !onConflict?.includes(column)) : [];
330
+ const target = onConflict && onConflict.length > 0 ? drizzleOrm.sql` ON CONFLICT (${drizzleOrm.sql.join(
330
331
  onConflict.map((field) => drizzleOrm.sql.identifier(toSnakeCase(field))),
331
332
  drizzleOrm.sql`, `
332
- )}) DO UPDATE SET ${drizzleOrm.sql.join(
333
- columns.filter((column) => !onConflict.includes(column)).map(
333
+ )})` : void 0;
334
+ const conflict = !target ? drizzleOrm.sql`` : updated.length === 0 ? drizzleOrm.sql`${target} DO NOTHING` : drizzleOrm.sql`${target} DO UPDATE SET ${drizzleOrm.sql.join(
335
+ updated.map(
334
336
  (column) => drizzleOrm.sql`${drizzleOrm.sql.identifier(toSnakeCase(column))} = EXCLUDED.${drizzleOrm.sql.identifier(
335
337
  toSnakeCase(column)
336
338
  )}`
337
339
  ),
338
340
  drizzleOrm.sql`, `
339
- )}` : drizzleOrm.sql``;
341
+ )}`;
340
342
  const inserted = await run(drizzleOrm.sql`
341
343
  INSERT INTO ${drizzleOrm.sql.identifier(table)} (${drizzleOrm.sql.join(
342
344
  columns.map((column) => drizzleOrm.sql.identifier(toSnakeCase(column))),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/base64url.ts","../../src/schema/declaration.ts","../../src/core/store.ts","../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["sql","options","pgTable","text","jsonb","timestamp","index","uniqueIndex","integer","boolean","primaryKey"],"mappings":"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","file":"drizzle.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","import { type SQL, sql } from \"drizzle-orm\";\nimport 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\";\n\ntype Row = Record<string, unknown>;\n\n/** Structural, not Drizzle's inferred type: that costs thousands of instantiations at a boundary. */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\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);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/** postgres-js rejects a Date bound to a ::timestamptz param; ISO strings bind everywhere. */\nconst ts = (value: Date) => value.toISOString();\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\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\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: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\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) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // App clock, not now(): markSeen compares against app-side cutoffs and NTP skew broke it.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // NULL dedupe keys never conflict, so undeduped rows coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\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\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED lets concurrent sweeps step around each other. RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\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\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return 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: 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 const values = releases.map(({ id, outcome, nextAttemptAt }) => {\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 return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // No claimed_by predicate on purpose: terminal state beats a wedged row. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text 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 db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id (RFC 0002 §2); no read_at IS NULL filter so re-marking stays idempotent.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\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\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const conflict =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )}) DO UPDATE SET ${sql.join(\n columns\n .filter((column) => !onConflict.includes(column))\n .map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`\n : sql``;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // NULLs are distinct here: unlimited rows without a dedupe key.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}
1
+ {"version":3,"sources":["../../src/core/base64url.ts","../../src/schema/declaration.ts","../../src/core/store.ts","../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["sql","options","pgTable","text","jsonb","timestamp","index","uniqueIndex","integer","boolean","primaryKey"],"mappings":"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","file":"drizzle.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 writable(table: string): TableDeclaration {\n const declaration = resolve(table);\n if (declaration.readOnly) {\n throw new ConfigError(\n `plugin \"${pluginId}\" tried to write \"${table}\", which it declares readOnly.`,\n );\n }\n return declaration;\n }\n\n function notEverything(table: string, where: WhereClause, action: string) {\n if (Object.keys(where).length === 0) {\n throw new ConfigError(\n `plugin \"${pluginId}\" called ${action}(\"${table}\", {}), which would touch every row. ` +\n \"Pass a condition.\",\n );\n }\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 = writable(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 = writable(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 = writable(table);\n checkWhere(declaration, where);\n notEverything(table, where, \"update\");\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 = writable(table);\n checkWhere(declaration, where);\n notEverything(table, where, \"remove\");\n return storage.deleteRows(qualified(declaration), where);\n },\n };\n}\n","import { type SQL, sql } from \"drizzle-orm\";\nimport 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\";\n\ntype Row = Record<string, unknown>;\n\n/** Structural, not Drizzle's inferred type: that costs thousands of instantiations at a boundary. */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\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);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/** postgres-js rejects a Date bound to a ::timestamptz param; ISO strings bind everywhere. */\nconst ts = (value: Date) => value.toISOString();\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\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\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: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\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) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // App clock, not now(): markSeen compares against app-side cutoffs and NTP skew broke it.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // NULL dedupe keys never conflict, so undeduped rows coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\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\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED lets concurrent sweeps step around each other. RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\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\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return 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: 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 const values = releases.map(({ id, outcome, nextAttemptAt }) => {\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 return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // No claimed_by predicate on purpose: terminal state beats a wedged row. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text 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 db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id (RFC 0002 §2); no read_at IS NULL filter so re-marking stays idempotent.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\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\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const updated = (onConflict ?? []).length\n ? columns.filter((column) => !onConflict?.includes(column))\n : [];\n const target =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )})`\n : undefined;\n const conflict = !target\n ? sql``\n : updated.length === 0\n ? sql`${target} DO NOTHING`\n : sql`${target} DO UPDATE SET ${sql.join(\n updated.map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // NULLs are distinct here: unlimited rows without a dedupe key.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}
@@ -1,4 +1,4 @@
1
- import { isOperator } from '../chunk-3VOQOGDR.js';
1
+ import { isOperator } from '../chunk-O2PBBL5X.js';
2
2
  import { toSnakeCase } from '../chunk-AEYYTE5I.js';
3
3
  import { decodeBase64Url, encodeBase64Url } from '../chunk-PTGHMCCG.js';
4
4
  import { sql } from 'drizzle-orm';
@@ -297,17 +297,19 @@ function drizzleAdapter(client, options = {}) {
297
297
  sql`, `
298
298
  )})`
299
299
  );
300
- const conflict = onConflict && onConflict.length > 0 ? sql` ON CONFLICT (${sql.join(
300
+ const updated = (onConflict ?? []).length ? columns.filter((column) => !onConflict?.includes(column)) : [];
301
+ const target = onConflict && onConflict.length > 0 ? sql` ON CONFLICT (${sql.join(
301
302
  onConflict.map((field) => sql.identifier(toSnakeCase(field))),
302
303
  sql`, `
303
- )}) DO UPDATE SET ${sql.join(
304
- columns.filter((column) => !onConflict.includes(column)).map(
304
+ )})` : void 0;
305
+ const conflict = !target ? sql`` : updated.length === 0 ? sql`${target} DO NOTHING` : sql`${target} DO UPDATE SET ${sql.join(
306
+ updated.map(
305
307
  (column) => sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(
306
308
  toSnakeCase(column)
307
309
  )}`
308
310
  ),
309
311
  sql`, `
310
- )}` : sql``;
312
+ )}`;
311
313
  const inserted = await run(sql`
312
314
  INSERT INTO ${sql.identifier(table)} (${sql.join(
313
315
  columns.map((column) => sql.identifier(toSnakeCase(column))),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["options","sql"],"mappings":"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","file":"drizzle.js","sourcesContent":["import { type SQL, sql } from \"drizzle-orm\";\nimport 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\";\n\ntype Row = Record<string, unknown>;\n\n/** Structural, not Drizzle's inferred type: that costs thousands of instantiations at a boundary. */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\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);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/** postgres-js rejects a Date bound to a ::timestamptz param; ISO strings bind everywhere. */\nconst ts = (value: Date) => value.toISOString();\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\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\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: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\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) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // App clock, not now(): markSeen compares against app-side cutoffs and NTP skew broke it.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // NULL dedupe keys never conflict, so undeduped rows coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\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\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED lets concurrent sweeps step around each other. RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\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\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return 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: 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 const values = releases.map(({ id, outcome, nextAttemptAt }) => {\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 return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // No claimed_by predicate on purpose: terminal state beats a wedged row. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text 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 db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id (RFC 0002 §2); no read_at IS NULL filter so re-marking stays idempotent.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\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\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const conflict =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )}) DO UPDATE SET ${sql.join(\n columns\n .filter((column) => !onConflict.includes(column))\n .map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`\n : sql``;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // NULLs are distinct here: unlimited rows without a dedupe key.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}
1
+ {"version":3,"sources":["../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["options","sql"],"mappings":"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","file":"drizzle.js","sourcesContent":["import { type SQL, sql } from \"drizzle-orm\";\nimport 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\";\n\ntype Row = Record<string, unknown>;\n\n/** Structural, not Drizzle's inferred type: that costs thousands of instantiations at a boundary. */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\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);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/** postgres-js rejects a Date bound to a ::timestamptz param; ISO strings bind everywhere. */\nconst ts = (value: Date) => value.toISOString();\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\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\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: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\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) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // App clock, not now(): markSeen compares against app-side cutoffs and NTP skew broke it.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // NULL dedupe keys never conflict, so undeduped rows coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\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\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED lets concurrent sweeps step around each other. RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\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\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return 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: 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 const values = releases.map(({ id, outcome, nextAttemptAt }) => {\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 return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // No claimed_by predicate on purpose: terminal state beats a wedged row. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text 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 db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id (RFC 0002 §2); no read_at IS NULL filter so re-marking stays idempotent.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\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\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const updated = (onConflict ?? []).length\n ? columns.filter((column) => !onConflict?.includes(column))\n : [];\n const target =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )})`\n : undefined;\n const conflict = !target\n ? sql``\n : updated.length === 0\n ? sql`${target} DO NOTHING`\n : sql`${target} DO UPDATE SET ${sql.join(\n updated.map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // NULLs are distinct here: unlimited rows without a dedupe key.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}