payweave 0.0.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/LICENSE +21 -0
- package/README.md +272 -0
- package/dist/_tsup-dts-rollup.d.ts +19470 -0
- package/dist/chunk-4R5OGOCC.js +94 -0
- package/dist/chunk-4R5OGOCC.js.map +1 -0
- package/dist/chunk-535Q3GUN.js +175 -0
- package/dist/chunk-535Q3GUN.js.map +1 -0
- package/dist/chunk-67NRYGRC.js +192 -0
- package/dist/chunk-67NRYGRC.js.map +1 -0
- package/dist/chunk-CGQ73I4I.js +568 -0
- package/dist/chunk-CGQ73I4I.js.map +1 -0
- package/dist/chunk-CJEYDHY6.js +18 -0
- package/dist/chunk-CJEYDHY6.js.map +1 -0
- package/dist/chunk-CR63JAAS.js +3 -0
- package/dist/chunk-CR63JAAS.js.map +1 -0
- package/dist/chunk-E633MKVX.js +1507 -0
- package/dist/chunk-E633MKVX.js.map +1 -0
- package/dist/chunk-FBPOCXRZ.js +1135 -0
- package/dist/chunk-FBPOCXRZ.js.map +1 -0
- package/dist/chunk-HTRGMZFH.js +267 -0
- package/dist/chunk-HTRGMZFH.js.map +1 -0
- package/dist/chunk-IUVGM3K7.js +765 -0
- package/dist/chunk-IUVGM3K7.js.map +1 -0
- package/dist/chunk-JD4OZHRI.js +326 -0
- package/dist/chunk-JD4OZHRI.js.map +1 -0
- package/dist/chunk-NV3MZF7L.js +139 -0
- package/dist/chunk-NV3MZF7L.js.map +1 -0
- package/dist/chunk-NXQBP35U.js +13 -0
- package/dist/chunk-NXQBP35U.js.map +1 -0
- package/dist/chunk-QJHXDZYC.js +412 -0
- package/dist/chunk-QJHXDZYC.js.map +1 -0
- package/dist/chunk-TWZK62TZ.js +83 -0
- package/dist/chunk-TWZK62TZ.js.map +1 -0
- package/dist/cli/index.js +35381 -0
- package/dist/core/index.d.ts +85 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/db/drizzle/index.d.ts +6 -0
- package/dist/db/drizzle/index.js +1532 -0
- package/dist/db/drizzle/index.js.map +1 -0
- package/dist/db/index.d.ts +43 -0
- package/dist/db/index.js +3 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/mongodb/index.d.ts +3 -0
- package/dist/db/mongodb/index.js +934 -0
- package/dist/db/mongodb/index.js.map +1 -0
- package/dist/db/mysql/index.d.ts +1 -0
- package/dist/db/mysql/index.js +12 -0
- package/dist/db/mysql/index.js.map +1 -0
- package/dist/db/postgres/index.d.ts +5 -0
- package/dist/db/postgres/index.js +791 -0
- package/dist/db/postgres/index.js.map +1 -0
- package/dist/db/prisma/index.d.ts +1 -0
- package/dist/db/prisma/index.js +12 -0
- package/dist/db/prisma/index.js.map +1 -0
- package/dist/db/sqlite/index.d.ts +5 -0
- package/dist/db/sqlite/index.js +750 -0
- package/dist/db/sqlite/index.js.map +1 -0
- package/dist/express/index.d.ts +1 -0
- package/dist/express/index.js +3 -0
- package/dist/express/index.js.map +1 -0
- package/dist/fastify/index.d.ts +1 -0
- package/dist/fastify/index.js +3 -0
- package/dist/fastify/index.js.map +1 -0
- package/dist/flutterwave/index.d.ts +27 -0
- package/dist/flutterwave/index.js +9 -0
- package/dist/flutterwave/index.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +3677 -0
- package/dist/index.js.map +1 -0
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.js +3 -0
- package/dist/next/index.js.map +1 -0
- package/dist/paystack/index.d.ts +33 -0
- package/dist/paystack/index.js +9 -0
- package/dist/paystack/index.js.map +1 -0
- package/dist/products/index.d.ts +22 -0
- package/dist/products/index.js +7 -0
- package/dist/products/index.js.map +1 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.js +69 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/unified/index.d.ts +41 -0
- package/dist/unified/index.js +6 -0
- package/dist/unified/index.js.map +1 -0
- package/dist/webhooks/index.d.ts +8 -0
- package/dist/webhooks/index.js +8 -0
- package/dist/webhooks/index.js.map +1 -0
- package/package.json +164 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db/postgres/errors.ts","../../../src/db/postgres/runner.ts","../../../src/db/postgres/url.ts","../../../src/db/postgres/id.ts","../../../src/db/postgres/migrations-executor.ts","../../../src/db/postgres/rows.ts","../../../src/db/postgres/period-sql.ts","../../../src/db/postgres/sql.ts","../../../src/db/postgres/adapter.ts","../../../src/db/postgres/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Error helpers for the postgres adapter (docs/v1/database.md §7, PW-704):\n * an actionable install-hint error when the optional peer driver (`pg`) is\n * missing (mirrors the sqlite/drizzle adapters' message style: name the\n * subpath, the missing package, and an install command), and a thin wrapper\n * turning raw `pg` errors into {@link PayweaveError} subclasses (AGENTS.md §2:\n * public SDK methods only ever throw `PayweaveError` subclasses).\n */\nimport { PayweaveConfigError, PayweaveError, PayweaveValidationError } from \"../../core/errors\";\n\n/**\n * The optional peer driver (`pg`) required by `payweave/db/postgres` is not\n * installed.\n */\nexport function installHintError(cause: unknown): PayweaveConfigError {\n return new PayweaveConfigError(\n 'payweave/db/postgres: this adapter requires the \"pg\" package, which is not installed (it is ' +\n 'an optional peerDependency of \"payweave\"). Run `npm install pg` (or your package manager\\'s ' +\n \"equivalent) and try again.\",\n { cause },\n );\n}\n\n/** Postgres error `.code` values (SQLSTATE) that mean \"a constraint was violated\". */\nconst CONSTRAINT_VIOLATION_CODES = new Set([\n \"23505\", // unique_violation — incl. the partial-unique active-subscription index\n \"23P01\", // exclusion_violation\n \"23503\", // foreign_key_violation\n \"23514\", // check_violation\n]);\n\nfunction pgErrorCode(error: unknown): string | undefined {\n const code = (error as { code?: unknown } | null)?.code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nfunction isConstraintViolation(error: unknown): boolean {\n const code = pgErrorCode(error);\n return code !== undefined && CONSTRAINT_VIOLATION_CODES.has(code);\n}\n\n/**\n * Normalize a raw `pg` driver error into a {@link PayweaveError} subclass.\n * Constraint violations (e.g. the partial-unique active-subscription rule,\n * `pw_customers.external_id`) become {@link PayweaveValidationError} — the\n * caller supplied input that conflicts with existing state; anything else\n * becomes a generic {@link PayweaveError}, preserving the driver error as\n * `cause` either way.\n */\nexport function wrapDriverError(error: unknown, message: string): PayweaveError {\n if (error instanceof PayweaveError) return error;\n if (isConstraintViolation(error)) {\n return new PayweaveValidationError(message, { cause: error });\n }\n return new PayweaveError(message, { cause: error, isRetryable: false });\n}\n","/**\n * Concurrency backbone for the postgres adapter (docs/v1/database.md §5,\n * PW-704).\n *\n * Unlike the sqlite adapter (one serialized connection) or the drizzle\n * Postgres adapter (a `db.transaction()` + `SELECT ... FOR UPDATE` per\n * `balances.consume` call), the direct `pg` adapter's hot paths\n * (`balances.consume`, `webhookEvents.claim`) are each a SINGLE SQL statement\n * sent over the pool's normal connection-per-query model — no dedicated\n * connection or transaction wrapper is needed for those two calls at all\n * (`./sql.ts`'s query text does its own row-locking internally via a\n * `FOR UPDATE` CTE, entirely inside that one round trip). `Runner.transaction`\n * exists for the handful of calls that genuinely need a read-then-conditional\n * -write spanning more than one statement — `plans.pushVersion` (content-hash\n * no-op gate) and `customers.linkProviderRef` (JSON merge) — mirroring the\n * sqlite/drizzle adapters' pattern for those same two operations, and for the\n * public `DatabaseAdapter.transaction(fn)` contract method itself.\n *\n * `PoolRunner` wraps the caller's pool directly for non-transactional calls\n * (each `query()` borrows whatever connection the pool hands out — safe\n * because pg pools are inherently safe for concurrent unrelated queries).\n * `transaction()` checks out ONE dedicated `PoolClient` via `pool.connect()`,\n * runs `BEGIN`/`COMMIT`/`ROLLBACK` around it, and always `release()`s it back\n * to the pool. `ClientRunner` is bound to that already-open transaction: its\n * `query()` runs directly on the held client, and its OWN `transaction()` is a\n * reentrant passthrough (`fn(this)`, no nested `BEGIN`/`SAVEPOINT`) — the same\n * reentrancy pattern the sqlite adapter's `TransactionRunner` uses, so a\n * caller's `db.transaction(tx => tx.plans.pushVersion(...))` composes\n * correctly without ever attempting a nested transaction.\n */\nimport type { PgPoolClientLike, PgPoolLike, PgQueryResultLike } from \"./url\";\n\n/** The uniform surface adapter code is written against. */\nexport interface Runner {\n query(text: string, params?: readonly unknown[]): Promise<PgQueryResultLike>;\n /**\n * Run `fn` as one atomic unit on a dedicated connection. Outermost callers\n * get a real `BEGIN`/`COMMIT`/`ROLLBACK`; a `Runner` already inside a\n * transaction (a `ClientRunner`) treats this as a reentrant passthrough.\n */\n transaction<T>(fn: (tx: Runner) => Promise<T>): Promise<T>;\n}\n\n/** The adapter's entry point over a caller-owned or lazily-constructed `pg` Pool. */\nexport class PoolRunner implements Runner {\n readonly #pool: PgPoolLike;\n\n constructor(pool: PgPoolLike) {\n this.#pool = pool;\n }\n\n query(text: string, params: readonly unknown[] = []): Promise<PgQueryResultLike> {\n return this.#pool.query(text, params);\n }\n\n async transaction<T>(fn: (tx: Runner) => Promise<T>): Promise<T> {\n const client = await this.#pool.connect();\n try {\n await client.query(\"BEGIN\");\n const txRunner = new ClientRunner(client);\n try {\n const result = await fn(txRunner);\n await client.query(\"COMMIT\");\n return result;\n } catch (error) {\n await client.query(\"ROLLBACK\").catch(() => undefined);\n throw error;\n }\n } finally {\n client.release();\n }\n }\n}\n\n/** Bound to an already-open transaction on one dedicated `pg` `PoolClient`. */\nexport class ClientRunner implements Runner {\n readonly #client: PgPoolClientLike;\n\n constructor(client: PgPoolClientLike) {\n this.#client = client;\n }\n\n query(text: string, params: readonly unknown[] = []): Promise<PgQueryResultLike> {\n return this.#client.query(text, params);\n }\n\n // Reentrant: already inside one atomic unit, so nested `transaction()`\n // calls (e.g. a user's `db.transaction(tx => tx.plans.pushVersion(...))`)\n // just run inline rather than attempting a nested BEGIN.\n transaction<T>(fn: (tx: Runner) => Promise<T>): Promise<T> {\n return fn(this);\n }\n}\n","/**\n * Input resolution for `postgresAdapter(...)` (docs/v1/database.md §1/§4,\n * PW-704).\n *\n * `postgresAdapter` accepts EITHER `{ connectionString }` (validated EAGERLY —\n * database.md §1: \"postgresAdapter rejects a non-`postgres://`/`postgresql://`\n * connection string\") — the `pg.Pool` itself is constructed LAZILY, on first\n * query, so a bad connection string never opens a socket just to fail — OR an\n * already-constructed `pg` `Pool` (or `Client`) instance, detected\n * structurally (no driver import needed to classify — core pulls no driver\n * code, database.md §7), matching how the sqlite/drizzle adapters accept a\n * caller-owned instance.\n *\n * All validation here is pure and synchronous — no driver import, no I/O.\n */\nimport { PayweaveConfigError } from \"../../core/errors\";\n\nconst VALID_SCHEMES = [\"postgres://\", \"postgresql://\"];\n\n/** The minimal `pg` query result shape this adapter relies on. */\nexport interface PgQueryResultLike {\n readonly rows: ReadonlyArray<Record<string, unknown>>;\n}\n\n/** The minimal shape of a `pg` `PoolClient` (a single, dedicated connection). */\nexport interface PgPoolClientLike {\n query(text: string, params?: readonly unknown[]): Promise<PgQueryResultLike>;\n release(err?: unknown): void;\n}\n\n/**\n * The minimal shape of a `pg` `Pool` this adapter relies on. Structural (not\n * `import(\"pg\").Pool`) so classifying a caller-supplied instance never\n * requires importing the driver.\n */\nexport interface PgPoolLike {\n query(text: string, params?: readonly unknown[]): Promise<PgQueryResultLike>;\n connect(): Promise<PgPoolClientLike>;\n}\n\n/** Where `postgresAdapter` should connect, resolved eagerly from its input. */\nexport type PostgresConnectTarget =\n | { readonly kind: \"connectionString\"; readonly connectionString: string }\n | { readonly kind: \"pool-instance\"; readonly pool: PgPoolLike };\n\n/**\n * Validate a `{ connectionString }` value eagerly. Throws\n * {@link PayweaveConfigError} for anything other than a `postgres://` or\n * `postgresql://` URL — a garbage/foreign scheme (e.g. `mysql://`) is\n * rejected synchronously, before any connection is attempted.\n */\nexport function assertPostgresConnectionString(value: unknown): string {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new PayweaveConfigError(\n \"payweave/db/postgres: postgresAdapter({ connectionString }) requires a non-empty string — \" +\n `got ${JSON.stringify(value)}.`,\n );\n }\n if (!VALID_SCHEMES.some((scheme) => value.startsWith(scheme))) {\n throw new PayweaveConfigError(\n `payweave/db/postgres: connectionString must start with \"postgres://\" or \"postgresql://\" — ` +\n \"got an unsupported scheme. Never log or include the full string in an error message (it \" +\n \"may carry credentials); check the beginning of your DATABASE_URL.\",\n );\n }\n return value;\n}\n\nfunction looksLikePgPool(value: object): value is PgPoolLike {\n const candidate = value as Partial<PgPoolLike>;\n return typeof candidate.query === \"function\" && typeof candidate.connect === \"function\";\n}\n\n/**\n * Resolve `postgresAdapter`'s single argument into a\n * {@link PostgresConnectTarget}. Synchronous and side-effect-free\n * — no driver import, no connection opened, no query run.\n */\nexport function resolvePostgresInput(input: unknown): PostgresConnectTarget {\n if (input === null || typeof input !== \"object\") {\n throw new PayweaveConfigError(\n \"payweave/db/postgres: postgresAdapter(...) expects { connectionString } (a postgres://\" +\n \"/postgresql:// URL) or an existing `pg` Pool instance — got \" +\n `${input === null ? \"null\" : typeof input}.`,\n );\n }\n if (\"connectionString\" in input) {\n const connectionString = assertPostgresConnectionString(\n (input as { connectionString: unknown }).connectionString,\n );\n return { kind: \"connectionString\", connectionString };\n }\n if (looksLikePgPool(input)) {\n return { kind: \"pool-instance\", pool: input };\n }\n throw new PayweaveConfigError(\n \"payweave/db/postgres: postgresAdapter(...) expects { connectionString } (a postgres://\" +\n \"/postgresql:// URL) or an existing `pg` Pool instance (has .query()/.connect()) — got an \" +\n \"object matching neither shape.\",\n );\n}\n","/**\n * `pwv_<ulid>` id generation for the postgres adapter (docs/v1/database.md §2,\n * PW-704). Deliberately self-contained — NOT imported from\n * `src/db/sqlite/id.ts` or `src/db/drizzle/id.ts` (both read-only for this\n * ticket) — each first-party adapter owns an independent copy so the\n * disjoint-directory parallel-safety the epic brief describes\n * (`epic-07-database.md` PW-704…709 preamble) holds for real, not just by\n * convention. This is a minimal, dependency-free ULID implementation (spec:\n * https://github.com/ulid/spec) — no third-party `ulid` package, keeping the\n * SDK's zod-only `dependencies` rule intact. Monotonicity\n * within the same millisecond is NOT implemented (row ids only need to be\n * unique, not strictly sortable under sub-ms bursts); randomness is\n * `node:crypto`'s CSPRNG.\n */\nimport { randomInt } from \"node:crypto\";\n\n/** Crockford's Base32 alphabet (32 symbols; excludes I, L, O, U). */\nconst ENCODING = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\nconst ENCODING_LEN = ENCODING.length;\nconst TIME_LEN = 10;\nconst RANDOM_LEN = 16;\n\nfunction encodeTime(timeMs: number, len: number): string {\n if (!Number.isSafeInteger(timeMs) || timeMs < 0) {\n throw new RangeError(`ulid: time must be a non-negative safe integer — got ${timeMs}`);\n }\n let remaining = timeMs;\n let out = \"\";\n for (let i = 0; i < len; i++) {\n const mod = remaining % ENCODING_LEN;\n out = ENCODING.charAt(mod) + out;\n remaining = Math.floor(remaining / ENCODING_LEN);\n }\n return out;\n}\n\nfunction encodeRandom(len: number): string {\n let out = \"\";\n for (let i = 0; i < len; i++) {\n out += ENCODING.charAt(randomInt(0, ENCODING_LEN));\n }\n return out;\n}\n\n/** A fresh ULID (26 chars: 10 time + 16 random), uppercase Crockford Base32. */\nexport function ulid(timeMs: number = Date.now()): string {\n return encodeTime(timeMs, TIME_LEN) + encodeRandom(RANDOM_LEN);\n}\n\n/**\n * A fresh Payweave row id: `pwv_` + a 26-char ULID — matches\n * `src/db/schema.ts`'s `pwIdSchema` exactly.\n */\nexport function generatePwId(timeMs: number = Date.now()): string {\n return `pwv_${ulid(timeMs)}`;\n}\n","/**\n * Bridges the postgres adapter's {@link Runner} to PW-703's driver-agnostic\n * {@link MigrationExecutor} (docs/v1/database.md §4). The postgres dialect\n * already emits `$1…` placeholders and expects `Date` binds for timestamp\n * columns (`src/db/migrations/ledger.ts`), so this bridge is a thin\n * pass-through — no dialect translation needed here.\n */\nimport type { MigrationExecutor, MigrationQueryResult } from \"../migrations/index\";\nimport type { Runner } from \"./runner\";\n\nexport class PostgresMigrationExecutor implements MigrationExecutor {\n readonly #runner: Runner;\n\n constructor(runner: Runner) {\n this.#runner = runner;\n }\n\n async query(sql: string, params: readonly unknown[] = []): Promise<MigrationQueryResult> {\n const { rows } = await this.#runner.query(sql, params);\n return { rows };\n }\n\n async transaction<T>(fn: (tx: MigrationExecutor) => Promise<T>): Promise<T> {\n return this.#runner.transaction((tx) => fn(new PostgresMigrationExecutor(tx)));\n }\n}\n","/**\n * Row (de)serialization between `pg`'s native result rows and the `z.infer`\n * row types in `src/db/schema.ts` (docs/v1/database.md §4 storage mapping:\n * `TIMESTAMPTZ`, `JSONB`, `BOOLEAN`, `BIGINT` — `src/db/migrations/ddl.ts`\n * header).\n *\n * `pg` already parses `TIMESTAMPTZ` -> `Date`, `JSONB` -> plain JS\n * object/array, and `BOOLEAN` -> `boolean` for us (unlike sqlite, which\n * stores everything as INTEGER/TEXT and needs manual encode/decode) — the one\n * thing `pg` does NOT do by default is `BIGINT`/`int8` (`used`, `\"limit\"`):\n * it returns those as strings to avoid silent precision loss for values\n * beyond `Number.MAX_SAFE_INTEGER`. Payweave's usage counters are always\n * well within safe-integer range (AGENTS.md §2 rule 7 — integers throughout),\n * so this module converts them back to `number` explicitly, per row, rather\n * than installing a process-wide `pg.types` parser override (which would\n * silently change how the CALLER's own, unrelated `pg` queries elsewhere in\n * their app parse `BIGINT` — too invasive for a library to do unasked).\n *\n * Every reader is defensive about column types (driver rows are\n * `Record<string, unknown>`) so a `pg` version returning an unexpected shape\n * fails loudly here instead of silently corrupting a row further up the stack.\n */\nimport type {\n PwCustomer,\n PwFeatureBalance,\n PwPlanVersion,\n PwSubscription,\n PwWebhookEvent,\n} from \"../schema\";\n\n/** One driver-returned row: column name -> raw value. */\nexport type SqlRow = Record<string, unknown>;\n\nfunction requireColumn(row: SqlRow, column: string): unknown {\n if (!(column in row)) {\n throw new Error(`postgres adapter: row is missing expected column \"${column}\"`);\n }\n return row[column];\n}\n\nfunction str(row: SqlRow, column: string): string {\n const value = requireColumn(row, column);\n if (typeof value !== \"string\") {\n throw new Error(`postgres adapter: expected column \"${column}\" to be a string, got ${typeof value}`);\n }\n return value;\n}\n\nfunction nullableStr(row: SqlRow, column: string): string | null {\n const value = requireColumn(row, column);\n if (value === null || value === undefined) return null;\n if (typeof value !== \"string\") {\n throw new Error(\n `postgres adapter: expected column \"${column}\" to be a string or null, got ${typeof value}`,\n );\n }\n return value;\n}\n\n/** `INTEGER` columns — `pg` already returns these as `number`. */\nfunction int(row: SqlRow, column: string): number {\n const value = requireColumn(row, column);\n if (typeof value !== \"number\") {\n throw new Error(`postgres adapter: expected column \"${column}\" to be a number, got ${typeof value}`);\n }\n return value;\n}\n\n/** `BIGINT` columns — `pg` returns these as `string`; see the module header. */\nfunction bigint(row: SqlRow, column: string): number {\n const value = requireColumn(row, column);\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\") {\n const n = Number(value);\n if (!Number.isSafeInteger(n)) {\n throw new Error(\n `postgres adapter: column \"${column}\" (${value}) is outside Number.isSafeInteger range`,\n );\n }\n return n;\n }\n throw new Error(\n `postgres adapter: expected column \"${column}\" to be a bigint string or number, got ${typeof value}`,\n );\n}\n\nfunction bool(row: SqlRow, column: string): boolean {\n const value = requireColumn(row, column);\n if (typeof value !== \"boolean\") {\n throw new Error(`postgres adapter: expected column \"${column}\" to be a boolean, got ${typeof value}`);\n }\n return value;\n}\n\nfunction dateOf(row: SqlRow, column: string): Date {\n const value = requireColumn(row, column);\n if (!(value instanceof Date)) {\n throw new Error(`postgres adapter: expected column \"${column}\" to be a Date, got ${typeof value}`);\n }\n return value;\n}\n\nfunction nullableDateOf(row: SqlRow, column: string): Date | null {\n const value = requireColumn(row, column);\n if (value === null || value === undefined) return null;\n if (!(value instanceof Date)) {\n throw new Error(\n `postgres adapter: expected column \"${column}\" to be a Date or null, got ${typeof value}`,\n );\n }\n return value;\n}\n\n/** `JSONB` columns — `pg` already parses these into a plain JS value. */\nfunction json<T>(row: SqlRow, column: string): T {\n return requireColumn(row, column) as T;\n}\n\n// ── Row mappers ──────────────────────────────────────────────────────────────\n\nexport function rowToCustomer(row: SqlRow): PwCustomer {\n return {\n id: str(row, \"id\"),\n externalId: str(row, \"external_id\"),\n providerIds: json<Record<string, string>>(row, \"provider_ids\"),\n email: nullableStr(row, \"email\"),\n createdAt: dateOf(row, \"created_at\"),\n updatedAt: dateOf(row, \"updated_at\"),\n };\n}\n\nexport function rowToPlanVersion(row: SqlRow): PwPlanVersion {\n return {\n id: str(row, \"id\"),\n planId: str(row, \"plan_id\"),\n version: int(row, \"version\"),\n group: str(row, \"group\"),\n isDefault: bool(row, \"is_default\"),\n name: nullableStr(row, \"name\"),\n priceMinor: (() => {\n const v = requireColumn(row, \"price_minor\");\n return v === null ? null : bigint(row, \"price_minor\");\n })(),\n priceCurrency: nullableStr(row, \"price_currency\"),\n priceInterval: nullableStr(row, \"price_interval\") as PwPlanVersion[\"priceInterval\"],\n features: json(row, \"features\"),\n providerRefs: json(row, \"provider_refs\"),\n pushedAt: dateOf(row, \"pushed_at\"),\n };\n}\n\nexport function rowToSubscription(row: SqlRow): PwSubscription {\n return {\n id: str(row, \"id\"),\n customerId: str(row, \"customer_id\"),\n planId: str(row, \"plan_id\"),\n planVersion: int(row, \"plan_version\"),\n group: str(row, \"group\"),\n status: str(row, \"status\") as PwSubscription[\"status\"],\n provider: nullableStr(row, \"provider\"),\n providerSubscriptionRef: nullableStr(row, \"provider_subscription_ref\"),\n currentPeriodStart: dateOf(row, \"current_period_start\"),\n currentPeriodEnd: dateOf(row, \"current_period_end\"),\n cancelAtPeriodEnd: bool(row, \"cancel_at_period_end\"),\n createdAt: dateOf(row, \"created_at\"),\n updatedAt: dateOf(row, \"updated_at\"),\n };\n}\n\nexport function rowToFeatureBalance(row: SqlRow): PwFeatureBalance {\n return {\n id: str(row, \"id\"),\n customerId: str(row, \"customer_id\"),\n featureId: str(row, \"feature_id\"),\n group: str(row, \"group\"),\n used: bigint(row, \"used\"),\n limit: bigint(row, \"limit\"),\n resetInterval: str(row, \"reset_interval\") as PwFeatureBalance[\"resetInterval\"],\n anchor: dateOf(row, \"anchor\"),\n periodStart: dateOf(row, \"period_start\"),\n periodEnd: dateOf(row, \"period_end\"),\n planId: str(row, \"plan_id\"),\n planVersion: int(row, \"plan_version\"),\n updatedAt: dateOf(row, \"updated_at\"),\n };\n}\n\nexport function rowToWebhookEvent(row: SqlRow): PwWebhookEvent {\n return {\n dedupeKey: str(row, \"dedupe_key\"),\n provider: str(row, \"provider\"),\n type: str(row, \"type\"),\n receivedAt: dateOf(row, \"received_at\"),\n claimedAt: nullableDateOf(row, \"claimed_at\"),\n appliedAt: nullableDateOf(row, \"applied_at\"),\n };\n}\n","/**\n * SQL translation of `src/products/period.ts`'s anchor-relative billing-period\n * math, for the ONE place `balances.consume`'s single-statement design needs\n * it: recomputing an EXISTING row's current window from its own stored\n * `anchor`/`reset_interval` when a lazy reset is due (metered-usage.md §5,\n * database.md §5 pg bullet — \"this ticket's headline\").\n *\n * ── Why this exists instead of reading the row in JS (deviation from the\n * sqlite/drizzle adapters) ──────────────────────────────────────────────────\n * `src/db/sqlite/adapter.ts` and `src/db/drizzle/postgres-adapter.ts` both\n * read the current row (locked, in a transaction), decide in JS via\n * `currentPeriod()` directly, and write the result back — sidestepping any\n * need to reimplement calendar math in SQL, at the cost of an explicit\n * multi-statement transaction. PW-704's brief is explicit that the DIRECT\n * `pg` adapter's headline requirement is different: `consume` must be ONE\n * statement leveraging pg's native row locking (database.md §5: \"pg row\n * locking / single-statement atomicity — NOT a read-then-write\"). Getting\n * that MUST express the reset-due branch's period math as SQL evaluated\n * against the locked row's own `anchor`/`reset_interval` — hence this module.\n *\n * The FRESH-row branch of `consume` (no existing row) needs NO SQL month\n * math at all: `src/db/postgres/adapter.ts` computes that branch's\n * `period_start`/`period_end` by calling `currentPeriod()` directly in JS\n * (zero drift risk — it IS the oracle) and passes the result in as bind\n * parameters. Only the reset-due branch — which by construction must react\n * to the EXISTING row's own anchor, visible only inside the SQL statement via\n * a `FOR UPDATE`-locked CTE (`./sql.ts`) — needs the translation below.\n *\n * ── The translation, term for term ──────────────────────────────────────────\n * `period.ts`'s `currentPeriod(anchorMs, reset, nowMs)`:\n * 1. `estimate` — an O(1) guess at the period index (day/week: integer\n * division of the elapsed ms; month/year: integer division of the\n * elapsed CALENDAR months, ignoring day-of-month/time-of-day) that is\n * PROVEN to never overshoot the true index and to undershoot it by AT\n * MOST 2 (`period.ts`'s own comment).\n * 2. `index = max(0, estimate - 1)` — never negative; the -1 makes room for\n * the undershoot correction below without ever having to walk backwards.\n * 3. A `while` loop increments `index` while `nowMs >= advance(index+1)` —\n * bounded to AT MOST 2 iterations by the estimate's proven error bound.\n *\n * SQL has no `while`. Since step 3 is bounded to exactly 0, 1, or 2\n * increments, it is UNROLLED into a closed form: evaluate `advance` at four\n * candidate offsets from `index0` (0..3 — offsets 1..3 cover every possible\n * final index, and offset 3 additionally covers `period_end` when the final\n * index is `index0 + 2`), then a single `CASE` picks the right pair using two\n * strict-less-than comparisons (`advance` is strictly increasing in its\n * count argument, so comparing against `adv1`/`adv2` alone is sufficient —\n * see {@link buildPeriodMathSql}'s `increments` expression). This is\n * algebraically IDENTICAL to `period.ts`'s loop, not an approximation.\n *\n * `advance`'s own month/year clamping (`addUtcMonthsClamped`) — add whole\n * calendar months to the anchor's UTC components, clamping day-of-month to\n * the target month's length ONCE per result, never iterating on a clamped\n * output — is reproduced via `make_timestamptz` with explicit UTC field\n * arithmetic (`AT TIME ZONE 'UTC'` on every extract, so the result is\n * independent of the connection's `timezone` session setting — postgres\n * itself does NOT clamp end-of-month interval arithmetic the way `period.ts`\n * does: `timestamptz '2026-01-31' + interval '1 month'` overflows to March,\n * it does not clamp to Feb 28, which is exactly the bug this hand-rolled\n * expression avoids).\n *\n * VERIFICATION NOTE (no docker in this environment — see the ticket's\n * handoff report): this SQL cannot be executed against a real postgres here.\n * `test/db/postgres.test.ts` instead cross-checks a byte-for-byte JS mirror\n * of this exact formula (same operations: `Math.floor` for `FLOOR`, `%` +\n * normalization for `MOD`, the same four-candidate/`CASE` structure) against\n * `src/products/period.ts`'s `currentPeriod` across day/week/month/year,\n * leap years, end-of-month anchors, and both directions of drift — the\n * strongest confidence available without a live database; a real postgres\n * run (PW-710's CI matrix) is the only thing that can confirm postgres's\n * own `EXTRACT`/`make_timestamptz`/interval semantics agree with the mirror.\n */\n\nconst DAY_MS = \"86400000\";\nconst WEEK_MS = \"604800000\";\n\n/** `(EXTRACT(DAY FROM (last day of the given year/month)))::int` — the target month's length. */\nfunction daysInMonthExpr(yearExpr: string, monthExpr: string): string {\n return (\n `(EXTRACT(DAY FROM (make_date((${yearExpr})::int, (${monthExpr})::int, 1) + ` +\n `INTERVAL '1 month - 1 day')))::int`\n );\n}\n\n/**\n * `addUtcMonthsClamped(anchor, totalMonths)` (period.ts) as a SQL scalar\n * expression. `anchorUtc` must already be a `(col AT TIME ZONE 'UTC')`\n * expression (a tz-naive UTC wall-clock `timestamp`); `totalMonthsExpr` is a\n * SQL integer expression for the (possibly negative) total month offset.\n * Returns a `timestamptz` expression, constructed with an EXPLICIT `'UTC'`\n * zone so the result never depends on the connection's `timezone` setting.\n */\nfunction clampedMonthAddExpr(anchorUtc: string, totalMonthsExpr: string): string {\n const rawMonths = `((EXTRACT(MONTH FROM ${anchorUtc}))::int - 1 + (${totalMonthsExpr}))`;\n const year = `((EXTRACT(YEAR FROM ${anchorUtc}))::int + FLOOR((${rawMonths})::numeric / 12))::int`;\n const monthIndex = `(MOD(MOD((${rawMonths})::int, 12) + 12, 12))::int`;\n const month = `(${monthIndex} + 1)`;\n const day = `LEAST((EXTRACT(DAY FROM ${anchorUtc}))::int, ${daysInMonthExpr(year, month)})`;\n return (\n `make_timestamptz(${year}, ${month}, (${day})::int, ` +\n `(EXTRACT(HOUR FROM ${anchorUtc}))::int, (EXTRACT(MINUTE FROM ${anchorUtc}))::int, ` +\n `(EXTRACT(SECOND FROM ${anchorUtc}))::double precision, 'UTC')`\n );\n}\n\n/**\n * `advance(anchor, reset, n)` (period.ts) as a SQL scalar expression, over\n * generic column/parameter references. `anchorRaw`/`nowRaw` are `timestamptz`\n * expressions; `resetIntervalRaw` is a `text` expression valued\n * `'day'|'week'|'month'|'year'`; `nExpr` is a (possibly parenthesized) SQL\n * integer expression for the count of whole intervals.\n */\nfunction advanceExpr(anchorRaw: string, resetIntervalRaw: string, nExpr: string): string {\n const anchorUtc = `(${anchorRaw} AT TIME ZONE 'UTC')`;\n return `(CASE ${resetIntervalRaw}\n WHEN 'day' THEN ${anchorRaw} + ((${nExpr}) * ${DAY_MS}) * INTERVAL '1 millisecond'\n WHEN 'week' THEN ${anchorRaw} + ((${nExpr}) * ${WEEK_MS}) * INTERVAL '1 millisecond'\n WHEN 'month' THEN ${clampedMonthAddExpr(anchorUtc, `(${nExpr}) * 1`)}\n WHEN 'year' THEN ${clampedMonthAddExpr(anchorUtc, `(${nExpr}) * 12`)}\n END)`;\n}\n\n/**\n * The O(1) `estimate` (period.ts) as a SQL scalar expression — day/week: the\n * floored elapsed-ms ratio; month/year: the floored elapsed-calendar-months\n * ratio (component-wise, ignoring day-of-month/time-of-day, exactly like\n * `period.ts`'s `monthDiff`).\n */\nfunction estimateExpr(anchorRaw: string, resetIntervalRaw: string, nowRaw: string): string {\n const anchorUtc = `(${anchorRaw} AT TIME ZONE 'UTC')`;\n const nowUtc = `(${nowRaw} AT TIME ZONE 'UTC')`;\n // ROUND (not a bare cast) protects against float epsilon in EXTRACT(EPOCH ...)\n // landing just under/over a whole millisecond for the same instant twice.\n const diffMs = `ROUND(EXTRACT(EPOCH FROM (${nowRaw} - ${anchorRaw})) * 1000)`;\n const monthDiff =\n `(((EXTRACT(YEAR FROM ${nowUtc}))::int - (EXTRACT(YEAR FROM ${anchorUtc}))::int) * 12 + ` +\n `((EXTRACT(MONTH FROM ${nowUtc}))::int - (EXTRACT(MONTH FROM ${anchorUtc}))::int))`;\n return `((CASE ${resetIntervalRaw}\n WHEN 'day' THEN FLOOR((${diffMs})::numeric / ${DAY_MS})\n WHEN 'week' THEN FLOOR((${diffMs})::numeric / ${WEEK_MS})\n WHEN 'month' THEN FLOOR((${monthDiff})::numeric / 1)\n WHEN 'year' THEN FLOOR((${monthDiff})::numeric / 12)\n END)::bigint)`;\n}\n\n/** The `{ periodStart, periodEnd }` SQL expression pair for `currentPeriod(anchor, reset, now)`. */\nexport interface PeriodMathSql {\n readonly periodStart: string;\n readonly periodEnd: string;\n}\n\n/**\n * Build the `period_start`/`period_end` SQL expressions for\n * `currentPeriod(anchorRaw, resetIntervalRaw, nowRaw)` (period.ts), over\n * arbitrary column/parameter references (used against a `FOR UPDATE`-locked\n * existing row's own `anchor`/`reset_interval` — see the module header).\n *\n * Unrolls `period.ts`'s bounded-2-iteration correction loop into four\n * candidate `advance()` evaluations (offsets 0..3 from the O(1) estimate)\n * plus one `CASE` that picks the true index from two strict comparisons —\n * see the module header for the full derivation.\n */\nexport function buildPeriodMathSql(\n anchorRaw: string,\n resetIntervalRaw: string,\n nowRaw: string,\n): PeriodMathSql {\n const estimate = estimateExpr(anchorRaw, resetIntervalRaw, nowRaw);\n const index0 = `(GREATEST(0, (${estimate}) - 1))`;\n const adv = (offset: number): string =>\n advanceExpr(anchorRaw, resetIntervalRaw, `(${index0}) + ${offset}`);\n const adv0 = adv(0);\n const adv1 = adv(1);\n const adv2 = adv(2);\n const adv3 = adv(3);\n // `advance` is strictly increasing in its count argument (period.ts), so\n // comparing `nowRaw` against `adv1`/`adv2` alone determines how many of the\n // (at most 2) corrections apply — exactly `period.ts`'s while loop, unrolled.\n const increments = `(CASE WHEN ${nowRaw} < ${adv1} THEN 0 WHEN ${nowRaw} < ${adv2} THEN 1 ELSE 2 END)`;\n return {\n periodStart: `(CASE ${increments} WHEN 0 THEN ${adv0} WHEN 1 THEN ${adv1} ELSE ${adv2} END)`,\n periodEnd: `(CASE ${increments} WHEN 0 THEN ${adv1} WHEN 1 THEN ${adv2} ELSE ${adv3} END)`,\n };\n}\n","/**\n * The two ATOMIC, single-statement queries this adapter treats as its\n * headline requirement: `balances.consume` and `webhookEvents.claim`. Both\n * are built here (rather than inline in `./adapter.ts`) because they are, by\n * design, large — see each builder's own doc comment for why every piece of\n * SQL text below exists.\n *\n * KNOWN PERFORMANCE CHARACTERISTIC (flagged, not hidden):\n * `buildConsumeQuery`'s text is large (tens of KB) because `./period-sql.ts`'s\n * reset-due CASE expression is referenced multiple times (in `used`,\n * `period_start`, `period_end`, `updated_at`, and `applied`) and each\n * reference is a full, independent copy of the formula — required for\n * correctness (see `buildConsumeQuery`'s doc comment: every value must be\n * derived from the SAME locked `computed` CTE, not re-read post-write), but\n * it means this text is rebuilt and re-sent, uninterned, on every call. A\n * follow-up optimization worth doing once this can be verified against a\n * real postgres (no docker here): send it as a NAMED prepared statement\n * (`pool.query({ text, values, name })`) so postgres parses/plans it once per\n * connection and every subsequent call on that connection is a cheap\n * Bind+Execute. Not done yet — `Runner.query` and the mock-pool\n * test harness would need to grow a `name` parameter, and prepared-statement\n * behavior under pool connection churn is exactly the kind of thing this\n * environment cannot verify; a real docker-backed postgres run is the right\n * place to add and prove it.\n */\nimport { currentPeriod } from \"../../products/period\";\nimport { PW_TABLES } from \"../schema\";\nimport type { PwConsumeInput } from \"../index\";\nimport { buildPeriodMathSql } from \"./period-sql\";\n\n/** A ready-to-execute parameterized query. */\nexport interface SqlQuery {\n readonly text: string;\n readonly params: readonly unknown[];\n}\n\nconst FEATURE_BALANCES = PW_TABLES.featureBalances;\nconst WEBHOOK_EVENTS = PW_TABLES.webhookEvents;\n\n/**\n * `balances.consume` — ONE `INSERT ... ON CONFLICT ... DO UPDATE ... RETURNING`\n * statement (database.md §5's postgres bullet; the PW-704 brief's headline\n * requirement) that atomically: lazy-resets the period if due, applies the\n * `conditional` gate, and decrements — all inside a single round trip, using\n * pg's own row locking rather than a read-then-write from the application.\n *\n * ── How the atomicity actually works ─────────────────────────────────────\n * A `WITH existing AS (SELECT ... FOR UPDATE)` CTE acquires — WITHIN this\n * same statement/transaction — a row lock on the (customer, feature, group)\n * row if one exists (0 rows if this is a first touch: nothing to lock, and\n * the subsequent `INSERT`'s own unique-constraint conflict handling\n * arbitrates any race between concurrent first-touches natively). A second\n * CTE, `computed`, derives every written value AND the `applied` flag from\n * that LOCKED row (or, for a first touch, from the `init` bind parameters)\n * exactly once. The final `INSERT ... ON CONFLICT DO UPDATE` and its\n * `RETURNING` clause then simply READ `computed`'s already-decided values via\n * correlated scalar subqueries — they never re-derive `applied`/`resetDue`\n * from the table's post-write columns, because RETURNING (like any\n * UPDATE...RETURNING) reflects values AFTER the SET clause has applied them:\n * re-deriving \"was a reset due\" from the NEW `period_end` would see it\n * already rolled forward and always answer \"no\". Reading everything off the\n * pre-write, LOCKED `computed` CTE instead sidesteps that trap entirely.\n *\n * This is genuinely one network round trip (one string sent to `pg`), and\n * the row-lock scope is exactly the (customer, feature, group) row this call\n * touches — concurrent calls for OTHER rows are unaffected, and concurrent\n * calls for the SAME row serialize on the lock exactly as\n * `SELECT ... FOR UPDATE` normally does (database.md §5's own sanctioned\n * \"pg row locking\" mechanism), never a lost update.\n *\n * ── Period math ──────────────────────────────────────────────────────────\n * The FIRST-TOUCH branch needs no SQL calendar math at all — its\n * `period_start`/`period_end` are computed by calling `currentPeriod()`\n * (the real `src/products/period.ts` oracle) directly in JS from `init`, and\n * passed in as `$13`/`$14`; there is no existing row to race against for\n * that computation. Only the RESET-DUE branch (an EXISTING row whose\n * `period_end` the locked read shows as `<= now`) needs the row's OWN\n * `anchor`/`reset_interval` re-evaluated — data only visible INSIDE this\n * statement — hence `./period-sql.ts`'s hand-rolled translation of\n * `currentPeriod`, invoked here exactly once via `buildPeriodMathSql(\"e.anchor\",\n * \"e.reset_interval\", \"$5\")`.\n *\n * `init` is a creation template only: the `DO UPDATE SET`\n * clause never touches `\"limit\"`/`reset_interval`/`anchor`/`plan_id`/\n * `plan_version` — an existing row's own values for those columns always win.\n */\nexport function buildConsumeQuery(input: PwConsumeInput, newId: string): SqlQuery {\n const conditional = input.conditional === true;\n const freshPeriod = currentPeriod(\n input.init.anchor.getTime(),\n input.init.resetInterval,\n input.now.getTime(),\n );\n\n // $1 id · $2 customerId · $3 featureId · $4 group · $5 now · $6 amount ·\n // $7 conditional · $8 init.limit · $9 init.resetInterval · $10 init.anchor ·\n // $11 init.planId · $12 init.planVersion · $13 freshPeriodStart · $14 freshPeriodEnd\n const params: unknown[] = [\n newId,\n input.customerId,\n input.featureId,\n input.group,\n input.now,\n input.amount,\n conditional,\n input.init.limit,\n input.init.resetInterval,\n input.init.anchor,\n input.init.planId,\n input.init.planVersion,\n new Date(freshPeriod.start),\n new Date(freshPeriod.end),\n ];\n\n const resetDue = `($5::timestamptz >= e.period_end)`;\n const baseUsed = `(CASE WHEN ${resetDue} THEN 0 ELSE e.used END)`;\n const remaining = `(e.\"limit\" - ${baseUsed})`;\n const appliedExisting = `(($7::boolean) IS NOT TRUE OR ${remaining} >= $6::bigint)`;\n const finalUsedExisting = `(CASE WHEN ${appliedExisting} THEN ${baseUsed} + $6::bigint ELSE ${baseUsed} END)`;\n const updatedAtExisting = `(CASE WHEN (${appliedExisting} OR ${resetDue}) THEN $5::timestamptz ELSE e.updated_at END)`;\n const existingPeriod = buildPeriodMathSql(\"e.anchor\", \"e.reset_interval\", \"$5::timestamptz\");\n const periodStartExisting = `(CASE WHEN ${resetDue} THEN ${existingPeriod.periodStart} ELSE e.period_start END)`;\n const periodEndExisting = `(CASE WHEN ${resetDue} THEN ${existingPeriod.periodEnd} ELSE e.period_end END)`;\n\n const freshDenied = `(($7::boolean) IS TRUE AND $8::bigint < $6::bigint)`;\n const freshUsed = `(CASE WHEN ${freshDenied} THEN 0 ELSE $6::bigint END)`;\n const freshApplied = `(CASE WHEN ${freshDenied} THEN FALSE ELSE TRUE END)`;\n\n const text = `\nWITH existing AS (\n SELECT * FROM ${FEATURE_BALANCES}\n WHERE customer_id = $2 AND feature_id = $3 AND \"group\" = $4\n FOR UPDATE\n),\ncomputed AS (\n SELECT\n CASE WHEN e.id IS NULL THEN ${freshUsed} ELSE ${finalUsedExisting} END AS used,\n CASE WHEN e.id IS NULL THEN $13::timestamptz ELSE ${periodStartExisting} END AS period_start,\n CASE WHEN e.id IS NULL THEN $14::timestamptz ELSE ${periodEndExisting} END AS period_end,\n CASE WHEN e.id IS NULL THEN $5::timestamptz ELSE ${updatedAtExisting} END AS updated_at,\n CASE WHEN e.id IS NULL THEN ${freshApplied} ELSE ${appliedExisting} END AS applied\n FROM (SELECT 1 AS one) dummy\n LEFT JOIN existing e ON true\n)\nINSERT INTO ${FEATURE_BALANCES}\n (id, customer_id, feature_id, \"group\", used, \"limit\", reset_interval, anchor, period_start, period_end, plan_id, plan_version, updated_at)\nSELECT $1, $2, $3, $4, computed.used, $8::bigint, $9::text, $10::timestamptz, computed.period_start, computed.period_end, $11::text, $12::int, computed.updated_at\nFROM computed\nON CONFLICT (customer_id, feature_id, \"group\") DO UPDATE SET\n used = (SELECT used FROM computed),\n period_start = (SELECT period_start FROM computed),\n period_end = (SELECT period_end FROM computed),\n updated_at = (SELECT updated_at FROM computed)\nRETURNING id, customer_id, feature_id, \"group\", used, \"limit\", reset_interval, anchor, period_start, period_end, plan_id, plan_version, updated_at,\n (SELECT applied FROM computed) AS applied\n`.trim();\n\n return { text, params };\n}\n\n/**\n * `webhookEvents.claim` — one insert-or-steal statement:\n * `INSERT ... ON CONFLICT (dedupe_key) DO UPDATE SET claimed_at = EXCLUDED\n * .claimed_at WHERE applied_at IS NULL AND claimed_at <= <now - stale>\n * RETURNING dedupe_key`. When the `WHERE` condition is false (already applied,\n * or claimed too recently by someone else), postgres's `ON CONFLICT DO\n * UPDATE ... WHERE` skips the write AND omits that row from `RETURNING`\n * entirely — so `rows.length > 0` is exactly \"the caller won\", with zero\n * follow-up query (mirrors `src/db/sqlite/adapter.ts`'s identical shape,\n * translated to `$n` placeholders).\n */\nexport function buildClaimQuery(\n dedupeKey: string,\n meta: { provider: string; type: string; now: Date; staleClaimAfterMs?: number },\n defaultStaleClaimAfterMs: number,\n): SqlQuery {\n const staleClaimAfterMs = meta.staleClaimAfterMs ?? defaultStaleClaimAfterMs;\n const staleThreshold = new Date(meta.now.getTime() - staleClaimAfterMs);\n const text = `\nINSERT INTO ${WEBHOOK_EVENTS} (dedupe_key, provider, type, received_at, claimed_at, applied_at)\nVALUES ($1, $2, $3, $4::timestamptz, $5::timestamptz, NULL)\nON CONFLICT (dedupe_key) DO UPDATE SET claimed_at = EXCLUDED.claimed_at\nWHERE ${WEBHOOK_EVENTS}.applied_at IS NULL AND ${WEBHOOK_EVENTS}.claimed_at <= $6::timestamptz\nRETURNING dedupe_key\n`.trim();\n return {\n text,\n params: [dedupeKey, meta.provider, meta.type, meta.now, meta.now, staleThreshold],\n };\n}\n","/**\n * Builds a `DatabaseAdapter` (docs/v1/database.md §3) over a {@link Runner} —\n * the postgres dialect's store implementations. `balances.consume` and\n * `webhookEvents.claim` are ONE statement each (`./sql.ts` — database.md §5's\n * \"this ticket's headline\"); every other store method is a straightforward\n * parameterized query, mirroring the sqlite/drizzle adapters' shapes with\n * `$n` placeholders and native `pg` types (no manual date/bool/json\n * encode/decode — see `./rows.ts`'s header for what `pg` already does for us).\n */\nimport { PayweaveNotFoundError } from \"../../core/errors\";\nimport { currentPeriod } from \"../../products/period\";\nimport { applyMigrations, planMigrations } from \"../migrations/index\";\nimport type { DatabaseAdapter, PwConsumeInput, PwConsumeResult } from \"../index\";\nimport {\n DEFAULT_STALE_CLAIM_AFTER_MS,\n PW_ACTIVE_SUBSCRIPTION_STATUSES,\n PW_TABLES,\n type PwCustomerUpsert,\n type PwFeatureBalanceInit,\n type PwPlanVersion,\n type PwPlanVersionInput,\n type PwSubscription,\n type PwSubscriptionInput,\n type PwSubscriptionPatch,\n} from \"../schema\";\nimport { wrapDriverError } from \"./errors\";\nimport { generatePwId } from \"./id\";\nimport { PostgresMigrationExecutor } from \"./migrations-executor\";\nimport {\n rowToCustomer,\n rowToFeatureBalance,\n rowToPlanVersion,\n rowToSubscription,\n rowToWebhookEvent,\n} from \"./rows\";\nimport type { Runner } from \"./runner\";\nimport { buildClaimQuery, buildConsumeQuery } from \"./sql\";\n\nconst ACTIVE_STATUS_PLACEHOLDERS = PW_ACTIVE_SUBSCRIPTION_STATUSES.map((_, i) => `$${i + 3}`).join(\", \");\n\n/** Stable (sorted-key) JSON for order-independent structural comparison. */\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n if (value !== null && typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>\n a < b ? -1 : a > b ? 1 : 0,\n );\n return `{${entries.map(([key, val]) => `${JSON.stringify(key)}:${stableStringify(val)}`).join(\",\")}}`;\n }\n return JSON.stringify(value);\n}\n\n/** The `pw_plans` fields that define plan \"content\" — everything except id/version/pushedAt. */\ninterface PlanContent {\n group: string;\n isDefault: boolean;\n name: string | null;\n priceMinor: number | null;\n priceCurrency: string | null;\n priceInterval: string | null;\n features: unknown;\n providerRefs: unknown;\n}\n\nconst planContent = (p: PwPlanVersion | PwPlanVersionInput): PlanContent => ({\n group: p.group,\n isDefault: p.isDefault,\n name: p.name,\n priceMinor: p.priceMinor,\n priceCurrency: p.priceCurrency,\n priceInterval: p.priceInterval,\n features: p.features,\n providerRefs: p.providerRefs,\n});\n\n/** Whether `input`'s comparable fields match `active`'s — the pushVersion no-op gate. */\nfunction planContentEquals(active: PwPlanVersion, input: PwPlanVersionInput): boolean {\n return stableStringify(planContent(active)) === stableStringify(planContent(input));\n}\n\nconst SUBSCRIPTION_PATCH_FIELDS: ReadonlyArray<{\n key: keyof PwSubscriptionPatch;\n column: string;\n}> = [\n { key: \"planId\", column: \"plan_id\" },\n { key: \"planVersion\", column: \"plan_version\" },\n { key: \"status\", column: \"status\" },\n { key: \"provider\", column: \"provider\" },\n { key: \"providerSubscriptionRef\", column: \"provider_subscription_ref\" },\n { key: \"currentPeriodStart\", column: \"current_period_start\" },\n { key: \"currentPeriodEnd\", column: \"current_period_end\" },\n { key: \"cancelAtPeriodEnd\", column: \"cancel_at_period_end\" },\n];\n\n/** Build a full `DatabaseAdapter` over `runner` (postgres dialect). */\nexport function buildAdapter(runner: Runner): DatabaseAdapter {\n return {\n dialect: \"postgres\",\n customers: {\n getByExternalId: (externalId) => customersGetByExternalId(runner, externalId),\n upsert: (input) => customersUpsert(runner, input),\n linkProviderRef: (externalId, provider, ref) =>\n customersLinkProviderRef(runner, externalId, provider, ref),\n },\n plans: {\n getActiveVersion: (planId) => plansGetActiveVersion(runner, planId),\n listActive: () => plansListActive(runner),\n pushVersion: (plan) => plansPushVersion(runner, plan),\n },\n subscriptions: {\n getActive: (customerId, group) => subscriptionsGetActive(runner, customerId, group),\n create: (input) => subscriptionsCreate(runner, input),\n update: (id, patch) => subscriptionsUpdate(runner, id, patch),\n },\n balances: {\n get: (customerId, featureId, group) => balancesGet(runner, customerId, featureId, group),\n consume: (input) => balancesConsume(runner, input),\n resetTo: (customerId, featureId, group, init) =>\n balancesResetTo(runner, customerId, featureId, group, init),\n },\n webhookEvents: {\n claim: (dedupeKey, meta) => webhookEventsClaim(runner, dedupeKey, meta),\n markApplied: (dedupeKey) => webhookEventsMarkApplied(runner, dedupeKey),\n },\n migrations: {\n status: () => planMigrations(new PostgresMigrationExecutor(runner), \"postgres\"),\n apply: () => applyMigrations(new PostgresMigrationExecutor(runner), \"postgres\"),\n },\n transaction: (fn) => runner.transaction((tx) => fn(buildAdapter(tx))),\n };\n}\n\n// ── customers ────────────────────────────────────────────────────────────────\n\nasync function customersGetByExternalId(runner: Runner, externalId: string) {\n const { rows } = await runner.query(\n `SELECT * FROM ${PW_TABLES.customers} WHERE external_id = $1`,\n [externalId],\n );\n const row = rows[0];\n return row ? rowToCustomer(row) : null;\n}\n\nasync function customersUpsert(runner: Runner, input: PwCustomerUpsert) {\n const now = new Date();\n const id = generatePwId(now.getTime());\n try {\n const { rows } = await runner.query(\n `INSERT INTO ${PW_TABLES.customers} (id, external_id, provider_ids, email, created_at, updated_at)\n VALUES ($1, $2, $3::jsonb, $4, $5, $6)\n ON CONFLICT (external_id) DO UPDATE SET\n email = COALESCE(excluded.email, ${PW_TABLES.customers}.email),\n updated_at = excluded.updated_at\n RETURNING *`,\n [id, input.externalId, JSON.stringify({}), input.email ?? null, now, now],\n );\n const row = rows[0];\n if (!row) throw new Error(\"postgres adapter: customers.upsert returned no row\");\n return rowToCustomer(row);\n } catch (error) {\n throw wrapDriverError(\n error,\n `payweave/db/postgres: customers.upsert(${JSON.stringify(input.externalId)}) failed.`,\n );\n }\n}\n\nasync function customersLinkProviderRef(\n runner: Runner,\n externalId: string,\n provider: string,\n ref: string,\n): Promise<void> {\n await runner.transaction(async (tx) => {\n const { rows } = await tx.query(\n `SELECT * FROM ${PW_TABLES.customers} WHERE external_id = $1 FOR UPDATE`,\n [externalId],\n );\n const row = rows[0];\n if (!row) {\n throw new PayweaveNotFoundError(\n `payweave/db/postgres: customers.linkProviderRef: no customer with externalId ` +\n `${JSON.stringify(externalId)}.`,\n );\n }\n const customer = rowToCustomer(row);\n const providerIds = { ...customer.providerIds, [provider]: ref };\n await tx.query(\n `UPDATE ${PW_TABLES.customers} SET provider_ids = $1::jsonb, updated_at = $2 WHERE external_id = $3`,\n [JSON.stringify(providerIds), new Date(), externalId],\n );\n });\n}\n\n// ── plans ────────────────────────────────────────────────────────────────────\n\nasync function plansGetActiveVersion(runner: Runner, planId: string) {\n const { rows } = await runner.query(\n `SELECT * FROM ${PW_TABLES.plans} WHERE plan_id = $1 ORDER BY version DESC LIMIT 1`,\n [planId],\n );\n const row = rows[0];\n return row ? rowToPlanVersion(row) : null;\n}\n\nasync function plansListActive(runner: Runner) {\n const { rows } = await runner.query(\n `SELECT p.* FROM ${PW_TABLES.plans} p\n INNER JOIN (\n SELECT plan_id, MAX(version) AS version FROM ${PW_TABLES.plans} GROUP BY plan_id\n ) latest ON latest.plan_id = p.plan_id AND latest.version = p.version`,\n );\n return rows.map(rowToPlanVersion);\n}\n\nasync function plansPushVersion(runner: Runner, plan: PwPlanVersionInput): Promise<PwPlanVersion> {\n return runner.transaction(async (tx) => {\n const { rows } = await tx.query(\n `SELECT * FROM ${PW_TABLES.plans} WHERE plan_id = $1 ORDER BY version DESC LIMIT 1 FOR UPDATE`,\n [plan.planId],\n );\n const activeRow = rows[0];\n const active = activeRow ? rowToPlanVersion(activeRow) : null;\n if (active && planContentEquals(active, plan)) {\n return active;\n }\n const now = new Date();\n const id = generatePwId(now.getTime());\n const nextVersion = (active?.version ?? 0) + 1;\n const { rows: inserted } = await tx.query(\n `INSERT INTO ${PW_TABLES.plans}\n (id, plan_id, version, \"group\", is_default, name, price_minor, price_currency, price_interval, features, provider_refs, pushed_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10::jsonb, $11::jsonb, $12)\n RETURNING *`,\n [\n id,\n plan.planId,\n nextVersion,\n plan.group,\n plan.isDefault,\n plan.name,\n plan.priceMinor,\n plan.priceCurrency,\n plan.priceInterval,\n JSON.stringify(plan.features),\n JSON.stringify(plan.providerRefs),\n now,\n ],\n );\n const row = inserted[0];\n if (!row) throw new Error(\"postgres adapter: plans.pushVersion returned no row\");\n return rowToPlanVersion(row);\n });\n}\n\n// ── subscriptions ────────────────────────────────────────────────────────────\n\nasync function subscriptionsGetActive(runner: Runner, customerId: string, group: string) {\n const { rows } = await runner.query(\n `SELECT * FROM ${PW_TABLES.subscriptions}\n WHERE customer_id = $1 AND \"group\" = $2 AND status IN (${ACTIVE_STATUS_PLACEHOLDERS})`,\n [customerId, group, ...PW_ACTIVE_SUBSCRIPTION_STATUSES],\n );\n const row = rows[0];\n return row ? rowToSubscription(row) : null;\n}\n\nasync function subscriptionsCreate(\n runner: Runner,\n input: PwSubscriptionInput,\n): Promise<PwSubscription> {\n const now = new Date();\n const id = generatePwId(now.getTime());\n try {\n const { rows } = await runner.query(\n `INSERT INTO ${PW_TABLES.subscriptions}\n (id, customer_id, plan_id, plan_version, \"group\", status, provider, provider_subscription_ref,\n current_period_start, current_period_end, cancel_at_period_end, created_at, updated_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\n RETURNING *`,\n [\n id,\n input.customerId,\n input.planId,\n input.planVersion,\n input.group,\n input.status,\n input.provider,\n input.providerSubscriptionRef,\n input.currentPeriodStart,\n input.currentPeriodEnd,\n input.cancelAtPeriodEnd,\n now,\n now,\n ],\n );\n const row = rows[0];\n if (!row) throw new Error(\"postgres adapter: subscriptions.create returned no row\");\n return rowToSubscription(row);\n } catch (error) {\n throw wrapDriverError(\n error,\n `payweave/db/postgres: subscriptions.create for customer ${JSON.stringify(input.customerId)} ` +\n `group ${JSON.stringify(input.group)} violated a uniqueness rule (an active-set ` +\n \"subscription already exists for this customer/group, or another constraint failed).\",\n );\n }\n}\n\nasync function subscriptionsUpdate(\n runner: Runner,\n id: string,\n patch: PwSubscriptionPatch,\n): Promise<PwSubscription> {\n const sets: string[] = [];\n const params: unknown[] = [];\n const patchRecord = patch as Record<string, unknown>;\n for (const field of SUBSCRIPTION_PATCH_FIELDS) {\n if (!(field.key in patch) || patchRecord[field.key] === undefined) continue;\n params.push(patchRecord[field.key]);\n sets.push(`${field.column} = $${params.length}`);\n }\n params.push(new Date());\n sets.push(`updated_at = $${params.length}`);\n params.push(id);\n const idParamIndex = params.length;\n\n try {\n const { rows } = await runner.query(\n `UPDATE ${PW_TABLES.subscriptions} SET ${sets.join(\", \")} WHERE id = $${idParamIndex} RETURNING *`,\n params,\n );\n const row = rows[0];\n if (!row) {\n throw new PayweaveNotFoundError(\n `payweave/db/postgres: subscriptions.update: no subscription with id ${JSON.stringify(id)}.`,\n );\n }\n return rowToSubscription(row);\n } catch (error) {\n if (error instanceof PayweaveNotFoundError) throw error;\n throw wrapDriverError(error, `payweave/db/postgres: subscriptions.update(${JSON.stringify(id)}) failed.`);\n }\n}\n\n// ── balances ─────────────────────────────────────────────────────────────────\n\nasync function balancesGet(runner: Runner, customerId: string, featureId: string, group: string) {\n const { rows } = await runner.query(\n `SELECT * FROM ${PW_TABLES.featureBalances} WHERE customer_id = $1 AND feature_id = $2 AND \"group\" = $3`,\n [customerId, featureId, group],\n );\n const row = rows[0];\n return row ? rowToFeatureBalance(row) : null;\n}\n\n/**\n * THE hot path — see `./sql.ts`'s `buildConsumeQuery` doc comment for the\n * full atomicity design. This wrapper's only job is to build the query, send\n * it as ONE call, and map the returned row + `applied` flag.\n */\nasync function balancesConsume(runner: Runner, input: PwConsumeInput): Promise<PwConsumeResult> {\n const id = generatePwId(input.now.getTime());\n const { text, params } = buildConsumeQuery(input, id);\n try {\n const { rows } = await runner.query(text, params);\n const row = rows[0];\n if (!row) throw new Error(\"postgres adapter: balances.consume returned no row\");\n const applied = row.applied;\n if (typeof applied !== \"boolean\") {\n throw new Error(\n `postgres adapter: balances.consume's RETURNING \"applied\" column was ${typeof applied}, expected boolean`,\n );\n }\n return { ...rowToFeatureBalance(row), applied };\n } catch (error) {\n throw wrapDriverError(\n error,\n `payweave/db/postgres: balances.consume for customer ${JSON.stringify(input.customerId)} ` +\n `feature ${JSON.stringify(input.featureId)} group ${JSON.stringify(input.group)} failed.`,\n );\n }\n}\n\nasync function balancesResetTo(\n runner: Runner,\n customerId: string,\n featureId: string,\n group: string,\n init: PwFeatureBalanceInit,\n): Promise<void> {\n // No injectable clock for `resetTo` (database.md §3 — unlike `consume`, it\n // takes no `now`), so the period it derives is computed directly via the\n // real `period.ts` oracle in JS — this is an unconditional overwrite, not a\n // concurrency-sensitive decision, so there is no atomicity reason to\n // recompute it in SQL the way `consume`'s reset-due branch must.\n const now = new Date();\n const period = currentPeriod(init.anchor.getTime(), init.resetInterval, now.getTime());\n const id = generatePwId(now.getTime());\n await runner.query(\n `INSERT INTO ${PW_TABLES.featureBalances}\n (id, customer_id, feature_id, \"group\", used, \"limit\", reset_interval, anchor, period_start, period_end, plan_id, plan_version, updated_at)\n VALUES ($1, $2, $3, $4, 0, $5, $6, $7, $8, $9, $10, $11, $12)\n ON CONFLICT (customer_id, feature_id, \"group\") DO UPDATE SET\n used = 0,\n \"limit\" = excluded.\"limit\",\n reset_interval = excluded.reset_interval,\n anchor = excluded.anchor,\n period_start = excluded.period_start,\n period_end = excluded.period_end,\n plan_id = excluded.plan_id,\n plan_version = excluded.plan_version,\n updated_at = excluded.updated_at`,\n [\n id,\n customerId,\n featureId,\n group,\n init.limit,\n init.resetInterval,\n init.anchor,\n new Date(period.start),\n new Date(period.end),\n init.planId,\n init.planVersion,\n now,\n ],\n );\n}\n\n// ── webhookEvents ────────────────────────────────────────────────────────────\n\nasync function webhookEventsClaim(\n runner: Runner,\n dedupeKey: string,\n meta: { provider: string; type: string; now: Date; staleClaimAfterMs?: number },\n): Promise<boolean> {\n const { text, params } = buildClaimQuery(dedupeKey, meta, DEFAULT_STALE_CLAIM_AFTER_MS);\n const { rows } = await runner.query(text, params);\n return rows.length > 0;\n}\n\nasync function webhookEventsMarkApplied(runner: Runner, dedupeKey: string): Promise<void> {\n await runner.query(\n `UPDATE ${PW_TABLES.webhookEvents} SET applied_at = $1 WHERE dedupe_key = $2`,\n [new Date(), dedupeKey],\n );\n}\n\n// Re-exported so tests can round-trip a raw row without duplicating the\n// mapping logic (e.g. asserting `rowToWebhookEvent` matches `claim`'s writes).\nexport { rowToWebhookEvent };\n","/**\n * `payweave/db/postgres` — PostgreSQL adapter (docs/v1/database.md §1/§4,\n * PW-704). Wraps `pg` (`node-postgres`) behind the shared\n * {@link DatabaseAdapter} contract.\n *\n * `postgresAdapter(...)` accepts EITHER:\n * - `{ connectionString }` — a `postgres://`/`postgresql://` URL, validated\n * EAGERLY (synchronously, at call time); the `pg.Pool` itself is\n * constructed LAZILY, on the first store method call, via a dynamic\n * `import(\"pg\")` — so importing this subpath (or `payweave` core) never\n * pulls `pg` into the module graph unless a query actually runs\n * - An existing `pg` `Pool` instance (accepted structurally — no `pg` import\n * needed to recognize it) — used directly, and never closed by this\n * adapter (the caller owns its lifecycle, matching how the sqlite/drizzle\n * adapters treat a caller-supplied driver instance).\n *\n * Construction is synchronous and side-effect-free: the\n * input is validated (and, for a connection string, its scheme classified)\n * eagerly, but no socket opens and no query runs until the first store call.\n *\n * `balances.consume` and `webhookEvents.claim` are each ONE SQL statement\n * relying on pg's own row locking (`./sql.ts`) — this is the adapter's\n * headline requirement (database.md §5's postgres bullet): NOT a\n * read-then-write from the application, unlike the sqlite/drizzle adapters'\n * transaction-based approach to the same operations (see `./sql.ts`'s and\n * `./period-sql.ts`'s doc comments for why postgres can do this atomically in\n * one round trip and the others don't).\n */\nimport { installHintError } from \"./errors\";\nimport { PoolRunner, type Runner } from \"./runner\";\nimport { resolvePostgresInput, type PgPoolLike, type PostgresConnectTarget } from \"./url\";\nimport { buildAdapter } from \"./adapter\";\nimport type { DatabaseAdapter } from \"../index\";\n\nexport type { PgPoolClientLike, PgPoolLike, PgQueryResultLike } from \"./url\";\n\n/** `postgresAdapter(...)`'s single argument — see the module header. */\nexport type PostgresAdapterInput = { connectionString: string } | PgPoolLike;\n\nasync function openPool(connectionString: string): Promise<PgPoolLike> {\n // No explicit type annotation on `mod`: relying on inference from the\n // dynamic import expression itself (mirrors `src/db/sqlite/index.ts`'s\n // identical `better-sqlite3` comment) — `pg`'s default export is the `Pool`\n // constructor's home under Node ESM interop.\n let mod;\n try {\n mod = await import(\"pg\");\n } catch (cause) {\n throw installHintError(cause);\n }\n const Pool = (mod.default ?? mod).Pool;\n return new Pool({ connectionString }) as PgPoolLike;\n}\n\nfunction connect(target: PostgresConnectTarget): Promise<PgPoolLike> {\n return target.kind === \"pool-instance\" ? Promise.resolve(target.pool) : openPool(target.connectionString);\n}\n\n/**\n * Create a PostgreSQL-backed {@link DatabaseAdapter}. See the module header\n * for the accepted input shapes and the eager-validate/lazy-connect contract.\n *\n * @throws {PayweaveConfigError} synchronously for a non-`postgres://`/\n * `postgresql://` connection string, or an unrecognized input shape;\n * asynchronously (on first query) if the required optional peer driver\n * (`pg`) is not installed.\n */\nexport function postgresAdapter(input: PostgresAdapterInput): DatabaseAdapter {\n const target = resolvePostgresInput(input);\n let poolPromise: Promise<PgPoolLike> | undefined;\n const getPool = (): Promise<PgPoolLike> => {\n poolPromise ??= connect(target);\n return poolPromise;\n };\n\n // A thin `Runner` that resolves the lazily-constructed pool on every call —\n // `PoolRunner` itself is built once the pool is available. Store methods\n // never see the pool-vs-not-yet-connected distinction.\n const runner: Runner = {\n query: async (text, params = []) => {\n const pool = await getPool();\n return pool.query(text, params);\n },\n transaction: async (fn) => {\n const pool = await getPool();\n return new PoolRunner(pool).transaction(fn);\n },\n };\n\n return buildAdapter(runner);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { prismaAdapter } from '../../_tsup-dts-rollup.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PayweaveConfigError } from '../../chunk-HTRGMZFH.js';
|
|
2
|
+
|
|
3
|
+
// src/db/prisma/index.ts
|
|
4
|
+
var prismaAdapter = () => {
|
|
5
|
+
throw new PayweaveConfigError(
|
|
6
|
+
'payweave/db/prisma is a placeholder subpath (PW-505) \u2014 the Prisma adapter ("@prisma/client") lands with PW-707. Until it ships, pass your own implementation of the DatabaseAdapter contract from "payweave/db" (docs/v1/database.md \xA73) as `database`, or track EPIC 7 in docs/v1/backlog.md.'
|
|
7
|
+
);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export { prismaAdapter };
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/db/prisma/index.ts"],"names":[],"mappings":";;;AAkBO,IAAM,gBAA6D,MAAM;AAC9E,EAAA,MAAM,IAAI,mBAAA;AAAA,IACR;AAAA,GAIF;AACF","file":"index.js","sourcesContent":["/**\n * `payweave/db/prisma` — Prisma adapter (docs/v1/database.md; ships with PW-707).\n *\n * PW-505 wires this subpath into the exports map ahead of the implementation so\n * the import path is stable. Placeholder only: no driver code is imported here\n * — `@prisma/client` becomes an optional peerDependency in PW-707, not now\n * (database.md §7 dependency policy).\n */\nimport { PayweaveConfigError } from \"../../core/errors\";\nimport type { DatabaseAdapter } from \"../index\";\n\n/**\n * Placeholder for the Prisma-backed adapter factory. The real factory\n * accepts your existing `PrismaClient` and returns a\n * {@link DatabaseAdapter}.\n *\n * @throws {PayweaveConfigError} always — the Prisma adapter lands with PW-707.\n */\nexport const prismaAdapter: (prismaClient?: unknown) => DatabaseAdapter = () => {\n throw new PayweaveConfigError(\n 'payweave/db/prisma is a placeholder subpath (PW-505) — the Prisma adapter (\"@prisma/client\") ' +\n 'lands with PW-707. Until it ships, pass your own implementation of the DatabaseAdapter ' +\n 'contract from \"payweave/db\" (docs/v1/database.md §3) as `database`, or track EPIC 7 in ' +\n \"docs/v1/backlog.md.\",\n );\n};\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { sqliteAdapter } from '../../_tsup-dts-rollup.js';
|
|
2
|
+
export { BetterSqlite3DatabaseLike } from '../../_tsup-dts-rollup.js';
|
|
3
|
+
export { LibsqlClientLike } from '../../_tsup-dts-rollup.js';
|
|
4
|
+
export { SqliteDriverKind } from '../../_tsup-dts-rollup.js';
|
|
5
|
+
export { SqliteAdapterInput } from '../../_tsup-dts-rollup.js';
|