easy-ping 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +548 -508
  2. package/dist/adapters/mongodb.cjs +142 -0
  3. package/dist/adapters/mongodb.cjs.map +1 -1
  4. package/dist/adapters/mongodb.d.cts +39 -1
  5. package/dist/adapters/mongodb.d.ts +39 -1
  6. package/dist/adapters/mongodb.js +73 -1
  7. package/dist/adapters/mongodb.js.map +1 -1
  8. package/dist/adapters/postgres.cjs +146 -0
  9. package/dist/adapters/postgres.cjs.map +1 -1
  10. package/dist/adapters/postgres.d.cts +36 -1
  11. package/dist/adapters/postgres.d.ts +36 -1
  12. package/dist/adapters/postgres.js +78 -3
  13. package/dist/adapters/postgres.js.map +1 -1
  14. package/dist/adapters/sqlite.js +1 -1
  15. package/dist/{chunk-GJNLOQJS.js → chunk-JKTMUMQK.js} +31 -6
  16. package/dist/chunk-JKTMUMQK.js.map +1 -0
  17. package/dist/{chunk-BECMTNK7.js → chunk-JOVIZXO6.js} +142 -6
  18. package/dist/chunk-JOVIZXO6.js.map +1 -0
  19. package/dist/chunk-ORZKH224.js +75 -0
  20. package/dist/chunk-ORZKH224.js.map +1 -0
  21. package/dist/client.cjs +297 -17
  22. package/dist/client.cjs.map +1 -1
  23. package/dist/client.d.cts +59 -1
  24. package/dist/client.d.ts +59 -1
  25. package/dist/client.js +297 -17
  26. package/dist/client.js.map +1 -1
  27. package/dist/index.cjs +293 -10
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +46 -1
  30. package/dist/index.d.ts +46 -1
  31. package/dist/index.js +57 -7
  32. package/dist/index.js.map +1 -1
  33. package/dist/node.cjs +26 -5
  34. package/dist/node.cjs.map +1 -1
  35. package/dist/node.d.cts +1 -1
  36. package/dist/node.d.ts +1 -1
  37. package/dist/node.js +28 -6
  38. package/dist/node.js.map +1 -1
  39. package/dist/plugins/preferences.cjs +2 -2
  40. package/dist/plugins/preferences.cjs.map +1 -1
  41. package/dist/plugins/preferences.js +2 -1
  42. package/dist/plugins/preferences.js.map +1 -1
  43. package/dist/plugins/push.cjs +2 -2
  44. package/dist/plugins/push.cjs.map +1 -1
  45. package/dist/plugins/push.js +3 -2
  46. package/dist/plugins/push.js.map +1 -1
  47. package/dist/react.cjs +320 -19
  48. package/dist/react.cjs.map +1 -1
  49. package/dist/react.d.cts +58 -0
  50. package/dist/react.d.ts +58 -0
  51. package/dist/react.js +320 -19
  52. package/dist/react.js.map +1 -1
  53. package/dist/schema.js +1 -1
  54. package/dist/signals-kPmOlKDX.d.cts +27 -0
  55. package/dist/signals-kPmOlKDX.d.ts +27 -0
  56. package/dist/sw.cjs +39 -0
  57. package/dist/sw.cjs.map +1 -0
  58. package/dist/sw.d.cts +52 -0
  59. package/dist/sw.d.ts +52 -0
  60. package/dist/sw.js +36 -0
  61. package/dist/sw.js.map +1 -0
  62. package/package.json +9 -3
  63. package/dist/chunk-BECMTNK7.js.map +0 -1
  64. package/dist/chunk-GJNLOQJS.js.map +0 -1
@@ -453,8 +453,150 @@ async function createPluginIndexes(db, schema, prefix = "") {
453
453
  }
454
454
  var createMongoIndexes = (db, options = {}) => createPluginIndexes(db, coreSchema, options.prefix ?? "");
455
455
 
456
+ // src/core/signals.ts
457
+ function createMemorySignals() {
458
+ const handlers = /* @__PURE__ */ new Map();
459
+ return {
460
+ crossProcess: false,
461
+ publish(channel) {
462
+ const set = handlers.get(channel);
463
+ if (!set) return;
464
+ for (const handler of [...set]) {
465
+ queueMicrotask(() => {
466
+ try {
467
+ handler();
468
+ } catch {
469
+ }
470
+ });
471
+ }
472
+ },
473
+ subscribe(channel, handler) {
474
+ let set = handlers.get(channel);
475
+ if (!set) {
476
+ set = /* @__PURE__ */ new Set();
477
+ handlers.set(channel, set);
478
+ }
479
+ set.add(handler);
480
+ return () => {
481
+ set?.delete(handler);
482
+ if (set?.size === 0) handlers.delete(channel);
483
+ };
484
+ }
485
+ };
486
+ }
487
+ function createBridgedSignals(transport, onError) {
488
+ const local = createMemorySignals();
489
+ const remoteUnsubscribes = /* @__PURE__ */ new Map();
490
+ const counts = /* @__PURE__ */ new Map();
491
+ return {
492
+ crossProcess: true,
493
+ publish(channel) {
494
+ local.publish(channel);
495
+ Promise.resolve().then(() => transport.publish(channel)).catch(onError);
496
+ },
497
+ subscribe(channel, handler) {
498
+ const unsubscribeLocal = local.subscribe(channel, handler);
499
+ counts.set(channel, (counts.get(channel) ?? 0) + 1);
500
+ if (!remoteUnsubscribes.has(channel)) {
501
+ remoteUnsubscribes.set(
502
+ channel,
503
+ Promise.resolve().then(() => transport.subscribe(channel, () => local.publish(channel))).catch((error) => {
504
+ onError(error);
505
+ return () => {
506
+ };
507
+ })
508
+ );
509
+ }
510
+ return () => {
511
+ unsubscribeLocal();
512
+ const remaining = (counts.get(channel) ?? 1) - 1;
513
+ if (remaining > 0) {
514
+ counts.set(channel, remaining);
515
+ return;
516
+ }
517
+ counts.delete(channel);
518
+ const pending = remoteUnsubscribes.get(channel);
519
+ remoteUnsubscribes.delete(channel);
520
+ pending?.then((unsubscribe) => unsubscribe()).catch(onError);
521
+ };
522
+ }
523
+ };
524
+ }
525
+
526
+ // src/adapters/mongodb/signals.ts
527
+ var originId = () => Math.random().toString(36).slice(2, 10);
528
+ function mongoSignals(db, options = {}) {
529
+ const name = options.collection ?? "easy_ping_signals";
530
+ const onError = options.onError ?? (() => {
531
+ });
532
+ const origin = originId();
533
+ const handlers = /* @__PURE__ */ new Map();
534
+ let ready;
535
+ let stream;
536
+ const ensureCollection = () => {
537
+ ready ??= db.createCollection(name, { capped: true, size: options.size ?? 1024 * 1024 }).then(
538
+ () => {
539
+ },
540
+ (error) => {
541
+ if (error?.code === 48) return;
542
+ ready = void 0;
543
+ throw error;
544
+ }
545
+ );
546
+ return ready;
547
+ };
548
+ const ensureWatching = async () => {
549
+ if (stream) return;
550
+ await ensureCollection();
551
+ if (stream) return;
552
+ const opened = db.collection(name).watch([{ $match: { operationType: "insert" } }], { fullDocument: "updateLookup" });
553
+ stream = opened;
554
+ opened.on("change", (change) => {
555
+ const doc = change.fullDocument;
556
+ if (!doc || doc.origin === origin) return;
557
+ for (const handler of handlers.get(doc.channel) ?? []) handler();
558
+ });
559
+ opened.on("error", (error) => {
560
+ onError(error);
561
+ if (stream === opened) stream = void 0;
562
+ });
563
+ };
564
+ const bridged = createBridgedSignals(
565
+ {
566
+ publish: async (logical) => {
567
+ await ensureCollection();
568
+ await db.collection(name).insertOne({ channel: logical, origin, at: /* @__PURE__ */ new Date() });
569
+ },
570
+ subscribe: async (logical, handler) => {
571
+ let set = handlers.get(logical);
572
+ if (!set) {
573
+ set = /* @__PURE__ */ new Set();
574
+ handlers.set(logical, set);
575
+ }
576
+ set.add(handler);
577
+ await ensureWatching();
578
+ return () => {
579
+ set?.delete(handler);
580
+ if (set?.size === 0) handlers.delete(logical);
581
+ };
582
+ }
583
+ },
584
+ onError
585
+ );
586
+ return {
587
+ ...bridged,
588
+ close: async () => {
589
+ const open = stream;
590
+ stream = void 0;
591
+ handlers.clear();
592
+ await open?.close();
593
+ }
594
+ };
595
+ }
596
+
456
597
  exports.createMongoIndexes = createMongoIndexes;
457
598
  exports.createPluginIndexes = createPluginIndexes;
458
599
  exports.mongoAdapter = mongoAdapter;
600
+ exports.mongoSignals = mongoSignals;
459
601
  //# sourceMappingURL=mongodb.cjs.map
460
602
  //# sourceMappingURL=mongodb.cjs.map
@@ -1 +1 @@
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"],"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 checkFields(table: TableDeclaration, fields: Iterable<string>, context: string) {\n for (const field of fields) {\n // hasOwn, not a lookup: `constructor` and `__proto__` are not columns.\n const spec = Object.hasOwn(table.fields, field) ? table.fields[field] : undefined;\n if (!spec) {\n throw new ConfigError(\n `plugin \"${pluginId}\" used unknown field \"${field}\" on \"${table.tableName}\" (${context}).`,\n );\n }\n if (context === \"where\" && spec.type === \"json\") {\n throw new ConfigError(\n `plugin \"${pluginId}\" cannot filter on json field \"${field}\"; ` +\n \"a bare object value is indistinguishable from an operator.\",\n );\n }\n }\n }\n\n function checkWhere(table: TableDeclaration, where: WhereClause) {\n checkFields(table, Object.keys(where), \"where\");\n for (const [field, condition] of Object.entries(where)) {\n assertCondition(pluginId, field, condition);\n }\n }\n\n function checkRow(table: TableDeclaration, row: Record<string, unknown>, context: string) {\n checkFields(table, Object.keys(row), context);\n for (const [field, value] of Object.entries(row)) {\n const spec = table.fields[field];\n if (spec) assertValue(pluginId, field, spec, value);\n }\n }\n\n const qualified = (table: TableDeclaration) => prefix + table.tableName;\n\n // A document store keeps the declared names; a SQL adapter wants columns.\n const column = (field: string) => (storage.naming === \"preserve\" ? field : toSnakeCase(field));\n\n // json must reach postgres-js as text.\n const serialize = (table: TableDeclaration, row: Record<string, unknown>) => {\n if (storage.serializesJson === false) return row;\n\n const out: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(row)) {\n out[field] =\n table.fields[field]?.type === \"json\" && value !== null && value !== undefined\n ? JSON.stringify(value)\n : value;\n }\n return out;\n };\n\n return {\n async find(table, where = {}, options = {}) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n if (options.orderBy) checkFields(declaration, [options.orderBy.field], \"orderBy\");\n\n const rows = await storage.queryTable(qualified(declaration), where, options);\n\n // SELECT * returns snake_case; plugins read camelCase.\n return rows.map((row) => {\n const mapped: Record<string, unknown> = {};\n for (const field of Object.keys(declaration.fields)) {\n const value = row[column(field)];\n const type = declaration.fields[field]?.type;\n // Drivers differ on jsonb (parsed or text) and timestamptz (Date or text).\n if (type === \"json\" && typeof value === \"string\") mapped[field] = JSON.parse(value);\n else if (type === \"date\" && typeof value === \"string\") mapped[field] = new Date(value);\n // MySQL and SQLite have no boolean column; they hand back 0 and 1.\n else if (type === \"boolean\" && typeof value === \"number\") mapped[field] = value !== 0;\n else mapped[field] = value;\n }\n return mapped;\n }) as never;\n },\n\n async insert(table, rows) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"insert\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n );\n },\n\n async upsert(table, rows, options) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"upsert\");\n checkFields(declaration, options.onConflict, \"onConflict\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n options.onConflict,\n );\n },\n\n async update(table, where, set) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n checkRow(declaration, set, \"update\");\n return storage.updateRows(qualified(declaration), where, serialize(declaration, set));\n },\n\n async remove(table, where) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n return storage.deleteRows(qualified(declaration), where);\n },\n };\n}\n","import type {\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"]}
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 checkFields(table: TableDeclaration, fields: Iterable<string>, context: string) {\n for (const field of fields) {\n // hasOwn, not a lookup: `constructor` and `__proto__` are not columns.\n const spec = Object.hasOwn(table.fields, field) ? table.fields[field] : undefined;\n if (!spec) {\n throw new ConfigError(\n `plugin \"${pluginId}\" used unknown field \"${field}\" on \"${table.tableName}\" (${context}).`,\n );\n }\n if (context === \"where\" && spec.type === \"json\") {\n throw new ConfigError(\n `plugin \"${pluginId}\" cannot filter on json field \"${field}\"; ` +\n \"a bare object value is indistinguishable from an operator.\",\n );\n }\n }\n }\n\n function checkWhere(table: TableDeclaration, where: WhereClause) {\n checkFields(table, Object.keys(where), \"where\");\n for (const [field, condition] of Object.entries(where)) {\n assertCondition(pluginId, field, condition);\n }\n }\n\n function checkRow(table: TableDeclaration, row: Record<string, unknown>, context: string) {\n checkFields(table, Object.keys(row), context);\n for (const [field, value] of Object.entries(row)) {\n const spec = table.fields[field];\n if (spec) assertValue(pluginId, field, spec, value);\n }\n }\n\n const qualified = (table: TableDeclaration) => prefix + table.tableName;\n\n // A document store keeps the declared names; a SQL adapter wants columns.\n const column = (field: string) => (storage.naming === \"preserve\" ? field : toSnakeCase(field));\n\n // json must reach postgres-js as text.\n const serialize = (table: TableDeclaration, row: Record<string, unknown>) => {\n if (storage.serializesJson === false) return row;\n\n const out: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(row)) {\n out[field] =\n table.fields[field]?.type === \"json\" && value !== null && value !== undefined\n ? JSON.stringify(value)\n : value;\n }\n return out;\n };\n\n return {\n async find(table, where = {}, options = {}) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n if (options.orderBy) checkFields(declaration, [options.orderBy.field], \"orderBy\");\n\n const rows = await storage.queryTable(qualified(declaration), where, options);\n\n // SELECT * returns snake_case; plugins read camelCase.\n return rows.map((row) => {\n const mapped: Record<string, unknown> = {};\n for (const field of Object.keys(declaration.fields)) {\n const value = row[column(field)];\n const type = declaration.fields[field]?.type;\n // Drivers differ on jsonb (parsed or text) and timestamptz (Date or text).\n if (type === \"json\" && typeof value === \"string\") mapped[field] = JSON.parse(value);\n else if (type === \"date\" && typeof value === \"string\") mapped[field] = new Date(value);\n // MySQL and SQLite have no boolean column; they hand back 0 and 1.\n else if (type === \"boolean\" && typeof value === \"number\") mapped[field] = value !== 0;\n else mapped[field] = value;\n }\n return mapped;\n }) as never;\n },\n\n async insert(table, rows) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"insert\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n );\n },\n\n async upsert(table, rows, options) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"upsert\");\n checkFields(declaration, options.onConflict, \"onConflict\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n options.onConflict,\n );\n },\n\n async update(table, where, set) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n checkRow(declaration, set, \"update\");\n return storage.updateRows(qualified(declaration), where, serialize(declaration, set));\n },\n\n async remove(table, where) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n return storage.deleteRows(qualified(declaration), where);\n },\n };\n}\n","import type {\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,5 +1,6 @@
1
1
  import { D as DatabaseAdapter } from '../adapter-D3lTy-4E.cjs';
2
2
  import { S as SchemaDeclaration } from '../plugin-CHd2ZiGC.cjs';
3
+ import { S as Signals } from '../signals-kPmOlKDX.cjs';
3
4
 
4
5
  type MongoAdapterOptions = {
5
6
  /** Prefixes every collection name, matching the SQL adapter's table prefix. */
@@ -16,4 +17,41 @@ declare const createMongoIndexes: (db: unknown, options?: {
16
17
  prefix?: string;
17
18
  }) => Promise<void>;
18
19
 
19
- export { type MongoAdapterOptions, createMongoIndexes, createPluginIndexes, mongoAdapter };
20
+ type SignalDocument = {
21
+ channel: string;
22
+ origin: string;
23
+ at: Date;
24
+ };
25
+ type ChangeStreamLike = {
26
+ on(event: "change", handler: (change: {
27
+ fullDocument?: SignalDocument;
28
+ }) => void): unknown;
29
+ on(event: "error", handler: (error: unknown) => void): unknown;
30
+ close(): Promise<unknown>;
31
+ };
32
+ /** Structural, so `mongodb` stays an optional peer dependency. */
33
+ type MongoSignalsDb = {
34
+ createCollection(name: string, options: {
35
+ capped: boolean;
36
+ size: number;
37
+ }): Promise<unknown>;
38
+ collection(name: string): {
39
+ insertOne(doc: SignalDocument): Promise<unknown>;
40
+ watch(pipeline?: unknown[], options?: Record<string, unknown>): ChangeStreamLike;
41
+ };
42
+ };
43
+ type MongoSignalsOptions = {
44
+ /** Capped collection the signals pass through. Default `easy_ping_signals`. */
45
+ collection?: string;
46
+ /** Capped size in bytes. Old signals fall off the end; nobody reads history. Default 1 MiB. */
47
+ size?: number;
48
+ onError?: (error: unknown) => void;
49
+ };
50
+ /**
51
+ * Cross-replica wake-ups over a change stream on a capped collection.
52
+ * Needs a replica set, which the adapter's transactions need anyway.
53
+ * RFC 0006 §4C.
54
+ */
55
+ declare function mongoSignals(db: MongoSignalsDb, options?: MongoSignalsOptions): Signals;
56
+
57
+ export { type MongoAdapterOptions, type MongoSignalsDb, type MongoSignalsOptions, createMongoIndexes, createPluginIndexes, mongoAdapter, mongoSignals };
@@ -1,5 +1,6 @@
1
1
  import { D as DatabaseAdapter } from '../adapter-D3lTy-4E.js';
2
2
  import { S as SchemaDeclaration } from '../plugin-Cg9usuUi.js';
3
+ import { S as Signals } from '../signals-kPmOlKDX.js';
3
4
 
4
5
  type MongoAdapterOptions = {
5
6
  /** Prefixes every collection name, matching the SQL adapter's table prefix. */
@@ -16,4 +17,41 @@ declare const createMongoIndexes: (db: unknown, options?: {
16
17
  prefix?: string;
17
18
  }) => Promise<void>;
18
19
 
19
- export { type MongoAdapterOptions, createMongoIndexes, createPluginIndexes, mongoAdapter };
20
+ type SignalDocument = {
21
+ channel: string;
22
+ origin: string;
23
+ at: Date;
24
+ };
25
+ type ChangeStreamLike = {
26
+ on(event: "change", handler: (change: {
27
+ fullDocument?: SignalDocument;
28
+ }) => void): unknown;
29
+ on(event: "error", handler: (error: unknown) => void): unknown;
30
+ close(): Promise<unknown>;
31
+ };
32
+ /** Structural, so `mongodb` stays an optional peer dependency. */
33
+ type MongoSignalsDb = {
34
+ createCollection(name: string, options: {
35
+ capped: boolean;
36
+ size: number;
37
+ }): Promise<unknown>;
38
+ collection(name: string): {
39
+ insertOne(doc: SignalDocument): Promise<unknown>;
40
+ watch(pipeline?: unknown[], options?: Record<string, unknown>): ChangeStreamLike;
41
+ };
42
+ };
43
+ type MongoSignalsOptions = {
44
+ /** Capped collection the signals pass through. Default `easy_ping_signals`. */
45
+ collection?: string;
46
+ /** Capped size in bytes. Old signals fall off the end; nobody reads history. Default 1 MiB. */
47
+ size?: number;
48
+ onError?: (error: unknown) => void;
49
+ };
50
+ /**
51
+ * Cross-replica wake-ups over a change stream on a capped collection.
52
+ * Needs a replica set, which the adapter's transactions need anyway.
53
+ * RFC 0006 §4C.
54
+ */
55
+ declare function mongoSignals(db: MongoSignalsDb, options?: MongoSignalsOptions): Signals;
56
+
57
+ export { type MongoAdapterOptions, type MongoSignalsDb, type MongoSignalsOptions, createMongoIndexes, createPluginIndexes, mongoAdapter, mongoSignals };
@@ -1,3 +1,4 @@
1
+ import { createBridgedSignals } from '../chunk-ORZKH224.js';
1
2
  import { isOperator } from '../chunk-3VOQOGDR.js';
2
3
  import { coreSchema } from '../chunk-AEYYTE5I.js';
3
4
  import { decodeBase64Url, encodeBase64Url } from '../chunk-PTGHMCCG.js';
@@ -372,6 +373,77 @@ async function createPluginIndexes(db, schema, prefix = "") {
372
373
  }
373
374
  var createMongoIndexes = (db, options = {}) => createPluginIndexes(db, coreSchema, options.prefix ?? "");
374
375
 
375
- export { createMongoIndexes, createPluginIndexes, mongoAdapter };
376
+ // src/adapters/mongodb/signals.ts
377
+ var originId = () => Math.random().toString(36).slice(2, 10);
378
+ function mongoSignals(db, options = {}) {
379
+ const name = options.collection ?? "easy_ping_signals";
380
+ const onError = options.onError ?? (() => {
381
+ });
382
+ const origin = originId();
383
+ const handlers = /* @__PURE__ */ new Map();
384
+ let ready;
385
+ let stream;
386
+ const ensureCollection = () => {
387
+ ready ??= db.createCollection(name, { capped: true, size: options.size ?? 1024 * 1024 }).then(
388
+ () => {
389
+ },
390
+ (error) => {
391
+ if (error?.code === 48) return;
392
+ ready = void 0;
393
+ throw error;
394
+ }
395
+ );
396
+ return ready;
397
+ };
398
+ const ensureWatching = async () => {
399
+ if (stream) return;
400
+ await ensureCollection();
401
+ if (stream) return;
402
+ const opened = db.collection(name).watch([{ $match: { operationType: "insert" } }], { fullDocument: "updateLookup" });
403
+ stream = opened;
404
+ opened.on("change", (change) => {
405
+ const doc = change.fullDocument;
406
+ if (!doc || doc.origin === origin) return;
407
+ for (const handler of handlers.get(doc.channel) ?? []) handler();
408
+ });
409
+ opened.on("error", (error) => {
410
+ onError(error);
411
+ if (stream === opened) stream = void 0;
412
+ });
413
+ };
414
+ const bridged = createBridgedSignals(
415
+ {
416
+ publish: async (logical) => {
417
+ await ensureCollection();
418
+ await db.collection(name).insertOne({ channel: logical, origin, at: /* @__PURE__ */ new Date() });
419
+ },
420
+ subscribe: async (logical, handler) => {
421
+ let set = handlers.get(logical);
422
+ if (!set) {
423
+ set = /* @__PURE__ */ new Set();
424
+ handlers.set(logical, set);
425
+ }
426
+ set.add(handler);
427
+ await ensureWatching();
428
+ return () => {
429
+ set?.delete(handler);
430
+ if (set?.size === 0) handlers.delete(logical);
431
+ };
432
+ }
433
+ },
434
+ onError
435
+ );
436
+ return {
437
+ ...bridged,
438
+ close: async () => {
439
+ const open = stream;
440
+ stream = void 0;
441
+ handlers.clear();
442
+ await open?.close();
443
+ }
444
+ };
445
+ }
446
+
447
+ export { createMongoIndexes, createPluginIndexes, mongoAdapter, mongoSignals };
376
448
  //# sourceMappingURL=mongodb.js.map
377
449
  //# sourceMappingURL=mongodb.js.map