@yielded/auth-persistence 0.1.0-beta.10 → 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 (85) hide show
  1. package/README.md +7 -7
  2. package/dist/Adapter.d.mts +2 -2
  3. package/dist/Adapter.mjs +4 -4
  4. package/dist/index.d.mts +1 -2
  5. package/dist/index.mjs +1 -2
  6. package/dist/internal/PasswordPreparedPostconditions.d.mts +1 -1
  7. package/dist/internal/configuration.d.mts +2 -2
  8. package/dist/internal/configuration.mjs.map +1 -1
  9. package/dist/internal/email-kernel.d.mts +6 -6
  10. package/dist/internal/email-kernel.mjs +8 -6
  11. package/dist/internal/email-kernel.mjs.map +1 -1
  12. package/dist/internal/models/email-model.d.mts +1 -1
  13. package/dist/internal/oauth-server.d.mts +1 -1
  14. package/dist/internal/oauth-server.mjs +2 -2
  15. package/dist/internal/oauth-server.mjs.map +1 -1
  16. package/dist/internal/passkey/state.mjs +3 -2
  17. package/dist/internal/passkey/state.mjs.map +1 -1
  18. package/dist/internal/passkey/target.d.mts +1 -1
  19. package/dist/internal/passkey/target.mjs +21 -12
  20. package/dist/internal/passkey/target.mjs.map +1 -1
  21. package/dist/internal/passkey/write-state.mjs +3 -2
  22. package/dist/internal/passkey/write-state.mjs.map +1 -1
  23. package/dist/internal/passkey/write-target.mjs +6 -6
  24. package/dist/internal/passkey/write-target.mjs.map +1 -1
  25. package/dist/internal/passkey-kernel.d.mts +13 -16
  26. package/dist/internal/passkeys.mjs +9 -8
  27. package/dist/internal/passkeys.mjs.map +1 -1
  28. package/dist/internal/password-kernel.d.mts +4 -4
  29. package/dist/internal/password-kernel.mjs +3 -2
  30. package/dist/internal/password-kernel.mjs.map +1 -1
  31. package/dist/internal/persistence.d.mts +4 -3
  32. package/dist/internal/persistence.mjs +23 -27
  33. package/dist/internal/persistence.mjs.map +1 -1
  34. package/dist/internal/proof-kernel.d.mts +3 -3
  35. package/dist/internal/proof-kernel.mjs +2 -1
  36. package/dist/internal/proof-kernel.mjs.map +1 -1
  37. package/dist/internal/query-operations.d.mts +1 -1
  38. package/dist/internal/registration.mjs +6 -1
  39. package/dist/internal/registration.mjs.map +1 -1
  40. package/dist/internal/session-kernel.d.mts +20 -10
  41. package/dist/internal/session-kernel.mjs +155 -147
  42. package/dist/internal/session-kernel.mjs.map +1 -1
  43. package/dist/internal/sql-persistence.mjs +3 -4
  44. package/dist/internal/sql-persistence.mjs.map +1 -1
  45. package/dist/internal/sql-query.mjs +4 -2
  46. package/dist/internal/sql-query.mjs.map +1 -1
  47. package/dist/internal/standalone.d.mts +2 -4
  48. package/dist/internal/standalone.mjs +2 -2
  49. package/dist/internal/standalone.mjs.map +1 -1
  50. package/dist/internal/storage-mapping.mjs +2 -2
  51. package/dist/internal/storage-validation.mjs +4 -2
  52. package/dist/internal/storage-validation.mjs.map +1 -1
  53. package/dist/internal/transaction-execution-kernel.d.mts +8 -9
  54. package/dist/internal/transaction-execution-kernel.mjs +9 -7
  55. package/dist/internal/transaction-execution-kernel.mjs.map +1 -1
  56. package/dist/internal/transaction-kernel.d.mts +9 -5
  57. package/dist/internal/transaction-kernel.mjs +5 -2
  58. package/dist/internal/transaction-kernel.mjs.map +1 -1
  59. package/package.json +1 -1
  60. package/src/Adapter.ts +6 -1
  61. package/src/index.ts +0 -1
  62. package/src/internal/configuration.ts +1 -1
  63. package/src/internal/email-kernel.ts +31 -36
  64. package/src/internal/oauth-server.ts +2 -2
  65. package/src/internal/passkey/state.ts +3 -2
  66. package/src/internal/passkey/target.ts +37 -44
  67. package/src/internal/passkey/write-state.ts +3 -2
  68. package/src/internal/passkey/write-target.ts +5 -15
  69. package/src/internal/passkeys.ts +5 -10
  70. package/src/internal/password-kernel.ts +3 -3
  71. package/src/internal/persistence.ts +78 -69
  72. package/src/internal/proof-kernel.ts +3 -3
  73. package/src/internal/query-operations.ts +1 -1
  74. package/src/internal/registration.ts +22 -7
  75. package/src/internal/session-kernel.ts +1123 -1140
  76. package/src/internal/sql-persistence.ts +2 -2
  77. package/src/internal/sql-query.ts +6 -4
  78. package/src/internal/standalone.ts +6 -8
  79. package/src/internal/storage-validation.ts +20 -16
  80. package/src/internal/transaction-execution-kernel.ts +20 -18
  81. package/src/internal/transaction-kernel.ts +10 -4
  82. package/dist/internal/oauth-app.d.mts +0 -11
  83. package/dist/internal/oauth-app.mjs +0 -57
  84. package/dist/internal/oauth-app.mjs.map +0 -1
  85. package/src/internal/oauth-app.ts +0 -82
@@ -1,27 +1,27 @@
1
1
  import { PersistenceConfigurationError } from "./configuration.mjs";
2
2
  import { PersistenceMappingError } from "./mapping-error.mjs";
3
3
  import { requireStandalone } from "./standalone.mjs";
4
- import { makeTransactionKernel } from "./transaction-kernel.mjs";
4
+ import { NativeDatabase, makeTransactionKernel } from "./transaction-kernel.mjs";
5
5
  import { makeTransactionExecutionKernel } from "./transaction-execution-kernel.mjs";
6
+ import { CurrentProofSql, makeProofKernel } from "./proof-kernel.mjs";
6
7
  import { storageTables, tableDefinition } from "./storage-tables.mjs";
7
- import { makeProofKernel } from "./proof-kernel.mjs";
8
- import { makeEmailKernel } from "./email-kernel.mjs";
9
- import { makePasswordKernel } from "./password-kernel.mjs";
8
+ import { CurrentEmailSql, makeEmailKernel } from "./email-kernel.mjs";
9
+ import { CurrentPasswordSql, makePasswordKernel } from "./password-kernel.mjs";
10
10
  import { CurrentPhoneTransaction, makePhoneKernel } from "./phone-kernel.mjs";
11
11
  import { makeRegistrationAuthority } from "./registration.mjs";
12
- import { makeSessionKernel } from "./session-kernel.mjs";
12
+ import { CurrentSessionSql, makeSessionKernel } from "./session-kernel.mjs";
13
13
  import { makeMappings } from "./storage-mapping.mjs";
14
14
  import { validateStorage } from "./storage-validation.mjs";
15
15
  import { Context, Effect, Layer, Schema } from "effect";
16
- import { SqlClient } from "effect/unstable/sql";
16
+ import { SqlClient } from "effect/sql";
17
17
  import { digest, randomId } from "@yielded/auth-crypto";
18
18
  import { LifecycleHooks } from "@yielded/auth/Hooks";
19
19
  import { AuthenticationAuthority, SessionUnavailable } from "@yielded/auth/Sessions";
20
20
  import { hooksLayer } from "@yielded/auth/Persistence";
21
+ import { ProofPersistence, ProofUnavailable } from "@yielded/auth/Proofs";
21
22
  import { EmailAddressPersistence, EmailUnavailable } from "@yielded/auth/Email";
22
23
  import { PasswordPersistence, PasswordUnavailable } from "@yielded/auth/Password";
23
24
  import { PhoneAdmission, PhoneOtpUnavailable, PhoneSignInTargets } from "@yielded/auth/PhoneOtp";
24
- import { ProofPersistence, ProofUnavailable } from "@yielded/auth/Proofs";
25
25
  //#region src/internal/persistence.ts
26
26
  const configError = (reason) => PersistenceConfigurationError.make({ reason });
27
27
  const mappingError = (cause) => PersistenceMappingError.make({
@@ -75,7 +75,6 @@ const createPersistence = (backend) => {
75
75
  const ConfigKey = Context.Service()(`@yielded/auth-persistence/${auth.namespace}/Config`);
76
76
  const Config = Object.assign(ConfigKey, { layer: (value) => Layer.succeed(ConfigKey, value) });
77
77
  const ProvisioningKey = Context.Service()(`@yielded/auth-persistence/${auth.namespace}/Provisioning`);
78
- const provisioners = management ? ProvisioningKey.pipe(Effect.map((value) => value)) : Effect.succeed({});
79
78
  const layout = (options, managed) => {
80
79
  const subject = options.subjects;
81
80
  if (passkeys.length > 0 && options.timestamps !== void 0) throw configError("Composed passkey storage uses integer milliseconds; use an explicit passkey adapter for a custom timestamp representation");
@@ -151,11 +150,11 @@ const createPersistence = (backend) => {
151
150
  const description = backend.describe(table);
152
151
  const columns = description.columns;
153
152
  for (const name of Object.keys(storageTables[role].columns)) if (columns[name] === void 0) return yield* configError(`Missing ${role}.${name} column`);
154
- yield* validateStorage(client, dialect, description, storageTables[role].unique);
153
+ yield* validateStorage(dialect, description, storageTables[role].unique);
155
154
  }
156
- yield* validateStorage(client, dialect, backend.describe(storage.subjects.table), [[storage.subjects.id]]);
155
+ yield* validateStorage(dialect, backend.describe(storage.subjects.table), [[storage.subjects.id]]);
157
156
  const mappings = makeMappings(storage);
158
- const standalone = (error) => requireStandalone(error, client);
157
+ const standalone = (error) => requireStandalone(error, client.transactionService);
159
158
  const native = database;
160
159
  const options = {
161
160
  mode: "interactive",
@@ -163,11 +162,11 @@ const createPersistence = (backend) => {
163
162
  standaloneGuard: standalone(() => SessionUnavailable.make({}))
164
163
  };
165
164
  const sessionMapping = mappings.sessions(auth.claims);
166
- const sessionServices = yield* sessionKernel.makeSqlStatefulSessions(native, sessionMapping, options);
167
- const authority = yield* sessionKernel.makeSqlAuthenticationAuthority(native, {
165
+ const sessionServices = yield* sessionKernel.makeSqlStatefulSessions(sessionMapping, options).pipe(Effect.provideService(CurrentSessionSql, native));
166
+ const authority = yield* sessionKernel.makeSqlAuthenticationAuthority({
168
167
  ...mappings.authority(),
169
168
  isConstraintConflict: () => false
170
- }, options);
169
+ }, options).pipe(Effect.provideService(CurrentSessionSql, native));
171
170
  let context = Context.make(AuthenticationAuthority, authority).pipe(Context.add(auth.sessions.StatefulSessionPersistence, sessionServices.statefulSessionPersistence), Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository));
172
171
  const proofConfiguration = proofs ? {
173
172
  mapping: mappings.proofs(),
@@ -178,32 +177,30 @@ const createPersistence = (backend) => {
178
177
  insertIfAbsent: (query) => query.onConflictDoNothing()
179
178
  }
180
179
  } : void 0;
181
- if (proofConfiguration !== void 0) context = Context.add(context, ProofPersistence, yield* proofKernel.makeSqlProofPersistence(native, proofConfiguration.mapping, proofConfiguration.configuration));
180
+ if (proofConfiguration !== void 0) context = Context.add(context, ProofPersistence, yield* proofKernel.makeSqlProofPersistence(proofConfiguration.mapping, proofConfiguration.configuration).pipe(Effect.provideService(CurrentProofSql, native)));
182
181
  if (password) {
183
- const persistence = yield* passwordKernel.makeSqlPasswordPersistence(native, mappings.passwords(), {
182
+ const persistence = yield* passwordKernel.makeSqlPasswordPersistence(mappings.passwords(), {
184
183
  mode: "interactive",
185
184
  locking: dialect === "pg",
186
185
  standaloneGuard: standalone(() => PasswordUnavailable.make({})),
187
186
  insertIfAbsent: (query) => query.onConflictDoNothing(),
188
187
  proof: proofConfiguration
189
- });
188
+ }).pipe(Effect.provideService(CurrentPasswordSql, native));
190
189
  context = Context.add(context, PasswordPersistence, persistence);
191
190
  }
192
- const creators = yield* provisioners;
193
191
  for (const [name, strategy] of Object.entries(auth.strategies)) {
194
192
  if (strategy.persistence?.kind !== "password" || !strategy.persistence.management) continue;
195
193
  const key = strategy.RegistrationAuthority;
196
- const create = creators[name];
197
- if (key === void 0 || create === void 0) return yield* configError(`Missing subject provisioning for ${name}`);
198
- const registration = yield* makeRegistrationAuthority(native, mappings, backend.operations, standalone(() => PasswordUnavailable.make({})), create);
194
+ if (key === void 0) return yield* configError(`Missing subject provisioning for ${name}`);
195
+ const registration = yield* makeRegistrationAuthority(mappings, backend.operations, standalone(() => PasswordUnavailable.make({})), ProvisioningKey, name).pipe(Effect.provideService(CurrentPasswordSql, native));
199
196
  context = Context.add(context, key, registration);
200
197
  }
201
- if (email) context = Context.add(context, EmailAddressPersistence, yield* emailKernel.makeSqlEmailAddressPersistence(native, mappings.emails(), {
198
+ if (email) context = Context.add(context, EmailAddressPersistence, yield* emailKernel.makeSqlEmailAddressPersistence(mappings.emails(), {
202
199
  mode: "interactive",
203
200
  locking: dialect === "pg",
204
201
  standaloneGuard: standalone(() => EmailUnavailable.make({})),
205
202
  proof: proofConfiguration
206
- }));
203
+ }).pipe(Effect.provideService(CurrentEmailSql, native)));
207
204
  if (phone) {
208
205
  const { column, eq } = backend.operations;
209
206
  const mapping = (moduleId) => ({
@@ -251,12 +248,12 @@ const createPersistence = (backend) => {
251
248
  engineNowMillis: backend.operations.sql`${dialect === "pg" ? backend.operations.sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)` : backend.operations.sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`}`,
252
249
  encodeInstant: storage.encodeInstant
253
250
  });
254
- const execution = executionKernel.makeTransactionExecution(CurrentPhoneTransaction, native, {
251
+ const execution = yield* executionKernel.makeTransactionExecution(CurrentPhoneTransaction, {
255
252
  mode: "interactive",
256
253
  dialect,
257
254
  locking: dialect === "pg",
258
255
  standaloneGuard: () => standalone(() => PhoneOtpUnavailable.make({}))
259
- }, () => PhoneOtpUnavailable.make({}), randomId);
256
+ }, () => PhoneOtpUnavailable.make({}), randomId).pipe(Effect.provideService(NativeDatabase, native));
260
257
  const run = (work, mutation = true) => execution.admit.pipe(Effect.andThen(execution.run(work, mutation)), Effect.provideService(LifecycleHooks, hooks));
261
258
  const allowed = (moduleId) => features.some((feature) => feature?.kind === "phone" && feature.moduleId === moduleId);
262
259
  const admission = PhoneAdmission.of({
@@ -268,14 +265,13 @@ const createPersistence = (backend) => {
268
265
  }
269
266
  if (passkeys.length > 0) {
270
267
  const services = backend.passkeys({
271
- database,
272
268
  storage,
273
269
  namespace: auth.namespace,
274
270
  dialect,
275
271
  features: passkeys,
276
272
  passwordModules: features.flatMap((feature) => feature?.kind === "password" ? [feature.moduleId] : [])
277
273
  });
278
- context = Context.merge(context, yield* services);
274
+ context = Context.merge(context, yield* services.pipe(Effect.provideService(NativeDatabase, native), Effect.provideService(CurrentProofSql, native)));
279
275
  }
280
276
  return context;
281
277
  })).pipe(Layer.provide(hooksLayer)),
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.mjs","names":[],"sources":["../../src/internal/persistence.ts"],"sourcesContent":["import { digest, randomId } from \"@yielded/auth-crypto\";\nimport { EmailAddressPersistence, EmailUnavailable } from \"@yielded/auth/Email\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { PasskeyConfig } from \"@yielded/auth/Passkey\";\nimport { PasswordPersistence, PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { hooksLayer } from \"@yielded/auth/Persistence\";\nimport { PhoneAdmission, PhoneSignInTargets, PhoneOtpUnavailable } from \"@yielded/auth/PhoneOtp\";\nimport { ProofPersistence, ProofUnavailable } from \"@yielded/auth/Proofs\";\nimport { AuthenticationAuthority, SessionUnavailable } from \"@yielded/auth/Sessions\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/unstable/sql\";\n\nimport {\n PersistenceConfigurationError,\n type ClaimsCodec,\n type ConfigId,\n type Definition,\n type PersistenceApi,\n type Ports,\n type Roles,\n type Provisioning,\n type ProvisioningRequirement,\n type StorageLayout,\n type SubjectMapping,\n type SubjectOptions,\n type PasskeyFeature,\n type PasskeyRequirement,\n type MappingInput,\n} from \"./configuration\";\nimport { makeEmailKernel, type EmailSqlDatabase } from \"./email-kernel\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport { makePasswordKernel, type PasswordSqlDatabase } from \"./password-kernel\";\nimport { makePhoneKernel, CurrentPhoneTransaction } from \"./phone-kernel\";\nimport { makeProofKernel, type ProofSqlDatabase, type ProofSqlQuery } from \"./proof-kernel\";\nimport type { QueryOperations } from \"./query-operations\";\nimport { makeRegistrationAuthority, type CreateSubject } from \"./registration\";\nimport { makeSessionKernel, type SessionSqlDatabase } from \"./session-kernel\";\nimport { requireStandalone } from \"./standalone\";\nimport { makeMappings } from \"./storage-mapping\";\nimport {\n tableDefinition,\n storageTables,\n type StorageRole,\n type StorageTable,\n} from \"./storage-tables\";\nimport { validateStorage } from \"./storage-validation\";\nimport { makeTransactionExecutionKernel } from \"./transaction-execution-kernel\";\nimport { makeTransactionKernel, type TransactionNativeDatabase } from \"./transaction-kernel\";\n\nexport interface Backend<T extends object, R> {\n readonly makeTable: (definition: StorageTable) => T;\n readonly describe: (table: T) => StorageTable;\n readonly acquire: Effect.Effect<object, PersistenceConfigurationError, R | SqlClient.SqlClient>;\n readonly operations: QueryOperations;\n readonly passkeys: (input: {\n readonly database: object;\n readonly storage: MappingInput;\n readonly namespace: string;\n readonly dialect: \"pg\" | \"sqlite\";\n readonly features: ReadonlyArray<PasskeyFeature>;\n readonly passwordModules: ReadonlyArray<string>;\n }) => Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n PasskeyConfig | LifecycleHooks | SqlClient.SqlClient\n >;\n}\n\nconst configError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappingError = (cause: unknown) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause });\n\nconst timestampKeys = new Set([\n \"verifiedAt\",\n \"createdAt\",\n \"lastIssueAt\",\n \"issuedAt\",\n \"expiresAt\",\n \"absoluteExpiresAt\",\n \"retentionUntil\",\n \"claimDeadline\",\n \"retryAt\",\n \"admittedAt\",\n \"deadline\",\n \"occurredAt\",\n \"dedupUntil\",\n]);\n\nexport const createPersistence = <T extends object, R>(\n backend: Backend<T, R>,\n): PersistenceApi<T, R> => {\n const proofKernel = makeProofKernel(backend.operations);\n const passwordKernel = makePasswordKernel(backend.operations, proofKernel);\n const emailKernel = makeEmailKernel(backend.operations, proofKernel);\n const sessionKernel = makeSessionKernel(backend.operations);\n const transactionKernel = makeTransactionKernel(backend.operations);\n const executionKernel = makeTransactionExecutionKernel(transactionKernel);\n const phoneKernel = makePhoneKernel(backend.operations, transactionKernel);\n\n const make = <C extends ClaimsCodec, const Id extends string, const A extends Definition<C, Id>>(\n auth: A & Definition<C, Id>,\n ) => {\n const features = Object.values(auth.strategies).map((strategy) => strategy.persistence);\n const phone = features.some((feature) => feature?.kind === \"phone\");\n const password = features.some((feature) => feature?.kind === \"password\");\n\n const passkeys = features.filter(\n (feature): feature is PasskeyFeature => feature?.kind === \"passkey\",\n );\n\n const management = features.some(\n (feature) => feature?.kind === \"password\" && feature.management,\n );\n\n const email = features.some((feature) => feature?.kind === \"email\" && feature.addresses);\n const proofs = phone || management || email;\n\n const roles: StorageRole[] = [\"identifiers\", \"credentials\", \"sessions\", \"sessionFlows\"];\n\n if (password)\n roles.push(\n \"passwords\",\n \"passwordAttempts\",\n \"passwordScopes\",\n \"passwordCharges\",\n \"passwordCommands\",\n );\n if (management) roles.push(\"passwordRegistrations\");\n if (email) roles.push(\"emailCredentials\", \"emailCommands\");\n if (phone) roles.push(\"phoneState\");\n if (passkeys.length > 0)\n roles.push(\n \"passkeyCredentials\",\n \"passkeyOwnership\",\n \"passkeyHandles\",\n \"passkeyModules\",\n \"passkeyFlows\",\n \"passkeyAdmissions\",\n \"passkeyCharges\",\n );\n if (passkeys.some((feature) => feature.management)) roles.push(\"passkeyCommands\");\n if (proofs)\n roles.push(\n \"proofRequests\",\n \"proofSeries\",\n \"proofGenerations\",\n \"proofContinuations\",\n \"proofScopes\",\n \"proofAbuse\",\n \"proofFailures\",\n \"proofCommands\",\n );\n\n const ConfigKey = Context.Service<\n ConfigId<A[\"namespace\"]>,\n StorageLayout<T, Roles<C, Id, A>>\n >()(`@yielded/auth-persistence/${auth.namespace}/Config`);\n\n const Config = Object.assign(ConfigKey, {\n layer: (value: StorageLayout<T, Roles<C, Id, A>>) => Layer.succeed(ConfigKey, value),\n });\n\n const ProvisioningKey = Context.Service<ProvisioningRequirement<A>, Provisioning<A>>()(\n `@yielded/auth-persistence/${auth.namespace}/Provisioning`,\n );\n\n // Capability metadata controls the conditional requirement, and core has\n // already decoded each registration with its strategy's Schema.\n const provisioners = management\n ? ProvisioningKey.pipe(\n Effect.map((value) => value as Readonly<Record<string, CreateSubject>>),\n )\n : Effect.succeed<Readonly<Record<string, CreateSubject>>>({});\n\n const layout = <N, Instant>(\n options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<StorageRole, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n },\n managed: boolean,\n ): StorageLayout<T, Roles<C, Id, A>> => {\n const subject = options.subjects;\n\n if (passkeys.length > 0 && options.timestamps !== undefined)\n throw configError(\n \"Composed passkey storage uses integer milliseconds; use an explicit passkey adapter for a custom timestamp representation\",\n );\n const description = backend.describe(subject.table);\n const idColumn = description.columns[subject.id];\n\n for (const key of [subject.id, subject.status, subject.securityRevision]) {\n if (description.columns[key] === undefined)\n throw configError(`Missing subject column ${key}`);\n }\n if (subject.activeValue === undefined)\n throw configError(\"An explicit active subject value is required\");\n\n if (idColumn === undefined || idColumn.type === \"boolean\")\n throw configError(\"Subject ID must map a text or integer column\");\n\n const prefix =\n options.prefix ?? `auth_${digest(auth.namespace).slice(0, 12).replaceAll(\"-\", \"_\")}`;\n\n const schema: Partial<Record<StorageRole, T>> = { ...options.tables };\n\n for (const role of roles) {\n if (schema[role] === undefined && managed) {\n const definition = tableDefinition(role, `${prefix}_${role}`, idColumn.type);\n\n const adjusted =\n options.timestamps === undefined\n ? definition\n : {\n ...definition,\n columns: Object.fromEntries(\n Object.entries(definition.columns).map(([key, column]) => [\n key,\n timestampKeys.has(key)\n ? { ...column, type: options.timestamps?.type ?? column.type }\n : column,\n ]),\n ),\n };\n\n schema[role] = backend.makeTable(adjusted);\n }\n }\n for (const role of roles) {\n if (schema[role] === undefined) throw configError(`Missing ${role} table`);\n }\n const instantCodec = options.timestamps?.codec;\n\n const decodeInstant =\n instantCodec === undefined\n ? Schema.decodeUnknownEffect(Schema.Int)\n : Schema.decodeUnknownEffect(instantCodec);\n\n const decodeInstantSync =\n instantCodec === undefined\n ? Schema.decodeUnknownSync(Schema.Int)\n : Schema.decodeUnknownSync(instantCodec);\n\n const subjects: SubjectMapping = {\n table: subject.table,\n id: subject.id,\n status: subject.status,\n securityRevision: subject.securityRevision,\n activeValue: subject.activeValue,\n requirements: subject.requirements,\n actionRequirements: subject.actionRequirements ?? subject.requirements,\n toSubject: (id) =>\n Schema.decodeUnknownEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toNative: (id) =>\n Schema.encodeEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toSubjectSync: Schema.decodeUnknownSync(subject.idCodec),\n toNativeSync: Schema.encodeSync(subject.idCodec),\n };\n\n return Object.freeze({\n namespace: auth.namespace,\n schema: Object.freeze(schema) as Readonly<Record<Roles<C, Id, A>, T>>,\n tables: schema,\n subjects,\n encodeInstant:\n instantCodec === undefined ? (millis: number) => millis : Schema.encodeSync(instantCodec),\n decodeInstant: (value: unknown) => decodeInstant(value).pipe(Effect.mapError(mappingError)),\n decodeInstantSync,\n });\n };\n\n const services = Layer.effectContext(\n Effect.gen(function* () {\n const storage = yield* ConfigKey;\n const hooks = yield* LifecycleHooks;\n const client = yield* SqlClient.SqlClient;\n const database = yield* backend.acquire;\n\n const dialect = client.onDialectOrElse({\n pg: () => \"pg\" as const,\n sqlite: () => \"sqlite\" as const,\n orElse: () => undefined,\n });\n\n if (dialect === undefined)\n return yield* configError(\"Use an explicit adapter for this SQL dialect\");\n if (auth.sessionMode !== \"stateful\")\n return yield* configError(\"The composed layer currently requires stateful sessions\");\n if (\n features.some(\n (feature) =>\n feature === undefined ||\n (\"lifecycle\" in feature && feature.lifecycle) ||\n (feature.kind === \"email\" && !feature.addresses),\n )\n )\n return yield* configError(\n \"Use explicit services for strategies without composed persistence support\",\n );\n if (storage.namespace !== auth.namespace)\n return yield* configError(\n \"Persistence configuration belongs to a different Auth definition\",\n );\n for (const role of roles) {\n const table = (storage.schema as Partial<Record<StorageRole, T>>)[role];\n\n if (table === undefined) return yield* configError(`Missing ${role} table`);\n const description = backend.describe(table);\n const columns = description.columns;\n\n for (const name of Object.keys(storageTables[role].columns)) {\n if (columns[name] === undefined)\n return yield* configError(`Missing ${role}.${name} column`);\n }\n yield* validateStorage(client, dialect, description, storageTables[role].unique);\n }\n yield* validateStorage(client, dialect, backend.describe(storage.subjects.table as T), [\n [storage.subjects.id],\n ]);\n const mappings = makeMappings(storage);\n\n const standalone = <E>(error: () => E) => requireStandalone(error, client);\n\n // Backend validation owns the foreign query-builder shape, never the decoded rows.\n const native = database as ProofSqlDatabase &\n PasswordSqlDatabase &\n EmailSqlDatabase &\n SessionSqlDatabase &\n TransactionNativeDatabase;\n\n const options = {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => SessionUnavailable.make({})),\n };\n\n const sessionMapping = mappings.sessions(auth.claims);\n\n const sessionServices = yield* sessionKernel.makeSqlStatefulSessions(\n native,\n sessionMapping,\n options,\n );\n\n const authority = yield* sessionKernel.makeSqlAuthenticationAuthority<C[\"Type\"]>(\n native,\n { ...mappings.authority(), isConstraintConflict: () => false },\n options,\n );\n\n let context: Context.Context<never> = Context.make(AuthenticationAuthority, authority).pipe(\n Context.add(\n auth.sessions.StatefulSessionPersistence,\n sessionServices.statefulSessionPersistence,\n ),\n Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository),\n );\n\n const proofConfiguration = proofs\n ? {\n mapping: mappings.proofs(),\n configuration: {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => ProofUnavailable.make({})),\n insertIfAbsent: (query: ProofSqlQuery) => query.onConflictDoNothing(),\n },\n }\n : undefined;\n\n if (proofConfiguration !== undefined) {\n context = Context.add(\n context,\n ProofPersistence,\n yield* proofKernel.makeSqlProofPersistence(\n native,\n proofConfiguration.mapping,\n proofConfiguration.configuration,\n ),\n );\n }\n\n if (password) {\n const persistence = yield* passwordKernel.makeSqlPasswordPersistence(\n native,\n mappings.passwords(),\n {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => PasswordUnavailable.make({})),\n insertIfAbsent: (query) => query.onConflictDoNothing(),\n proof: proofConfiguration,\n },\n );\n\n context = Context.add(context, PasswordPersistence, persistence);\n }\n const creators = yield* provisioners;\n\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n const create = creators[name];\n\n if (key === undefined || create === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n const registration = yield* makeRegistrationAuthority(\n native,\n mappings,\n backend.operations,\n standalone(() => PasswordUnavailable.make({})),\n create,\n );\n\n context = Context.add(context, key, registration);\n }\n if (email) {\n context = Context.add(\n context,\n EmailAddressPersistence,\n yield* emailKernel.makeSqlEmailAddressPersistence(native, mappings.emails(), {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => EmailUnavailable.make({})),\n proof: proofConfiguration,\n }),\n );\n }\n if (phone) {\n const { column, eq } = backend.operations;\n\n const mapping = (moduleId: string) => ({\n moduleId,\n subject: {\n table: storage.subjects.table,\n id: storage.subjects.id,\n securityRevision: storage.subjects.securityRevision,\n activeCondition: eq(\n column(storage.subjects.table, storage.subjects.status),\n storage.subjects.activeValue,\n ),\n },\n subjectIds: {\n toNative: storage.subjects.toNativeSync,\n toSubject: storage.subjects.toSubjectSync,\n },\n identifier: {\n table: mappings.table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n verifiedAt: \"verifiedAt\",\n activeCondition: eq(column(mappings.table(\"identifiers\"), \"active\"), true),\n },\n credential: {\n table: mappings.table(\"credentials\"),\n id: \"credentialId\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n activeCondition: eq(column(mappings.table(\"credentials\"), \"active\"), true),\n },\n state: {\n table: mappings.table(\"phoneState\"),\n scope: \"scope\",\n state: \"state\",\n version: \"version\",\n encodeInsert: (row: object) => row,\n },\n admission: {\n windowMillis: 60_000,\n networkRequests: 10,\n networkAttempts: 100,\n maximumMessages: 10,\n requestRetentionMillis: 86_400_000,\n },\n engineNowMillis: backend.operations\n .sql`${dialect === \"pg\" ? backend.operations.sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)` : backend.operations.sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`}`,\n encodeInstant: storage.encodeInstant,\n });\n\n const execution = executionKernel.makeTransactionExecution(\n CurrentPhoneTransaction,\n native,\n {\n mode: \"interactive\",\n dialect,\n locking: dialect === \"pg\",\n standaloneGuard: () => standalone(() => PhoneOtpUnavailable.make({})),\n },\n () => PhoneOtpUnavailable.make({}),\n randomId,\n );\n\n const run = <Value, E, Requirements>(\n work: Effect.Effect<Value, E, Requirements>,\n mutation = true,\n ) =>\n execution.admit.pipe(\n Effect.andThen(execution.run(work, mutation)),\n Effect.provideService(LifecycleHooks, hooks),\n );\n\n const allowed = (moduleId: string) =>\n features.some((feature) => feature?.kind === \"phone\" && feature.moduleId === moduleId);\n\n const admission = PhoneAdmission.of({\n admit: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.admitPhone(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n cleanup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.cleanupPhoneAdmission(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n const targets = PhoneSignInTargets.of({\n lookup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.lookupPhone(mapping(request.moduleId), request), false)\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n context = context.pipe(\n Context.add(PhoneAdmission, admission),\n Context.add(PhoneSignInTargets, targets),\n );\n }\n\n if (passkeys.length > 0) {\n // Auth capability metadata determines whether PasskeyConfig is required.\n const services = backend.passkeys({\n database,\n storage,\n namespace: auth.namespace,\n dialect,\n features: passkeys,\n passwordModules: features.flatMap((feature) =>\n feature?.kind === \"password\" ? [feature.moduleId] : [],\n ),\n }) as Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n PasskeyRequirement<A> | LifecycleHooks | SqlClient.SqlClient\n >;\n\n context = Context.merge(context, yield* services);\n }\n\n // The checked capability metadata above determines exactly these service keys.\n return context as Context.Context<Ports<C, Id, A>>;\n }),\n ).pipe(Layer.provide(hooksLayer));\n\n return {\n Config,\n Provisioning: ProvisioningKey,\n layer: services,\n managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, true),\n map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Partial<Record<StorageRole, T>>;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, false),\n };\n };\n\n return { make };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"persistence.mjs","names":[],"sources":["../../src/internal/persistence.ts"],"sourcesContent":["import { digest, randomId } from \"@yielded/auth-crypto\";\nimport { EmailAddressPersistence, EmailUnavailable } from \"@yielded/auth/Email\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { PasskeyConfig } from \"@yielded/auth/Passkey\";\nimport { PasswordPersistence, PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { hooksLayer } from \"@yielded/auth/Persistence\";\nimport { PhoneAdmission, PhoneSignInTargets, PhoneOtpUnavailable } from \"@yielded/auth/PhoneOtp\";\nimport { ProofPersistence, ProofUnavailable } from \"@yielded/auth/Proofs\";\nimport { AuthenticationAuthority, SessionUnavailable } from \"@yielded/auth/Sessions\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport {\n PersistenceConfigurationError,\n type ClaimsCodec,\n type ConfigId,\n type Definition,\n type PersistenceApi,\n type Ports,\n type Roles,\n type Provisioning,\n type ProvisioningRequirement,\n type StorageLayout,\n type SubjectMapping,\n type SubjectOptions,\n type PasskeyFeature,\n type PasskeyRequirement,\n type MappingInput,\n} from \"./configuration\";\nimport { makeEmailKernel, CurrentEmailSql, type EmailSqlDatabase } from \"./email-kernel\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport {\n makePasswordKernel,\n CurrentPasswordSql,\n type PasswordSqlDatabase,\n} from \"./password-kernel\";\nimport { makePhoneKernel, CurrentPhoneTransaction } from \"./phone-kernel\";\nimport {\n makeProofKernel,\n CurrentProofSql,\n type ProofSqlDatabase,\n type ProofSqlQuery,\n} from \"./proof-kernel\";\nimport type { QueryOperations } from \"./query-operations\";\nimport { makeRegistrationAuthority } from \"./registration\";\nimport { makeSessionKernel, CurrentSessionSql, type SessionSqlDatabase } from \"./session-kernel\";\nimport { requireStandalone } from \"./standalone\";\nimport { makeMappings } from \"./storage-mapping\";\nimport {\n tableDefinition,\n storageTables,\n type StorageRole,\n type StorageTable,\n} from \"./storage-tables\";\nimport { validateStorage } from \"./storage-validation\";\nimport { makeTransactionExecutionKernel } from \"./transaction-execution-kernel\";\nimport {\n makeTransactionKernel,\n NativeDatabase,\n type TransactionNativeDatabase,\n} from \"./transaction-kernel\";\n\nexport interface Backend<T extends object, R> {\n readonly makeTable: (definition: StorageTable) => T;\n readonly describe: (table: T) => StorageTable;\n readonly acquire: Effect.Effect<object, PersistenceConfigurationError, R | SqlClient.SqlClient>;\n readonly operations: QueryOperations;\n readonly passkeys: (input: {\n readonly storage: MappingInput;\n readonly namespace: string;\n readonly dialect: \"pg\" | \"sqlite\";\n readonly features: ReadonlyArray<PasskeyFeature>;\n readonly passwordModules: ReadonlyArray<string>;\n }) => Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n PasskeyConfig | LifecycleHooks | SqlClient.SqlClient | NativeDatabase | CurrentProofSql\n >;\n}\n\nconst configError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappingError = (cause: unknown) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause });\n\nconst timestampKeys = new Set([\n \"verifiedAt\",\n \"createdAt\",\n \"lastIssueAt\",\n \"issuedAt\",\n \"expiresAt\",\n \"absoluteExpiresAt\",\n \"retentionUntil\",\n \"claimDeadline\",\n \"retryAt\",\n \"admittedAt\",\n \"deadline\",\n \"occurredAt\",\n \"dedupUntil\",\n]);\n\nexport const createPersistence = <T extends object, R>(\n backend: Backend<T, R>,\n): PersistenceApi<T, R> => {\n const proofKernel = makeProofKernel(backend.operations);\n const passwordKernel = makePasswordKernel(backend.operations, proofKernel);\n const emailKernel = makeEmailKernel(backend.operations, proofKernel);\n const sessionKernel = makeSessionKernel(backend.operations);\n const transactionKernel = makeTransactionKernel(backend.operations);\n const executionKernel = makeTransactionExecutionKernel(transactionKernel);\n const phoneKernel = makePhoneKernel(backend.operations, transactionKernel);\n\n const make = <C extends ClaimsCodec, const Id extends string, const A extends Definition<C, Id>>(\n auth: A & Definition<C, Id>,\n ) => {\n const features = Object.values(auth.strategies).map((strategy) => strategy.persistence);\n const phone = features.some((feature) => feature?.kind === \"phone\");\n const password = features.some((feature) => feature?.kind === \"password\");\n\n const passkeys = features.filter(\n (feature): feature is PasskeyFeature => feature?.kind === \"passkey\",\n );\n\n const management = features.some(\n (feature) => feature?.kind === \"password\" && feature.management,\n );\n\n const email = features.some((feature) => feature?.kind === \"email\" && feature.addresses);\n const proofs = phone || management || email;\n\n const roles: StorageRole[] = [\"identifiers\", \"credentials\", \"sessions\", \"sessionFlows\"];\n\n if (password)\n roles.push(\n \"passwords\",\n \"passwordAttempts\",\n \"passwordScopes\",\n \"passwordCharges\",\n \"passwordCommands\",\n );\n if (management) roles.push(\"passwordRegistrations\");\n if (email) roles.push(\"emailCredentials\", \"emailCommands\");\n if (phone) roles.push(\"phoneState\");\n if (passkeys.length > 0)\n roles.push(\n \"passkeyCredentials\",\n \"passkeyOwnership\",\n \"passkeyHandles\",\n \"passkeyModules\",\n \"passkeyFlows\",\n \"passkeyAdmissions\",\n \"passkeyCharges\",\n );\n if (passkeys.some((feature) => feature.management)) roles.push(\"passkeyCommands\");\n if (proofs)\n roles.push(\n \"proofRequests\",\n \"proofSeries\",\n \"proofGenerations\",\n \"proofContinuations\",\n \"proofScopes\",\n \"proofAbuse\",\n \"proofFailures\",\n \"proofCommands\",\n );\n\n const ConfigKey = Context.Service<\n ConfigId<A[\"namespace\"]>,\n StorageLayout<T, Roles<C, Id, A>>\n >()(`@yielded/auth-persistence/${auth.namespace}/Config`);\n\n const Config = Object.assign(ConfigKey, {\n layer: (value: StorageLayout<T, Roles<C, Id, A>>) => Layer.succeed(ConfigKey, value),\n });\n\n const ProvisioningKey = Context.Service<ProvisioningRequirement<A>, Provisioning<A>>()(\n `@yielded/auth-persistence/${auth.namespace}/Provisioning`,\n );\n\n const layout = <N, Instant>(\n options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<StorageRole, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n },\n managed: boolean,\n ): StorageLayout<T, Roles<C, Id, A>> => {\n const subject = options.subjects;\n\n if (passkeys.length > 0 && options.timestamps !== undefined)\n throw configError(\n \"Composed passkey storage uses integer milliseconds; use an explicit passkey adapter for a custom timestamp representation\",\n );\n const description = backend.describe(subject.table);\n const idColumn = description.columns[subject.id];\n\n for (const key of [subject.id, subject.status, subject.securityRevision]) {\n if (description.columns[key] === undefined)\n throw configError(`Missing subject column ${key}`);\n }\n if (subject.activeValue === undefined)\n throw configError(\"An explicit active subject value is required\");\n\n if (idColumn === undefined || idColumn.type === \"boolean\")\n throw configError(\"Subject ID must map a text or integer column\");\n\n const prefix =\n options.prefix ?? `auth_${digest(auth.namespace).slice(0, 12).replaceAll(\"-\", \"_\")}`;\n\n const schema: Partial<Record<StorageRole, T>> = { ...options.tables };\n\n for (const role of roles) {\n if (schema[role] === undefined && managed) {\n const definition = tableDefinition(role, `${prefix}_${role}`, idColumn.type);\n\n const adjusted =\n options.timestamps === undefined\n ? definition\n : {\n ...definition,\n columns: Object.fromEntries(\n Object.entries(definition.columns).map(([key, column]) => [\n key,\n timestampKeys.has(key)\n ? { ...column, type: options.timestamps?.type ?? column.type }\n : column,\n ]),\n ),\n };\n\n schema[role] = backend.makeTable(adjusted);\n }\n }\n for (const role of roles) {\n if (schema[role] === undefined) throw configError(`Missing ${role} table`);\n }\n const instantCodec = options.timestamps?.codec;\n\n const decodeInstant =\n instantCodec === undefined\n ? Schema.decodeUnknownEffect(Schema.Int)\n : Schema.decodeUnknownEffect(instantCodec);\n\n const decodeInstantSync =\n instantCodec === undefined\n ? Schema.decodeUnknownSync(Schema.Int)\n : Schema.decodeUnknownSync(instantCodec);\n\n const subjects: SubjectMapping = {\n table: subject.table,\n id: subject.id,\n status: subject.status,\n securityRevision: subject.securityRevision,\n activeValue: subject.activeValue,\n requirements: subject.requirements,\n actionRequirements: subject.actionRequirements ?? subject.requirements,\n toSubject: (id) =>\n Schema.decodeUnknownEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toNative: (id) =>\n Schema.encodeEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toSubjectSync: Schema.decodeUnknownSync(subject.idCodec),\n toNativeSync: Schema.encodeSync(subject.idCodec),\n };\n\n return Object.freeze({\n namespace: auth.namespace,\n schema: Object.freeze(schema) as Readonly<Record<Roles<C, Id, A>, T>>,\n tables: schema,\n subjects,\n encodeInstant:\n instantCodec === undefined ? (millis: number) => millis : Schema.encodeSync(instantCodec),\n decodeInstant: (value: unknown) => decodeInstant(value).pipe(Effect.mapError(mappingError)),\n decodeInstantSync,\n });\n };\n\n const services = Layer.effectContext(\n Effect.gen(function* () {\n const storage = yield* ConfigKey;\n const hooks = yield* LifecycleHooks;\n const client = yield* SqlClient.SqlClient;\n const database = yield* backend.acquire;\n\n const dialect = client.onDialectOrElse({\n pg: () => \"pg\" as const,\n sqlite: () => \"sqlite\" as const,\n orElse: () => undefined,\n });\n\n if (dialect === undefined)\n return yield* configError(\"Use an explicit adapter for this SQL dialect\");\n if (auth.sessionMode !== \"stateful\")\n return yield* configError(\"The composed layer currently requires stateful sessions\");\n if (\n features.some(\n (feature) =>\n feature === undefined ||\n (\"lifecycle\" in feature && feature.lifecycle) ||\n (feature.kind === \"email\" && !feature.addresses),\n )\n )\n return yield* configError(\n \"Use explicit services for strategies without composed persistence support\",\n );\n if (storage.namespace !== auth.namespace)\n return yield* configError(\n \"Persistence configuration belongs to a different Auth definition\",\n );\n for (const role of roles) {\n const table = (storage.schema as Partial<Record<StorageRole, T>>)[role];\n\n if (table === undefined) return yield* configError(`Missing ${role} table`);\n const description = backend.describe(table);\n const columns = description.columns;\n\n for (const name of Object.keys(storageTables[role].columns)) {\n if (columns[name] === undefined)\n return yield* configError(`Missing ${role}.${name} column`);\n }\n yield* validateStorage(dialect, description, storageTables[role].unique);\n }\n yield* validateStorage(dialect, backend.describe(storage.subjects.table as T), [\n [storage.subjects.id],\n ]);\n const mappings = makeMappings(storage);\n\n const standalone = <E>(error: () => E) =>\n requireStandalone(error, client.transactionService);\n\n // Backend validation owns the foreign query-builder shape, never the decoded rows.\n const native = database as ProofSqlDatabase &\n PasswordSqlDatabase &\n EmailSqlDatabase &\n SessionSqlDatabase &\n TransactionNativeDatabase;\n\n const options = {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => SessionUnavailable.make({})),\n };\n\n const sessionMapping = mappings.sessions(auth.claims);\n\n const sessionServices = yield* sessionKernel\n .makeSqlStatefulSessions(sessionMapping, options)\n .pipe(Effect.provideService(CurrentSessionSql, native));\n\n const authority = yield* sessionKernel\n .makeSqlAuthenticationAuthority<C[\"Type\"]>(\n { ...mappings.authority(), isConstraintConflict: () => false },\n options,\n )\n .pipe(Effect.provideService(CurrentSessionSql, native));\n\n let context: Context.Context<never> = Context.make(AuthenticationAuthority, authority).pipe(\n Context.add(\n auth.sessions.StatefulSessionPersistence,\n sessionServices.statefulSessionPersistence,\n ),\n Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository),\n );\n\n const proofConfiguration = proofs\n ? {\n mapping: mappings.proofs(),\n configuration: {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => ProofUnavailable.make({})),\n insertIfAbsent: (query: ProofSqlQuery) => query.onConflictDoNothing(),\n },\n }\n : undefined;\n\n if (proofConfiguration !== undefined) {\n context = Context.add(\n context,\n ProofPersistence,\n yield* proofKernel\n .makeSqlProofPersistence(proofConfiguration.mapping, proofConfiguration.configuration)\n .pipe(Effect.provideService(CurrentProofSql, native)),\n );\n }\n\n if (password) {\n const persistence = yield* passwordKernel\n .makeSqlPasswordPersistence(mappings.passwords(), {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => PasswordUnavailable.make({})),\n insertIfAbsent: (query) => query.onConflictDoNothing(),\n proof: proofConfiguration,\n })\n .pipe(Effect.provideService(CurrentPasswordSql, native));\n\n context = Context.add(context, PasswordPersistence, persistence);\n }\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n\n if (key === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n const registration = yield* makeRegistrationAuthority(\n mappings,\n backend.operations,\n standalone(() => PasswordUnavailable.make({})),\n ProvisioningKey,\n name,\n ).pipe(Effect.provideService(CurrentPasswordSql, native));\n\n context = Context.add(context, key, registration);\n }\n if (email) {\n context = Context.add(\n context,\n EmailAddressPersistence,\n yield* emailKernel\n .makeSqlEmailAddressPersistence(mappings.emails(), {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => EmailUnavailable.make({})),\n proof: proofConfiguration,\n })\n .pipe(Effect.provideService(CurrentEmailSql, native)),\n );\n }\n if (phone) {\n const { column, eq } = backend.operations;\n\n const mapping = (moduleId: string) => ({\n moduleId,\n subject: {\n table: storage.subjects.table,\n id: storage.subjects.id,\n securityRevision: storage.subjects.securityRevision,\n activeCondition: eq(\n column(storage.subjects.table, storage.subjects.status),\n storage.subjects.activeValue,\n ),\n },\n subjectIds: {\n toNative: storage.subjects.toNativeSync,\n toSubject: storage.subjects.toSubjectSync,\n },\n identifier: {\n table: mappings.table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n verifiedAt: \"verifiedAt\",\n activeCondition: eq(column(mappings.table(\"identifiers\"), \"active\"), true),\n },\n credential: {\n table: mappings.table(\"credentials\"),\n id: \"credentialId\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n activeCondition: eq(column(mappings.table(\"credentials\"), \"active\"), true),\n },\n state: {\n table: mappings.table(\"phoneState\"),\n scope: \"scope\",\n state: \"state\",\n version: \"version\",\n encodeInsert: (row: object) => row,\n },\n admission: {\n windowMillis: 60_000,\n networkRequests: 10,\n networkAttempts: 100,\n maximumMessages: 10,\n requestRetentionMillis: 86_400_000,\n },\n engineNowMillis: backend.operations\n .sql`${dialect === \"pg\" ? backend.operations.sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)` : backend.operations.sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`}`,\n encodeInstant: storage.encodeInstant,\n });\n\n const execution = yield* executionKernel\n .makeTransactionExecution(\n CurrentPhoneTransaction,\n {\n mode: \"interactive\",\n dialect,\n locking: dialect === \"pg\",\n standaloneGuard: () => standalone(() => PhoneOtpUnavailable.make({})),\n },\n () => PhoneOtpUnavailable.make({}),\n randomId,\n )\n .pipe(Effect.provideService(NativeDatabase, native));\n\n const run = <Value, E, Requirements>(\n work: Effect.Effect<Value, E, Requirements>,\n mutation = true,\n ) =>\n execution.admit.pipe(\n Effect.andThen(execution.run(work, mutation)),\n Effect.provideService(LifecycleHooks, hooks),\n );\n\n const allowed = (moduleId: string) =>\n features.some((feature) => feature?.kind === \"phone\" && feature.moduleId === moduleId);\n\n const admission = PhoneAdmission.of({\n admit: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.admitPhone(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n cleanup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.cleanupPhoneAdmission(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n const targets = PhoneSignInTargets.of({\n lookup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.lookupPhone(mapping(request.moduleId), request), false)\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n context = context.pipe(\n Context.add(PhoneAdmission, admission),\n Context.add(PhoneSignInTargets, targets),\n );\n }\n\n if (passkeys.length > 0) {\n // Auth capability metadata determines whether PasskeyConfig is required.\n const services = backend.passkeys({\n storage,\n namespace: auth.namespace,\n dialect,\n features: passkeys,\n passwordModules: features.flatMap((feature) =>\n feature?.kind === \"password\" ? [feature.moduleId] : [],\n ),\n }) as Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n | PasskeyRequirement<A>\n | LifecycleHooks\n | SqlClient.SqlClient\n | NativeDatabase\n | CurrentProofSql\n >;\n\n context = Context.merge(\n context,\n yield* services.pipe(\n Effect.provideService(NativeDatabase, native),\n Effect.provideService(CurrentProofSql, native),\n ),\n );\n }\n\n // The checked capability metadata above determines exactly these service keys.\n return context as Context.Context<Ports<C, Id, A>>;\n }),\n ).pipe(Layer.provide(hooksLayer));\n\n return {\n Config,\n Provisioning: ProvisioningKey,\n layer: services,\n managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, true),\n map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Partial<Record<StorageRole, T>>;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, false),\n };\n };\n\n return { make };\n};\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { AnyProofPersistenceMapping, ProofPersistenceMapping } from "./models/pr
4
4
  import { Context, Effect } from "effect";
5
5
  import { CurrentCommitJournal, LifecycleHooks } from "@yielded/auth/Hooks";
6
6
  import { ProofAttemptDecision, ProofBinding, ProofCleanupResult, ProofCompletionDecision, ProofCompletionPlan, ProofDeliveryClaim, ProofDeliveryOutcome, ProofPolicy, ProofRequestConflict, ProofUnavailable, ProofVersion } from "@yielded/auth/Proofs";
7
- import * as SqlError$1 from "effect/unstable/sql/SqlError";
7
+ import * as SqlError$1 from "effect/sql/SqlError";
8
8
  //#region src/internal/proof-kernel.d.ts
9
9
  type AdapterFailure = QueryFailure | PersistenceMappingError | SqlError$1.SqlError;
10
10
  export interface ProofSqlQuery<A = ReadonlyArray<any>> extends Effect.Effect<A, AdapterFailure> {
@@ -37,7 +37,7 @@ export interface ProofSqlConfiguration {
37
37
  readonly insertIfAbsent: (query: ProofSqlQuery, selfKey: string, selfValue: unknown) => ProofSqlQuery;
38
38
  }
39
39
  export declare const makeProofKernel: <Fragment extends SqlFragment = SqlFragment, Column extends SqlColumn = SqlColumn>(operations: QueryOperations<Fragment, Column>) => {
40
- makeSqlProofPersistence: (database: ProofSqlDatabase, mapping: AnyProofPersistenceMapping<Fragment>, configuration: ProofSqlConfiguration) => Effect.Effect<{
40
+ makeSqlProofPersistence: (mapping: AnyProofPersistenceMapping<Fragment>, configuration: ProofSqlConfiguration) => Effect.Effect<{
41
41
  readonly issue: <A>(input: {
42
42
  readonly record: import("@yielded/auth/Proofs").ProofRecord;
43
43
  readonly policy: ProofPolicy;
@@ -85,7 +85,7 @@ export declare const makeProofKernel: <Fragment extends SqlFragment = SqlFragmen
85
85
  readonly nowMillis: number;
86
86
  readonly limit: number;
87
87
  }, prepare: import("@yielded/auth/Proofs").PrepareProofCommit<ProofCleanupResult, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, ProofUnavailable>;
88
- }, never, LifecycleHooks>;
88
+ }, never, CurrentProofSql | LifecycleHooks>;
89
89
  checkProofCompletionIn: (mapping: AnyProofPersistenceMapping<Fragment>, configuration: ProofSqlConfiguration, input: import("@yielded/auth/Proofs").ProofCompletionInput) => Effect.Effect<boolean, ProofUnavailable | QueryFailure, CurrentProofSql>;
90
90
  completeProofPlanIn: <Rq extends TableModel, S extends TableModel, G extends TableModel, Cn extends TableModel, Rs extends TableModel, Aev extends TableModel, F extends TableModel, C extends TableModel, Sub extends TableModel, I extends TableModel, Cr extends TableModel, NativeId, A, E, R>(mapping: ProofPersistenceMapping<Rq, S, G, Cn, Rs, Aev, F, C, Sub, I, Cr, NativeId, SqlExpression>, configuration: ProofSqlConfiguration, plan: ProofCompletionPlan, protectedMutation: Effect.Effect<boolean, E, R>, project: (decision: ProofCompletionDecision) => A) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, E | ProofUnavailable | QueryFailure, R | CurrentCommitJournal | CurrentProofSql>;
91
91
  };
@@ -246,7 +246,8 @@ const makeProofKernel = (operations) => {
246
246
  return yield* run;
247
247
  }) : run;
248
248
  };
249
- const makeSqlProofPersistence = Effect.fn("makeSqlProofPersistence")(function* (database, mapping, configuration) {
249
+ const makeSqlProofPersistence = Effect.fn("makeSqlProofPersistence")(function* (mapping, configuration) {
250
+ const database = yield* CurrentProofSql;
250
251
  const hooks = yield* LifecycleHooks;
251
252
  return ProofPersistence.of({
252
253
  issue: (input, prepare) => owned(database, mapping, configuration, Effect.gen(function* () {