easy-ping 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/dist/adapters/drizzle.cjs +0 -2
- package/dist/adapters/drizzle.js +3 -5
- package/dist/adapters/mongodb.cjs +0 -2
- package/dist/adapters/mongodb.js +4 -6
- package/dist/adapters/mysql.cjs +0 -2
- package/dist/adapters/mysql.js +6 -8
- package/dist/adapters/postgres.cjs +0 -2
- package/dist/adapters/postgres.js +8 -10
- package/dist/adapters/sqlite.cjs +0 -2
- package/dist/adapters/sqlite.js +6 -8
- package/dist/browser.cjs +0 -2
- package/dist/browser.js +0 -2
- package/dist/{chunk-JKTMUMQK.js → chunk-2UOEAG6H.js} +1 -3
- package/dist/{chunk-R3BE67L7.js → chunk-74KSKP6B.js} +0 -2
- package/dist/{chunk-O2PBBL5X.js → chunk-7C4K5WKW.js} +1 -3
- package/dist/{chunk-CK5UPVYP.js → chunk-CRSGL5SG.js} +0 -2
- package/dist/{chunk-PTGHMCCG.js → chunk-D3UX3WWD.js} +0 -2
- package/dist/{chunk-CMWOIYVQ.js → chunk-EN3NMHSI.js} +4 -6
- package/dist/{chunk-ORZKH224.js → chunk-G32BYQAT.js} +0 -2
- package/dist/{chunk-A4HX5YTG.js → chunk-IXXPJMYS.js} +3 -5
- package/dist/{chunk-CFLVAF2R.js → chunk-JDR3U7X4.js} +2 -4
- package/dist/{chunk-AEYYTE5I.js → chunk-JRZ2U4IT.js} +0 -2
- package/dist/{chunk-UM2L26PV.js → chunk-KOS3YZMZ.js} +1 -3
- package/dist/{chunk-HSB5T3LD.js → chunk-OKIQ5BEV.js} +1 -3
- package/dist/{chunk-JN3UCQBP.js → chunk-SZWEW3WN.js} +0 -2
- package/dist/{chunk-SSHVZHSJ.js → chunk-VA4W4UFI.js} +0 -2
- package/dist/client.cjs +0 -2
- package/dist/client.js +0 -2
- package/dist/index.cjs +0 -2
- package/dist/index.js +12 -14
- package/dist/node.cjs +0 -2
- package/dist/node.js +3 -5
- package/dist/plugins/digests.cjs +0 -2
- package/dist/plugins/digests.js +1 -3
- package/dist/plugins/mobile-push.cjs +0 -2
- package/dist/plugins/mobile-push.js +3 -5
- package/dist/plugins/preferences-client.cjs +0 -2
- package/dist/plugins/preferences-client.js +1 -3
- package/dist/plugins/preferences-react.cjs +0 -1
- package/dist/plugins/preferences-react.js +0 -1
- package/dist/plugins/preferences.cjs +0 -2
- package/dist/plugins/preferences.js +3 -5
- package/dist/plugins/push.cjs +0 -2
- package/dist/plugins/push.js +4 -6
- package/dist/plugins/telegram.cjs +0 -2
- package/dist/plugins/telegram.js +5 -7
- package/dist/providers/expo-push.cjs +0 -2
- package/dist/providers/expo-push.js +0 -2
- package/dist/providers/resend.cjs +0 -2
- package/dist/providers/resend.js +0 -2
- package/dist/providers/telegram.cjs +0 -2
- package/dist/providers/telegram.js +1 -3
- package/dist/providers/web-push.cjs +0 -2
- package/dist/providers/web-push.js +1 -3
- package/dist/react-native.cjs +0 -1
- package/dist/react-native.js +0 -1
- package/dist/react.cjs +0 -1
- package/dist/react.js +0 -1
- package/dist/schema.cjs +0 -2
- package/dist/schema.js +4 -6
- package/dist/sw.cjs +0 -2
- package/dist/sw.js +0 -2
- package/dist/testing.cjs +0 -2
- package/dist/testing.js +0 -2
- package/package.json +3 -3
- package/dist/adapters/drizzle.cjs.map +0 -1
- package/dist/adapters/drizzle.js.map +0 -1
- package/dist/adapters/mongodb.cjs.map +0 -1
- package/dist/adapters/mongodb.js.map +0 -1
- package/dist/adapters/mysql.cjs.map +0 -1
- package/dist/adapters/mysql.js.map +0 -1
- package/dist/adapters/postgres.cjs.map +0 -1
- package/dist/adapters/postgres.js.map +0 -1
- package/dist/adapters/sqlite.cjs.map +0 -1
- package/dist/adapters/sqlite.js.map +0 -1
- package/dist/browser.cjs.map +0 -1
- package/dist/browser.js.map +0 -1
- package/dist/chunk-A4HX5YTG.js.map +0 -1
- package/dist/chunk-AEYYTE5I.js.map +0 -1
- package/dist/chunk-CFLVAF2R.js.map +0 -1
- package/dist/chunk-CK5UPVYP.js.map +0 -1
- package/dist/chunk-CMWOIYVQ.js.map +0 -1
- package/dist/chunk-HSB5T3LD.js.map +0 -1
- package/dist/chunk-JKTMUMQK.js.map +0 -1
- package/dist/chunk-JN3UCQBP.js.map +0 -1
- package/dist/chunk-O2PBBL5X.js.map +0 -1
- package/dist/chunk-ORZKH224.js.map +0 -1
- package/dist/chunk-PTGHMCCG.js.map +0 -1
- package/dist/chunk-R3BE67L7.js.map +0 -1
- package/dist/chunk-SSHVZHSJ.js.map +0 -1
- package/dist/chunk-UM2L26PV.js.map +0 -1
- package/dist/client.cjs.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/node.cjs.map +0 -1
- package/dist/node.js.map +0 -1
- package/dist/plugins/digests.cjs.map +0 -1
- package/dist/plugins/digests.js.map +0 -1
- package/dist/plugins/mobile-push.cjs.map +0 -1
- package/dist/plugins/mobile-push.js.map +0 -1
- package/dist/plugins/preferences-client.cjs.map +0 -1
- package/dist/plugins/preferences-client.js.map +0 -1
- package/dist/plugins/preferences-react.cjs.map +0 -1
- package/dist/plugins/preferences-react.js.map +0 -1
- package/dist/plugins/preferences.cjs.map +0 -1
- package/dist/plugins/preferences.js.map +0 -1
- package/dist/plugins/push.cjs.map +0 -1
- package/dist/plugins/push.js.map +0 -1
- package/dist/plugins/telegram.cjs.map +0 -1
- package/dist/plugins/telegram.js.map +0 -1
- package/dist/providers/expo-push.cjs.map +0 -1
- package/dist/providers/expo-push.js.map +0 -1
- package/dist/providers/resend.cjs.map +0 -1
- package/dist/providers/resend.js.map +0 -1
- package/dist/providers/telegram.cjs.map +0 -1
- package/dist/providers/telegram.js.map +0 -1
- package/dist/providers/web-push.cjs.map +0 -1
- package/dist/providers/web-push.js.map +0 -1
- package/dist/react-native.cjs.map +0 -1
- package/dist/react-native.js.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/schema.cjs.map +0 -1
- package/dist/schema.js.map +0 -1
- package/dist/sw.cjs.map +0 -1
- package/dist/sw.js.map +0 -1
- package/dist/testing.cjs.map +0 -1
- package/dist/testing.js.map +0 -1
|
@@ -229,5 +229,3 @@ exports.InvalidSubscriptionError = InvalidSubscriptionError;
|
|
|
229
229
|
exports.MAX_PAYLOAD_BYTES = MAX_PAYLOAD_BYTES;
|
|
230
230
|
exports.generateVapidKeys = generateVapidKeys;
|
|
231
231
|
exports.webPush = webPush;
|
|
232
|
-
//# sourceMappingURL=web-push.cjs.map
|
|
233
|
-
//# sourceMappingURL=web-push.cjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { encodeBase64Url, decodeBase64UrlBytes } from '../chunk-
|
|
1
|
+
import { encodeBase64Url, decodeBase64UrlBytes } from '../chunk-D3UX3WWD.js';
|
|
2
2
|
|
|
3
3
|
// src/providers/web-push/crypto.ts
|
|
4
4
|
var utf8 = (value) => new TextEncoder().encode(value);
|
|
@@ -210,5 +210,3 @@ function webPush(options) {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
export { InvalidSubscriptionError, MAX_PAYLOAD_BYTES, generateVapidKeys, webPush };
|
|
213
|
-
//# sourceMappingURL=web-push.js.map
|
|
214
|
-
//# sourceMappingURL=web-push.js.map
|
package/dist/react-native.cjs
CHANGED
package/dist/react-native.js
CHANGED
package/dist/react.cjs
CHANGED
package/dist/react.js
CHANGED
package/dist/schema.cjs
CHANGED
package/dist/schema.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
export { INTROSPECT_SQL, MYSQL_INTROSPECT_COLUMNS_SQL, MYSQL_INTROSPECT_INDEXES_SQL, SQLITE_INTROSPECT_SQL, planMysqlMigration, planPostgresMigration, planSqliteMigration, renderDrizzleSchema, renderPostgresDdl } from './chunk-
|
|
2
|
-
export { renderMysqlDdl } from './chunk-
|
|
3
|
-
export { renderSqliteDdl } from './chunk-
|
|
4
|
-
export { coreSchema, toSnakeCase } from './chunk-
|
|
5
|
-
//# sourceMappingURL=schema.js.map
|
|
6
|
-
//# sourceMappingURL=schema.js.map
|
|
1
|
+
export { INTROSPECT_SQL, MYSQL_INTROSPECT_COLUMNS_SQL, MYSQL_INTROSPECT_INDEXES_SQL, SQLITE_INTROSPECT_SQL, planMysqlMigration, planPostgresMigration, planSqliteMigration, renderDrizzleSchema, renderPostgresDdl } from './chunk-IXXPJMYS.js';
|
|
2
|
+
export { renderMysqlDdl } from './chunk-KOS3YZMZ.js';
|
|
3
|
+
export { renderSqliteDdl } from './chunk-OKIQ5BEV.js';
|
|
4
|
+
export { coreSchema, toSnakeCase } from './chunk-JRZ2U4IT.js';
|
package/dist/sw.cjs
CHANGED
package/dist/sw.js
CHANGED
package/dist/testing.cjs
CHANGED
package/dist/testing.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "easy-ping",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Free, open-source notifications for TypeScript: in-app inbox, email, web push, mobile push and Telegram, self-hosted in your own Postgres, MySQL, SQLite or MongoDB.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Teklu Moges",
|
|
@@ -210,8 +210,8 @@
|
|
|
210
210
|
"react": "^19.2.8",
|
|
211
211
|
"tsup": "^8.5.1",
|
|
212
212
|
"typescript": "^5.7.0",
|
|
213
|
-
"vite": "^8.3.
|
|
214
|
-
"vitest": "^5.0.
|
|
213
|
+
"vite": "^8.3.5",
|
|
214
|
+
"vitest": "^5.0.5"
|
|
215
215
|
},
|
|
216
216
|
"engines": {
|
|
217
217
|
"node": ">=20"
|
|
@@ -1 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
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"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/base64url.ts","../../src/schema/declaration.ts","../../src/core/store.ts","../../src/adapters/mongodb/adapter.ts","../../src/adapters/mongodb/indexes.ts","../../src/core/signals.ts","../../src/adapters/mongodb/signals.ts"],"names":["options","spec"],"mappings":"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","file":"mongodb.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 {\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\";\n\ntype Document = Record<string, unknown>;\n\n/** Structural, so `mongodb` stays an optional peer dependency. */\ntype MongoCollection = {\n insertMany(docs: Document[], options?: unknown): Promise<unknown>;\n insertOne(doc: Document, options?: unknown): Promise<unknown>;\n find(filter: Document, options?: Document): { toArray(): Promise<Document[]> };\n findOne(filter: Document, options?: Document): Promise<Document | null>;\n findOneAndUpdate(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<Document | null>;\n updateOne(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n upsertedCount?: number;\n }>;\n updateMany(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n }>;\n deleteMany(filter: Document, options?: Document): Promise<{ deletedCount: number }>;\n countDocuments(filter: Document, options?: Document): Promise<number>;\n createIndex(spec: Document, options?: Document): Promise<string>;\n};\n\ntype MongoDb = {\n collection(name: string): MongoCollection;\n};\n\ntype MongoSession = {\n withTransaction<T>(fn: () => Promise<T>): Promise<T>;\n endSession(): Promise<void>;\n};\n\ntype MongoClient = {\n startSession(): MongoSession;\n};\n\nexport type MongoAdapterOptions = {\n /** Prefixes every collection name, matching the SQL adapter's table prefix. */\n prefix?: string;\n /** Makes createNotifications atomic. Needs a replica set, so it is opt-in. */\n client?: unknown;\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\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\n/** Documents carry the id as `_id`; the rest of the library never sees that. */\nfunction toNotification(doc: Document): NotificationRecord {\n return {\n id: str(doc._id),\n userId: str(doc.userId),\n type: str(doc.type),\n payload: doc.payload,\n actorId: nullableStr(doc.actorId),\n groupKey: nullableStr(doc.groupKey),\n dedupeKey: nullableStr(doc.dedupeKey),\n seenAt: nullableDate(doc.seenAt),\n readAt: nullableDate(doc.readAt),\n archivedAt: nullableDate(doc.archivedAt),\n createdAt: date(doc.createdAt),\n };\n}\n\nfunction toDelivery(doc: Document): DeliveryRecord {\n return {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n status: str(doc.status) as DeliveryStatus,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notBefore: date(doc.notBefore),\n claimedAt: nullableDate(doc.claimedAt),\n claimedBy: nullableStr(doc.claimedBy),\n lastError: nullableStr(doc.lastError),\n updatedAt: date(doc.updatedAt),\n };\n}\n\n/** The store hands `id`; documents key on `_id`. */\nconst toMongoField = (field: string) => (field === \"id\" ? \"_id\" : field);\n\nfunction toFilter(where: WhereClause): Document {\n const filter: Document = {};\n\n for (const [field, condition] of Object.entries(where)) {\n const key = toMongoField(field);\n\n if (condition === null) {\n filter[key] = null;\n continue;\n }\n\n if (!isOperator(condition)) {\n // Last line before the driver, where `{ $ne: null }` becomes a query.\n if (typeof condition === \"object\" && !(condition instanceof Date)) {\n throw new Error(`mongo filter on \"${field}\" received an object; only scalars are bound`);\n }\n filter[key] = condition;\n continue;\n }\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) filter[key] = { $in: operator.in };\n else if (\"lt\" in operator) filter[key] = { $lt: operator.lt };\n else if (\"lte\" in operator) filter[key] = { $lte: operator.lte };\n else if (\"gt\" in operator) filter[key] = { $gt: operator.gt };\n else if (\"gte\" in operator) filter[key] = { $gte: operator.gte };\n else if (\"not\" in operator) {\n // $ne null also matches a missing field, which is what \"not null\" means.\n filter[key] = { $ne: operator.not };\n }\n }\n\n return filter;\n}\n\n/** A duplicate on a unique index, rather than a real write failure. */\nconst isDuplicateKey = (error: unknown): boolean => {\n const code = (error as { code?: number; writeErrors?: { code?: number }[] })?.code;\n if (code === 11000) return true;\n const writeErrors = (error as { writeErrors?: { code?: number }[] })?.writeErrors;\n return Array.isArray(writeErrors) && writeErrors.some((entry) => entry?.code === 11000);\n};\n\nexport function mongoAdapter(db: unknown, options: MongoAdapterOptions = {}): DatabaseAdapter {\n const database = db as MongoDb;\n const prefix = options.prefix ?? \"\";\n\n const client = options.client as MongoClient | undefined;\n\n const notifications = () => database.collection(`${prefix}notification`);\n const deliveries = () => database.collection(`${prefix}notification_delivery`);\n\n /** One transaction per notification: a duplicate key aborts the transaction it happens in, and dedupe is the expected path. */\n async function atomically<T>(fn: (session?: MongoSession) => Promise<T>): Promise<T> {\n if (!client) return fn();\n\n const session = client.startSession();\n try {\n return await session.withTransaction(() => fn(session));\n } finally {\n await session.endSession();\n }\n }\n\n return {\n name: \"mongodb\",\n // Documents keep the declared camelCase, and store objects natively.\n naming: \"preserve\",\n serializesJson: false,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n const created: string[] = [];\n const deduped: string[] = [];\n\n for (const row of input) {\n const now = new Date();\n\n try {\n await atomically(async (session) => {\n const options = session ? { session } : undefined;\n\n // Notification first: it carries the unique dedupe index.\n await notifications().insertOne(\n {\n _id: row.id,\n userId: row.userId,\n type: row.type,\n payload: row.payload ?? null,\n actorId: row.actorId ?? null,\n groupKey: row.groupKey ?? null,\n dedupeKey: row.dedupeKey ?? null,\n seenAt: null,\n readAt: null,\n archivedAt: null,\n createdAt: now,\n },\n options,\n );\n\n if (row.deliveries.length > 0) {\n await deliveries().insertMany(\n row.deliveries.map((delivery) => ({\n _id: delivery.id,\n notificationId: row.id,\n channel: delivery.channel,\n status: \"pending\",\n attempts: 0,\n maxAttempts: delivery.maxAttempts,\n notBefore: delivery.notBefore,\n claimedAt: null,\n claimedBy: null,\n lastError: null,\n updatedAt: now,\n })),\n options,\n );\n }\n });\n\n created.push(row.id);\n } catch (error) {\n if (!isDuplicateKey(error)) throw error;\n deduped.push(row.id);\n }\n }\n\n return { created, deduped };\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 eligible: Document = {\n $and: [\n {\n $or: [{ status: \"pending\" }, { status: \"claimed\", claimedAt: { $lt: staleBefore } }],\n },\n { notBefore: { $lte: now } },\n { $expr: { $lt: [\"$attempts\", \"$maxAttempts\"] } },\n ],\n };\n\n if (args.channels && args.channels.length > 0) {\n (eligible.$and as Document[]).push({ channel: { $in: [...args.channels] } });\n }\n if (args.ids && args.ids.length > 0) {\n (eligible.$and as Document[]).push({ _id: { $in: [...args.ids] } });\n }\n\n // findOneAndUpdate is atomic per document; updateMany cannot say which rows this call won.\n const claimed: Document[] = [];\n for (let taken = 0; taken < args.limit; taken += 1) {\n const doc = await deliveries().findOneAndUpdate(\n eligible,\n { $set: { status: \"claimed\", claimedAt: now, claimedBy: args.claimToken } },\n { sort: { notBefore: 1, _id: 1 }, returnDocument: \"after\" },\n );\n if (!doc) break;\n claimed.push(doc);\n }\n\n if (claimed.length === 0) return [];\n\n const parents = await notifications()\n .find({ _id: { $in: claimed.map((doc) => doc.notificationId) } })\n .toArray();\n const byId = new Map(parents.map((doc) => [str(doc._id), doc]));\n\n return claimed.flatMap((doc) => {\n const parent = byId.get(str(doc.notificationId));\n if (!parent) return [];\n\n return [\n {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notification: {\n userId: str(parent.userId),\n type: str(parent.type),\n payload: parent.payload,\n actorId: nullableStr(parent.actorId),\n },\n },\n ];\n });\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n for (const { id, outcome, nextAttemptAt } of releases) {\n const failed = outcome.result === \"failed\";\n const skipped = outcome.result === \"skipped\";\n const retryable = failed && outcome.retryable;\n\n // Pipeline update, so the retry decision reads maxAttempts from the document.\n await deliveries().updateOne({ _id: id }, [\n {\n $set: {\n attempts: failed ? { $add: [\"$attempts\", 1] } : \"$attempts\",\n status: failed\n ? {\n $cond: [\n { $and: [retryable, { $lt: [{ $add: [\"$attempts\", 1] }, \"$maxAttempts\"] }] },\n \"pending\",\n \"failed\",\n ],\n }\n : skipped\n ? \"skipped\"\n : \"sent\",\n // $literal: an error starting with \"$\" would be read as a field path.\n lastError: failed\n ? { $literal: outcome.error.slice(0, 2000) }\n : skipped\n ? { $literal: outcome.reason.slice(0, 2000) }\n : null,\n notBefore: nextAttemptAt ?? \"$notBefore\",\n // Unconditional: terminal state beats a wedged row. RFC 0003 §6.\n claimedAt: null,\n claimedBy: null,\n updatedAt: now,\n },\n },\n ]);\n }\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const filter: Document = { userId: query.userId, archivedAt: null };\n if (query.unreadOnly) filter.readAt = null;\n\n if (cursor) {\n // Matches the SQL row comparison (createdAt, id) < (cursor, cursorId).\n filter.$or = [\n { createdAt: { $lt: cursor.createdAt } },\n { createdAt: cursor.createdAt, _id: { $lt: cursor.id } },\n ];\n }\n\n const docs = await notifications()\n .find(filter, { sort: { createdAt: -1, _id: -1 }, limit: query.limit + 1 })\n .toArray();\n\n const page = docs.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n docs.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n return notifications().countDocuments({ userId, seenAt: null, archivedAt: null });\n },\n\n async markSeen(userId: string, before: Date) {\n await notifications().updateMany(\n { userId, seenAt: null, createdAt: { $lte: before } },\n { $set: { seenAt: new Date() } },\n );\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by userId; idempotent, so no 404 on a re-mark.\n const filter = { userId, _id: { $in: [...notificationIds] } };\n await notifications().updateMany(\n { ...filter, readAt: null },\n {\n $set: { readAt: new Date() },\n },\n );\n\n return notifications().countDocuments(filter);\n },\n\n async markAllRead(userId: string) {\n const result = await notifications().updateMany(\n { userId, readAt: null },\n { $set: { readAt: new Date() } },\n );\n return result.modifiedCount;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const docs = await deliveries()\n .find(\n { status: \"failed\", updatedAt: { $gte: args.since } },\n { sort: { updatedAt: -1 }, limit: args.limit },\n )\n .toArray();\n\n return docs.map(toDelivery);\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const find: Document = {};\n if (options.limit) find.limit = options.limit;\n if (options.orderBy) {\n const direction = options.orderBy.direction === \"desc\" ? -1 : 1;\n find.sort = { [toMongoField(options.orderBy.field)]: direction };\n }\n\n const docs = await database.collection(table).find(toFilter(where), find).toArray();\n\n // `_id` is a storage detail; plugins declared the field as `id`.\n return docs.map(({ _id, ...rest }) => (_id === undefined ? rest : { id: _id, ...rest }));\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 documents = rows.map(({ id, ...rest }) =>\n id === undefined ? { ...rest } : { _id: id, ...rest },\n );\n\n if (!onConflict || onConflict.length === 0) {\n await database.collection(table).insertMany(documents as Document[]);\n return documents.length;\n }\n\n let written = 0;\n for (const document of documents as Document[]) {\n const key: Document = {};\n for (const field of onConflict) key[toMongoField(field)] = document[toMongoField(field)];\n\n // _id only in $setOnInsert: Mongo rejects an update that would modify it.\n const { _id, ...updatable } = document;\n const update: Document = { $set: updatable };\n if (_id !== undefined) update.$setOnInsert = { _id };\n\n const result = await database.collection(table).updateOne(key, update, { upsert: true });\n written += result.matchedCount + (result.upsertedCount ?? 0);\n }\n return written;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments: Document = {};\n for (const [field, value] of Object.entries(set)) assignments[toMongoField(field)] = value;\n if (Object.keys(assignments).length === 0) return 0;\n\n const result = await database\n .collection(table)\n .updateMany(toFilter(where), { $set: assignments });\n return result.matchedCount;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const result = await database.collection(table).deleteMany(toFilter(where));\n return result.deletedCount;\n },\n };\n}\n","import type { FieldDeclaration, SchemaDeclaration } from \"../../core/plugin\";\nimport { coreSchema } from \"../../schema/declaration\";\n\ntype IndexSpec = Record<string, 1 | -1>;\n\ntype IndexOptions = {\n name: string;\n unique?: boolean;\n partialFilterExpression?: Record<string, unknown>;\n};\n\ntype IndexableDb = {\n collection(name: string): {\n createIndex(spec: IndexSpec, options: IndexOptions): Promise<string>;\n };\n};\n\nconst BSON_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"string\",\n number: \"number\",\n boolean: \"bool\",\n date: \"date\",\n json: \"object\",\n};\n\n/** Applies a SchemaDeclaration's indexes. A unique index over a nullable field gets a partial filter, since Mongo treats all NULLs as one value. */\nexport async function createPluginIndexes(\n db: unknown,\n schema: SchemaDeclaration,\n prefix = \"\",\n): Promise<void> {\n const database = db as IndexableDb;\n\n for (const table of Object.values(schema)) {\n const collection = database.collection(prefix + table.tableName);\n\n // A single \"id\" key is stored as _id, which is already unique.\n if (table.primaryKey && table.primaryKey.length > 0 && table.primaryKey[0] !== \"id\") {\n const spec: IndexSpec = {};\n for (const field of table.primaryKey) spec[field] = 1;\n await collection.createIndex(spec, {\n name: `${table.tableName}_pk`,\n unique: true,\n });\n }\n\n for (const declaration of table.indexes ?? []) {\n const spec: IndexSpec = {};\n for (const field of declaration.on) spec[field] = 1;\n\n const options: IndexOptions = {\n name: prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`),\n };\n\n if (declaration.unique) {\n options.unique = true;\n\n const partial: Record<string, unknown> = {};\n for (const field of declaration.on) {\n const spec = table.fields[field];\n if (spec && !spec.required) partial[field] = { $type: BSON_TYPE[spec.type] };\n }\n if (Object.keys(partial).length > 0) options.partialFilterExpression = partial;\n }\n\n await collection.createIndex(spec, options);\n }\n }\n}\n\n/** Creates the indexes the core tables need. Call once at startup. */\nexport const createMongoIndexes = (db: unknown, options: { prefix?: string } = {}) =>\n createPluginIndexes(db, coreSchema, options.prefix ?? \"\");\n","/**\n * The wake-up seam. A publish carries no payload: it says \"something changed\n * on this channel, go look\", so losing one costs latency, never data.\n * RFC 0006 §4C.\n */\nexport type Signals = {\n /** True when a publish in one process reaches subscribers in another. */\n readonly crossProcess: boolean;\n publish(channel: string): void;\n subscribe(channel: string, handler: () => void): () => void;\n close?(): Promise<void> | void;\n};\n\nexport const DELIVERIES_CHANNEL = \"deliveries\";\nexport const inboxChannel = (userId: string) => `inbox:${userId}`;\n\n/** In-process only. The default, and exactly right on SQLite or a single replica. */\nexport function createMemorySignals(): Signals {\n const handlers = new Map<string, Set<() => void>>();\n\n return {\n crossProcess: false,\n publish(channel) {\n const set = handlers.get(channel);\n if (!set) return;\n for (const handler of [...set]) {\n queueMicrotask(() => {\n try {\n handler();\n } catch {\n // a subscriber's failure is its own problem\n }\n });\n }\n },\n subscribe(channel, handler) {\n let set = handlers.get(channel);\n if (!set) {\n set = new Set();\n handlers.set(channel, set);\n }\n set.add(handler);\n return () => {\n set?.delete(handler);\n if (set?.size === 0) handlers.delete(channel);\n };\n },\n };\n}\n\n/**\n * Wraps a cross-process transport (LISTEN/NOTIFY, a change stream) so local\n * subscribers still hear local publishes even if the transport drops them,\n * and a transport failure degrades to in-process rather than to silence.\n */\nexport function createBridgedSignals(\n transport: {\n publish(channel: string): Promise<void> | void;\n subscribe(channel: string, handler: () => void): Promise<() => void> | (() => void);\n },\n onError: (error: unknown) => void,\n): Signals {\n const local = createMemorySignals();\n const remoteUnsubscribes = new Map<string, Promise<() => void>>();\n const counts = new Map<string, number>();\n\n return {\n crossProcess: true,\n publish(channel) {\n local.publish(channel);\n Promise.resolve()\n .then(() => transport.publish(channel))\n .catch(onError);\n },\n subscribe(channel, handler) {\n const unsubscribeLocal = local.subscribe(channel, handler);\n counts.set(channel, (counts.get(channel) ?? 0) + 1);\n\n if (!remoteUnsubscribes.has(channel)) {\n remoteUnsubscribes.set(\n channel,\n Promise.resolve()\n .then(() => transport.subscribe(channel, () => local.publish(channel)))\n .catch((error) => {\n onError(error);\n return () => {};\n }),\n );\n }\n\n return () => {\n unsubscribeLocal();\n const remaining = (counts.get(channel) ?? 1) - 1;\n if (remaining > 0) {\n counts.set(channel, remaining);\n return;\n }\n counts.delete(channel);\n const pending = remoteUnsubscribes.get(channel);\n remoteUnsubscribes.delete(channel);\n pending?.then((unsubscribe) => unsubscribe()).catch(onError);\n };\n },\n };\n}\n","import { createBridgedSignals, type Signals } from \"../../core/signals\";\n\ntype SignalDocument = { channel: string; origin: string; at: Date };\n\ntype ChangeStreamLike = {\n on(event: \"change\", handler: (change: { fullDocument?: SignalDocument }) => void): unknown;\n on(event: \"error\", handler: (error: unknown) => void): unknown;\n close(): Promise<unknown>;\n};\n\n/** Structural, so `mongodb` stays an optional peer dependency. */\nexport type MongoSignalsDb = {\n createCollection(name: string, options: { capped: boolean; size: number }): Promise<unknown>;\n collection(name: string): {\n insertOne(doc: SignalDocument): Promise<unknown>;\n watch(pipeline?: unknown[], options?: Record<string, unknown>): ChangeStreamLike;\n };\n};\n\nexport type MongoSignalsOptions = {\n /** Capped collection the signals pass through. Default `easy_ping_signals`. */\n collection?: string;\n /** Capped size in bytes. Old signals fall off the end; nobody reads history. Default 1 MiB. */\n size?: number;\n onError?: (error: unknown) => void;\n};\n\nconst originId = () => Math.random().toString(36).slice(2, 10);\n\n/**\n * Cross-replica wake-ups over a change stream on a capped collection.\n * Needs a replica set, which the adapter's transactions need anyway.\n * RFC 0006 §4C.\n */\nexport function mongoSignals(db: MongoSignalsDb, options: MongoSignalsOptions = {}): Signals {\n const name = options.collection ?? \"easy_ping_signals\";\n const onError = options.onError ?? (() => {});\n const origin = originId();\n const handlers = new Map<string, Set<() => void>>();\n let ready: Promise<void> | undefined;\n let stream: ChangeStreamLike | undefined;\n\n const ensureCollection = () => {\n ready ??= db.createCollection(name, { capped: true, size: options.size ?? 1024 * 1024 }).then(\n () => {},\n (error: unknown) => {\n // 48: NamespaceExists. Another replica got there first.\n if ((error as { code?: number })?.code === 48) return;\n ready = undefined;\n throw error;\n },\n );\n return ready;\n };\n\n const ensureWatching = async () => {\n if (stream) return;\n await ensureCollection();\n if (stream) return;\n const opened = db\n .collection(name)\n .watch([{ $match: { operationType: \"insert\" } }], { fullDocument: \"updateLookup\" });\n stream = opened;\n opened.on(\"change\", (change) => {\n const doc = change.fullDocument;\n if (!doc || doc.origin === origin) return;\n for (const handler of handlers.get(doc.channel) ?? []) handler();\n });\n opened.on(\"error\", (error) => {\n onError(error);\n if (stream === opened) stream = undefined;\n });\n };\n\n const bridged = createBridgedSignals(\n {\n publish: async (logical) => {\n await ensureCollection();\n await db.collection(name).insertOne({ channel: logical, origin, at: new Date() });\n },\n subscribe: async (logical, handler) => {\n let set = handlers.get(logical);\n if (!set) {\n set = new Set();\n handlers.set(logical, set);\n }\n set.add(handler);\n await ensureWatching();\n return () => {\n set?.delete(handler);\n if (set?.size === 0) handlers.delete(logical);\n };\n },\n },\n onError,\n );\n\n return {\n ...bridged,\n close: async () => {\n const open = stream;\n stream = undefined;\n handlers.clear();\n await open?.close();\n },\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/mongodb/adapter.ts","../../src/adapters/mongodb/indexes.ts","../../src/adapters/mongodb/signals.ts"],"names":["options","spec"],"mappings":"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","file":"mongodb.js","sourcesContent":["import type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\n\ntype Document = Record<string, unknown>;\n\n/** Structural, so `mongodb` stays an optional peer dependency. */\ntype MongoCollection = {\n insertMany(docs: Document[], options?: unknown): Promise<unknown>;\n insertOne(doc: Document, options?: unknown): Promise<unknown>;\n find(filter: Document, options?: Document): { toArray(): Promise<Document[]> };\n findOne(filter: Document, options?: Document): Promise<Document | null>;\n findOneAndUpdate(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<Document | null>;\n updateOne(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n upsertedCount?: number;\n }>;\n updateMany(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n }>;\n deleteMany(filter: Document, options?: Document): Promise<{ deletedCount: number }>;\n countDocuments(filter: Document, options?: Document): Promise<number>;\n createIndex(spec: Document, options?: Document): Promise<string>;\n};\n\ntype MongoDb = {\n collection(name: string): MongoCollection;\n};\n\ntype MongoSession = {\n withTransaction<T>(fn: () => Promise<T>): Promise<T>;\n endSession(): Promise<void>;\n};\n\ntype MongoClient = {\n startSession(): MongoSession;\n};\n\nexport type MongoAdapterOptions = {\n /** Prefixes every collection name, matching the SQL adapter's table prefix. */\n prefix?: string;\n /** Makes createNotifications atomic. Needs a replica set, so it is opt-in. */\n client?: unknown;\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\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\n/** Documents carry the id as `_id`; the rest of the library never sees that. */\nfunction toNotification(doc: Document): NotificationRecord {\n return {\n id: str(doc._id),\n userId: str(doc.userId),\n type: str(doc.type),\n payload: doc.payload,\n actorId: nullableStr(doc.actorId),\n groupKey: nullableStr(doc.groupKey),\n dedupeKey: nullableStr(doc.dedupeKey),\n seenAt: nullableDate(doc.seenAt),\n readAt: nullableDate(doc.readAt),\n archivedAt: nullableDate(doc.archivedAt),\n createdAt: date(doc.createdAt),\n };\n}\n\nfunction toDelivery(doc: Document): DeliveryRecord {\n return {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n status: str(doc.status) as DeliveryStatus,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notBefore: date(doc.notBefore),\n claimedAt: nullableDate(doc.claimedAt),\n claimedBy: nullableStr(doc.claimedBy),\n lastError: nullableStr(doc.lastError),\n updatedAt: date(doc.updatedAt),\n };\n}\n\n/** The store hands `id`; documents key on `_id`. */\nconst toMongoField = (field: string) => (field === \"id\" ? \"_id\" : field);\n\nfunction toFilter(where: WhereClause): Document {\n const filter: Document = {};\n\n for (const [field, condition] of Object.entries(where)) {\n const key = toMongoField(field);\n\n if (condition === null) {\n filter[key] = null;\n continue;\n }\n\n if (!isOperator(condition)) {\n // Last line before the driver, where `{ $ne: null }` becomes a query.\n if (typeof condition === \"object\" && !(condition instanceof Date)) {\n throw new Error(`mongo filter on \"${field}\" received an object; only scalars are bound`);\n }\n filter[key] = condition;\n continue;\n }\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) filter[key] = { $in: operator.in };\n else if (\"lt\" in operator) filter[key] = { $lt: operator.lt };\n else if (\"lte\" in operator) filter[key] = { $lte: operator.lte };\n else if (\"gt\" in operator) filter[key] = { $gt: operator.gt };\n else if (\"gte\" in operator) filter[key] = { $gte: operator.gte };\n else if (\"not\" in operator) {\n // $ne null also matches a missing field, which is what \"not null\" means.\n filter[key] = { $ne: operator.not };\n }\n }\n\n return filter;\n}\n\n/** A duplicate on a unique index, rather than a real write failure. */\nconst isDuplicateKey = (error: unknown): boolean => {\n const code = (error as { code?: number; writeErrors?: { code?: number }[] })?.code;\n if (code === 11000) return true;\n const writeErrors = (error as { writeErrors?: { code?: number }[] })?.writeErrors;\n return Array.isArray(writeErrors) && writeErrors.some((entry) => entry?.code === 11000);\n};\n\nexport function mongoAdapter(db: unknown, options: MongoAdapterOptions = {}): DatabaseAdapter {\n const database = db as MongoDb;\n const prefix = options.prefix ?? \"\";\n\n const client = options.client as MongoClient | undefined;\n\n const notifications = () => database.collection(`${prefix}notification`);\n const deliveries = () => database.collection(`${prefix}notification_delivery`);\n\n /** One transaction per notification: a duplicate key aborts the transaction it happens in, and dedupe is the expected path. */\n async function atomically<T>(fn: (session?: MongoSession) => Promise<T>): Promise<T> {\n if (!client) return fn();\n\n const session = client.startSession();\n try {\n return await session.withTransaction(() => fn(session));\n } finally {\n await session.endSession();\n }\n }\n\n return {\n name: \"mongodb\",\n // Documents keep the declared camelCase, and store objects natively.\n naming: \"preserve\",\n serializesJson: false,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n const created: string[] = [];\n const deduped: string[] = [];\n\n for (const row of input) {\n const now = new Date();\n\n try {\n await atomically(async (session) => {\n const options = session ? { session } : undefined;\n\n // Notification first: it carries the unique dedupe index.\n await notifications().insertOne(\n {\n _id: row.id,\n userId: row.userId,\n type: row.type,\n payload: row.payload ?? null,\n actorId: row.actorId ?? null,\n groupKey: row.groupKey ?? null,\n dedupeKey: row.dedupeKey ?? null,\n seenAt: null,\n readAt: null,\n archivedAt: null,\n createdAt: now,\n },\n options,\n );\n\n if (row.deliveries.length > 0) {\n await deliveries().insertMany(\n row.deliveries.map((delivery) => ({\n _id: delivery.id,\n notificationId: row.id,\n channel: delivery.channel,\n status: \"pending\",\n attempts: 0,\n maxAttempts: delivery.maxAttempts,\n notBefore: delivery.notBefore,\n claimedAt: null,\n claimedBy: null,\n lastError: null,\n updatedAt: now,\n })),\n options,\n );\n }\n });\n\n created.push(row.id);\n } catch (error) {\n if (!isDuplicateKey(error)) throw error;\n deduped.push(row.id);\n }\n }\n\n return { created, deduped };\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 eligible: Document = {\n $and: [\n {\n $or: [{ status: \"pending\" }, { status: \"claimed\", claimedAt: { $lt: staleBefore } }],\n },\n { notBefore: { $lte: now } },\n { $expr: { $lt: [\"$attempts\", \"$maxAttempts\"] } },\n ],\n };\n\n if (args.channels && args.channels.length > 0) {\n (eligible.$and as Document[]).push({ channel: { $in: [...args.channels] } });\n }\n if (args.ids && args.ids.length > 0) {\n (eligible.$and as Document[]).push({ _id: { $in: [...args.ids] } });\n }\n\n // findOneAndUpdate is atomic per document; updateMany cannot say which rows this call won.\n const claimed: Document[] = [];\n for (let taken = 0; taken < args.limit; taken += 1) {\n const doc = await deliveries().findOneAndUpdate(\n eligible,\n { $set: { status: \"claimed\", claimedAt: now, claimedBy: args.claimToken } },\n { sort: { notBefore: 1, _id: 1 }, returnDocument: \"after\" },\n );\n if (!doc) break;\n claimed.push(doc);\n }\n\n if (claimed.length === 0) return [];\n\n const parents = await notifications()\n .find({ _id: { $in: claimed.map((doc) => doc.notificationId) } })\n .toArray();\n const byId = new Map(parents.map((doc) => [str(doc._id), doc]));\n\n return claimed.flatMap((doc) => {\n const parent = byId.get(str(doc.notificationId));\n if (!parent) return [];\n\n return [\n {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notification: {\n userId: str(parent.userId),\n type: str(parent.type),\n payload: parent.payload,\n actorId: nullableStr(parent.actorId),\n },\n },\n ];\n });\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n for (const { id, outcome, nextAttemptAt } of releases) {\n const failed = outcome.result === \"failed\";\n const skipped = outcome.result === \"skipped\";\n const retryable = failed && outcome.retryable;\n\n // Pipeline update, so the retry decision reads maxAttempts from the document.\n await deliveries().updateOne({ _id: id }, [\n {\n $set: {\n attempts: failed ? { $add: [\"$attempts\", 1] } : \"$attempts\",\n status: failed\n ? {\n $cond: [\n { $and: [retryable, { $lt: [{ $add: [\"$attempts\", 1] }, \"$maxAttempts\"] }] },\n \"pending\",\n \"failed\",\n ],\n }\n : skipped\n ? \"skipped\"\n : \"sent\",\n // $literal: an error starting with \"$\" would be read as a field path.\n lastError: failed\n ? { $literal: outcome.error.slice(0, 2000) }\n : skipped\n ? { $literal: outcome.reason.slice(0, 2000) }\n : null,\n notBefore: nextAttemptAt ?? \"$notBefore\",\n // Unconditional: terminal state beats a wedged row. RFC 0003 §6.\n claimedAt: null,\n claimedBy: null,\n updatedAt: now,\n },\n },\n ]);\n }\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const filter: Document = { userId: query.userId, archivedAt: null };\n if (query.unreadOnly) filter.readAt = null;\n\n if (cursor) {\n // Matches the SQL row comparison (createdAt, id) < (cursor, cursorId).\n filter.$or = [\n { createdAt: { $lt: cursor.createdAt } },\n { createdAt: cursor.createdAt, _id: { $lt: cursor.id } },\n ];\n }\n\n const docs = await notifications()\n .find(filter, { sort: { createdAt: -1, _id: -1 }, limit: query.limit + 1 })\n .toArray();\n\n const page = docs.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n docs.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n return notifications().countDocuments({ userId, seenAt: null, archivedAt: null });\n },\n\n async markSeen(userId: string, before: Date) {\n await notifications().updateMany(\n { userId, seenAt: null, createdAt: { $lte: before } },\n { $set: { seenAt: new Date() } },\n );\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by userId; idempotent, so no 404 on a re-mark.\n const filter = { userId, _id: { $in: [...notificationIds] } };\n await notifications().updateMany(\n { ...filter, readAt: null },\n {\n $set: { readAt: new Date() },\n },\n );\n\n return notifications().countDocuments(filter);\n },\n\n async markAllRead(userId: string) {\n const result = await notifications().updateMany(\n { userId, readAt: null },\n { $set: { readAt: new Date() } },\n );\n return result.modifiedCount;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const docs = await deliveries()\n .find(\n { status: \"failed\", updatedAt: { $gte: args.since } },\n { sort: { updatedAt: -1 }, limit: args.limit },\n )\n .toArray();\n\n return docs.map(toDelivery);\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const find: Document = {};\n if (options.limit) find.limit = options.limit;\n if (options.orderBy) {\n const direction = options.orderBy.direction === \"desc\" ? -1 : 1;\n find.sort = { [toMongoField(options.orderBy.field)]: direction };\n }\n\n const docs = await database.collection(table).find(toFilter(where), find).toArray();\n\n // `_id` is a storage detail; plugins declared the field as `id`.\n return docs.map(({ _id, ...rest }) => (_id === undefined ? rest : { id: _id, ...rest }));\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 documents = rows.map(({ id, ...rest }) =>\n id === undefined ? { ...rest } : { _id: id, ...rest },\n );\n\n if (!onConflict || onConflict.length === 0) {\n await database.collection(table).insertMany(documents as Document[]);\n return documents.length;\n }\n\n let written = 0;\n for (const document of documents as Document[]) {\n const key: Document = {};\n for (const field of onConflict) key[toMongoField(field)] = document[toMongoField(field)];\n\n // _id only in $setOnInsert: Mongo rejects an update that would modify it.\n const { _id, ...updatable } = document;\n const update: Document = { $set: updatable };\n if (_id !== undefined) update.$setOnInsert = { _id };\n\n const result = await database.collection(table).updateOne(key, update, { upsert: true });\n written += result.matchedCount + (result.upsertedCount ?? 0);\n }\n return written;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments: Document = {};\n for (const [field, value] of Object.entries(set)) assignments[toMongoField(field)] = value;\n if (Object.keys(assignments).length === 0) return 0;\n\n const result = await database\n .collection(table)\n .updateMany(toFilter(where), { $set: assignments });\n return result.matchedCount;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const result = await database.collection(table).deleteMany(toFilter(where));\n return result.deletedCount;\n },\n };\n}\n","import type { FieldDeclaration, SchemaDeclaration } from \"../../core/plugin\";\nimport { coreSchema } from \"../../schema/declaration\";\n\ntype IndexSpec = Record<string, 1 | -1>;\n\ntype IndexOptions = {\n name: string;\n unique?: boolean;\n partialFilterExpression?: Record<string, unknown>;\n};\n\ntype IndexableDb = {\n collection(name: string): {\n createIndex(spec: IndexSpec, options: IndexOptions): Promise<string>;\n };\n};\n\nconst BSON_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"string\",\n number: \"number\",\n boolean: \"bool\",\n date: \"date\",\n json: \"object\",\n};\n\n/** Applies a SchemaDeclaration's indexes. A unique index over a nullable field gets a partial filter, since Mongo treats all NULLs as one value. */\nexport async function createPluginIndexes(\n db: unknown,\n schema: SchemaDeclaration,\n prefix = \"\",\n): Promise<void> {\n const database = db as IndexableDb;\n\n for (const table of Object.values(schema)) {\n const collection = database.collection(prefix + table.tableName);\n\n // A single \"id\" key is stored as _id, which is already unique.\n if (table.primaryKey && table.primaryKey.length > 0 && table.primaryKey[0] !== \"id\") {\n const spec: IndexSpec = {};\n for (const field of table.primaryKey) spec[field] = 1;\n await collection.createIndex(spec, {\n name: `${table.tableName}_pk`,\n unique: true,\n });\n }\n\n for (const declaration of table.indexes ?? []) {\n const spec: IndexSpec = {};\n for (const field of declaration.on) spec[field] = 1;\n\n const options: IndexOptions = {\n name: prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`),\n };\n\n if (declaration.unique) {\n options.unique = true;\n\n const partial: Record<string, unknown> = {};\n for (const field of declaration.on) {\n const spec = table.fields[field];\n if (spec && !spec.required) partial[field] = { $type: BSON_TYPE[spec.type] };\n }\n if (Object.keys(partial).length > 0) options.partialFilterExpression = partial;\n }\n\n await collection.createIndex(spec, options);\n }\n }\n}\n\n/** Creates the indexes the core tables need. Call once at startup. */\nexport const createMongoIndexes = (db: unknown, options: { prefix?: string } = {}) =>\n createPluginIndexes(db, coreSchema, options.prefix ?? \"\");\n","import { createBridgedSignals, type Signals } from \"../../core/signals\";\n\ntype SignalDocument = { channel: string; origin: string; at: Date };\n\ntype ChangeStreamLike = {\n on(event: \"change\", handler: (change: { fullDocument?: SignalDocument }) => void): unknown;\n on(event: \"error\", handler: (error: unknown) => void): unknown;\n close(): Promise<unknown>;\n};\n\n/** Structural, so `mongodb` stays an optional peer dependency. */\nexport type MongoSignalsDb = {\n createCollection(name: string, options: { capped: boolean; size: number }): Promise<unknown>;\n collection(name: string): {\n insertOne(doc: SignalDocument): Promise<unknown>;\n watch(pipeline?: unknown[], options?: Record<string, unknown>): ChangeStreamLike;\n };\n};\n\nexport type MongoSignalsOptions = {\n /** Capped collection the signals pass through. Default `easy_ping_signals`. */\n collection?: string;\n /** Capped size in bytes. Old signals fall off the end; nobody reads history. Default 1 MiB. */\n size?: number;\n onError?: (error: unknown) => void;\n};\n\nconst originId = () => Math.random().toString(36).slice(2, 10);\n\n/**\n * Cross-replica wake-ups over a change stream on a capped collection.\n * Needs a replica set, which the adapter's transactions need anyway.\n * RFC 0006 §4C.\n */\nexport function mongoSignals(db: MongoSignalsDb, options: MongoSignalsOptions = {}): Signals {\n const name = options.collection ?? \"easy_ping_signals\";\n const onError = options.onError ?? (() => {});\n const origin = originId();\n const handlers = new Map<string, Set<() => void>>();\n let ready: Promise<void> | undefined;\n let stream: ChangeStreamLike | undefined;\n\n const ensureCollection = () => {\n ready ??= db.createCollection(name, { capped: true, size: options.size ?? 1024 * 1024 }).then(\n () => {},\n (error: unknown) => {\n // 48: NamespaceExists. Another replica got there first.\n if ((error as { code?: number })?.code === 48) return;\n ready = undefined;\n throw error;\n },\n );\n return ready;\n };\n\n const ensureWatching = async () => {\n if (stream) return;\n await ensureCollection();\n if (stream) return;\n const opened = db\n .collection(name)\n .watch([{ $match: { operationType: \"insert\" } }], { fullDocument: \"updateLookup\" });\n stream = opened;\n opened.on(\"change\", (change) => {\n const doc = change.fullDocument;\n if (!doc || doc.origin === origin) return;\n for (const handler of handlers.get(doc.channel) ?? []) handler();\n });\n opened.on(\"error\", (error) => {\n onError(error);\n if (stream === opened) stream = undefined;\n });\n };\n\n const bridged = createBridgedSignals(\n {\n publish: async (logical) => {\n await ensureCollection();\n await db.collection(name).insertOne({ channel: logical, origin, at: new Date() });\n },\n subscribe: async (logical, handler) => {\n let set = handlers.get(logical);\n if (!set) {\n set = new Set();\n handlers.set(logical, set);\n }\n set.add(handler);\n await ensureWatching();\n return () => {\n set?.delete(handler);\n if (set?.size === 0) handlers.delete(logical);\n };\n },\n },\n onError,\n );\n\n return {\n ...bridged,\n close: async () => {\n const open = stream;\n stream = undefined;\n handlers.clear();\n await open?.close();\n },\n };\n}\n"]}
|