easy-ping 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +44 -2
  2. package/dist/{adapter-f0OR2DhY.d.cts → adapter-BfLe2J0t.d.cts} +10 -0
  3. package/dist/{adapter-f0OR2DhY.d.ts → adapter-BfLe2J0t.d.ts} +10 -0
  4. package/dist/adapters/drizzle.cjs +6 -2
  5. package/dist/adapters/drizzle.cjs.map +1 -1
  6. package/dist/adapters/drizzle.d.cts +1 -1
  7. package/dist/adapters/drizzle.d.ts +1 -1
  8. package/dist/adapters/drizzle.js +6 -2
  9. package/dist/adapters/drizzle.js.map +1 -1
  10. package/dist/adapters/mongodb.cjs +3 -2
  11. package/dist/adapters/mongodb.cjs.map +1 -1
  12. package/dist/adapters/mongodb.d.cts +2 -2
  13. package/dist/adapters/mongodb.d.ts +2 -2
  14. package/dist/adapters/mongodb.js +3 -2
  15. package/dist/adapters/mongodb.js.map +1 -1
  16. package/dist/adapters/postgres.cjs +484 -0
  17. package/dist/adapters/postgres.cjs.map +1 -0
  18. package/dist/adapters/postgres.d.cts +81 -0
  19. package/dist/adapters/postgres.d.ts +81 -0
  20. package/dist/adapters/postgres.js +360 -0
  21. package/dist/adapters/postgres.js.map +1 -0
  22. package/dist/chunk-RBDW4S6F.js +199 -0
  23. package/dist/chunk-RBDW4S6F.js.map +1 -0
  24. package/dist/client.cjs +3 -5
  25. package/dist/client.cjs.map +1 -1
  26. package/dist/client.js +3 -5
  27. package/dist/client.js.map +1 -1
  28. package/dist/index.cjs +17 -11
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +6 -4
  31. package/dist/index.d.ts +6 -4
  32. package/dist/index.js +17 -11
  33. package/dist/index.js.map +1 -1
  34. package/dist/{plugin-bTJKmnlq.d.ts → plugin-CmPOFVmn.d.ts} +1 -1
  35. package/dist/{plugin-Bqj9xAOS.d.cts → plugin-f5KaFWSN.d.cts} +1 -1
  36. package/dist/plugins/digests.d.cts +2 -2
  37. package/dist/plugins/digests.d.ts +2 -2
  38. package/dist/plugins/preferences-client.d.cts +2 -2
  39. package/dist/plugins/preferences-client.d.ts +2 -2
  40. package/dist/plugins/preferences.d.cts +2 -2
  41. package/dist/plugins/preferences.d.ts +2 -2
  42. package/dist/plugins/push.cjs +25 -23
  43. package/dist/plugins/push.cjs.map +1 -1
  44. package/dist/plugins/push.d.cts +59 -3
  45. package/dist/plugins/push.d.ts +59 -3
  46. package/dist/plugins/push.js +25 -24
  47. package/dist/plugins/push.js.map +1 -1
  48. package/dist/providers/web-push.d.cts +2 -2
  49. package/dist/providers/web-push.d.ts +2 -2
  50. package/dist/react.cjs +3 -5
  51. package/dist/react.cjs.map +1 -1
  52. package/dist/react.js +3 -5
  53. package/dist/react.js.map +1 -1
  54. package/dist/schema.d.cts +2 -2
  55. package/dist/schema.d.ts +2 -2
  56. package/dist/schema.js +1 -197
  57. package/dist/schema.js.map +1 -1
  58. package/dist/testing.cjs +29 -0
  59. package/dist/testing.cjs.map +1 -1
  60. package/dist/testing.d.cts +1 -1
  61. package/dist/testing.d.ts +1 -1
  62. package/dist/testing.js +29 -0
  63. package/dist/testing.js.map +1 -1
  64. package/package.json +15 -11
@@ -286,6 +286,7 @@ function mongoAdapter(db, options = {}) {
286
286
  const now = /* @__PURE__ */ new Date();
287
287
  for (const { id, outcome, nextAttemptAt } of releases) {
288
288
  const failed = outcome.result === "failed";
289
+ const skipped = outcome.result === "skipped";
289
290
  const retryable = failed && outcome.retryable;
290
291
  await deliveries().updateOne({ _id: id }, [
291
292
  {
@@ -297,10 +298,10 @@ function mongoAdapter(db, options = {}) {
297
298
  "pending",
298
299
  "failed"
299
300
  ]
300
- } : "sent",
301
+ } : skipped ? "skipped" : "sent",
301
302
  // $literal: an error message starting with "$" would otherwise
302
303
  // be read as a field path.
303
- lastError: failed ? { $literal: outcome.error.slice(0, 2e3) } : null,
304
+ lastError: failed ? { $literal: outcome.error.slice(0, 2e3) } : skipped ? { $literal: outcome.reason.slice(0, 2e3) } : null,
304
305
  notBefore: nextAttemptAt ?? "$notBefore",
305
306
  // Written unconditionally: if the lease expired and another
306
307
  // worker re-sent, the duplicate already happened and the true
@@ -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/**\n * Core tables in the format plugins use. Less expressive than the hand-written\n * Drizzle schema (no partial indexes, ordering or cascade) — a drift test\n * asserts the two agree on the fields they share.\n */\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 },\n primaryKey: [\"userId\", \"type\", \"channel\"],\n },\n} satisfies SchemaDeclaration;\n","import { toSnakeCase } from \"../schema/declaration\";\nimport { ConfigError } from \"./errors\";\nimport type { SchemaDeclaration, TableDeclaration } from \"./plugin\";\n\nexport type Scalar = string | number | boolean | Date | null;\n\n/**\n * One operator per condition. Operators are tagged objects so a bare value is\n * always an equality test; json columns therefore cannot be filtered, since an\n * object value would be ambiguous.\n */\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/**\n * Table access for plugins, scoped to the tables that plugin declared.\n *\n * Plugins could always declare tables via schema() but had no way to read\n * them, so preferences had to bolt its queries onto the core adapter. That\n * does not generalise to digests or push.\n */\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) => op in value);\n\n/**\n * Every table and column a plugin touches is checked against its own\n * declaration. Without this a plugin could read the notification table, and\n * unvalidated identifiers would reach the SQL builder.\n */\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 const spec = table.fields[field];\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 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 /**\n * json columns must be handed to the driver as text; postgres-js cannot bind\n * a plain object and the insert fails outright.\n */\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 checkFields(declaration, Object.keys(where), \"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 columns; plugins declare camelCase fields\n // and type their reads that way. Without this every property is\n // undefined at runtime while typechecking perfectly.\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 // Drivers differ: some hand back parsed jsonb, some raw text.\n mapped[field] =\n declaration.fields[field]?.type === \"json\" && typeof value === \"string\"\n ? JSON.parse(value)\n : 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) checkFields(declaration, Object.keys(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) checkFields(declaration, Object.keys(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 checkFields(declaration, Object.keys(where), \"where\");\n checkFields(declaration, Object.keys(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 checkFields(declaration, Object.keys(where), \"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/**\n * Minimal structural view of the pieces of the Mongo driver this uses.\n *\n * Typed structurally rather than against the real `Db` so `mongodb` stays an\n * optional peer dependency: an app on Postgres never installs it, and its\n * types are not needed to typecheck this file.\n */\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 /**\n * The MongoClient the db came from. Supplying it makes createNotifications\n * atomic; without it a crash between the two writes can leave a notification\n * with no deliveries. Transactions need a replica set, so it is opt-in — a\n * standalone mongod rejects the session outright.\n */\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\n/** Translates a WhereClause into a Mongo filter. */\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 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 /**\n * Runs `fn` in a transaction when a client was supplied, and plainly\n * otherwise. The session must reach every command inside, so `fn` receives\n * it — a write that omits it silently runs outside the transaction.\n *\n * One transaction per notification, not per batch: a duplicate key aborts\n * the transaction it happens in, and dedupe is the expected path here, so a\n * batch-wide transaction would throw away the notifications around it.\n */\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 // The notification goes in first: it carries the unique dedupe\n // index, so a duplicate is rejected before any delivery is written.\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, so two concurrent callers\n // cannot be handed the same delivery. updateMany would be one round trip\n // but gives no way to learn which documents this call actually 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 // One lookup for the batch rather than one per delivery.\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 retryable = failed && outcome.retryable;\n\n // An aggregation-pipeline update so the terminal-vs-retry decision\n // reads maxAttempts from the document itself, as the SQL CASE does.\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 : \"sent\",\n // $literal: an error message starting with \"$\" would otherwise\n // be read as a field path.\n lastError: failed ? { $literal: outcome.error.slice(0, 2000) } : null,\n notBefore: nextAttemptAt ?? \"$notBefore\",\n // Written unconditionally: if the lease expired and another\n // worker re-sent, the duplicate already happened and the true\n // terminal state beats leaving the row wedged in \"claimed\".\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 as well as id, and idempotent: re-marking a read\n // notification reports success rather than a 404.\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 // Upsert keyed on the conflict fields, matching ON CONFLICT DO UPDATE.\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 goes in $setOnInsert, never $set: Mongo rejects an update that\n // would modify it, so a conflicting upsert must leave it alone.\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/**\n * Applies a SchemaDeclaration's indexes to Mongo. The document counterpart of\n * renderPostgresDdl — there are no tables to create, only indexes, and the\n * declaration is the same source of truth.\n *\n * A unique index over a nullable field gets a partial filter. Postgres treats\n * every NULL as distinct, so unlimited rows may leave dedupeKey unset; a plain\n * Mongo unique index treats them as one value and would allow exactly one.\n */\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"],"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/**\n * Core tables in the format plugins use. Less expressive than the hand-written\n * Drizzle schema (no partial indexes, ordering or cascade) — a drift test\n * asserts the two agree on the fields they share.\n */\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 },\n primaryKey: [\"userId\", \"type\", \"channel\"],\n },\n} satisfies SchemaDeclaration;\n","import { toSnakeCase } from \"../schema/declaration\";\nimport { ConfigError } from \"./errors\";\nimport type { SchemaDeclaration, TableDeclaration } from \"./plugin\";\n\nexport type Scalar = string | number | boolean | Date | null;\n\n/**\n * One operator per condition. Operators are tagged objects so a bare value is\n * always an equality test; json columns therefore cannot be filtered, since an\n * object value would be ambiguous.\n */\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/**\n * Table access for plugins, scoped to the tables that plugin declared.\n *\n * Plugins could always declare tables via schema() but had no way to read\n * them, so preferences had to bolt its queries onto the core adapter. That\n * does not generalise to digests or push.\n */\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) => op in value);\n\n/**\n * Every table and column a plugin touches is checked against its own\n * declaration. Without this a plugin could read the notification table, and\n * unvalidated identifiers would reach the SQL builder.\n */\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 const spec = table.fields[field];\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 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 /**\n * json columns must be handed to the driver as text; postgres-js cannot bind\n * a plain object and the insert fails outright.\n */\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 checkFields(declaration, Object.keys(where), \"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 columns; plugins declare camelCase fields\n // and type their reads that way. Without this every property is\n // undefined at runtime while typechecking perfectly.\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 // Drivers differ: some hand back parsed jsonb, some raw text.\n mapped[field] =\n declaration.fields[field]?.type === \"json\" && typeof value === \"string\"\n ? JSON.parse(value)\n : 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) checkFields(declaration, Object.keys(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) checkFields(declaration, Object.keys(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 checkFields(declaration, Object.keys(where), \"where\");\n checkFields(declaration, Object.keys(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 checkFields(declaration, Object.keys(where), \"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/**\n * Minimal structural view of the pieces of the Mongo driver this uses.\n *\n * Typed structurally rather than against the real `Db` so `mongodb` stays an\n * optional peer dependency: an app on Postgres never installs it, and its\n * types are not needed to typecheck this file.\n */\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 /**\n * The MongoClient the db came from. Supplying it makes createNotifications\n * atomic; without it a crash between the two writes can leave a notification\n * with no deliveries. Transactions need a replica set, so it is opt-in — a\n * standalone mongod rejects the session outright.\n */\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\n/** Translates a WhereClause into a Mongo filter. */\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 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 /**\n * Runs `fn` in a transaction when a client was supplied, and plainly\n * otherwise. The session must reach every command inside, so `fn` receives\n * it — a write that omits it silently runs outside the transaction.\n *\n * One transaction per notification, not per batch: a duplicate key aborts\n * the transaction it happens in, and dedupe is the expected path here, so a\n * batch-wide transaction would throw away the notifications around it.\n */\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 // The notification goes in first: it carries the unique dedupe\n // index, so a duplicate is rejected before any delivery is written.\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, so two concurrent callers\n // cannot be handed the same delivery. updateMany would be one round trip\n // but gives no way to learn which documents this call actually 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 // One lookup for the batch rather than one per delivery.\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 // An aggregation-pipeline update so the terminal-vs-retry decision\n // reads maxAttempts from the document itself, as the SQL CASE does.\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 message starting with \"$\" would otherwise\n // 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 // Written unconditionally: if the lease expired and another\n // worker re-sent, the duplicate already happened and the true\n // terminal state beats leaving the row wedged in \"claimed\".\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 as well as id, and idempotent: re-marking a read\n // notification reports success rather than a 404.\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 // Upsert keyed on the conflict fields, matching ON CONFLICT DO UPDATE.\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 goes in $setOnInsert, never $set: Mongo rejects an update that\n // would modify it, so a conflicting upsert must leave it alone.\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/**\n * Applies a SchemaDeclaration's indexes to Mongo. The document counterpart of\n * renderPostgresDdl — there are no tables to create, only indexes, and the\n * declaration is the same source of truth.\n *\n * A unique index over a nullable field gets a partial filter. Postgres treats\n * every NULL as distinct, so unlimited rows may leave dedupeKey unset; a plain\n * Mongo unique index treats them as one value and would allow exactly one.\n */\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,5 +1,5 @@
1
- import { D as DatabaseAdapter } from '../adapter-f0OR2DhY.cjs';
2
- import { S as SchemaDeclaration } from '../plugin-Bqj9xAOS.cjs';
1
+ import { D as DatabaseAdapter } from '../adapter-BfLe2J0t.cjs';
2
+ import { S as SchemaDeclaration } from '../plugin-f5KaFWSN.cjs';
3
3
 
4
4
  type MongoAdapterOptions = {
5
5
  /** Prefixes every collection name, matching the SQL adapter's table prefix. */
@@ -1,5 +1,5 @@
1
- import { D as DatabaseAdapter } from '../adapter-f0OR2DhY.js';
2
- import { S as SchemaDeclaration } from '../plugin-bTJKmnlq.js';
1
+ import { D as DatabaseAdapter } from '../adapter-BfLe2J0t.js';
2
+ import { S as SchemaDeclaration } from '../plugin-CmPOFVmn.js';
3
3
 
4
4
  type MongoAdapterOptions = {
5
5
  /** Prefixes every collection name, matching the SQL adapter's table prefix. */
@@ -206,6 +206,7 @@ function mongoAdapter(db, options = {}) {
206
206
  const now = /* @__PURE__ */ new Date();
207
207
  for (const { id, outcome, nextAttemptAt } of releases) {
208
208
  const failed = outcome.result === "failed";
209
+ const skipped = outcome.result === "skipped";
209
210
  const retryable = failed && outcome.retryable;
210
211
  await deliveries().updateOne({ _id: id }, [
211
212
  {
@@ -217,10 +218,10 @@ function mongoAdapter(db, options = {}) {
217
218
  "pending",
218
219
  "failed"
219
220
  ]
220
- } : "sent",
221
+ } : skipped ? "skipped" : "sent",
221
222
  // $literal: an error message starting with "$" would otherwise
222
223
  // be read as a field path.
223
- lastError: failed ? { $literal: outcome.error.slice(0, 2e3) } : null,
224
+ lastError: failed ? { $literal: outcome.error.slice(0, 2e3) } : skipped ? { $literal: outcome.reason.slice(0, 2e3) } : null,
224
225
  notBefore: nextAttemptAt ?? "$notBefore",
225
226
  // Written unconditionally: if the lease expired and another
226
227
  // worker re-sent, the duplicate already happened and the true
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/mongodb/adapter.ts","../../src/adapters/mongodb/indexes.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/**\n * Minimal structural view of the pieces of the Mongo driver this uses.\n *\n * Typed structurally rather than against the real `Db` so `mongodb` stays an\n * optional peer dependency: an app on Postgres never installs it, and its\n * types are not needed to typecheck this file.\n */\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 /**\n * The MongoClient the db came from. Supplying it makes createNotifications\n * atomic; without it a crash between the two writes can leave a notification\n * with no deliveries. Transactions need a replica set, so it is opt-in — a\n * standalone mongod rejects the session outright.\n */\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\n/** Translates a WhereClause into a Mongo filter. */\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 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 /**\n * Runs `fn` in a transaction when a client was supplied, and plainly\n * otherwise. The session must reach every command inside, so `fn` receives\n * it — a write that omits it silently runs outside the transaction.\n *\n * One transaction per notification, not per batch: a duplicate key aborts\n * the transaction it happens in, and dedupe is the expected path here, so a\n * batch-wide transaction would throw away the notifications around it.\n */\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 // The notification goes in first: it carries the unique dedupe\n // index, so a duplicate is rejected before any delivery is written.\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, so two concurrent callers\n // cannot be handed the same delivery. updateMany would be one round trip\n // but gives no way to learn which documents this call actually 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 // One lookup for the batch rather than one per delivery.\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 retryable = failed && outcome.retryable;\n\n // An aggregation-pipeline update so the terminal-vs-retry decision\n // reads maxAttempts from the document itself, as the SQL CASE does.\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 : \"sent\",\n // $literal: an error message starting with \"$\" would otherwise\n // be read as a field path.\n lastError: failed ? { $literal: outcome.error.slice(0, 2000) } : null,\n notBefore: nextAttemptAt ?? \"$notBefore\",\n // Written unconditionally: if the lease expired and another\n // worker re-sent, the duplicate already happened and the true\n // terminal state beats leaving the row wedged in \"claimed\".\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 as well as id, and idempotent: re-marking a read\n // notification reports success rather than a 404.\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 // Upsert keyed on the conflict fields, matching ON CONFLICT DO UPDATE.\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 goes in $setOnInsert, never $set: Mongo rejects an update that\n // would modify it, so a conflicting upsert must leave it alone.\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/**\n * Applies a SchemaDeclaration's indexes to Mongo. The document counterpart of\n * renderPostgresDdl — there are no tables to create, only indexes, and the\n * declaration is the same source of truth.\n *\n * A unique index over a nullable field gets a partial filter. Postgres treats\n * every NULL as distinct, so unlimited rows may leave dedupeKey unset; a plain\n * Mongo unique index treats them as one value and would allow exactly one.\n */\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/adapters/mongodb/adapter.ts","../../src/adapters/mongodb/indexes.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/**\n * Minimal structural view of the pieces of the Mongo driver this uses.\n *\n * Typed structurally rather than against the real `Db` so `mongodb` stays an\n * optional peer dependency: an app on Postgres never installs it, and its\n * types are not needed to typecheck this file.\n */\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 /**\n * The MongoClient the db came from. Supplying it makes createNotifications\n * atomic; without it a crash between the two writes can leave a notification\n * with no deliveries. Transactions need a replica set, so it is opt-in — a\n * standalone mongod rejects the session outright.\n */\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\n/** Translates a WhereClause into a Mongo filter. */\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 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 /**\n * Runs `fn` in a transaction when a client was supplied, and plainly\n * otherwise. The session must reach every command inside, so `fn` receives\n * it — a write that omits it silently runs outside the transaction.\n *\n * One transaction per notification, not per batch: a duplicate key aborts\n * the transaction it happens in, and dedupe is the expected path here, so a\n * batch-wide transaction would throw away the notifications around it.\n */\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 // The notification goes in first: it carries the unique dedupe\n // index, so a duplicate is rejected before any delivery is written.\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, so two concurrent callers\n // cannot be handed the same delivery. updateMany would be one round trip\n // but gives no way to learn which documents this call actually 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 // One lookup for the batch rather than one per delivery.\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 // An aggregation-pipeline update so the terminal-vs-retry decision\n // reads maxAttempts from the document itself, as the SQL CASE does.\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 message starting with \"$\" would otherwise\n // 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 // Written unconditionally: if the lease expired and another\n // worker re-sent, the duplicate already happened and the true\n // terminal state beats leaving the row wedged in \"claimed\".\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 as well as id, and idempotent: re-marking a read\n // notification reports success rather than a 404.\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 // Upsert keyed on the conflict fields, matching ON CONFLICT DO UPDATE.\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 goes in $setOnInsert, never $set: Mongo rejects an update that\n // would modify it, so a conflicting upsert must leave it alone.\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/**\n * Applies a SchemaDeclaration's indexes to Mongo. The document counterpart of\n * renderPostgresDdl — there are no tables to create, only indexes, and the\n * declaration is the same source of truth.\n *\n * A unique index over a nullable field gets a partial filter. Postgres treats\n * every NULL as distinct, so unlimited rows may leave dedupeKey unset; a plain\n * Mongo unique index treats them as one value and would allow exactly one.\n */\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"]}