@yielded/auth-persistence 0.1.0-beta.11 → 0.1.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +6 -1
  2. package/dist/Adapter.d.mts +2 -2
  3. package/dist/Adapter.mjs +4 -4
  4. package/dist/internal/PasswordPreparedPostconditions.d.mts +1 -1
  5. package/dist/internal/configuration.d.mts +1 -1
  6. package/dist/internal/email-kernel.d.mts +5 -5
  7. package/dist/internal/email-kernel.mjs +8 -6
  8. package/dist/internal/email-kernel.mjs.map +1 -1
  9. package/dist/internal/models/email-model.d.mts +1 -1
  10. package/dist/internal/oauth-server.mjs +1 -1
  11. package/dist/internal/oauth-server.mjs.map +1 -1
  12. package/dist/internal/passkey/target.mjs +21 -12
  13. package/dist/internal/passkey/target.mjs.map +1 -1
  14. package/dist/internal/passkey/write-target.mjs +6 -6
  15. package/dist/internal/passkey/write-target.mjs.map +1 -1
  16. package/dist/internal/passkey-kernel.d.mts +9 -12
  17. package/dist/internal/passkeys.mjs +8 -7
  18. package/dist/internal/passkeys.mjs.map +1 -1
  19. package/dist/internal/password-kernel.d.mts +3 -3
  20. package/dist/internal/password-kernel.mjs +3 -2
  21. package/dist/internal/password-kernel.mjs.map +1 -1
  22. package/dist/internal/persistence.d.mts +3 -2
  23. package/dist/internal/persistence.mjs +22 -26
  24. package/dist/internal/persistence.mjs.map +1 -1
  25. package/dist/internal/proof-kernel.d.mts +2 -2
  26. package/dist/internal/proof-kernel.mjs +2 -1
  27. package/dist/internal/proof-kernel.mjs.map +1 -1
  28. package/dist/internal/registration.mjs +6 -1
  29. package/dist/internal/registration.mjs.map +1 -1
  30. package/dist/internal/session-kernel.d.mts +19 -9
  31. package/dist/internal/session-kernel.mjs +155 -147
  32. package/dist/internal/session-kernel.mjs.map +1 -1
  33. package/dist/internal/sql-persistence.mjs +2 -3
  34. package/dist/internal/sql-persistence.mjs.map +1 -1
  35. package/dist/internal/sql-query.mjs +4 -2
  36. package/dist/internal/sql-query.mjs.map +1 -1
  37. package/dist/internal/standalone.d.mts +2 -4
  38. package/dist/internal/standalone.mjs +2 -2
  39. package/dist/internal/standalone.mjs.map +1 -1
  40. package/dist/internal/storage-mapping.mjs +2 -2
  41. package/dist/internal/storage-validation.mjs +4 -2
  42. package/dist/internal/storage-validation.mjs.map +1 -1
  43. package/dist/internal/transaction-execution-kernel.d.mts +6 -7
  44. package/dist/internal/transaction-execution-kernel.mjs +9 -7
  45. package/dist/internal/transaction-execution-kernel.mjs.map +1 -1
  46. package/dist/internal/transaction-kernel.d.mts +7 -3
  47. package/dist/internal/transaction-kernel.mjs +5 -2
  48. package/dist/internal/transaction-kernel.mjs.map +1 -1
  49. package/package.json +1 -1
  50. package/src/Adapter.ts +6 -1
  51. package/src/internal/email-kernel.ts +30 -35
  52. package/src/internal/oauth-server.ts +1 -1
  53. package/src/internal/passkey/target.ts +36 -43
  54. package/src/internal/passkey/write-target.ts +4 -14
  55. package/src/internal/passkeys.ts +4 -9
  56. package/src/internal/password-kernel.ts +2 -2
  57. package/src/internal/persistence.ts +77 -68
  58. package/src/internal/proof-kernel.ts +2 -2
  59. package/src/internal/registration.ts +22 -7
  60. package/src/internal/session-kernel.ts +1122 -1139
  61. package/src/internal/sql-persistence.ts +1 -1
  62. package/src/internal/sql-query.ts +5 -3
  63. package/src/internal/standalone.ts +5 -7
  64. package/src/internal/storage-validation.ts +20 -16
  65. package/src/internal/transaction-execution-kernel.ts +17 -15
  66. package/src/internal/transaction-kernel.ts +7 -1
@@ -1 +1 @@
1
- {"version":3,"file":"transaction-kernel.mjs","names":[],"sources":["../../src/internal/transaction-kernel.ts"],"sourcesContent":["import { type CommitJournal, type PreparedCommit } from \"@yielded/auth/Hooks\";\nimport { reportAuthFailure } from \"@yielded/auth/Persistence\";\n/* oxlint-disable no-explicit-any -- existing storage kernels erase foreign table shapes; domain errors remain typed. */\nimport { Cause, Effect } from \"effect\";\nimport type * as SqlClient from \"effect/sql/SqlClient\";\nimport type { SqlError } from \"effect/sql/SqlError\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport type {\n SqlExpression as SQL,\n QueryFailure,\n QueryOperations,\n SqlFragment,\n SqlColumn,\n} from \"./query-operations\";\n\ntype Table = object;\n\nexport type Row = Record<string, any>;\n\n/** Only query-builder/table shapes are erased here. Installed native\n * queries have captured clients, and their error channel remains explicit. */\ntype NativeQuery<A> = Effect.Effect<A, QueryFailure | SqlError>;\n\nexport interface TransactionNativeDatabase {\n readonly $client: SqlClient.SqlClient & {\n readonly batch: (statements: ReadonlyArray<Statement<any>>) => Effect.Effect<any, SqlError>;\n };\n readonly transaction: <A, E, R>(\n body: (transaction: any) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SqlError, R>;\n}\n\nexport interface Observation {\n readonly table: Table;\n readonly where: SQL;\n rows: ReadonlyArray<Row>;\n}\n\n/** Expressions deliberately do not replace observed values. Read only semantic\n * columns when telemetry changes atomically, and state the physical result. */\nexport interface GuardedUpdate {\n readonly rows: number;\n readonly postcondition: SQL;\n}\n\nexport interface TransactionOwner<Failure> {\n readonly database: any;\n readonly journal: CommitJournal;\n readonly marker: string;\n readonly batch: boolean;\n readonly observations: Observation[];\n readonly postconditions: Array<SQL | (() => SQL)>;\n readonly statements: Statement<any>[];\n readonly guards: PreparedCommit<void>[];\n exact(table: Table, row: Row): SQL;\n read(\n table: Table,\n where: SQL,\n options?: {\n readonly lock?: boolean;\n readonly limit?: number;\n readonly observe?: boolean;\n readonly admissionOnly?: boolean;\n readonly takeOnly?: boolean;\n readonly orderBy?: any;\n readonly columns?: ReadonlyArray<string>;\n },\n ): Effect.Effect<Observation, Failure>;\n write(query: any): Effect.Effect<void, Failure>;\n insert(\n table: Table,\n values: Row,\n key: Row,\n absent?: boolean,\n ): Effect.Effect<Observation, Failure>;\n update(table: Table, key: Row, values: Row): Effect.Effect<void, Failure>;\n updateGuarded(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n /** Internal SQL only, run once after application work and before final guards. */\n finalUpdate(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n remove(table: Table, key: Row): Effect.Effect<void, Failure>;\n check(condition: SQL): Effect.Effect<boolean, Failure>;\n now(clock: { readonly engineNowMillis: SQL }): Effect.Effect<number, Failure>;\n finish(): Effect.Effect<void, Failure>;\n}\n\nexport const makeTransactionKernel = <\n Fragment extends SqlFragment = SqlFragment,\n Column extends SqlColumn = SqlColumn,\n>(\n operations: QueryOperations<Fragment, Column>,\n) => {\n const { eq, getTableColumns, isNull, sql, balancedD1And, compactD1GeneratedStatement } =\n operations;\n\n const isUnavailableCause = <Failure>(cause: Cause.Cause<unknown>, unavailable: () => Failure) => {\n const expected = unavailable();\n\n const tag =\n typeof expected === \"object\" && expected !== null && \"_tag\" in expected\n ? expected._tag\n : undefined;\n\n return (\n tag !== undefined &&\n cause.reasons.length > 0 &&\n cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n typeof reason.error === \"object\" &&\n reason.error !== null &&\n \"_tag\" in reason.error &&\n reason.error._tag === tag,\n )\n );\n };\n\n /** Report once, before an adapter replaces the raw cause with its public\n * unavailable error. Already translated failures stay quiet at outer owners. */\n const reportTransactionFailure = <A, E, R, Failure>(\n effect: Effect.Effect<A, E, R>,\n unavailable: () => Failure,\n ): Effect.Effect<A, E, R> =>\n Effect.catchCause(effect, (cause) =>\n isUnavailableCause(cause, unavailable)\n ? Effect.failCause(cause)\n : reportAuthFailure(\"auth-persistence\", cause).pipe(\n Effect.andThen(Effect.failCause(cause)),\n ),\n );\n\n const both = (...parts: ReadonlyArray<SQL | undefined>) => balancedD1And(...parts) ?? sql`1 = 1`;\n\n const makeTransactionRows = <Failure>(unavailable: () => Failure) => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const col = (table: Table, key: string) => {\n const value = getTableColumns(table)[key];\n\n invariant(value !== undefined);\n\n return value;\n };\n\n const equal = (table: Table, values: Row) =>\n both(\n ...Object.entries(values).map(([key, value]) =>\n value === null ? isNull(col(table, key)) : eq(col(table, key), value),\n ),\n );\n\n /** Mapped driver values use plain data, Dates and binary views. Application\n * identity classes are reconstructed by the mapped codecs, never cloned here. */\n const copiedRow = (row: Row) => {\n const seen = new WeakSet<object>();\n\n const supported = (value: unknown): void => {\n if (value === null || typeof value !== \"object\" || seen.has(value)) return;\n seen.add(value);\n if (value instanceof Date || value instanceof ArrayBuffer || ArrayBuffer.isView(value))\n return;\n invariant(\n Array.isArray(value) ||\n Object.getPrototypeOf(value) === Object.prototype ||\n Object.getPrototypeOf(value) === null,\n );\n for (const item of Object.values(value)) supported(item);\n };\n\n supported(row);\n\n return structuredClone(row);\n };\n\n const nativeKey = (value: unknown): string => {\n const packed = (tag: string, text: string) => tag + text.length + \":\" + text;\n\n if (value instanceof Date) return packed(\"date\", value.toISOString());\n if (typeof value === \"bigint\") return packed(\"bigint\", value.toString());\n\n const bytes =\n value instanceof ArrayBuffer\n ? new Uint8Array(value)\n : ArrayBuffer.isView(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : undefined;\n\n if (bytes !== undefined) return packed(\"bytes\", Array.from(bytes).join(\",\"));\n if (value === null || typeof value !== \"object\") return packed(typeof value, String(value));\n if (Array.isArray(value)) return packed(\"array\", value.map(nativeKey).join(\"\"));\n invariant(\n Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null,\n );\n\n return packed(\n \"object\",\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([name, item]) => nativeKey(name) + nativeKey(item))\n .join(\"\"),\n );\n };\n\n const matchesNativeRow = (table: Table, row: Row, key: Row) =>\n Object.entries(key).every(([name, value]) => {\n if (value === null || row[name] === null) return value === row[name];\n const column = col(table, name);\n\n return (\n nativeKey(column.mapToDriverValue(row[name])) ===\n nativeKey(column.mapToDriverValue(value))\n );\n });\n\n return { col, equal, copiedRow, matchesNativeRow };\n };\n\n const makeTransactionOwner = <Failure>(\n database: any,\n journal: CommitJournal,\n marker: string,\n unavailable: () => Failure,\n configuration: {\n readonly client?: any;\n readonly batch: boolean;\n readonly locking: boolean;\n readonly mysql: boolean;\n readonly dialect: \"pg\" | \"mysql\" | \"sqlite\";\n },\n ): TransactionOwner<Failure> => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const { col, equal, matchesNativeRow } = makeTransactionRows(unavailable);\n let phase: \"open\" | \"finishing\" | \"finished\" = \"open\";\n let poisoned = false;\n const open = () => invariant(phase === \"open\" && !poisoned);\n\n const result = <A, E>(effect: Effect.Effect<A, E>) =>\n effect.pipe(\n (operation) => reportTransactionFailure(operation, unavailable),\n Effect.mapError(unavailable),\n Effect.catchDefect(() => Effect.fail(unavailable())),\n Effect.onExit((exit) =>\n Effect.sync(() => {\n if (exit._tag === \"Failure\") poisoned = true;\n }),\n ),\n );\n\n const observations: Observation[] = [];\n const statements: Statement<any>[] = [];\n const postconditions: Array<SQL | (() => SQL)> = [];\n const guards: PreparedCommit<void>[] = [];\n const finalUpdates: Array<{ readonly query: any; readonly guard: GuardedUpdate }> = [];\n\n const exactRow = (table: Table, row: Row) =>\n both(\n ...Object.entries(row).map(([key, value]) => {\n if (typeof value !== \"string\") return equal(table, { [key]: value });\n\n const column = col(table, key),\n bound = sql.param(value, column);\n\n return configuration.dialect === \"mysql\"\n ? sql`binary ${column} = binary ${bound}`\n : configuration.dialect === \"pg\"\n ? sql`convert_to(cast(${column} as text), 'UTF8') = convert_to(cast(${bound} as text), 'UTF8')`\n : sql`cast(${column} as blob) = cast(${bound} as blob)`;\n }),\n );\n\n const toStatement = (query: any): Statement<any> => {\n const rendered = query.toSQL();\n const client = configuration.client ?? database.$client;\n\n return compactD1GeneratedStatement(\n client,\n client.unsafe(rendered.sql, rendered.params),\n unavailable,\n );\n };\n\n const assertion = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else json_extract('[]', ${\"$[oauth-owner-\" + marker + \"]\"}) end`,\n })\n .from(sql`(select 1) as oauth_assertion`);\n\n const observedConditions = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => [\n sql`(select count(*) from ${table} where ${where}) = ${rows.length}`,\n ...rows.map(\n (row) => sql`exists(select 1 from ${table} where ${both(where, exactRow(table, row))})`,\n ),\n ];\n\n // All chunks remain inside the same native owner or atomic D1 batch. A single\n // wide row is compacted; separate observations cannot accumulate unbounded\n // bind parameters or expression depth in one final SELECT.\n const chunks = (conditions: ReadonlyArray<SQL>) => {\n const output: SQL[] = [];\n let pending: SQL[] = [];\n\n for (const condition of conditions) {\n const candidate = [...pending, condition];\n const rendered = assertion(both(...candidate)).toSQL();\n\n if (\n pending.length > 0 &&\n (rendered.params.length > 96 || new TextEncoder().encode(rendered.sql).length > 48_000)\n ) {\n output.push(both(...pending));\n pending = [condition];\n } else pending = candidate;\n }\n if (pending.length > 0) output.push(both(...pending));\n\n return output;\n };\n\n const appendAssertions = (conditions: ReadonlyArray<SQL>) => {\n for (const condition of chunks(conditions))\n statements.push(toStatement(assertion(condition)));\n };\n\n const observed = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => {\n const observation = { table, where, rows };\n\n observations.push(observation);\n\n return observation;\n };\n\n const queryCondition = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else 0 end`.mapWith(Number).as(\"value\"),\n })\n .from(sql`(select 1) as oauth_guard`);\n\n const conditionHolds = (condition: SQL) =>\n Effect.gen(function* () {\n const query = queryCondition(condition);\n\n const rows: ReadonlyArray<Row> = yield* configuration.dialect === \"sqlite\"\n ? toStatement(query)\n : (query as NativeQuery<Row[]>);\n\n invariant(rows.length === 1);\n\n return rows[0]!.value === 1;\n });\n\n const guardedQuery = (table: Table, where: SQL, values: Row, guard: GuardedUpdate) => {\n invariant(Number.isSafeInteger(guard.rows) && guard.rows > 0 && guard.rows <= 128);\n\n return { query: database.update(table).set(values).where(where), guard: { ...guard } };\n };\n\n const applyGuarded = (entry: { readonly query: any; readonly guard: GuardedUpdate }) =>\n Effect.gen(function* () {\n if (configuration.batch) {\n statements.push(toStatement(entry.query));\n statements.push(toStatement(assertion(sql`changes() = ${entry.guard.rows}`)));\n appendAssertions([entry.guard.postcondition]);\n } else {\n if (configuration.mysql) {\n // mysql2 reports matched rows (FOUND_ROWS), including a telemetry no-op.\n const changed = yield* entry.query as NativeQuery<{ readonly affectedRows: number }>;\n\n invariant(changed.affectedRows === entry.guard.rows);\n } else {\n const changed = yield* entry.query.returning({ value: sql`1` }) as NativeQuery<\n ReadonlyArray<Row>\n >;\n\n invariant(changed.length === entry.guard.rows);\n }\n invariant(yield* conditionHolds(entry.guard.postcondition));\n }\n });\n\n const owner: TransactionOwner<Failure> = {\n database,\n journal,\n marker,\n batch: configuration.batch,\n observations,\n statements,\n postconditions,\n guards,\n exact: exactRow,\n read: (table, where, options = {}) =>\n result(\n Effect.gen(function* () {\n open();\n const limit = options.limit ?? 64;\n\n let query = database\n .select(\n options.columns === undefined\n ? undefined\n : Object.fromEntries(options.columns.map((key) => [key, col(table, key)])),\n )\n .from(table)\n .where(where)\n .limit(options.takeOnly ? limit : limit + 1);\n\n if (options.orderBy !== undefined) query = query.orderBy(options.orderBy);\n if (options.lock !== false && configuration.locking) query = query.for(\"update\");\n const rows: Row[] = yield* query as NativeQuery<Row[]>;\n\n invariant(rows.length <= limit);\n if (configuration.batch && (options.observe !== false || options.admissionOnly))\n appendAssertions(observedConditions(table, where, rows));\n\n return options.observe === false || options.admissionOnly\n ? { table, where, rows }\n : observed(table, where, rows);\n }),\n ),\n write: (query) =>\n result(\n Effect.gen(function* () {\n open();\n if (configuration.batch) statements.push(toStatement(query));\n else yield* query as NativeQuery<unknown>;\n }),\n ),\n insert: (table, values, key, absent = false) =>\n result(\n Effect.gen(function* () {\n open();\n let query = database.insert(table).values(values);\n\n if (absent)\n query = configuration.mysql\n ? query.onDuplicateKeyUpdate({\n set: { [Object.keys(key)[0]!]: col(table, Object.keys(key)[0]!) },\n })\n : query.onConflictDoNothing();\n yield* owner.write(query);\n const where = equal(table, key);\n\n if (configuration.batch) return observed(table, where, [values]);\n const found = yield* owner.read(table, where, { limit: 1 });\n const markerColumn = Object.keys(values).find((key) => values[key] === marker);\n\n if (!absent || (markerColumn !== undefined && found.rows[0]?.[markerColumn] === marker))\n invariant(\n yield* owner.check(\n sql`exists(select 1 from ${table} where ${both(where, exactRow(table, values))})`,\n ),\n );\n\n return found;\n }),\n ),\n update: (table, key, values) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.update(table).set(values).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.map((row) =>\n matchesNativeRow(table, row, key) ? { ...row, ...values } : row,\n );\n }),\n ),\n updateGuarded: (table, where, values, guard) =>\n result(\n Effect.gen(function* () {\n open();\n const entry = guardedQuery(table, where, values, guard);\n\n yield* applyGuarded(entry);\n postconditions.push(entry.guard.postcondition);\n }),\n ),\n finalUpdate: (table, where, values, guard) =>\n result(\n Effect.sync(() => {\n open();\n invariant(finalUpdates.length < 128);\n finalUpdates.push(guardedQuery(table, where, values, guard));\n }),\n ),\n remove: (table, key) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.delete(table).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.filter(\n (row) => !matchesNativeRow(table, row, key),\n );\n }),\n ),\n check: (condition) =>\n result(\n Effect.gen(function* () {\n open();\n const holds = yield* conditionHolds(condition);\n\n if (configuration.batch)\n statements.push(toStatement(assertion(holds ? condition : sql`not (${condition})`)));\n\n return holds;\n }),\n ),\n now: (clock) =>\n result(\n Effect.gen(function* () {\n open();\n\n const rows: Row[] = yield* database\n .select({\n value: sql`${clock.engineNowMillis}`.mapWith(Number),\n })\n .from(sql`(select 1) as oauth_clock`) as NativeQuery<Row[]>;\n\n const value = rows[0]?.value;\n\n invariant(Number.isSafeInteger(value) && value >= 0);\n\n return value as number;\n }),\n ),\n finish: () =>\n result(\n Effect.gen(function* () {\n open();\n phase = \"finishing\";\n Object.freeze(observations);\n Object.freeze(postconditions);\n Object.freeze(guards);\n Object.freeze(finalUpdates);\n\n // Close registration before any late-bound SQL predicate is materialized.\n // No callback is invoked after the first final write.\n const conditions: SQL[] = observations.flatMap((observation) =>\n observedConditions(observation.table, observation.where, observation.rows),\n );\n\n conditions.push(\n ...postconditions.map((condition) =>\n typeof condition === \"function\" ? condition() : condition,\n ),\n );\n conditions.push(...finalUpdates.map((entry) => entry.guard.postcondition));\n for (const guard of guards) {\n const status = yield* Effect.result(guard.read);\n\n invariant(status._tag === \"Failure\" && status.failure._tag === \"CommitPending\");\n }\n invariant(!poisoned);\n for (const entry of finalUpdates) yield* applyGuarded(entry);\n if (configuration.batch) appendAssertions(conditions);\n else\n for (const condition of chunks(conditions))\n invariant(yield* conditionHolds(condition));\n invariant(!poisoned);\n }).pipe(\n Effect.ensuring(\n Effect.sync(() => {\n phase = \"finished\";\n }),\n ),\n ),\n ),\n };\n\n return owner;\n };\n\n return { reportTransactionFailure, both, makeTransactionRows, makeTransactionOwner };\n};\n"],"mappings":";;;;AAgGA,MAAa,yBAIX,eACG;CACH,MAAM,EAAE,IAAI,iBAAiB,QAAQ,KAAK,eAAe,gCACvD;CAEF,MAAM,sBAA+B,OAA6B,gBAA+B;EAC/F,MAAM,WAAW,YAAY;EAE7B,MAAM,MACJ,OAAO,aAAa,YAAY,aAAa,QAAQ,UAAU,WAC3D,SAAS,OACT,KAAA;EAEN,OACE,QAAQ,KAAA,KACR,MAAM,QAAQ,SAAS,KACvB,MAAM,QAAQ,OACX,WACC,MAAM,aAAa,MAAM,KACzB,OAAO,OAAO,UAAU,YACxB,OAAO,UAAU,QACjB,UAAU,OAAO,SACjB,OAAO,MAAM,SAAS,GAC1B;CAEJ;;;CAIA,MAAM,4BACJ,QACA,gBAEA,OAAO,WAAW,SAAS,UACzB,mBAAmB,OAAO,WAAW,IACjC,OAAO,UAAU,KAAK,IACtB,kBAAkB,oBAAoB,KAAK,CAAC,CAAC,KAC3C,OAAO,QAAQ,OAAO,UAAU,KAAK,CAAC,CACxC,CACN;CAEF,MAAM,QAAQ,GAAG,UAA0C,cAAc,GAAG,KAAK,KAAK,GAAG;CAEzF,MAAM,uBAAgC,gBAA+B;EACnE,MAAM,aAAgD,UAAU;GAC9D,IAAI,CAAC,OAAO,MAAM,YAAY;EAChC;EAEA,MAAM,OAAO,OAAc,QAAgB;GACzC,MAAM,QAAQ,gBAAgB,KAAK,CAAC,CAAC;GAErC,UAAU,UAAU,KAAA,CAAS;GAE7B,OAAO;EACT;EAEA,MAAM,SAAS,OAAc,WAC3B,KACE,GAAG,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WACnC,UAAU,OAAO,OAAO,IAAI,OAAO,GAAG,CAAC,IAAI,GAAG,IAAI,OAAO,GAAG,GAAG,KAAK,CACtE,CACF;;;EAIF,MAAM,aAAa,QAAa;GAC9B,MAAM,uBAAO,IAAI,QAAgB;GAEjC,MAAM,aAAa,UAAyB;IAC1C,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,KAAK,IAAI,KAAK,GAAG;IACpE,KAAK,IAAI,KAAK;IACd,IAAI,iBAAiB,QAAQ,iBAAiB,eAAe,YAAY,OAAO,KAAK,GACnF;IACF,UACE,MAAM,QAAQ,KAAK,KACjB,OAAO,eAAe,KAAK,MAAM,OAAO,aACxC,OAAO,eAAe,KAAK,MAAM,IACrC;IACA,KAAK,MAAM,QAAQ,OAAO,OAAO,KAAK,GAAG,UAAU,IAAI;GACzD;GAEA,UAAU,GAAG;GAEb,OAAO,gBAAgB,GAAG;EAC5B;EAEA,MAAM,aAAa,UAA2B;GAC5C,MAAM,UAAU,KAAa,SAAiB,MAAM,KAAK,SAAS,MAAM;GAExE,IAAI,iBAAiB,MAAM,OAAO,OAAO,QAAQ,MAAM,YAAY,CAAC;GACpE,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,UAAU,MAAM,SAAS,CAAC;GAEvE,MAAM,QACJ,iBAAiB,cACb,IAAI,WAAW,KAAK,IACpB,YAAY,OAAO,KAAK,IACtB,IAAI,WAAW,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU,IAC/D,KAAA;GAER,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,SAAS,MAAM,KAAK,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC;GAC3E,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK,CAAC;GAC1F,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC;GAC9E,UACE,OAAO,eAAe,KAAK,MAAM,OAAO,aAAa,OAAO,eAAe,KAAK,MAAM,IACxF;GAEA,OAAO,OACL,UACA,OAAO,QAAQ,KAAK,CAAC,CAClB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CACtC,KAAK,CAAC,MAAM,UAAU,UAAU,IAAI,IAAI,UAAU,IAAI,CAAC,CAAC,CACxD,KAAK,EAAE,CACZ;EACF;EAEA,MAAM,oBAAoB,OAAc,KAAU,QAChD,OAAO,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,WAAW;GAC3C,IAAI,UAAU,QAAQ,IAAI,UAAU,MAAM,OAAO,UAAU,IAAI;GAC/D,MAAM,SAAS,IAAI,OAAO,IAAI;GAE9B,OACE,UAAU,OAAO,iBAAiB,IAAI,KAAK,CAAC,MAC5C,UAAU,OAAO,iBAAiB,KAAK,CAAC;EAE5C,CAAC;EAEH,OAAO;GAAE;GAAK;GAAO;GAAW;EAAiB;CACnD;CAEA,MAAM,wBACJ,UACA,SACA,QACA,aACA,kBAO8B;EAC9B,MAAM,aAAgD,UAAU;GAC9D,IAAI,CAAC,OAAO,MAAM,YAAY;EAChC;EAEA,MAAM,EAAE,KAAK,OAAO,qBAAqB,oBAAoB,WAAW;EACxE,IAAI,QAA2C;EAC/C,IAAI,WAAW;EACf,MAAM,aAAa,UAAU,UAAU,UAAU,CAAC,QAAQ;EAE1D,MAAM,UAAgB,WACpB,OAAO,MACJ,cAAc,yBAAyB,WAAW,WAAW,GAC9D,OAAO,SAAS,WAAW,GAC3B,OAAO,kBAAkB,OAAO,KAAK,YAAY,CAAC,CAAC,GACnD,OAAO,QAAQ,SACb,OAAO,WAAW;GAChB,IAAI,KAAK,SAAS,WAAW,WAAW;EAC1C,CAAC,CACH,CACF;EAEF,MAAM,eAA8B,CAAC;EACrC,MAAM,aAA+B,CAAC;EACtC,MAAM,iBAA2C,CAAC;EAClD,MAAM,SAAiC,CAAC;EACxC,MAAM,eAA8E,CAAC;EAErF,MAAM,YAAY,OAAc,QAC9B,KACE,GAAG,OAAO,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW;GAC3C,IAAI,OAAO,UAAU,UAAU,OAAO,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC;GAEnE,MAAM,SAAS,IAAI,OAAO,GAAG,GAC3B,QAAQ,IAAI,MAAM,OAAO,MAAM;GAEjC,OAAO,cAAc,YAAY,UAC7B,GAAG,UAAU,OAAO,YAAY,UAChC,cAAc,YAAY,OACxB,GAAG,mBAAmB,OAAO,uCAAuC,MAAM,sBAC1E,GAAG,QAAQ,OAAO,mBAAmB,MAAM;EACnD,CAAC,CACH;EAEF,MAAM,eAAe,UAA+B;GAClD,MAAM,WAAW,MAAM,MAAM;GAC7B,MAAM,SAAS,cAAc,UAAU,SAAS;GAEhD,OAAO,4BACL,QACA,OAAO,OAAO,SAAS,KAAK,SAAS,MAAM,GAC3C,WACF;EACF;EAEA,MAAM,aAAa,cACjB,SACG,OAAO,EACN,OAAO,GAAG,aAAa,UAAU,kCAAkC,mBAAmB,SAAS,IAAI,OACrG,CAAC,CAAC,CACD,KAAK,GAAG,+BAA+B;EAE5C,MAAM,sBAAsB,OAAc,OAAY,SAA6B,CACjF,GAAG,yBAAyB,MAAM,SAAS,MAAM,MAAM,KAAK,UAC5D,GAAG,KAAK,KACL,QAAQ,GAAG,wBAAwB,MAAM,SAAS,KAAK,OAAO,SAAS,OAAO,GAAG,CAAC,EAAE,EACvF,CACF;EAKA,MAAM,UAAU,eAAmC;GACjD,MAAM,SAAgB,CAAC;GACvB,IAAI,UAAiB,CAAC;GAEtB,KAAK,MAAM,aAAa,YAAY;IAClC,MAAM,YAAY,CAAC,GAAG,SAAS,SAAS;IACxC,MAAM,WAAW,UAAU,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM;IAErD,IACE,QAAQ,SAAS,MAChB,SAAS,OAAO,SAAS,MAAM,IAAI,YAAY,CAAC,CAAC,OAAO,SAAS,GAAG,CAAC,CAAC,SAAS,OAChF;KACA,OAAO,KAAK,KAAK,GAAG,OAAO,CAAC;KAC5B,UAAU,CAAC,SAAS;IACtB,OAAO,UAAU;GACnB;GACA,IAAI,QAAQ,SAAS,GAAG,OAAO,KAAK,KAAK,GAAG,OAAO,CAAC;GAEpD,OAAO;EACT;EAEA,MAAM,oBAAoB,eAAmC;GAC3D,KAAK,MAAM,aAAa,OAAO,UAAU,GACvC,WAAW,KAAK,YAAY,UAAU,SAAS,CAAC,CAAC;EACrD;EAEA,MAAM,YAAY,OAAc,OAAY,SAA6B;GACvE,MAAM,cAAc;IAAE;IAAO;IAAO;GAAK;GAEzC,aAAa,KAAK,WAAW;GAE7B,OAAO;EACT;EAEA,MAAM,kBAAkB,cACtB,SACG,OAAO,EACN,OAAO,GAAG,aAAa,UAAU,oBAAoB,QAAQ,MAAM,CAAC,CAAC,GAAG,OAAO,EACjF,CAAC,CAAC,CACD,KAAK,GAAG,2BAA2B;EAExC,MAAM,kBAAkB,cACtB,OAAO,IAAI,aAAa;GACtB,MAAM,QAAQ,eAAe,SAAS;GAEtC,MAAM,OAA2B,OAAO,cAAc,YAAY,WAC9D,YAAY,KAAK,IAChB;GAEL,UAAU,KAAK,WAAW,CAAC;GAE3B,OAAO,KAAK,EAAE,CAAE,UAAU;EAC5B,CAAC;EAEH,MAAM,gBAAgB,OAAc,OAAY,QAAa,UAAyB;GACpF,UAAU,OAAO,cAAc,MAAM,IAAI,KAAK,MAAM,OAAO,KAAK,MAAM,QAAQ,GAAG;GAEjF,OAAO;IAAE,OAAO,SAAS,OAAO,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,KAAK;IAAG,OAAO,EAAE,GAAG,MAAM;GAAE;EACvF;EAEA,MAAM,gBAAgB,UACpB,OAAO,IAAI,aAAa;GACtB,IAAI,cAAc,OAAO;IACvB,WAAW,KAAK,YAAY,MAAM,KAAK,CAAC;IACxC,WAAW,KAAK,YAAY,UAAU,GAAG,eAAe,MAAM,MAAM,MAAM,CAAC,CAAC;IAC5E,iBAAiB,CAAC,MAAM,MAAM,aAAa,CAAC;GAC9C,OAAO;IACL,IAAI,cAAc,OAAO;KAEvB,MAAM,UAAU,OAAO,MAAM;KAE7B,UAAU,QAAQ,iBAAiB,MAAM,MAAM,IAAI;IACrD,OAAO;KACL,MAAM,UAAU,OAAO,MAAM,MAAM,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;KAI9D,UAAU,QAAQ,WAAW,MAAM,MAAM,IAAI;IAC/C;IACA,UAAU,OAAO,eAAe,MAAM,MAAM,aAAa,CAAC;GAC5D;EACF,CAAC;EAEH,MAAM,QAAmC;GACvC;GACA;GACA;GACA,OAAO,cAAc;GACrB;GACA;GACA;GACA;GACA,OAAO;GACP,OAAO,OAAO,OAAO,UAAU,CAAC,MAC9B,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,MAAM,QAAQ,QAAQ,SAAS;IAE/B,IAAI,QAAQ,SACT,OACC,QAAQ,YAAY,KAAA,IAChB,KAAA,IACA,OAAO,YAAY,QAAQ,QAAQ,KAAK,QAAQ,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,CAC7E,CAAC,CACA,KAAK,KAAK,CAAC,CACX,MAAM,KAAK,CAAC,CACZ,MAAM,QAAQ,WAAW,QAAQ,QAAQ,CAAC;IAE7C,IAAI,QAAQ,YAAY,KAAA,GAAW,QAAQ,MAAM,QAAQ,QAAQ,OAAO;IACxE,IAAI,QAAQ,SAAS,SAAS,cAAc,SAAS,QAAQ,MAAM,IAAI,QAAQ;IAC/E,MAAM,OAAc,OAAO;IAE3B,UAAU,KAAK,UAAU,KAAK;IAC9B,IAAI,cAAc,UAAU,QAAQ,YAAY,SAAS,QAAQ,gBAC/D,iBAAiB,mBAAmB,OAAO,OAAO,IAAI,CAAC;IAEzD,OAAO,QAAQ,YAAY,SAAS,QAAQ,gBACxC;KAAE;KAAO;KAAO;IAAK,IACrB,SAAS,OAAO,OAAO,IAAI;GACjC,CAAC,CACH;GACF,QAAQ,UACN,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,IAAI,cAAc,OAAO,WAAW,KAAK,YAAY,KAAK,CAAC;SACtD,OAAO;GACd,CAAC,CACH;GACF,SAAS,OAAO,QAAQ,KAAK,SAAS,UACpC,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,IAAI,QAAQ,SAAS,OAAO,KAAK,CAAC,CAAC,OAAO,MAAM;IAEhD,IAAI,QACF,QAAQ,cAAc,QAClB,MAAM,qBAAqB,EACzB,KAAK,GAAG,OAAO,KAAK,GAAG,CAAC,CAAC,KAAM,IAAI,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,EAAG,EAAE,EAClE,CAAC,IACD,MAAM,oBAAoB;IAChC,OAAO,MAAM,MAAM,KAAK;IACxB,MAAM,QAAQ,MAAM,OAAO,GAAG;IAE9B,IAAI,cAAc,OAAO,OAAO,SAAS,OAAO,OAAO,CAAC,MAAM,CAAC;IAC/D,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,OAAO,EAAE,OAAO,EAAE,CAAC;IAC1D,MAAM,eAAe,OAAO,KAAK,MAAM,CAAC,CAAC,MAAM,QAAQ,OAAO,SAAS,MAAM;IAE7E,IAAI,CAAC,UAAW,iBAAiB,KAAA,KAAa,MAAM,KAAK,EAAE,GAAG,kBAAkB,QAC9E,UACE,OAAO,MAAM,MACX,GAAG,wBAAwB,MAAM,SAAS,KAAK,OAAO,SAAS,OAAO,MAAM,CAAC,EAAE,EACjF,CACF;IAEF,OAAO;GACT,CAAC,CACH;GACF,SAAS,OAAO,KAAK,WACnB,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,OAAO,MAAM,MAAM,SAAS,OAAO,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC;IAC9E,KAAK,MAAM,eAAe,cACxB,IAAI,YAAY,UAAU,OACxB,YAAY,OAAO,YAAY,KAAK,KAAK,QACvC,iBAAiB,OAAO,KAAK,GAAG,IAAI;KAAE,GAAG;KAAK,GAAG;IAAO,IAAI,GAC9D;GACN,CAAC,CACH;GACF,gBAAgB,OAAO,OAAO,QAAQ,UACpC,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,MAAM,QAAQ,aAAa,OAAO,OAAO,QAAQ,KAAK;IAEtD,OAAO,aAAa,KAAK;IACzB,eAAe,KAAK,MAAM,MAAM,aAAa;GAC/C,CAAC,CACH;GACF,cAAc,OAAO,OAAO,QAAQ,UAClC,OACE,OAAO,WAAW;IAChB,KAAK;IACL,UAAU,aAAa,SAAS,GAAG;IACnC,aAAa,KAAK,aAAa,OAAO,OAAO,QAAQ,KAAK,CAAC;GAC7D,CAAC,CACH;GACF,SAAS,OAAO,QACd,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,OAAO,MAAM,MAAM,SAAS,OAAO,KAAK,CAAC,CAAC,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC;IAClE,KAAK,MAAM,eAAe,cACxB,IAAI,YAAY,UAAU,OACxB,YAAY,OAAO,YAAY,KAAK,QACjC,QAAQ,CAAC,iBAAiB,OAAO,KAAK,GAAG,CAC5C;GACN,CAAC,CACH;GACF,QAAQ,cACN,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,MAAM,QAAQ,OAAO,eAAe,SAAS;IAE7C,IAAI,cAAc,OAChB,WAAW,KAAK,YAAY,UAAU,QAAQ,YAAY,GAAG,QAAQ,UAAU,EAAE,CAAC,CAAC;IAErF,OAAO;GACT,CAAC,CACH;GACF,MAAM,UACJ,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IAQL,MAAM,SAAQ,OANa,SACxB,OAAO,EACN,OAAO,GAAG,GAAG,MAAM,kBAAkB,QAAQ,MAAM,EACrD,CAAC,CAAC,CACD,KAAK,GAAG,2BAA2B,EAAA,CAEnB,EAAE,EAAE;IAEvB,UAAU,OAAO,cAAc,KAAK,KAAK,SAAS,CAAC;IAEnD,OAAO;GACT,CAAC,CACH;GACF,cACE,OACE,OAAO,IAAI,aAAa;IACtB,KAAK;IACL,QAAQ;IACR,OAAO,OAAO,YAAY;IAC1B,OAAO,OAAO,cAAc;IAC5B,OAAO,OAAO,MAAM;IACpB,OAAO,OAAO,YAAY;IAI1B,MAAM,aAAoB,aAAa,SAAS,gBAC9C,mBAAmB,YAAY,OAAO,YAAY,OAAO,YAAY,IAAI,CAC3E;IAEA,WAAW,KACT,GAAG,eAAe,KAAK,cACrB,OAAO,cAAc,aAAa,UAAU,IAAI,SAClD,CACF;IACA,WAAW,KAAK,GAAG,aAAa,KAAK,UAAU,MAAM,MAAM,aAAa,CAAC;IACzE,KAAK,MAAM,SAAS,QAAQ;KAC1B,MAAM,SAAS,OAAO,OAAO,OAAO,MAAM,IAAI;KAE9C,UAAU,OAAO,SAAS,aAAa,OAAO,QAAQ,SAAS,eAAe;IAChF;IACA,UAAU,CAAC,QAAQ;IACnB,KAAK,MAAM,SAAS,cAAc,OAAO,aAAa,KAAK;IAC3D,IAAI,cAAc,OAAO,iBAAiB,UAAU;SAElD,KAAK,MAAM,aAAa,OAAO,UAAU,GACvC,UAAU,OAAO,eAAe,SAAS,CAAC;IAC9C,UAAU,CAAC,QAAQ;GACrB,CAAC,CAAC,CAAC,KACD,OAAO,SACL,OAAO,WAAW;IAChB,QAAQ;GACV,CAAC,CACH,CACF,CACF;EACJ;EAEA,OAAO;CACT;CAEA,OAAO;EAAE;EAA0B;EAAM;EAAqB;CAAqB;AACrF"}
1
+ {"version":3,"file":"transaction-kernel.mjs","names":[],"sources":["../../src/internal/transaction-kernel.ts"],"sourcesContent":["import { type CommitJournal, type PreparedCommit } from \"@yielded/auth/Hooks\";\nimport { reportAuthFailure } from \"@yielded/auth/Persistence\";\n/* oxlint-disable no-explicit-any -- existing storage kernels erase foreign table shapes; domain errors remain typed. */\nimport { Cause, Context, Effect } from \"effect\";\nimport type * as SqlClient from \"effect/sql/SqlClient\";\nimport type { SqlError } from \"effect/sql/SqlError\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport type {\n SqlExpression as SQL,\n QueryFailure,\n QueryOperations,\n SqlFragment,\n SqlColumn,\n} from \"./query-operations\";\n\ntype Table = object;\n\nexport type Row = Record<string, any>;\n\n/** Only query-builder/table shapes are erased here. Installed native\n * queries have captured clients, and their error channel remains explicit. */\ntype NativeQuery<A> = Effect.Effect<A, QueryFailure | SqlError>;\n\nexport interface TransactionNativeDatabase {\n readonly $client: SqlClient.SqlClient & {\n readonly batch: (statements: ReadonlyArray<Statement<any>>) => Effect.Effect<any, SqlError>;\n };\n readonly transaction: <A, E, R>(\n body: (transaction: any) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SqlError, R>;\n}\n\n/** Root native database required only while constructing standalone services.\n * Active transactions remain owned by their coordinator and journal. */\nexport class NativeDatabase extends Context.Service<NativeDatabase, TransactionNativeDatabase>()(\n \"effect-auth/persistence/NativeDatabase\",\n) {}\n\nexport interface Observation {\n readonly table: Table;\n readonly where: SQL;\n rows: ReadonlyArray<Row>;\n}\n\n/** Expressions deliberately do not replace observed values. Read only semantic\n * columns when telemetry changes atomically, and state the physical result. */\nexport interface GuardedUpdate {\n readonly rows: number;\n readonly postcondition: SQL;\n}\n\nexport interface TransactionOwner<Failure> {\n readonly database: any;\n readonly journal: CommitJournal;\n readonly marker: string;\n readonly batch: boolean;\n readonly observations: Observation[];\n readonly postconditions: Array<SQL | (() => SQL)>;\n readonly statements: Statement<any>[];\n readonly guards: PreparedCommit<void>[];\n exact(table: Table, row: Row): SQL;\n read(\n table: Table,\n where: SQL,\n options?: {\n readonly lock?: boolean;\n readonly limit?: number;\n readonly observe?: boolean;\n readonly admissionOnly?: boolean;\n readonly takeOnly?: boolean;\n readonly orderBy?: any;\n readonly columns?: ReadonlyArray<string>;\n },\n ): Effect.Effect<Observation, Failure>;\n write(query: any): Effect.Effect<void, Failure>;\n insert(\n table: Table,\n values: Row,\n key: Row,\n absent?: boolean,\n ): Effect.Effect<Observation, Failure>;\n update(table: Table, key: Row, values: Row): Effect.Effect<void, Failure>;\n updateGuarded(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n /** Internal SQL only, run once after application work and before final guards. */\n finalUpdate(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n remove(table: Table, key: Row): Effect.Effect<void, Failure>;\n check(condition: SQL): Effect.Effect<boolean, Failure>;\n now(clock: { readonly engineNowMillis: SQL }): Effect.Effect<number, Failure>;\n finish(): Effect.Effect<void, Failure>;\n}\n\nexport const makeTransactionKernel = <\n Fragment extends SqlFragment = SqlFragment,\n Column extends SqlColumn = SqlColumn,\n>(\n operations: QueryOperations<Fragment, Column>,\n) => {\n const { eq, getTableColumns, isNull, sql, balancedD1And, compactD1GeneratedStatement } =\n operations;\n\n const isUnavailableCause = <Failure>(cause: Cause.Cause<unknown>, unavailable: () => Failure) => {\n const expected = unavailable();\n\n const tag =\n typeof expected === \"object\" && expected !== null && \"_tag\" in expected\n ? expected._tag\n : undefined;\n\n return (\n tag !== undefined &&\n cause.reasons.length > 0 &&\n cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n typeof reason.error === \"object\" &&\n reason.error !== null &&\n \"_tag\" in reason.error &&\n reason.error._tag === tag,\n )\n );\n };\n\n /** Report once, before an adapter replaces the raw cause with its public\n * unavailable error. Already translated failures stay quiet at outer owners. */\n const reportTransactionFailure = <A, E, R, Failure>(\n effect: Effect.Effect<A, E, R>,\n unavailable: () => Failure,\n ): Effect.Effect<A, E, R> =>\n Effect.catchCause(effect, (cause) =>\n isUnavailableCause(cause, unavailable)\n ? Effect.failCause(cause)\n : reportAuthFailure(\"auth-persistence\", cause).pipe(\n Effect.andThen(Effect.failCause(cause)),\n ),\n );\n\n const both = (...parts: ReadonlyArray<SQL | undefined>) => balancedD1And(...parts) ?? sql`1 = 1`;\n\n const makeTransactionRows = <Failure>(unavailable: () => Failure) => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const col = (table: Table, key: string) => {\n const value = getTableColumns(table)[key];\n\n invariant(value !== undefined);\n\n return value;\n };\n\n const equal = (table: Table, values: Row) =>\n both(\n ...Object.entries(values).map(([key, value]) =>\n value === null ? isNull(col(table, key)) : eq(col(table, key), value),\n ),\n );\n\n /** Mapped driver values use plain data, Dates and binary views. Application\n * identity classes are reconstructed by the mapped codecs, never cloned here. */\n const copiedRow = (row: Row) => {\n const seen = new WeakSet<object>();\n\n const supported = (value: unknown): void => {\n if (value === null || typeof value !== \"object\" || seen.has(value)) return;\n seen.add(value);\n if (value instanceof Date || value instanceof ArrayBuffer || ArrayBuffer.isView(value))\n return;\n invariant(\n Array.isArray(value) ||\n Object.getPrototypeOf(value) === Object.prototype ||\n Object.getPrototypeOf(value) === null,\n );\n for (const item of Object.values(value)) supported(item);\n };\n\n supported(row);\n\n return structuredClone(row);\n };\n\n const nativeKey = (value: unknown): string => {\n const packed = (tag: string, text: string) => tag + text.length + \":\" + text;\n\n if (value instanceof Date) return packed(\"date\", value.toISOString());\n if (typeof value === \"bigint\") return packed(\"bigint\", value.toString());\n\n const bytes =\n value instanceof ArrayBuffer\n ? new Uint8Array(value)\n : ArrayBuffer.isView(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : undefined;\n\n if (bytes !== undefined) return packed(\"bytes\", Array.from(bytes).join(\",\"));\n if (value === null || typeof value !== \"object\") return packed(typeof value, String(value));\n if (Array.isArray(value)) return packed(\"array\", value.map(nativeKey).join(\"\"));\n invariant(\n Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null,\n );\n\n return packed(\n \"object\",\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([name, item]) => nativeKey(name) + nativeKey(item))\n .join(\"\"),\n );\n };\n\n const matchesNativeRow = (table: Table, row: Row, key: Row) =>\n Object.entries(key).every(([name, value]) => {\n if (value === null || row[name] === null) return value === row[name];\n const column = col(table, name);\n\n return (\n nativeKey(column.mapToDriverValue(row[name])) ===\n nativeKey(column.mapToDriverValue(value))\n );\n });\n\n return { col, equal, copiedRow, matchesNativeRow };\n };\n\n const makeTransactionOwner = <Failure>(\n database: any,\n journal: CommitJournal,\n marker: string,\n unavailable: () => Failure,\n configuration: {\n readonly client?: any;\n readonly batch: boolean;\n readonly locking: boolean;\n readonly mysql: boolean;\n readonly dialect: \"pg\" | \"mysql\" | \"sqlite\";\n },\n ): TransactionOwner<Failure> => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const { col, equal, matchesNativeRow } = makeTransactionRows(unavailable);\n let phase: \"open\" | \"finishing\" | \"finished\" = \"open\";\n let poisoned = false;\n const open = () => invariant(phase === \"open\" && !poisoned);\n\n const result = <A, E>(effect: Effect.Effect<A, E>) =>\n effect.pipe(\n (operation) => reportTransactionFailure(operation, unavailable),\n Effect.mapError(unavailable),\n Effect.catchDefect(() => Effect.fail(unavailable())),\n Effect.onExit((exit) =>\n Effect.sync(() => {\n if (exit._tag === \"Failure\") poisoned = true;\n }),\n ),\n );\n\n const observations: Observation[] = [];\n const statements: Statement<any>[] = [];\n const postconditions: Array<SQL | (() => SQL)> = [];\n const guards: PreparedCommit<void>[] = [];\n const finalUpdates: Array<{ readonly query: any; readonly guard: GuardedUpdate }> = [];\n\n const exactRow = (table: Table, row: Row) =>\n both(\n ...Object.entries(row).map(([key, value]) => {\n if (typeof value !== \"string\") return equal(table, { [key]: value });\n\n const column = col(table, key),\n bound = sql.param(value, column);\n\n return configuration.dialect === \"mysql\"\n ? sql`binary ${column} = binary ${bound}`\n : configuration.dialect === \"pg\"\n ? sql`convert_to(cast(${column} as text), 'UTF8') = convert_to(cast(${bound} as text), 'UTF8')`\n : sql`cast(${column} as blob) = cast(${bound} as blob)`;\n }),\n );\n\n const toStatement = (query: any): Statement<any> => {\n const rendered = query.toSQL();\n const client = configuration.client ?? database.$client;\n\n return compactD1GeneratedStatement(\n client,\n client.unsafe(rendered.sql, rendered.params),\n unavailable,\n );\n };\n\n const assertion = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else json_extract('[]', ${\"$[oauth-owner-\" + marker + \"]\"}) end`,\n })\n .from(sql`(select 1) as oauth_assertion`);\n\n const observedConditions = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => [\n sql`(select count(*) from ${table} where ${where}) = ${rows.length}`,\n ...rows.map(\n (row) => sql`exists(select 1 from ${table} where ${both(where, exactRow(table, row))})`,\n ),\n ];\n\n // All chunks remain inside the same native owner or atomic D1 batch. A single\n // wide row is compacted; separate observations cannot accumulate unbounded\n // bind parameters or expression depth in one final SELECT.\n const chunks = (conditions: ReadonlyArray<SQL>) => {\n const output: SQL[] = [];\n let pending: SQL[] = [];\n\n for (const condition of conditions) {\n const candidate = [...pending, condition];\n const rendered = assertion(both(...candidate)).toSQL();\n\n if (\n pending.length > 0 &&\n (rendered.params.length > 96 || new TextEncoder().encode(rendered.sql).length > 48_000)\n ) {\n output.push(both(...pending));\n pending = [condition];\n } else pending = candidate;\n }\n if (pending.length > 0) output.push(both(...pending));\n\n return output;\n };\n\n const appendAssertions = (conditions: ReadonlyArray<SQL>) => {\n for (const condition of chunks(conditions))\n statements.push(toStatement(assertion(condition)));\n };\n\n const observed = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => {\n const observation = { table, where, rows };\n\n observations.push(observation);\n\n return observation;\n };\n\n const queryCondition = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else 0 end`.mapWith(Number).as(\"value\"),\n })\n .from(sql`(select 1) as oauth_guard`);\n\n const conditionHolds = (condition: SQL) =>\n Effect.gen(function* () {\n const query = queryCondition(condition);\n\n const rows: ReadonlyArray<Row> = yield* configuration.dialect === \"sqlite\"\n ? toStatement(query)\n : (query as NativeQuery<Row[]>);\n\n invariant(rows.length === 1);\n\n return rows[0]!.value === 1;\n });\n\n const guardedQuery = (table: Table, where: SQL, values: Row, guard: GuardedUpdate) => {\n invariant(Number.isSafeInteger(guard.rows) && guard.rows > 0 && guard.rows <= 128);\n\n return { query: database.update(table).set(values).where(where), guard: { ...guard } };\n };\n\n const applyGuarded = (entry: { readonly query: any; readonly guard: GuardedUpdate }) =>\n Effect.gen(function* () {\n if (configuration.batch) {\n statements.push(toStatement(entry.query));\n statements.push(toStatement(assertion(sql`changes() = ${entry.guard.rows}`)));\n appendAssertions([entry.guard.postcondition]);\n } else {\n if (configuration.mysql) {\n // mysql2 reports matched rows (FOUND_ROWS), including a telemetry no-op.\n const changed = yield* entry.query as NativeQuery<{ readonly affectedRows: number }>;\n\n invariant(changed.affectedRows === entry.guard.rows);\n } else {\n const changed = yield* entry.query.returning({ value: sql`1` }) as NativeQuery<\n ReadonlyArray<Row>\n >;\n\n invariant(changed.length === entry.guard.rows);\n }\n invariant(yield* conditionHolds(entry.guard.postcondition));\n }\n });\n\n const owner: TransactionOwner<Failure> = {\n database,\n journal,\n marker,\n batch: configuration.batch,\n observations,\n statements,\n postconditions,\n guards,\n exact: exactRow,\n read: (table, where, options = {}) =>\n result(\n Effect.gen(function* () {\n open();\n const limit = options.limit ?? 64;\n\n let query = database\n .select(\n options.columns === undefined\n ? undefined\n : Object.fromEntries(options.columns.map((key) => [key, col(table, key)])),\n )\n .from(table)\n .where(where)\n .limit(options.takeOnly ? limit : limit + 1);\n\n if (options.orderBy !== undefined) query = query.orderBy(options.orderBy);\n if (options.lock !== false && configuration.locking) query = query.for(\"update\");\n const rows: Row[] = yield* query as NativeQuery<Row[]>;\n\n invariant(rows.length <= limit);\n if (configuration.batch && (options.observe !== false || options.admissionOnly))\n appendAssertions(observedConditions(table, where, rows));\n\n return options.observe === false || options.admissionOnly\n ? { table, where, rows }\n : observed(table, where, rows);\n }),\n ),\n write: (query) =>\n result(\n Effect.gen(function* () {\n open();\n if (configuration.batch) statements.push(toStatement(query));\n else yield* query as NativeQuery<unknown>;\n }),\n ),\n insert: (table, values, key, absent = false) =>\n result(\n Effect.gen(function* () {\n open();\n let query = database.insert(table).values(values);\n\n if (absent)\n query = configuration.mysql\n ? query.onDuplicateKeyUpdate({\n set: { [Object.keys(key)[0]!]: col(table, Object.keys(key)[0]!) },\n })\n : query.onConflictDoNothing();\n yield* owner.write(query);\n const where = equal(table, key);\n\n if (configuration.batch) return observed(table, where, [values]);\n const found = yield* owner.read(table, where, { limit: 1 });\n const markerColumn = Object.keys(values).find((key) => values[key] === marker);\n\n if (!absent || (markerColumn !== undefined && found.rows[0]?.[markerColumn] === marker))\n invariant(\n yield* owner.check(\n sql`exists(select 1 from ${table} where ${both(where, exactRow(table, values))})`,\n ),\n );\n\n return found;\n }),\n ),\n update: (table, key, values) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.update(table).set(values).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.map((row) =>\n matchesNativeRow(table, row, key) ? { ...row, ...values } : row,\n );\n }),\n ),\n updateGuarded: (table, where, values, guard) =>\n result(\n Effect.gen(function* () {\n open();\n const entry = guardedQuery(table, where, values, guard);\n\n yield* applyGuarded(entry);\n postconditions.push(entry.guard.postcondition);\n }),\n ),\n finalUpdate: (table, where, values, guard) =>\n result(\n Effect.sync(() => {\n open();\n invariant(finalUpdates.length < 128);\n finalUpdates.push(guardedQuery(table, where, values, guard));\n }),\n ),\n remove: (table, key) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.delete(table).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.filter(\n (row) => !matchesNativeRow(table, row, key),\n );\n }),\n ),\n check: (condition) =>\n result(\n Effect.gen(function* () {\n open();\n const holds = yield* conditionHolds(condition);\n\n if (configuration.batch)\n statements.push(toStatement(assertion(holds ? condition : sql`not (${condition})`)));\n\n return holds;\n }),\n ),\n now: (clock) =>\n result(\n Effect.gen(function* () {\n open();\n\n const rows: Row[] = yield* database\n .select({\n value: sql`${clock.engineNowMillis}`.mapWith(Number),\n })\n .from(sql`(select 1) as oauth_clock`) as NativeQuery<Row[]>;\n\n const value = rows[0]?.value;\n\n invariant(Number.isSafeInteger(value) && value >= 0);\n\n return value as number;\n }),\n ),\n finish: () =>\n result(\n Effect.gen(function* () {\n open();\n phase = \"finishing\";\n Object.freeze(observations);\n Object.freeze(postconditions);\n Object.freeze(guards);\n Object.freeze(finalUpdates);\n\n // Close registration before any late-bound SQL predicate is materialized.\n // No callback is invoked after the first final write.\n const conditions: SQL[] = observations.flatMap((observation) =>\n observedConditions(observation.table, observation.where, observation.rows),\n );\n\n conditions.push(\n ...postconditions.map((condition) =>\n typeof condition === \"function\" ? condition() : condition,\n ),\n );\n conditions.push(...finalUpdates.map((entry) => entry.guard.postcondition));\n for (const guard of guards) {\n const status = yield* Effect.result(guard.read);\n\n invariant(status._tag === \"Failure\" && status.failure._tag === \"CommitPending\");\n }\n invariant(!poisoned);\n for (const entry of finalUpdates) yield* applyGuarded(entry);\n if (configuration.batch) appendAssertions(conditions);\n else\n for (const condition of chunks(conditions))\n invariant(yield* conditionHolds(condition));\n invariant(!poisoned);\n }).pipe(\n Effect.ensuring(\n Effect.sync(() => {\n phase = \"finished\";\n }),\n ),\n ),\n ),\n };\n\n return owner;\n };\n\n return { reportTransactionFailure, both, makeTransactionRows, makeTransactionOwner };\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@yielded/auth-persistence","version":"0.1.0-beta.11","dependencies":{"@noble/hashes":"2.3.0","@yielded/auth":"0.1.0-beta.11","@yielded/auth-crypto":"0.1.0-beta.1"},"devDependencies":{"@effect/platform-node":"4.0.0","@effect/sql-libsql":"4.0.0","@effect/sql-sqlite-node":"4.0.0","@effect/vitest":"4.0.0","effect":"4.0.0","typescript":"7.0.2","vite-plus":"0.3.3"},"peerDependencies":{"effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./Adapter":{"types":"./dist/Adapter.d.mts","default":"./dist/Adapter.mjs"}},"description":"Direct Effect SQL persistence and shared storage contracts for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
1
+ {"name":"@yielded/auth-persistence","version":"0.1.0-beta.12","dependencies":{"@noble/hashes":"2.3.0","@yielded/auth":"0.1.0-beta.12","@yielded/auth-crypto":"0.1.0-beta.12"},"devDependencies":{"@effect/platform-node":"4.0.0","@effect/sql-libsql":"4.0.0","@effect/sql-sqlite-node":"4.0.0","@effect/vitest":"4.0.0","effect":"4.0.0","typescript":"7.0.2","vite-plus":"0.3.3"},"peerDependencies":{"effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./Adapter":{"types":"./dist/Adapter.d.mts","default":"./dist/Adapter.mjs"}},"description":"Direct Effect SQL persistence and shared storage contracts for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
package/src/Adapter.ts CHANGED
@@ -1,4 +1,8 @@
1
- /** Shared storage contracts and kernels for persistence adapter authors. */
1
+ /** Shared storage contracts and kernels for persistence adapter authors.
2
+ * Standalone constructors require the matching Current*Sql or NativeDatabase
3
+ * service during acquisition. Provide a coordinator's exact transaction when
4
+ * constructing bound services; do not provide the root database around their
5
+ * later operations, where Current*Sql identifies an active transaction. */
2
6
  export {
3
7
  type EmailSubjectReadTable,
4
8
  type EmailSubjectTable,
@@ -271,6 +275,7 @@ export {
271
275
  type GuardedUpdate,
272
276
  type Observation,
273
277
  type Row,
278
+ NativeDatabase,
274
279
  type TransactionNativeDatabase,
275
280
  type TransactionOwner,
276
281
  makeTransactionKernel,
@@ -379,41 +379,36 @@ export const makeEmailKernel = <
379
379
  return snapshot;
380
380
  });
381
381
 
382
- const makeSqlEmailSignInTargets = Effect.fn("makeSqlEmailSignInTargets")(function (
383
- database: EmailSqlDatabase,
382
+ const makeSqlEmailSignInTargets = Effect.fn("makeSqlEmailSignInTargets")(function* (
384
383
  mapping: SignInMapping,
385
384
  configuration: EmailSqlConfiguration,
386
- ): Effect.Effect<EmailSignInTargets["Service"]> {
387
- return Effect.succeed(
388
- EmailSignInTargets.of({
389
- lookup: (input) =>
390
- (validEmailSignInConstraints(mapping)
391
- ? safeRead(
392
- database,
393
- configuration,
394
- Effect.gen(function* () {
395
- const row = (yield* emailLookupRows(
396
- mapping,
397
- input.moduleId,
398
- input.identifier,
399
- ))[0];
400
-
401
- if (row === undefined) return Option.none();
402
-
403
- const snapshot = yield* decodeEmailSnapshot(
404
- mapping,
405
- input.moduleId,
406
- input.identifier,
407
- row,
408
- );
409
-
410
- return snapshot === undefined ? Option.none() : Option.some(snapshot);
411
- }),
412
- )
413
- : Effect.fail(unavailable())
414
- ).pipe(Effect.provideService(CurrentEmailSql, database), translateFailure),
415
- }),
416
- );
385
+ ): Effect.fn.Return<EmailSignInTargets["Service"], never, CurrentEmailSql> {
386
+ const database = yield* CurrentEmailSql;
387
+
388
+ return EmailSignInTargets.of({
389
+ lookup: (input) =>
390
+ (validEmailSignInConstraints(mapping)
391
+ ? safeRead(
392
+ database,
393
+ configuration,
394
+ Effect.gen(function* () {
395
+ const row = (yield* emailLookupRows(mapping, input.moduleId, input.identifier))[0];
396
+
397
+ if (row === undefined) return Option.none();
398
+
399
+ const snapshot = yield* decodeEmailSnapshot(
400
+ mapping,
401
+ input.moduleId,
402
+ input.identifier,
403
+ row,
404
+ );
405
+
406
+ return snapshot === undefined ? Option.none() : Option.some(snapshot);
407
+ }),
408
+ )
409
+ : Effect.fail(unavailable())
410
+ ).pipe(Effect.provideService(CurrentEmailSql, database), translateFailure),
411
+ });
417
412
  });
418
413
 
419
414
  const readSubject = Effect.fn("DrizzleEmail.readSubject")(function* (
@@ -1224,10 +1219,10 @@ export const makeEmailKernel = <
1224
1219
  });
1225
1220
 
1226
1221
  const makeSqlEmailAddressPersistence = Effect.fn("makeSqlEmailAddressPersistence")(function* (
1227
- database: EmailSqlDatabase,
1228
1222
  mapping: AddressMapping,
1229
1223
  configuration: EmailSqlConfiguration,
1230
- ): Effect.fn.Return<EmailAddressPersistence["Service"], never, LifecycleHooks> {
1224
+ ): Effect.fn.Return<EmailAddressPersistence["Service"], never, LifecycleHooks | CurrentEmailSql> {
1225
+ const database = yield* CurrentEmailSql;
1231
1226
  const hooks = yield* LifecycleHooks;
1232
1227
 
1233
1228
  return EmailAddressPersistence.of({
@@ -33,7 +33,7 @@ const layer = Layer.effect(
33
33
 
34
34
  if (!sql.onDialectOrElse({ sqlite: () => true, pg: () => true, orElse: () => false }))
35
35
  return yield* Unavailable.make({});
36
- const standalone = requireStandalone(() => Unavailable.make({}), sql);
36
+ const standalone = requireStandalone(() => Unavailable.make({}), sql.transactionService);
37
37
 
38
38
  const failure = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
39
39
  effect.pipe(Effect.mapError(() => Unavailable.make({})));
@@ -1,6 +1,5 @@
1
- /* oxlint-disable no-explicit-any -- existing mapped-row bridge; public adapters preserve table, ID, and Effect types. */
2
-
3
1
  import { type PreparedCommit, LifecycleHooks } from "@yielded/auth/Hooks";
2
+ /* oxlint-disable no-explicit-any -- existing mapped-row bridge; public adapters preserve table, ID, and Effect types. */
4
3
  import {
5
4
  PasskeyConfigurationError,
6
5
  type PasskeyUnavailable,
@@ -44,6 +43,7 @@ import type {
44
43
  TransactionTargetConfiguration,
45
44
  makeTransactionExecutionKernel,
46
45
  } from "../transaction-execution-kernel";
46
+ import type { NativeDatabase } from "../transaction-kernel";
47
47
  import type { makePasskeyCredentialsKernel } from "./credentials";
48
48
  import type { makePasskeyFlowKernel } from "./flow";
49
49
  import type { makePasskeyRegistrationCeremonyKernel } from "./registration-ceremony";
@@ -114,22 +114,21 @@ export const makePasskeyTargetKernel = (
114
114
  } = execution;
115
115
 
116
116
  const sqlClientPasskeyStandaloneGuard = (
117
- database: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],
118
- ) => sqlClientTransactionStandaloneGuard(unavailable, database);
117
+ transactionService: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],
118
+ ) => sqlClientTransactionStandaloneGuard(unavailable, transactionService);
119
119
 
120
120
  const emptyHooks: LifecycleHooks["Service"] = {
121
121
  before: () => Effect.void,
122
122
  after: () => Effect.succeed([]),
123
123
  };
124
124
 
125
- const makePasskeyExecution = (
126
- database: Parameters<typeof makeTransactionExecution>[1],
127
- hooks: LifecycleHooks["Service"],
125
+ const makePasskeyExecution = Effect.fnUntraced(function* (
128
126
  configuration: PasskeyTargetConfiguration,
129
- ): PasskeyExecution => {
130
- const execution = makeTransactionExecution(
127
+ ): Effect.fn.Return<PasskeyExecution, never, LifecycleHooks | NativeDatabase> {
128
+ const hooks = yield* LifecycleHooks;
129
+
130
+ const execution = yield* makeTransactionExecution(
131
131
  CurrentPasskeyTransaction,
132
- database,
133
132
  configuration,
134
133
  unavailable,
135
134
  nonce,
@@ -140,7 +139,7 @@ export const makePasskeyTargetKernel = (
140
139
  run: (operation, mutation) =>
141
140
  execution.run(operation, mutation).pipe(Effect.provideService(LifecycleHooks, hooks)),
142
141
  };
143
- };
142
+ });
144
143
 
145
144
  const issueInput = Schema.Struct({ ceremony: PasskeyCeremony, policy: PasskeyMethodPolicy });
146
145
 
@@ -422,77 +421,71 @@ export const makePasskeyTargetKernel = (
422
421
  );
423
422
 
424
423
  const makeTargetPasskeyCredentials = <M, RSetup>(
425
- database: any,
426
424
  source: PasskeyMappingSource<M, RSetup>,
427
425
  configuration: PasskeyTargetConfiguration,
428
426
  ): Effect.Effect<
429
427
  PasskeyCredentialServices,
430
428
  PasskeyConfigurationError | PersistenceMappingError,
431
- RSetup
429
+ RSetup | NativeDatabase
432
430
  > =>
433
- Effect.map(capturedMapping(source, "read", configuration), (mapping) => ({
434
- passkeyCredentials: credentialService(
435
- mapping,
436
- makePasskeyExecution(database, emptyHooks, configuration),
437
- ),
438
- }));
431
+ Effect.gen(function* () {
432
+ const mapping = yield* capturedMapping(source, "read", configuration);
433
+
434
+ const execution = yield* makePasskeyExecution(configuration).pipe(
435
+ Effect.provideService(LifecycleHooks, emptyHooks),
436
+ );
437
+
438
+ return { passkeyCredentials: credentialService(mapping, execution) };
439
+ });
439
440
 
440
441
  const makeTargetPasskeyEnrollmentContext = <M, RSetup>(
441
- database: any,
442
442
  source: PasskeyMappingSource<M, RSetup>,
443
443
  configuration: PasskeyTargetConfiguration,
444
444
  ): Effect.Effect<
445
445
  PasskeyEnrollmentContextServices,
446
446
  PasskeyConfigurationError | PersistenceMappingError,
447
- RSetup
447
+ RSetup | NativeDatabase
448
448
  > =>
449
- Effect.map(capturedMapping(source, "context", configuration), (mapping) => ({
450
- passkeyEnrollmentContext: enrollmentService(
451
- mapping,
452
- makePasskeyExecution(database, emptyHooks, configuration),
453
- ),
454
- }));
449
+ Effect.gen(function* () {
450
+ const mapping = yield* capturedMapping(source, "context", configuration);
451
+
452
+ const execution = yield* makePasskeyExecution(configuration).pipe(
453
+ Effect.provideService(LifecycleHooks, emptyHooks),
454
+ );
455
+
456
+ return { passkeyEnrollmentContext: enrollmentService(mapping, execution) };
457
+ });
455
458
 
456
459
  const makeTargetPasskeyPersistence = <M, RSetup>(
457
- database: any,
458
460
  source: PasskeyMappingSource<M, RSetup>,
459
461
  configuration: PasskeyTargetConfiguration,
460
462
  ): Effect.Effect<
461
463
  PasskeyPersistenceServices,
462
464
  PasskeyConfigurationError | PersistenceMappingError,
463
- RSetup | LifecycleHooks
465
+ RSetup | LifecycleHooks | NativeDatabase
464
466
  > =>
465
467
  Effect.gen(function* () {
466
468
  const mapping = yield* capturedMapping(source, "assertion", configuration);
467
- const hooks = yield* LifecycleHooks;
469
+ const execution = yield* makePasskeyExecution(configuration);
468
470
 
469
471
  return {
470
- passkeyPersistence: makePasskeyPersistence(
471
- mapping,
472
- makePasskeyExecution(database, hooks, configuration),
473
- configuration,
474
- ),
472
+ passkeyPersistence: makePasskeyPersistence(mapping, execution, configuration),
475
473
  };
476
474
  });
477
475
 
478
476
  const makeTargetPasskeyRegistration = <M, RSetup>(
479
- database: any,
480
477
  source: PasskeyMappingSource<M, RSetup>,
481
478
  configuration: PasskeyTargetConfiguration,
482
479
  ): Effect.Effect<
483
480
  PasskeyRegistrationCeremonyServices,
484
481
  PasskeyConfigurationError | PersistenceMappingError,
485
- RSetup | LifecycleHooks
482
+ RSetup | LifecycleHooks | NativeDatabase
486
483
  > =>
487
484
  Effect.gen(function* () {
488
485
  const mapping = yield* capturedMapping(source, "registration", configuration);
489
- const hooks = yield* LifecycleHooks;
486
+ const execution = yield* makePasskeyExecution(configuration);
490
487
 
491
- return registrationServices(
492
- mapping,
493
- makePasskeyExecution(database, hooks, configuration),
494
- configuration,
495
- );
488
+ return registrationServices(mapping, execution, configuration);
496
489
  });
497
490
 
498
491
  const coordinateTargetPasskey = <M, RSetup, Transaction, A, E, R>(
@@ -341,35 +341,25 @@ export const makePasskeyWriteTargetKernel = (
341
341
  });
342
342
 
343
343
  const makeTargetPasskeyManagement = <M, RSetup>(
344
- database: any,
345
344
  source: PasskeyMappingSource<M, RSetup>,
346
345
  configuration: PasskeyTargetConfiguration,
347
346
  ) =>
348
347
  Effect.gen(function* () {
349
348
  const mapping = yield* writeMapping(source, configuration, false);
350
- const hooks = yield* LifecycleHooks;
349
+ const execution = yield* makePasskeyExecution(configuration);
351
350
 
352
- return managementServices(
353
- mapping,
354
- makePasskeyExecution(database, hooks, configuration),
355
- configuration,
356
- );
351
+ return managementServices(mapping, execution, configuration);
357
352
  });
358
353
 
359
354
  const makeTargetPasskeyRegistrationWriter = <M, R, RSetup>(
360
- database: any,
361
355
  source: PasskeyMappingSource<M, RSetup>,
362
356
  configuration: PasskeyTargetConfiguration,
363
357
  ) =>
364
358
  Effect.gen(function* () {
365
359
  const mapping = yield* writeMapping(source, configuration, true);
366
- const hooks = yield* LifecycleHooks;
360
+ const execution = yield* makePasskeyExecution(configuration);
367
361
 
368
- return registrationServices<R>(
369
- mapping,
370
- makePasskeyExecution(database, hooks, configuration),
371
- configuration,
372
- );
362
+ return registrationServices<R>(mapping, execution, configuration);
373
363
  });
374
364
 
375
365
  const coordinateTargetPasskeyManagement = <M, RSetup, Transaction, A, E, R>(
@@ -33,7 +33,7 @@ import {
33
33
  import { makePasskeyKernel } from "./passkey-kernel";
34
34
  import type { PasskeyTargetConfiguration } from "./passkey/target";
35
35
  import type { Backend } from "./persistence";
36
- import type { ProofSqlDatabase } from "./proof-kernel";
36
+ import { CurrentProofSql } from "./proof-kernel";
37
37
  import type { SqlExpression as SQL, QueryOperations, TableModel } from "./query-operations";
38
38
  import { requireStandalone } from "./standalone";
39
39
  import { storageTables, type StorageRole } from "./storage-tables";
@@ -386,7 +386,7 @@ export const makeComposedPasskeys = (
386
386
  };
387
387
 
388
388
  const make: Backend<object, never>["passkeys"] = Effect.fn("AuthPersistence.passkeys")(
389
- function* ({ database, storage, namespace, dialect, features, passwordModules }) {
389
+ function* ({ storage, namespace, dialect, features, passwordModules }) {
390
390
  const client = yield* SqlClient.SqlClient;
391
391
 
392
392
  const policies = yield* Effect.forEach(features, (feature) =>
@@ -409,11 +409,10 @@ export const makeComposedPasskeys = (
409
409
  mode: "interactive",
410
410
  dialect,
411
411
  locking: dialect === "pg",
412
- standaloneGuard: () => requireStandalone(unavailable, client),
412
+ standaloneGuard: () => requireStandalone(unavailable, client.transactionService),
413
413
  };
414
414
 
415
- // The backend has already checked the native query builder; schemas check stored values.
416
- const native = database as ProofSqlDatabase;
415
+ const native = yield* CurrentProofSql;
417
416
 
418
417
  yield* client.withTransaction(
419
418
  Effect.gen(function* () {
@@ -492,7 +491,6 @@ export const makeComposedPasskeys = (
492
491
  );
493
492
 
494
493
  const credential = yield* makeTargetPasskeyCredentials<ReadMapping, never>(
495
- database,
496
494
  m.read,
497
495
  configuration,
498
496
  );
@@ -510,7 +508,6 @@ export const makeComposedPasskeys = (
510
508
  });
511
509
 
512
510
  const services = yield* makeTargetPasskeyManagement<ManagementMapping, never>(
513
- database,
514
511
  mapping,
515
512
  configuration,
516
513
  );
@@ -520,7 +517,6 @@ export const makeComposedPasskeys = (
520
517
  enrollment.set(
521
518
  feature.moduleId,
522
519
  (yield* makeTargetPasskeyEnrollmentContext<ManagementMapping, never>(
523
- database,
524
520
  mapping,
525
521
  configuration,
526
522
  )).passkeyEnrollmentContext,
@@ -529,7 +525,6 @@ export const makeComposedPasskeys = (
529
525
  persistence.set(
530
526
  feature.moduleId,
531
527
  (yield* makeTargetPasskeyPersistence<BaseMapping, never>(
532
- database,
533
528
  m.base(feature),
534
529
  configuration,
535
530
  )).passkeyPersistence,
@@ -1121,10 +1121,10 @@ export const makePasswordKernel = <
1121
1121
  });
1122
1122
 
1123
1123
  const makeSqlPasswordPersistence = Effect.fn("makeSqlPasswordPersistence")(function* (
1124
- database: Database,
1125
1124
  mapping: Mapping,
1126
1125
  configuration: PasswordSqlConfiguration,
1127
- ): Effect.fn.Return<PasswordPersistence["Service"], never, LifecycleHooks> {
1126
+ ): Effect.fn.Return<PasswordPersistence["Service"], never, LifecycleHooks | CurrentPasswordSql> {
1127
+ const database = yield* CurrentPasswordSql;
1128
1128
  const hooks = yield* LifecycleHooks;
1129
1129
 
1130
1130
  return PasswordPersistence.of({