easy-ping 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -82
- package/dist/adapter-B7R4rXtJ.d.cts +17 -0
- package/dist/adapter-B7R4rXtJ.d.ts +17 -0
- package/dist/{adapter-BfLe2J0t.d.cts → adapter-D3lTy-4E.d.cts} +6 -32
- package/dist/{adapter-BfLe2J0t.d.ts → adapter-D3lTy-4E.d.ts} +6 -32
- package/dist/adapters/drizzle.cjs +4 -4
- package/dist/adapters/drizzle.cjs.map +1 -1
- package/dist/adapters/drizzle.d.cts +35 -1
- package/dist/adapters/drizzle.d.ts +35 -1
- package/dist/adapters/drizzle.js +5 -5
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/adapters/mongodb.cjs +8 -7
- package/dist/adapters/mongodb.cjs.map +1 -1
- package/dist/adapters/mongodb.d.cts +4 -17
- package/dist/adapters/mongodb.d.ts +4 -17
- package/dist/adapters/mongodb.js +7 -7
- package/dist/adapters/mongodb.js.map +1 -1
- package/dist/adapters/mysql.cjs +605 -0
- package/dist/adapters/mysql.cjs.map +1 -0
- package/dist/adapters/mysql.d.cts +38 -0
- package/dist/adapters/mysql.d.ts +38 -0
- package/dist/adapters/mysql.js +51 -0
- package/dist/adapters/mysql.js.map +1 -0
- package/dist/adapters/postgres.cjs +19 -11
- package/dist/adapters/postgres.cjs.map +1 -1
- package/dist/adapters/postgres.d.cts +9 -54
- package/dist/adapters/postgres.d.ts +9 -54
- package/dist/adapters/postgres.js +6 -41
- package/dist/adapters/postgres.js.map +1 -1
- package/dist/adapters/sqlite.cjs +593 -0
- package/dist/adapters/sqlite.cjs.map +1 -0
- package/dist/adapters/sqlite.d.cts +37 -0
- package/dist/adapters/sqlite.d.ts +37 -0
- package/dist/adapters/sqlite.js +53 -0
- package/dist/adapters/sqlite.js.map +1 -0
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +2 -14
- package/dist/browser.d.ts +2 -14
- package/dist/browser.js.map +1 -1
- package/dist/chunk-2EYKPF5A.js +393 -0
- package/dist/chunk-2EYKPF5A.js.map +1 -0
- package/dist/{chunk-OZSOIX23.js → chunk-3VOQOGDR.js} +54 -12
- package/dist/chunk-3VOQOGDR.js.map +1 -0
- package/dist/{chunk-NYDVNMKG.js → chunk-AEYYTE5I.js} +4 -3
- package/dist/chunk-AEYYTE5I.js.map +1 -0
- package/dist/chunk-BECMTNK7.js +315 -0
- package/dist/chunk-BECMTNK7.js.map +1 -0
- package/dist/chunk-CK5UPVYP.js +48 -0
- package/dist/chunk-CK5UPVYP.js.map +1 -0
- package/dist/{chunk-BV3U542P.js → chunk-E4IZ2CQC.js} +2 -2
- package/dist/chunk-E4IZ2CQC.js.map +1 -0
- package/dist/chunk-GJNLOQJS.js +226 -0
- package/dist/chunk-GJNLOQJS.js.map +1 -0
- package/dist/chunk-HY47TQMY.js +52 -0
- package/dist/chunk-HY47TQMY.js.map +1 -0
- package/dist/chunk-M4R77BJD.js +64 -0
- package/dist/chunk-M4R77BJD.js.map +1 -0
- package/dist/{chunk-RBDW4S6F.js → chunk-XIDVLYNQ.js} +14 -4
- package/dist/chunk-XIDVLYNQ.js.map +1 -0
- package/dist/client.cjs.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +362 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -37
- package/dist/index.d.ts +56 -37
- package/dist/index.js +120 -359
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +27 -6
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +8 -2
- package/dist/node.d.ts +8 -2
- package/dist/node.js +26 -6
- package/dist/node.js.map +1 -1
- package/dist/{plugin-CmPOFVmn.d.ts → plugin-CHd2ZiGC.d.cts} +37 -25
- package/dist/{plugin-f5KaFWSN.d.cts → plugin-Cg9usuUi.d.ts} +37 -25
- package/dist/plugins/digests.cjs +1 -4
- package/dist/plugins/digests.cjs.map +1 -1
- package/dist/plugins/digests.d.cts +6 -31
- package/dist/plugins/digests.d.ts +6 -31
- package/dist/plugins/digests.js +1 -4
- package/dist/plugins/digests.js.map +1 -1
- package/dist/plugins/preferences-client.cjs.map +1 -1
- package/dist/plugins/preferences-client.d.cts +2 -2
- package/dist/plugins/preferences-client.d.ts +2 -2
- package/dist/plugins/preferences-client.js +1 -1
- package/dist/plugins/preferences-react.cjs.map +1 -1
- package/dist/plugins/preferences-react.js.map +1 -1
- package/dist/plugins/preferences.cjs +101 -17
- package/dist/plugins/preferences.cjs.map +1 -1
- package/dist/plugins/preferences.d.cts +4 -2
- package/dist/plugins/preferences.d.ts +4 -2
- package/dist/plugins/preferences.js +36 -9
- package/dist/plugins/preferences.js.map +1 -1
- package/dist/plugins/push.cjs +198 -40
- package/dist/plugins/push.cjs.map +1 -1
- package/dist/plugins/push.d.cts +20 -18
- package/dist/plugins/push.d.ts +20 -18
- package/dist/plugins/push.js +141 -41
- package/dist/plugins/push.js.map +1 -1
- package/dist/providers/web-push.cjs +37 -11
- package/dist/providers/web-push.cjs.map +1 -1
- package/dist/providers/web-push.d.cts +10 -11
- package/dist/providers/web-push.d.ts +10 -11
- package/dist/providers/web-push.js +37 -12
- package/dist/providers/web-push.js.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -4
- package/dist/react.d.ts +1 -4
- package/dist/react.js.map +1 -1
- package/dist/schema.cjs +121 -2
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +25 -14
- package/dist/schema.d.ts +25 -14
- package/dist/schema.js +4 -2
- package/dist/testing.cjs +3 -19
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +4 -22
- package/dist/testing.d.ts +4 -22
- package/dist/testing.js +3 -19
- package/dist/testing.js.map +1 -1
- package/package.json +12 -1
- package/dist/chunk-BV3U542P.js.map +0 -1
- package/dist/chunk-NYDVNMKG.js.map +0 -1
- package/dist/chunk-OZSOIX23.js.map +0 -1
- package/dist/chunk-RBDW4S6F.js.map +0 -1
- package/dist/chunk-W3BMEPPQ.js +0 -50
- package/dist/chunk-W3BMEPPQ.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/base64url.ts","../../src/schema/declaration.ts","../../src/core/store.ts","../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["sql","options","pgTable","text","jsonb","timestamp","index","uniqueIndex","integer","boolean","primaryKey"],"mappings":"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","file":"drizzle.cjs","sourcesContent":["// Web APIs, not Buffer: this runs on Workers and Vercel Edge.\n\nexport function encodeBase64Url(input: string | Uint8Array): string {\n const bytes = typeof input === \"string\" ? new TextEncoder().encode(input) : input;\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// Uint8Array<ArrayBuffer>: bare Uint8Array widens and is not a BufferSource.\nexport function decodeBase64UrlBytes(value: string): Uint8Array<ArrayBuffer> | null {\n try {\n const binary = atob(value.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n return Uint8Array.from(binary, (char) => char.charCodeAt(0));\n } catch {\n return null;\n }\n}\n\nexport function decodeBase64Url(value: string): string | null {\n const bytes = decodeBase64UrlBytes(value);\n return bytes ? new TextDecoder().decode(bytes) : null;\n}\n","import type { SchemaDeclaration } from \"../core/plugin\";\n\nexport const toSnakeCase = (value: string) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n\n/**\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 SQL, sql } from \"drizzle-orm\";\nimport type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\nimport { toSnakeCase } from \"../../schema/declaration\";\n\ntype Row = Record<string, unknown>;\n\n/**\n * Minimal structural view of a Drizzle client. Deliberately not the real\n * inferred type — introspecting Drizzle's generics at a boundary costs\n * thousands of type instantiations for nothing. See plan §16.\n */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\n}\n\nconst str = (value: unknown): string => String(value);\nconst nullableStr = (value: unknown): string | null => (value == null ? null : String(value));\nconst num = (value: unknown): number => Number(value);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/**\n * postgres-js rejects a Date bound to an explicitly-typed ::timestamptz param.\n * ISO strings bind cleanly on every driver, and the cast does the conversion.\n */\nconst ts = (value: Date) => value.toISOString();\n\nconst encodeCursor = (createdAt: Date, id: string) =>\n encodeBase64Url(`${createdAt.toISOString()}|${id}`);\n\nfunction decodeCursor(cursor: string): { createdAt: Date; id: string } | null {\n const decoded = decodeBase64Url(cursor);\n if (!decoded) return null;\n\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n status: str(row.status) as DeliveryStatus,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notBefore: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\n/** Dates bind as ISO strings; see the note on `ts` above. */\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\n/**\n * Identifiers here are already validated by the PluginStore against the\n * plugin's own schema, and still go through sql.identifier rather than\n * interpolation. Values are always bound.\n */\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) {\n const list = operator.in as readonly (string | number)[];\n if (list.length === 0) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // One clock. created_at/updated_at have a DEFAULT now() for hand-written\n // SQL, but now() is the *database* clock while every cutoff the library\n // compares it against (markSeen, getFailedDeliveries) comes from the app.\n // App and database are different hosts in production, and NTP skew of a\n // few hundred ms is routine, so the newest rows fell outside markSeen and\n // the unseen badge never cleared. The mongo adapter always wrote these in\n // the app; this makes both agree.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // Rows with a NULL dedupe_key never conflict — Postgres treats NULLs\n // as distinct — so unlimited undeduped notifications coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\n });\n },\n\n async claimPendingDeliveries(args: ClaimArgs): Promise<readonly ClaimedDelivery[]> {\n const now = args.now ?? new Date();\n const staleBefore = new Date(now.getTime() - args.leaseMs);\n\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED is what lets concurrent sweeps step around each other\n // rather than block. The CTE joins the notification in the same round\n // trip — claiming 20 rows then looking each one up is the N+1 this\n // primitive exists to avoid. See RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\n SELECT c.id, c.notification_id, c.channel, c.attempts, c.max_attempts,\n n.user_id, n.type, n.payload, n.actor_id\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return rows.map((row) => ({\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notification: {\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n },\n }));\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n const values = releases.map(({ id, outcome, nextAttemptAt }) => {\n const retryable = outcome.result === \"failed\" && outcome.retryable;\n const error =\n outcome.result === \"failed\"\n ? outcome.error.slice(0, 2000)\n : outcome.result === \"skipped\"\n ? outcome.reason.slice(0, 2000)\n : null;\n\n return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // Written unconditionally — no claimed_by predicate. If the lease expired\n // and another worker re-sent, the duplicate already happened; recording\n // the true terminal state beats wedging the row in 'claimed'. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND archived_at IS NULL\n `);\n return num(rows[0]?.count ?? 0);\n },\n\n async markSeen(userId: string, before: Date) {\n await db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id as well as id — a caller must never be able to flip\n // someone else's row by guessing an id. RFC 0002 §2.\n // No `read_at IS NULL` filter: re-marking must be idempotent. Returning\n // 0 for an already-read row made the route 404, which made the client\n // roll its optimistic update back and show the item as unread again.\n // COALESCE preserves the original timestamp.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\n },\n\n async insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ) {\n if (rows.length === 0) return 0;\n\n // Column order is taken from the first row and every row is projected\n // onto it, so a ragged batch cannot shift values into other columns.\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const conflict =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )}) DO UPDATE SET ${sql.join(\n columns\n .filter((column) => !onConflict.includes(column))\n .map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`\n : sql``;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // Postgres treats NULLs as distinct here, so unlimited rows may carry no\n // dedupe key while a present one is enforced unique per user.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/base64url.ts","../../src/schema/declaration.ts","../../src/core/store.ts","../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["sql","options","pgTable","text","jsonb","timestamp","index","uniqueIndex","integer","boolean","primaryKey"],"mappings":"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","file":"drizzle.cjs","sourcesContent":["// Web APIs, not Buffer: this runs on Workers and Vercel Edge.\n\nexport function encodeBase64Url(input: string | Uint8Array): string {\n const bytes = typeof input === \"string\" ? new TextEncoder().encode(input) : input;\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// Uint8Array<ArrayBuffer>: bare Uint8Array widens and is not a BufferSource.\nexport function decodeBase64UrlBytes(value: string): Uint8Array<ArrayBuffer> | null {\n try {\n const binary = atob(value.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n return Uint8Array.from(binary, (char) => char.charCodeAt(0));\n } catch {\n return null;\n }\n}\n\nexport function decodeBase64Url(value: string): string | null {\n const bytes = decodeBase64UrlBytes(value);\n return bytes ? new TextDecoder().decode(bytes) : null;\n}\n","import type { SchemaDeclaration } from \"../core/plugin\";\n\nexport const toSnakeCase = (value: string) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n\n/** Core tables in the plugin format. A drift test asserts it agrees with the Drizzle schema. */\nexport const coreSchema = {\n notification: {\n tableName: \"notification\",\n fields: {\n id: { type: \"string\", required: true },\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n payload: { type: \"json\", required: true },\n actorId: { type: \"string\" },\n groupKey: { type: \"string\" },\n dedupeKey: { type: \"string\" },\n seenAt: { type: \"date\" },\n readAt: { type: \"date\" },\n archivedAt: { type: \"date\" },\n createdAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"userId\", \"createdAt\"], name: \"notification_feed_idx\" },\n { on: [\"userId\", \"groupKey\"], name: \"notification_group_idx\" },\n { on: [\"userId\", \"dedupeKey\"], unique: true, name: \"notification_dedupe_idx\" },\n ],\n },\n\n notificationDelivery: {\n tableName: \"notification_delivery\",\n fields: {\n id: { type: \"string\", required: true },\n notificationId: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n status: { type: \"string\", required: true, default: \"pending\" },\n attempts: { type: \"number\", required: true, default: 0 },\n maxAttempts: { type: \"number\", required: true, default: 5 },\n notBefore: { type: \"date\", required: true, defaultNow: true },\n claimedAt: { type: \"date\" },\n claimedBy: { type: \"string\" },\n lastError: { type: \"string\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"id\"],\n indexes: [\n { on: [\"status\", \"notBefore\"], name: \"delivery_claim_idx\" },\n { on: [\"notificationId\"], name: \"delivery_notification_idx\" },\n ],\n },\n\n notificationPreference: {\n tableName: \"notification_preference\",\n fields: {\n userId: { type: \"string\", required: true },\n type: { type: \"string\", required: true },\n channel: { type: \"string\", required: true },\n enabled: { type: \"boolean\", required: true, default: true },\n frequency: { type: \"string\", required: true, default: \"instant\" },\n updatedAt: { type: \"date\", required: true, defaultNow: true },\n },\n primaryKey: [\"userId\", \"type\", \"channel\"],\n },\n} satisfies SchemaDeclaration;\n","import { toSnakeCase } from \"../schema/declaration\";\nimport { ConfigError } from \"./errors\";\nimport type { FieldDeclaration, SchemaDeclaration, TableDeclaration } from \"./plugin\";\n\nexport type Scalar = string | number | boolean | Date | null;\n\n/** Operators are tagged objects so a bare value is always equality; json columns cannot be filtered. */\nexport type WhereCondition =\n | Scalar\n | { in: readonly (string | number)[] }\n | { lt: Date | number }\n | { lte: Date | number }\n | { gt: Date | number }\n | { gte: Date | number }\n | { not: Scalar };\n\nexport type WhereClause = Record<string, WhereCondition>;\n\nexport type QueryOptions = {\n limit?: number;\n orderBy?: { field: string; direction: \"asc\" | \"desc\" };\n};\n\nexport type UpsertOptions = { onConflict: readonly string[] };\n\n/** Table access for plugins, scoped to the tables the plugin declared. */\nexport type PluginStore = {\n find<T = Record<string, unknown>>(\n table: string,\n where?: WhereClause,\n options?: QueryOptions,\n ): Promise<T[]>;\n insert(table: string, rows: readonly Record<string, unknown>[]): Promise<number>;\n upsert(\n table: string,\n rows: readonly Record<string, unknown>[],\n options: UpsertOptions,\n ): Promise<number>;\n update(table: string, where: WhereClause, set: Record<string, unknown>): Promise<number>;\n remove(table: string, where: WhereClause): Promise<number>;\n};\n\nexport type TableStorage = {\n readonly naming?: \"snake_case\" | \"preserve\";\n readonly serializesJson?: boolean;\n\n queryTable(\n table: string,\n where: WhereClause,\n options: QueryOptions,\n ): Promise<Record<string, unknown>[]>;\n insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ): Promise<number>;\n updateRows(table: string, where: WhereClause, set: Record<string, unknown>): Promise<number>;\n deleteRows(table: string, where: WhereClause): Promise<number>;\n};\n\nconst OPERATORS = [\"in\", \"lt\", \"lte\", \"gt\", \"gte\", \"not\"] as const;\n\nexport const isOperator = (value: unknown): boolean =>\n typeof value === \"object\" &&\n value !== null &&\n !(value instanceof Date) &&\n OPERATORS.some((op) => Object.hasOwn(value, op));\n\nconst isScalar = (value: unknown): value is Scalar =>\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value instanceof Date;\n\n/** A forwarded JSON body can carry `{ $ne: … }`; refuse anything that is not a scalar or a known operator. */\nfunction assertCondition(pluginId: string, field: string, condition: unknown): void {\n if (isScalar(condition)) return;\n\n if (isOperator(condition)) {\n const operator = condition as Record<string, unknown>;\n const keys = Object.keys(operator);\n const [op] = keys;\n if (keys.length !== 1 || op === undefined) {\n throw new ConfigError(`plugin \"${pluginId}\" gave field \"${field}\" more than one operator.`);\n }\n const payload = operator[op];\n const valid =\n op === \"in\"\n ? Array.isArray(payload) &&\n payload.every((item) => typeof item === \"string\" || typeof item === \"number\")\n : isScalar(payload);\n if (valid) return;\n }\n\n throw new ConfigError(\n `plugin \"${pluginId}\" passed a non-scalar value for field \"${field}\"; ` +\n \"validate request bodies before querying with them.\",\n );\n}\n\nfunction assertValue(pluginId: string, field: string, spec: FieldDeclaration, value: unknown) {\n if (value === undefined || isScalar(value)) return;\n if (spec.type === \"json\" && typeof value === \"object\") return;\n throw new ConfigError(\n `plugin \"${pluginId}\" passed a non-scalar value for ${spec.type} field \"${field}\".`,\n );\n}\n\n/** Every table and column is checked against the plugin's own declaration. */\nexport function createPluginStore(\n pluginId: string,\n schema: SchemaDeclaration | undefined,\n storage: TableStorage,\n prefix: string,\n): PluginStore {\n const byTableName = new Map<string, TableDeclaration>();\n for (const declaration of Object.values(schema ?? {})) {\n byTableName.set(declaration.tableName, declaration);\n }\n\n function resolve(table: string): TableDeclaration {\n const declaration = byTableName.get(table);\n if (!declaration) {\n throw new ConfigError(\n `plugin \"${pluginId}\" accessed table \"${table}\", which it does not declare in schema().`,\n );\n }\n return declaration;\n }\n\n function checkFields(table: TableDeclaration, fields: Iterable<string>, context: string) {\n for (const field of fields) {\n // hasOwn, not a lookup: `constructor` and `__proto__` are not columns.\n const spec = Object.hasOwn(table.fields, field) ? table.fields[field] : undefined;\n if (!spec) {\n throw new ConfigError(\n `plugin \"${pluginId}\" used unknown field \"${field}\" on \"${table.tableName}\" (${context}).`,\n );\n }\n if (context === \"where\" && spec.type === \"json\") {\n throw new ConfigError(\n `plugin \"${pluginId}\" cannot filter on json field \"${field}\"; ` +\n \"a bare object value is indistinguishable from an operator.\",\n );\n }\n }\n }\n\n function checkWhere(table: TableDeclaration, where: WhereClause) {\n checkFields(table, Object.keys(where), \"where\");\n for (const [field, condition] of Object.entries(where)) {\n assertCondition(pluginId, field, condition);\n }\n }\n\n function checkRow(table: TableDeclaration, row: Record<string, unknown>, context: string) {\n checkFields(table, Object.keys(row), context);\n for (const [field, value] of Object.entries(row)) {\n const spec = table.fields[field];\n if (spec) assertValue(pluginId, field, spec, value);\n }\n }\n\n const qualified = (table: TableDeclaration) => prefix + table.tableName;\n\n // A document store keeps the declared names; a SQL adapter wants columns.\n const column = (field: string) => (storage.naming === \"preserve\" ? field : toSnakeCase(field));\n\n // json must reach postgres-js as text.\n const serialize = (table: TableDeclaration, row: Record<string, unknown>) => {\n if (storage.serializesJson === false) return row;\n\n const out: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(row)) {\n out[field] =\n table.fields[field]?.type === \"json\" && value !== null && value !== undefined\n ? JSON.stringify(value)\n : value;\n }\n return out;\n };\n\n return {\n async find(table, where = {}, options = {}) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n if (options.orderBy) checkFields(declaration, [options.orderBy.field], \"orderBy\");\n\n const rows = await storage.queryTable(qualified(declaration), where, options);\n\n // SELECT * returns snake_case; plugins read camelCase.\n return rows.map((row) => {\n const mapped: Record<string, unknown> = {};\n for (const field of Object.keys(declaration.fields)) {\n const value = row[column(field)];\n const type = declaration.fields[field]?.type;\n // Drivers differ on jsonb (parsed or text) and timestamptz (Date or text).\n if (type === \"json\" && typeof value === \"string\") mapped[field] = JSON.parse(value);\n else if (type === \"date\" && typeof value === \"string\") mapped[field] = new Date(value);\n // MySQL and SQLite have no boolean column; they hand back 0 and 1.\n else if (type === \"boolean\" && typeof value === \"number\") mapped[field] = value !== 0;\n else mapped[field] = value;\n }\n return mapped;\n }) as never;\n },\n\n async insert(table, rows) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"insert\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n );\n },\n\n async upsert(table, rows, options) {\n const declaration = resolve(table);\n for (const row of rows) checkRow(declaration, row, \"upsert\");\n checkFields(declaration, options.onConflict, \"onConflict\");\n return storage.insertRows(\n qualified(declaration),\n rows.map((row) => serialize(declaration, row)),\n options.onConflict,\n );\n },\n\n async update(table, where, set) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n checkRow(declaration, set, \"update\");\n return storage.updateRows(qualified(declaration), where, serialize(declaration, set));\n },\n\n async remove(table, where) {\n const declaration = resolve(table);\n checkWhere(declaration, where);\n return storage.deleteRows(qualified(declaration), where);\n },\n };\n}\n","import { type SQL, sql } from \"drizzle-orm\";\nimport type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\nimport { toSnakeCase } from \"../../schema/declaration\";\n\ntype Row = Record<string, unknown>;\n\n/** Structural, not Drizzle's inferred type: that costs thousands of instantiations at a boundary. */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\n}\n\nconst str = (value: unknown): string => String(value);\nconst nullableStr = (value: unknown): string | null => (value == null ? null : String(value));\nconst num = (value: unknown): number => Number(value);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/** postgres-js rejects a Date bound to a ::timestamptz param; ISO strings bind everywhere. */\nconst ts = (value: Date) => value.toISOString();\n\nconst encodeCursor = (createdAt: Date, id: string) =>\n encodeBase64Url(`${createdAt.toISOString()}|${id}`);\n\nfunction decodeCursor(cursor: string): { createdAt: Date; id: string } | null {\n const decoded = decodeBase64Url(cursor);\n if (!decoded) return null;\n\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n status: str(row.status) as DeliveryStatus,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notBefore: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) {\n const list = operator.in as readonly (string | number)[];\n if (list.length === 0) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // App clock, not now(): markSeen compares against app-side cutoffs and NTP skew broke it.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // NULL dedupe keys never conflict, so undeduped rows coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\n });\n },\n\n async claimPendingDeliveries(args: ClaimArgs): Promise<readonly ClaimedDelivery[]> {\n const now = args.now ?? new Date();\n const staleBefore = new Date(now.getTime() - args.leaseMs);\n\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED lets concurrent sweeps step around each other. RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\n SELECT c.id, c.notification_id, c.channel, c.attempts, c.max_attempts,\n n.user_id, n.type, n.payload, n.actor_id\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return rows.map((row) => ({\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notification: {\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n },\n }));\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n const values = releases.map(({ id, outcome, nextAttemptAt }) => {\n const retryable = outcome.result === \"failed\" && outcome.retryable;\n const error =\n outcome.result === \"failed\"\n ? outcome.error.slice(0, 2000)\n : outcome.result === \"skipped\"\n ? outcome.reason.slice(0, 2000)\n : null;\n\n return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // No claimed_by predicate on purpose: terminal state beats a wedged row. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND archived_at IS NULL\n `);\n return num(rows[0]?.count ?? 0);\n },\n\n async markSeen(userId: string, before: Date) {\n await db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id (RFC 0002 §2); no read_at IS NULL filter so re-marking stays idempotent.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\n },\n\n async insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ) {\n if (rows.length === 0) return 0;\n\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const conflict =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )}) DO UPDATE SET ${sql.join(\n columns\n .filter((column) => !onConflict.includes(column))\n .map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`\n : sql``;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // NULLs are distinct here: unlimited rows without a dedupe key.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DatabaseAdapter, C as Channel, a as DeliveryStatus, F as Frequency } from '../adapter-
|
|
1
|
+
import { D as DatabaseAdapter, C as Channel, a as DeliveryStatus, F as Frequency } from '../adapter-D3lTy-4E.cjs';
|
|
2
2
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
3
3
|
|
|
4
4
|
type DrizzleAdapterOptions = {
|
|
@@ -492,6 +492,23 @@ declare function createSchema(prefix?: string): {
|
|
|
492
492
|
}, {}, {
|
|
493
493
|
$type: Frequency;
|
|
494
494
|
}>;
|
|
495
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
496
|
+
name: "updated_at";
|
|
497
|
+
tableName: string;
|
|
498
|
+
dataType: "date";
|
|
499
|
+
columnType: "PgTimestamp";
|
|
500
|
+
data: Date;
|
|
501
|
+
driverParam: string;
|
|
502
|
+
notNull: true;
|
|
503
|
+
hasDefault: true;
|
|
504
|
+
isPrimaryKey: false;
|
|
505
|
+
isAutoincrement: false;
|
|
506
|
+
hasRuntimeDefault: false;
|
|
507
|
+
enumValues: undefined;
|
|
508
|
+
baseColumn: never;
|
|
509
|
+
identity: undefined;
|
|
510
|
+
generated: undefined;
|
|
511
|
+
}, {}, {}>;
|
|
495
512
|
};
|
|
496
513
|
dialect: "pg";
|
|
497
514
|
}>;
|
|
@@ -983,6 +1000,23 @@ declare const schema: {
|
|
|
983
1000
|
}, {}, {
|
|
984
1001
|
$type: Frequency;
|
|
985
1002
|
}>;
|
|
1003
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1004
|
+
name: "updated_at";
|
|
1005
|
+
tableName: string;
|
|
1006
|
+
dataType: "date";
|
|
1007
|
+
columnType: "PgTimestamp";
|
|
1008
|
+
data: Date;
|
|
1009
|
+
driverParam: string;
|
|
1010
|
+
notNull: true;
|
|
1011
|
+
hasDefault: true;
|
|
1012
|
+
isPrimaryKey: false;
|
|
1013
|
+
isAutoincrement: false;
|
|
1014
|
+
hasRuntimeDefault: false;
|
|
1015
|
+
enumValues: undefined;
|
|
1016
|
+
baseColumn: never;
|
|
1017
|
+
identity: undefined;
|
|
1018
|
+
generated: undefined;
|
|
1019
|
+
}, {}, {}>;
|
|
986
1020
|
};
|
|
987
1021
|
dialect: "pg";
|
|
988
1022
|
}>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DatabaseAdapter, C as Channel, a as DeliveryStatus, F as Frequency } from '../adapter-
|
|
1
|
+
import { D as DatabaseAdapter, C as Channel, a as DeliveryStatus, F as Frequency } from '../adapter-D3lTy-4E.js';
|
|
2
2
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
3
3
|
|
|
4
4
|
type DrizzleAdapterOptions = {
|
|
@@ -492,6 +492,23 @@ declare function createSchema(prefix?: string): {
|
|
|
492
492
|
}, {}, {
|
|
493
493
|
$type: Frequency;
|
|
494
494
|
}>;
|
|
495
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
496
|
+
name: "updated_at";
|
|
497
|
+
tableName: string;
|
|
498
|
+
dataType: "date";
|
|
499
|
+
columnType: "PgTimestamp";
|
|
500
|
+
data: Date;
|
|
501
|
+
driverParam: string;
|
|
502
|
+
notNull: true;
|
|
503
|
+
hasDefault: true;
|
|
504
|
+
isPrimaryKey: false;
|
|
505
|
+
isAutoincrement: false;
|
|
506
|
+
hasRuntimeDefault: false;
|
|
507
|
+
enumValues: undefined;
|
|
508
|
+
baseColumn: never;
|
|
509
|
+
identity: undefined;
|
|
510
|
+
generated: undefined;
|
|
511
|
+
}, {}, {}>;
|
|
495
512
|
};
|
|
496
513
|
dialect: "pg";
|
|
497
514
|
}>;
|
|
@@ -983,6 +1000,23 @@ declare const schema: {
|
|
|
983
1000
|
}, {}, {
|
|
984
1001
|
$type: Frequency;
|
|
985
1002
|
}>;
|
|
1003
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1004
|
+
name: "updated_at";
|
|
1005
|
+
tableName: string;
|
|
1006
|
+
dataType: "date";
|
|
1007
|
+
columnType: "PgTimestamp";
|
|
1008
|
+
data: Date;
|
|
1009
|
+
driverParam: string;
|
|
1010
|
+
notNull: true;
|
|
1011
|
+
hasDefault: true;
|
|
1012
|
+
isPrimaryKey: false;
|
|
1013
|
+
isAutoincrement: false;
|
|
1014
|
+
hasRuntimeDefault: false;
|
|
1015
|
+
enumValues: undefined;
|
|
1016
|
+
baseColumn: never;
|
|
1017
|
+
identity: undefined;
|
|
1018
|
+
generated: undefined;
|
|
1019
|
+
}, {}, {}>;
|
|
986
1020
|
};
|
|
987
1021
|
dialect: "pg";
|
|
988
1022
|
}>;
|
package/dist/adapters/drizzle.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isOperator } from '../chunk-
|
|
1
|
+
import { isOperator } from '../chunk-3VOQOGDR.js';
|
|
2
|
+
import { toSnakeCase } from '../chunk-AEYYTE5I.js';
|
|
2
3
|
import { decodeBase64Url, encodeBase64Url } from '../chunk-PTGHMCCG.js';
|
|
3
|
-
import { toSnakeCase } from '../chunk-NYDVNMKG.js';
|
|
4
4
|
import { sql } from 'drizzle-orm';
|
|
5
5
|
import { pgTable, timestamp, text, jsonb, index, uniqueIndex, integer, boolean, primaryKey } from 'drizzle-orm/pg-core';
|
|
6
6
|
|
|
@@ -368,8 +368,7 @@ function createSchema(prefix = "") {
|
|
|
368
368
|
index(name("notification_feed_idx")).on(table.userId, table.createdAt.desc()),
|
|
369
369
|
index(name("notification_unseen_idx")).on(table.userId).where(sql`${table.seenAt} is null`),
|
|
370
370
|
index(name("notification_group_idx")).on(table.userId, table.groupKey),
|
|
371
|
-
//
|
|
372
|
-
// dedupe key while a present one is enforced unique per user.
|
|
371
|
+
// NULLs are distinct here: unlimited rows without a dedupe key.
|
|
373
372
|
uniqueIndex(name("notification_dedupe_idx")).on(table.userId, table.dedupeKey)
|
|
374
373
|
]
|
|
375
374
|
);
|
|
@@ -400,7 +399,8 @@ function createSchema(prefix = "") {
|
|
|
400
399
|
type: text("type").notNull(),
|
|
401
400
|
channel: text("channel").$type().notNull(),
|
|
402
401
|
enabled: boolean("enabled").notNull().default(true),
|
|
403
|
-
frequency: text("frequency").$type().notNull().default("instant")
|
|
402
|
+
frequency: text("frequency").$type().notNull().default("instant"),
|
|
403
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
404
404
|
},
|
|
405
405
|
(table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })]
|
|
406
406
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["options","sql"],"mappings":"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","file":"drizzle.js","sourcesContent":["import { type SQL, sql } from \"drizzle-orm\";\nimport type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\nimport { toSnakeCase } from \"../../schema/declaration\";\n\ntype Row = Record<string, unknown>;\n\n/**\n * Minimal structural view of a Drizzle client. Deliberately not the real\n * inferred type — introspecting Drizzle's generics at a boundary costs\n * thousands of type instantiations for nothing. See plan §16.\n */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\n}\n\nconst str = (value: unknown): string => String(value);\nconst nullableStr = (value: unknown): string | null => (value == null ? null : String(value));\nconst num = (value: unknown): number => Number(value);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/**\n * postgres-js rejects a Date bound to an explicitly-typed ::timestamptz param.\n * ISO strings bind cleanly on every driver, and the cast does the conversion.\n */\nconst ts = (value: Date) => value.toISOString();\n\nconst encodeCursor = (createdAt: Date, id: string) =>\n encodeBase64Url(`${createdAt.toISOString()}|${id}`);\n\nfunction decodeCursor(cursor: string): { createdAt: Date; id: string } | null {\n const decoded = decodeBase64Url(cursor);\n if (!decoded) return null;\n\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n status: str(row.status) as DeliveryStatus,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notBefore: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\n/** Dates bind as ISO strings; see the note on `ts` above. */\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\n/**\n * Identifiers here are already validated by the PluginStore against the\n * plugin's own schema, and still go through sql.identifier rather than\n * interpolation. Values are always bound.\n */\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) {\n const list = operator.in as readonly (string | number)[];\n if (list.length === 0) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // One clock. created_at/updated_at have a DEFAULT now() for hand-written\n // SQL, but now() is the *database* clock while every cutoff the library\n // compares it against (markSeen, getFailedDeliveries) comes from the app.\n // App and database are different hosts in production, and NTP skew of a\n // few hundred ms is routine, so the newest rows fell outside markSeen and\n // the unseen badge never cleared. The mongo adapter always wrote these in\n // the app; this makes both agree.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // Rows with a NULL dedupe_key never conflict — Postgres treats NULLs\n // as distinct — so unlimited undeduped notifications coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\n });\n },\n\n async claimPendingDeliveries(args: ClaimArgs): Promise<readonly ClaimedDelivery[]> {\n const now = args.now ?? new Date();\n const staleBefore = new Date(now.getTime() - args.leaseMs);\n\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED is what lets concurrent sweeps step around each other\n // rather than block. The CTE joins the notification in the same round\n // trip — claiming 20 rows then looking each one up is the N+1 this\n // primitive exists to avoid. See RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\n SELECT c.id, c.notification_id, c.channel, c.attempts, c.max_attempts,\n n.user_id, n.type, n.payload, n.actor_id\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return rows.map((row) => ({\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notification: {\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n },\n }));\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n const values = releases.map(({ id, outcome, nextAttemptAt }) => {\n const retryable = outcome.result === \"failed\" && outcome.retryable;\n const error =\n outcome.result === \"failed\"\n ? outcome.error.slice(0, 2000)\n : outcome.result === \"skipped\"\n ? outcome.reason.slice(0, 2000)\n : null;\n\n return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // Written unconditionally — no claimed_by predicate. If the lease expired\n // and another worker re-sent, the duplicate already happened; recording\n // the true terminal state beats wedging the row in 'claimed'. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND archived_at IS NULL\n `);\n return num(rows[0]?.count ?? 0);\n },\n\n async markSeen(userId: string, before: Date) {\n await db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id as well as id — a caller must never be able to flip\n // someone else's row by guessing an id. RFC 0002 §2.\n // No `read_at IS NULL` filter: re-marking must be idempotent. Returning\n // 0 for an already-read row made the route 404, which made the client\n // roll its optimistic update back and show the item as unread again.\n // COALESCE preserves the original timestamp.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\n },\n\n async insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ) {\n if (rows.length === 0) return 0;\n\n // Column order is taken from the first row and every row is projected\n // onto it, so a ragged batch cannot shift values into other columns.\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const conflict =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )}) DO UPDATE SET ${sql.join(\n columns\n .filter((column) => !onConflict.includes(column))\n .map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`\n : sql``;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // Postgres treats NULLs as distinct here, so unlimited rows may carry no\n // dedupe key while a present one is enforced unique per user.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/drizzle/adapter.ts","../../src/adapters/drizzle/schema.ts"],"names":["options","sql"],"mappings":"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","file":"drizzle.js","sourcesContent":["import { type SQL, sql } from \"drizzle-orm\";\nimport type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\nimport { toSnakeCase } from \"../../schema/declaration\";\n\ntype Row = Record<string, unknown>;\n\n/** Structural, not Drizzle's inferred type: that costs thousands of instantiations at a boundary. */\ntype ExecutableDb = {\n execute: (query: SQL) => Promise<unknown>;\n transaction: <T>(fn: (tx: ExecutableDb) => Promise<T>) => Promise<T>;\n};\n\nexport type DrizzleAdapterOptions = {\n prefix?: string;\n};\n\n/** postgres-js returns rows directly; node-postgres wraps them in { rows }. */\nfunction toRows(result: unknown): Row[] {\n if (Array.isArray(result)) return result as Row[];\n if (result && typeof result === \"object\" && \"rows\" in result) {\n const { rows } = result as { rows: unknown };\n if (Array.isArray(rows)) return rows as Row[];\n }\n return [];\n}\n\nconst str = (value: unknown): string => String(value);\nconst nullableStr = (value: unknown): string | null => (value == null ? null : String(value));\nconst num = (value: unknown): number => Number(value);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\n/** postgres-js rejects a Date bound to a ::timestamptz param; ISO strings bind everywhere. */\nconst ts = (value: Date) => value.toISOString();\n\nconst encodeCursor = (createdAt: Date, id: string) =>\n encodeBase64Url(`${createdAt.toISOString()}|${id}`);\n\nfunction decodeCursor(cursor: string): { createdAt: Date; id: string } | null {\n const decoded = decodeBase64Url(cursor);\n if (!decoded) return null;\n\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\nfunction toNotification(row: Row): NotificationRecord {\n return {\n id: str(row.id),\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n groupKey: nullableStr(row.group_key),\n dedupeKey: nullableStr(row.dedupe_key),\n seenAt: nullableDate(row.seen_at),\n readAt: nullableDate(row.read_at),\n archivedAt: nullableDate(row.archived_at),\n createdAt: date(row.created_at),\n };\n}\n\nfunction toDelivery(row: Row): DeliveryRecord {\n return {\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n status: str(row.status) as DeliveryStatus,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notBefore: date(row.not_before),\n claimedAt: nullableDate(row.claimed_at),\n claimedBy: nullableStr(row.claimed_by),\n lastError: nullableStr(row.last_error),\n updatedAt: date(row.updated_at),\n };\n}\n\nconst bind = (value: unknown): unknown => (value instanceof Date ? value.toISOString() : value);\n\nfunction whereSql(where: WhereClause): SQL {\n const entries = Object.entries(where);\n if (entries.length === 0) return sql``;\n\n const conditions = entries.map(([field, condition]) => {\n const column = sql.identifier(toSnakeCase(field));\n\n if (condition === null) return sql`${column} IS NULL`;\n if (!isOperator(condition)) return sql`${column} = ${bind(condition)}`;\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) {\n const list = operator.in as readonly (string | number)[];\n if (list.length === 0) return sql`FALSE`;\n return sql`${column} IN (${sql.join(\n list.map((item) => sql`${item}`),\n sql`, `,\n )})`;\n }\n if (\"lt\" in operator) return sql`${column} < ${bind(operator.lt)}`;\n if (\"lte\" in operator) return sql`${column} <= ${bind(operator.lte)}`;\n if (\"gt\" in operator) return sql`${column} > ${bind(operator.gt)}`;\n if (\"gte\" in operator) return sql`${column} >= ${bind(operator.gte)}`;\n if (\"not\" in operator) {\n return operator.not === null\n ? sql`${column} IS NOT NULL`\n : sql`${column} IS DISTINCT FROM ${bind(operator.not)}`;\n }\n return sql`TRUE`;\n });\n\n return sql` WHERE ${sql.join(conditions, sql` AND `)}`;\n}\n\nexport function drizzleAdapter(\n client: unknown,\n options: DrizzleAdapterOptions = {},\n): DatabaseAdapter {\n const db = client as ExecutableDb;\n const prefix = options.prefix ?? \"\";\n\n const NOTIFICATION = sql.identifier(`${prefix}notification`);\n const DELIVERY = sql.identifier(`${prefix}notification_delivery`);\n\n const run = async (query: SQL, on: ExecutableDb = db) => toRows(await on.execute(query));\n\n return {\n name: \"drizzle-pg\",\n naming: \"snake_case\",\n serializesJson: true,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n // App clock, not now(): markSeen compares against app-side cutoffs and NTP skew broke it.\n const now = new Date();\n\n return db.transaction(async (tx) => {\n const values = input.map(\n (row) => sql`(\n ${row.id}::text,\n ${row.userId}::text,\n ${row.type}::text,\n ${JSON.stringify(row.payload ?? null)}::jsonb,\n ${row.actorId ?? null}::text,\n ${row.groupKey ?? null}::text,\n ${row.dedupeKey ?? null}::text,\n ${ts(now)}::timestamptz\n )`,\n );\n\n // NULL dedupe keys never conflict, so undeduped rows coexist.\n const inserted = await run(\n sql`\n INSERT INTO ${NOTIFICATION} (id, user_id, type, payload, actor_id, group_key, dedupe_key, created_at)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT (user_id, dedupe_key) DO NOTHING\n RETURNING id\n `,\n tx,\n );\n\n const created = new Set(inserted.map((row) => str(row.id)));\n\n const deliveries = input\n .filter((row) => created.has(row.id))\n .flatMap((row) =>\n row.deliveries.map(\n (delivery) => sql`(\n ${delivery.id}::text,\n ${row.id}::text,\n ${delivery.channel}::text,\n ${delivery.maxAttempts}::integer,\n ${ts(delivery.notBefore)}::timestamptz,\n ${ts(now)}::timestamptz\n )`,\n ),\n );\n\n if (deliveries.length > 0) {\n await tx.execute(sql`\n INSERT INTO ${DELIVERY} (id, notification_id, channel, max_attempts, not_before, updated_at)\n VALUES ${sql.join(deliveries, sql`, `)}\n `);\n }\n\n return {\n created: [...created],\n deduped: input.filter((row) => !created.has(row.id)).map((row) => row.id),\n };\n });\n },\n\n async claimPendingDeliveries(args: ClaimArgs): Promise<readonly ClaimedDelivery[]> {\n const now = args.now ?? new Date();\n const staleBefore = new Date(now.getTime() - args.leaseMs);\n\n const channelFilter =\n args.channels && args.channels.length > 0\n ? sql`AND channel IN (${sql.join(\n args.channels.map((channel) => sql`${channel}`),\n sql`, `,\n )})`\n : sql``;\n\n const idFilter =\n args.ids && args.ids.length > 0\n ? sql`AND id IN (${sql.join(\n args.ids.map((id) => sql`${id}`),\n sql`, `,\n )})`\n : sql``;\n\n // SKIP LOCKED lets concurrent sweeps step around each other. RFC 0003 §5.\n const rows = await run(sql`\n WITH claimed AS (\n UPDATE ${DELIVERY}\n SET status = 'claimed', claimed_at = ${ts(now)}::timestamptz, claimed_by = ${args.claimToken}::text\n WHERE id IN (\n SELECT id FROM ${DELIVERY}\n WHERE (status = 'pending' OR (status = 'claimed' AND claimed_at < ${ts(staleBefore)}::timestamptz))\n AND not_before <= ${ts(now)}::timestamptz\n AND attempts < max_attempts\n ${channelFilter}\n ${idFilter}\n ORDER BY not_before ASC, id ASC\n LIMIT ${args.limit}\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, notification_id, channel, attempts, max_attempts\n )\n SELECT c.id, c.notification_id, c.channel, c.attempts, c.max_attempts,\n n.user_id, n.type, n.payload, n.actor_id\n FROM claimed c\n JOIN ${NOTIFICATION} n ON n.id = c.notification_id\n `);\n\n return rows.map((row) => ({\n id: str(row.id),\n notificationId: str(row.notification_id),\n channel: str(row.channel) as Channel,\n attempts: num(row.attempts),\n maxAttempts: num(row.max_attempts),\n notification: {\n userId: str(row.user_id),\n type: str(row.type),\n payload: row.payload,\n actorId: nullableStr(row.actor_id),\n },\n }));\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n const values = releases.map(({ id, outcome, nextAttemptAt }) => {\n const retryable = outcome.result === \"failed\" && outcome.retryable;\n const error =\n outcome.result === \"failed\"\n ? outcome.error.slice(0, 2000)\n : outcome.result === \"skipped\"\n ? outcome.reason.slice(0, 2000)\n : null;\n\n return sql`(\n ${id}::text,\n ${outcome.result}::text,\n ${retryable}::boolean,\n ${error}::text,\n ${nextAttemptAt ? ts(nextAttemptAt) : null}::timestamptz\n )`;\n });\n\n // No claimed_by predicate on purpose: terminal state beats a wedged row. RFC 0003 §6.\n await db.execute(sql`\n UPDATE ${DELIVERY} d\n SET status = CASE\n WHEN v.result = 'sent' THEN 'sent'\n WHEN v.result = 'skipped' THEN 'skipped'\n WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending'\n ELSE 'failed'\n END,\n attempts = CASE\n WHEN v.result IN ('sent', 'skipped') THEN d.attempts\n ELSE d.attempts + 1\n END,\n last_error = v.error,\n not_before = COALESCE(v.not_before, d.not_before),\n claimed_at = NULL,\n claimed_by = NULL,\n updated_at = ${ts(now)}::timestamptz\n FROM (VALUES ${sql.join(values, sql`, `)}) AS v(id, result, retryable, error, not_before)\n WHERE d.id = v.id\n `);\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const rows = await run(sql`\n SELECT * FROM ${NOTIFICATION}\n WHERE user_id = ${query.userId}::text\n AND archived_at IS NULL\n ${query.unreadOnly ? sql`AND read_at IS NULL` : sql``}\n ${\n cursor\n ? sql`AND (created_at, id) < (${ts(cursor.createdAt)}::timestamptz, ${cursor.id}::text)`\n : sql``\n }\n ORDER BY created_at DESC, id DESC\n LIMIT ${query.limit + 1}\n `);\n\n const page = rows.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n rows.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n const rows = await run(sql`\n SELECT count(*)::int AS count FROM ${NOTIFICATION}\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND archived_at IS NULL\n `);\n return num(rows[0]?.count ?? 0);\n },\n\n async markSeen(userId: string, before: Date) {\n await db.execute(sql`\n UPDATE ${NOTIFICATION} SET seen_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND seen_at IS NULL AND created_at <= ${ts(before)}::timestamptz\n `);\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by user_id (RFC 0002 §2); no read_at IS NULL filter so re-marking stays idempotent.\n const rows = await run(sql`\n UPDATE ${NOTIFICATION}\n SET read_at = COALESCE(read_at, ${ts(new Date())}::timestamptz)\n WHERE user_id = ${userId}::text\n AND id IN (${sql.join(\n notificationIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n RETURNING id\n `);\n return rows.length;\n },\n\n async markAllRead(userId: string) {\n const rows = await run(sql`\n UPDATE ${NOTIFICATION} SET read_at = ${ts(new Date())}::timestamptz\n WHERE user_id = ${userId}::text AND read_at IS NULL\n RETURNING id\n `);\n return rows.length;\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const order = options.orderBy\n ? sql` ORDER BY ${sql.identifier(toSnakeCase(options.orderBy.field))} ${\n options.orderBy.direction === \"desc\" ? sql`DESC` : sql`ASC`\n }`\n : sql``;\n const limit = options.limit ? sql` LIMIT ${options.limit}` : sql``;\n\n return run(\n sql`SELECT * FROM ${sql.identifier(table)}${whereSql(where)}${order}${limit}`,\n ) as Promise<Record<string, unknown>[]>;\n },\n\n async insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ) {\n if (rows.length === 0) return 0;\n\n const columns = Object.keys(rows[0] ?? {});\n if (columns.length === 0) return 0;\n\n const values = rows.map(\n (row) =>\n sql`(${sql.join(\n columns.map((column) => sql`${bind(row[column])}`),\n sql`, `,\n )})`,\n );\n\n const conflict =\n onConflict && onConflict.length > 0\n ? sql` ON CONFLICT (${sql.join(\n onConflict.map((field) => sql.identifier(toSnakeCase(field))),\n sql`, `,\n )}) DO UPDATE SET ${sql.join(\n columns\n .filter((column) => !onConflict.includes(column))\n .map(\n (column) =>\n sql`${sql.identifier(toSnakeCase(column))} = EXCLUDED.${sql.identifier(\n toSnakeCase(column),\n )}`,\n ),\n sql`, `,\n )}`\n : sql``;\n\n const inserted = await run(sql`\n INSERT INTO ${sql.identifier(table)} (${sql.join(\n columns.map((column) => sql.identifier(toSnakeCase(column))),\n sql`, `,\n )})\n VALUES ${sql.join(values, sql`, `)}${conflict}\n RETURNING 1 AS ok\n `);\n return inserted.length;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments = Object.entries(set).map(\n ([field, value]) => sql`${sql.identifier(toSnakeCase(field))} = ${bind(value)}`,\n );\n if (assignments.length === 0) return 0;\n\n const rows = await run(sql`\n UPDATE ${sql.identifier(table)}\n SET ${sql.join(assignments, sql`, `)}${whereSql(where)}\n RETURNING 1 AS ok\n `);\n return rows.length;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const rows = await run(\n sql`DELETE FROM ${sql.identifier(table)}${whereSql(where)} RETURNING 1 AS ok`,\n );\n return rows.length;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const rows = await run(sql`\n SELECT * FROM ${DELIVERY}\n WHERE status = 'failed' AND updated_at >= ${ts(args.since)}::timestamptz\n ORDER BY updated_at DESC\n LIMIT ${args.limit}\n `);\n return rows.map(toDelivery);\n },\n };\n}\n","import { sql } from \"drizzle-orm\";\nimport {\n boolean,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n uniqueIndex,\n} from \"drizzle-orm/pg-core\";\nimport type { Channel, DeliveryStatus, Frequency } from \"../../core/types\";\n\nexport function createSchema(prefix = \"\") {\n const name = (base: string) => `${prefix}${base}`;\n\n const notification = pgTable(\n name(\"notification\"),\n {\n id: text(\"id\").primaryKey(),\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n actorId: text(\"actor_id\"),\n groupKey: text(\"group_key\"),\n dedupeKey: text(\"dedupe_key\"),\n seenAt: timestamp(\"seen_at\", { withTimezone: true }),\n readAt: timestamp(\"read_at\", { withTimezone: true }),\n archivedAt: timestamp(\"archived_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"notification_feed_idx\")).on(table.userId, table.createdAt.desc()),\n index(name(\"notification_unseen_idx\")).on(table.userId).where(sql`${table.seenAt} is null`),\n index(name(\"notification_group_idx\")).on(table.userId, table.groupKey),\n // NULLs are distinct here: unlimited rows without a dedupe key.\n uniqueIndex(name(\"notification_dedupe_idx\")).on(table.userId, table.dedupeKey),\n ],\n );\n\n const notificationDelivery = pgTable(\n name(\"notification_delivery\"),\n {\n id: text(\"id\").primaryKey(),\n notificationId: text(\"notification_id\")\n .notNull()\n .references(() => notification.id, { onDelete: \"cascade\" }),\n channel: text(\"channel\").$type<Channel>().notNull(),\n status: text(\"status\").$type<DeliveryStatus>().notNull().default(\"pending\"),\n attempts: integer(\"attempts\").notNull().default(0),\n maxAttempts: integer(\"max_attempts\").notNull().default(5),\n notBefore: timestamp(\"not_before\", { withTimezone: true }).notNull().defaultNow(),\n claimedAt: timestamp(\"claimed_at\", { withTimezone: true }),\n claimedBy: text(\"claimed_by\"),\n lastError: text(\"last_error\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [\n index(name(\"delivery_claim_idx\")).on(table.status, table.notBefore),\n index(name(\"delivery_notification_idx\")).on(table.notificationId),\n ],\n );\n\n const notificationPreference = pgTable(\n name(\"notification_preference\"),\n {\n userId: text(\"user_id\").notNull(),\n type: text(\"type\").notNull(),\n channel: text(\"channel\").$type<Channel>().notNull(),\n enabled: boolean(\"enabled\").notNull().default(true),\n frequency: text(\"frequency\").$type<Frequency>().notNull().default(\"instant\"),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => [primaryKey({ columns: [table.userId, table.type, table.channel] })],\n );\n\n return { notification, notificationDelivery, notificationPreference };\n}\n\nexport type EasyPingSchema = ReturnType<typeof createSchema>;\n\nexport const schema = createSchema();\n"]}
|