@yielded/auth-persistence 0.1.0-beta.29 → 0.1.0-beta.31

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 (65) hide show
  1. package/README.md +6 -6
  2. package/dist/Adapter.d.mts +1 -1
  3. package/dist/Testing.d.mts +44 -0
  4. package/dist/Testing.mjs +310 -0
  5. package/dist/Testing.mjs.map +1 -0
  6. package/dist/internal/configuration.d.mts +18 -8
  7. package/dist/internal/configuration.mjs.map +1 -1
  8. package/dist/internal/models/oauth-model.d.mts +10 -1
  9. package/dist/internal/models/oauth-model.mjs.map +1 -1
  10. package/dist/internal/models/password-model.d.mts +2 -1
  11. package/dist/internal/models/password-model.mjs.map +1 -1
  12. package/dist/internal/oauth/native-accounts.mjs +42 -1
  13. package/dist/internal/oauth/native-accounts.mjs.map +1 -1
  14. package/dist/internal/oauth/native-state.d.mts +1 -0
  15. package/dist/internal/oauth/native-state.mjs +2 -2
  16. package/dist/internal/oauth/native-state.mjs.map +1 -1
  17. package/dist/internal/passkey-managed.mjs +4 -2
  18. package/dist/internal/passkey-managed.mjs.map +1 -1
  19. package/dist/internal/password-native.mjs +14 -0
  20. package/dist/internal/password-native.mjs.map +1 -1
  21. package/dist/internal/password-registration-native.d.mts +1 -1
  22. package/dist/internal/persistence.d.mts +3 -0
  23. package/dist/internal/persistence.mjs +4 -6
  24. package/dist/internal/persistence.mjs.map +1 -1
  25. package/dist/internal/registration.mjs +17 -8
  26. package/dist/internal/registration.mjs.map +1 -1
  27. package/dist/internal/session-native-authority.mjs +2 -1
  28. package/dist/internal/session-native-authority.mjs.map +1 -1
  29. package/dist/internal/session-native-login.mjs +2 -1
  30. package/dist/internal/session-native-login.mjs.map +1 -1
  31. package/dist/internal/session-native-pending-read.mjs +1 -1
  32. package/dist/internal/session-native-pending-read.mjs.map +1 -1
  33. package/dist/internal/session-native-state.mjs +21 -8
  34. package/dist/internal/session-native-state.mjs.map +1 -1
  35. package/dist/internal/session-native-stateful.mjs +2 -1
  36. package/dist/internal/session-native-stateful.mjs.map +1 -1
  37. package/dist/internal/session-native-step-up.mjs +4 -2
  38. package/dist/internal/session-native-step-up.mjs.map +1 -1
  39. package/dist/internal/sql-change.mjs +11 -1
  40. package/dist/internal/sql-change.mjs.map +1 -1
  41. package/dist/internal/sqlite-policy-guard.mjs +23 -0
  42. package/dist/internal/sqlite-policy-guard.mjs.map +1 -0
  43. package/dist/internal/storage-mapping.d.mts +9 -5
  44. package/dist/internal/storage-mapping.mjs +16 -4
  45. package/dist/internal/storage-mapping.mjs.map +1 -1
  46. package/package.json +1 -1
  47. package/src/Testing.ts +652 -0
  48. package/src/internal/configuration.ts +26 -8
  49. package/src/internal/models/oauth-model.ts +10 -0
  50. package/src/internal/models/password-model.ts +2 -1
  51. package/src/internal/oauth/native-accounts.ts +72 -1
  52. package/src/internal/oauth/native-state.ts +6 -2
  53. package/src/internal/passkey-managed.ts +8 -2
  54. package/src/internal/password-native.ts +28 -2
  55. package/src/internal/persistence.ts +174 -164
  56. package/src/internal/registration.ts +53 -40
  57. package/src/internal/session-native-authority.ts +3 -1
  58. package/src/internal/session-native-login.ts +3 -1
  59. package/src/internal/session-native-pending-read.ts +1 -1
  60. package/src/internal/session-native-state.ts +29 -10
  61. package/src/internal/session-native-stateful.ts +3 -1
  62. package/src/internal/session-native-step-up.ts +5 -2
  63. package/src/internal/sql-change.ts +14 -1
  64. package/src/internal/sqlite-policy-guard.ts +34 -0
  65. package/src/internal/storage-mapping.ts +40 -4
@@ -1 +1 @@
1
- {"version":3,"file":"storage-mapping.mjs","names":[],"sources":["../../src/internal/storage-mapping.ts"],"sourcesContent":["import { EmailCredentialSnapshot } from \"@yielded/auth/Email\";\nimport { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport {\n PasswordCredentialSnapshot,\n EncodedPasswordHash,\n type PasswordReplacement,\n} from \"@yielded/auth/Password\";\nimport { TokenDigest } from \"@yielded/auth/Schema\";\nimport {\n SecurityRevision,\n AuthenticationEvidence,\n SessionId,\n SessionMetadata,\n SessionAuthenticationProvenance,\n SessionCredentialVersion,\n type StatefulSessionRecord,\n} from \"@yielded/auth/Sessions\";\nimport { Crypto, DateTime, Effect, Redacted, Schema, Struct } from \"effect\";\n\nimport type { MappingInput } from \"./configuration\";\nimport { randomId } from \"./crypto\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport { requiredEmailAddressConstraints, type AnyEmailAddressMapping } from \"./models/email-model\";\nimport {\n requiredPasswordConstraints,\n type AnyPasswordPersistenceMapping,\n} from \"./models/password-model\";\nimport { requiredProofConstraints, type AnyProofPersistenceMapping } from \"./models/proof-model\";\nimport type { StatefulSessionMapping, PendingAuthenticationMapping } from \"./models/session-model\";\nimport { makeStorageClock } from \"./storage-clock\";\nimport { storageTables, type StorageRole } from \"./storage-tables\";\nimport type { TableModel, SqlExpression } from \"./table-model\";\n\nconst failure = (cause: unknown) => PersistenceMappingError.make({ operation: \"decode\", cause });\n\nconst decode = <S extends Schema.Codec<unknown, unknown>>(schema: S, value: unknown) =>\n Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(failure));\n\nconst string = (value: unknown) => Schema.decodeUnknownSync(Schema.String)(value);\n\n/** Derive shared row mappings from a managed or custom storage layout.\n * Acquire Effect Crypto once; the returned allocators retain that implementation.\n * Each factory requires its role tables to exist. Adapter authors supply typed\n * table handles and dialect-specific clocks/commit predicates, and may refine\n * authority policy for explicit services. This does not alter composed defaults.\n */\nexport const makeMappings = Effect.fnUntraced(function* (input: MappingInput) {\n const crypto = yield* Crypto.Crypto;\n\n const allocate = randomId.pipe(\n Effect.provideService(Crypto.Crypto, crypto),\n Effect.mapError(failure),\n );\n\n const table = (role: StorageRole) => {\n const found = input.tables[role];\n\n if (found === undefined) throw failure(`Missing ${role} mapping`);\n\n return found;\n };\n\n const mapped = (role: StorageRole) => ({\n table: table(role),\n ...Object.fromEntries(Object.keys(storageTables[role].columns).map((key) => [key, key])),\n });\n\n const { subjects: s, encodeInstant: instant, decodeInstant: readInstant } = input;\n const subjectId = { toNative: s.toNative, toSubject: s.toSubject, equals: Object.is };\n\n const subject = {\n table: s.table,\n id: s.id,\n status: s.status,\n securityRevision: s.securityRevision,\n isActiveStatus: (value: unknown) => Object.is(value, s.activeValue),\n d1ActiveStatusValue: s.activeValue,\n activeStatusValue: s.activeValue,\n decodeRequirement: s.requirements,\n decodeActionRequirement: s.actionRequirements,\n nextSecurityRevision: () => allocate.pipe(Effect.map(SecurityRevision.make)),\n };\n\n const authorityCredential = () => ({\n ...mapped(\"credentials\"),\n subjectId: \"subjectId\",\n credentialId: \"credentialId\",\n revision: \"revision\",\n status: \"active\",\n activeStatusValue: true,\n isActiveStatus: (value: unknown) => value === true,\n encodeInsert: (row: object) => ({ ...row, active: true }),\n encodeRevision: (revision: SecurityRevision) => ({ revision }),\n });\n\n const authority = () => ({ subjectId, subject, credential: authorityCredential() });\n\n const clock = yield* makeStorageClock(input);\n\n const proofs = (): AnyProofPersistenceMapping<SqlExpression> => ({\n constraints: requiredProofConstraints,\n subjectId,\n subject: { table: s.table, id: s.id },\n clock,\n proof: {\n ...mapped(\"proofs\"),\n moduleId: \"moduleId\",\n purpose: \"purpose\",\n seriesKey: \"seriesKey\",\n proofId: \"proofId\",\n binding: \"binding\",\n verifierKeyId: \"verifierKeyId\",\n verifierDigest: \"verifierDigest\",\n issuedAt: \"issuedAt\",\n expiresAt: \"expiresAt\",\n failedAttempts: \"failedAttempts\",\n encodeInsert: () => ({}),\n },\n });\n\n const passwords = (): AnyPasswordPersistenceMapping<SqlExpression> => {\n const verifier = (replacement: PasswordReplacement) => ({\n verifier: Redacted.value(replacement.verifier),\n normalization: replacement.normalization,\n });\n\n return {\n subjectId,\n subject,\n authorityCredential: authorityCredential(),\n constraints: requiredPasswordConstraints,\n encodeInstant: instant,\n decodeInstant: readInstant,\n allocateCredentialId: allocate,\n allocateRevision: allocate.pipe(Effect.map(SecurityRevision.make)),\n sessionInvalidation: \"same-authority-immediate\",\n identifier: {\n table: table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n verifiedAt: \"verifiedAt\",\n bindingRevision: \"revision\",\n isCurrent: (row) => row.active === true,\n encodeInitialInsert: (identifier, subjectId, revision) => ({\n ...identifier,\n subjectId,\n revision,\n verifiedAt: null,\n active: true,\n }),\n },\n credential: {\n ...mapped(\"passwords\"),\n moduleId: \"moduleId\",\n subjectId: \"subjectId\",\n credentialId: \"credentialId\",\n credentialRevision: \"credentialRevision\",\n verifierVersion: \"verifierVersion\",\n verifier: \"verifier\",\n normalization: \"normalization\",\n encodeInsert: ({ replacement, ...row }) => ({ ...row, ...verifier(replacement) }),\n encodeVerifier: (hash, verifierVersion) => ({\n verifier: Redacted.value(hash),\n verifierVersion,\n }),\n encodeReplacement: ({ replacement, ...row }) => ({ ...row, ...verifier(replacement) }),\n decode: ({ moduleId, subject: row, identifier, credential }) =>\n Effect.gen(function* () {\n const id = yield* s.toSubject(row[s.id]);\n const hash = yield* decode(EncodedPasswordHash, credential.verifier);\n\n return yield* decode(PasswordCredentialSnapshot, {\n moduleId,\n revision: {\n subjectId: id,\n securityRevision: row[s.securityRevision],\n credentials: [\n {\n credentialId: credential.credentialId,\n revision: credential.credentialRevision,\n },\n ],\n },\n credentialId: credential.credentialId,\n credentialRevision: credential.credentialRevision,\n verifierVersion: credential.verifierVersion,\n verifier: hash,\n normalization: credential.normalization,\n identifier: yield* decode(LoginIdentifier, {\n namespace: identifier.namespace,\n value: identifier.value,\n }),\n identifierBindingRevision: identifier.revision,\n ...(identifier.verifiedAt === null\n ? {}\n : { identifierVerifiedAtMillis: yield* readInstant(identifier.verifiedAt) }),\n });\n }),\n },\n clock,\n };\n };\n\n const emails = (): AnyEmailAddressMapping<SqlExpression> => ({\n subjectId,\n subject: { ...subject, activeStatusValue: s.activeValue },\n constraints: requiredEmailAddressConstraints,\n addressCardinality: \"single\",\n changeDisposition: \"retire-source\",\n clock,\n encodeInstant: instant,\n decodeInstant: readInstant,\n allocateCredentialId: allocate,\n allocateRevision: allocate.pipe(Effect.map(SecurityRevision.make)),\n sessionInvalidation: \"same-authority-immediate\",\n isIdentifierConflict: () => false,\n isCredentialConflict: () => false,\n authorityCredential: {\n ...authorityCredential(),\n encodeActivation: (revision) => ({ revision, active: true }),\n encodeRetirement: (revision) => ({ revision, active: false }),\n },\n identifier: {\n table: table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n verifiedAt: \"verifiedAt\",\n bindingRevision: \"revision\",\n isCurrent: (row) => row.active === true && row.verifiedAt !== null,\n isMutableTarget: (row) => row.active === true && row.verifiedAt === null,\n encodeVerifiedInsert: ({ identifier, subjectId, verifiedAtMillis, bindingRevision }) => ({\n ...identifier,\n subjectId,\n verifiedAt: instant(verifiedAtMillis),\n revision: bindingRevision,\n active: true,\n }),\n encodeVerification: ({ verifiedAtMillis, bindingRevision }) => ({\n verifiedAt: instant(verifiedAtMillis),\n revision: bindingRevision,\n active: true,\n }),\n encodeRetirement: ({ bindingRevision }) => ({ revision: bindingRevision, active: false }),\n },\n credential: {\n activeStatusValue: true,\n table: table(\"emailCredentials\"),\n moduleId: \"moduleId\",\n subjectId: \"subjectId\",\n credentialId: \"credentialId\",\n identifierNamespace: \"identifierNamespace\",\n identifierValue: \"identifierValue\",\n credentialRevision: \"credentialRevision\",\n status: \"active\",\n isActiveStatus: (value) => value === true,\n encodeVerifiedInsert: ({ identifier, ...row }) => ({\n ...row,\n identifierNamespace: identifier.namespace,\n identifierValue: identifier.value,\n active: true,\n }),\n encodeActivation: ({ identifier, credentialRevision }) => ({\n identifierNamespace: identifier.namespace,\n identifierValue: identifier.value,\n credentialRevision,\n active: true,\n }),\n encodeRetirement: ({ credentialRevision }) => ({ credentialRevision, active: false }),\n decode: ({ moduleId, subject: row, identifier, credential }) =>\n Effect.gen(function* () {\n return yield* decode(\n Schema.Struct(Struct.omit(EmailCredentialSnapshot.fields, [\"requirement\"])),\n {\n moduleId,\n identifier: { namespace: identifier.namespace, value: identifier.value },\n identifierRevision: identifier.revision,\n verifiedAtMillis: yield* readInstant(identifier.verifiedAt),\n credentialId: credential.credentialId,\n credentialRevision: credential.credentialRevision,\n revision: {\n subjectId: yield* s.toSubject(row[s.id]),\n securityRevision: row[s.securityRevision],\n credentials: [\n {\n credentialId: credential.credentialId,\n revision: credential.credentialRevision,\n },\n ],\n },\n },\n );\n }),\n },\n });\n\n const pending = <C extends Schema.Codec<unknown, unknown, never, never>>(\n claims: C,\n moduleId: string,\n ): PendingAuthenticationMapping<C[\"Type\"], TableModel, TableModel, TableModel, unknown> => {\n const record = Schema.fromJsonString(\n Schema.Struct({\n digest: TokenDigest,\n version: SecurityRevision,\n evidence: AuthenticationEvidence,\n expiresAt: Schema.DateTimeUtcFromMillis,\n attemptLimit: Schema.Int.check(Schema.isGreaterThan(0)),\n claims: Schema.Unknown,\n }),\n );\n\n return {\n ...authority(),\n moduleId,\n clock,\n isConstraintConflict: () => false,\n constraints: { pendingDigest: \"unique(pending.digest)\" },\n pending: {\n table: table(\"pending\"),\n moduleId: \"moduleId\",\n kind: \"kind\",\n digest: \"digest\",\n version: \"version\",\n flowId: \"flowId\",\n subjectId: \"subjectId\",\n bindingDigest: \"bindingDigest\",\n snapshot: \"snapshot\",\n expiresAt: \"expiresAt\",\n attemptLimit: \"attemptLimit\",\n failedAttempts: \"failedAttempts\",\n consumed: \"consumed\",\n encodeInstant: (date) => instant(DateTime.toEpochMillis(date)),\n allocateVersion: allocate.pipe(Effect.map(SecurityRevision.make)),\n encodeInsert: (value) => ({\n ...value,\n expiresAt: instant(DateTime.toEpochMillis(value.expiresAt)),\n failedAttempts: 0,\n consumed: false,\n }),\n },\n login: {\n encode: (value) =>\n Schema.encodeEffect(claims)(value.claims).pipe(\n Effect.flatMap((saved) => Schema.encodeEffect(record)({ ...value, claims: saved })),\n Effect.mapError(failure),\n ),\n decode: (value) =>\n decode(record, value).pipe(\n Effect.flatMap((saved) =>\n decode(claims, saved.claims).pipe(\n Effect.map((decoded) => ({ ...saved, claims: decoded })),\n ),\n ),\n ),\n },\n };\n };\n\n const sessions = <C extends Schema.Codec<unknown, unknown, never, never>>(\n claims: C,\n moduleId: string,\n ): StatefulSessionMapping<\n C[\"Type\"],\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n unknown,\n unknown\n > => {\n const record = Schema.fromJsonString(\n Schema.Struct({\n ...SessionMetadata.fields,\n claims: Schema.Unknown,\n digest: TokenDigest,\n provenance: SessionAuthenticationProvenance,\n credentialVersion: SessionCredentialVersion,\n }),\n );\n\n const encodeRow = (value: StatefulSessionRecord<C[\"Type\"]>) => ({\n digest: value.digest,\n securityRevision: value.securityRevision,\n issuedAt: instant(DateTime.toEpochMillis(value.issuedAt)),\n expiresAt: instant(DateTime.toEpochMillis(value.expiresAt)),\n absoluteExpiresAt: instant(DateTime.toEpochMillis(value.absoluteExpiresAt)),\n record: Schema.encodeSync(record)({\n ...value,\n claims: Schema.encodeSync(claims)(value.claims),\n }),\n });\n\n const login = pending(claims, moduleId);\n\n return {\n ...authority(),\n moduleId,\n clock,\n isConstraintConflict: () => false,\n pending: { pending: login.pending, login: login.login },\n constraints: {\n sessionDigest: \"unique(session.digest)\",\n pendingDigest: \"unique(pending.digest)\",\n },\n sessionId: {\n toNative: (id) => Effect.succeed(id),\n toSession: (id) => decode(SessionId, id),\n equals: Object.is,\n },\n session: {\n table: table(\"sessions\"),\n sessionId: \"sessionId\",\n subjectId: \"subjectId\",\n digest: \"digest\",\n securityRevision: \"securityRevision\",\n issuedAt: \"issuedAt\",\n expiresAt: \"expiresAt\",\n absoluteExpiresAt: \"absoluteExpiresAt\",\n encodeInstant: (date) => instant(DateTime.toEpochMillis(date)),\n allocateId: allocate,\n encodeInsert: (value, ids) => ({ ...encodeRow(value), ...ids }),\n encodeRotation: encodeRow,\n decode: (row) =>\n Effect.gen(function* () {\n const saved = yield* decode(record, row.record),\n decodedClaims = yield* decode(claims, saved.claims);\n\n return {\n ...saved,\n issuedAt: DateTime.makeUnsafe(yield* readInstant(row.issuedAt)),\n claims: decodedClaims,\n };\n }),\n },\n };\n };\n\n return { table, authority, proofs, passwords, emails, sessions, pending, string };\n});\n"],"mappings":";;;;;;;;;;;;;;AAiCA,MAAM,WAAW,UAAmB,wBAAwB,KAAK;CAAE,WAAW;CAAU;AAAM,CAAC;AAE/F,MAAM,UAAoD,QAAW,UACnE,OAAO,oBAAoB,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,OAAO,SAAS,OAAO,CAAC;AAEzE,MAAM,UAAU,UAAmB,OAAO,kBAAkB,OAAO,MAAM,CAAC,CAAC,KAAK;;;;;;;AAQhF,MAAa,eAAe,OAAO,WAAW,WAAW,OAAqB;CAC5E,MAAM,SAAS,OAAO,OAAO;CAE7B,MAAM,WAAW,SAAS,KACxB,OAAO,eAAe,OAAO,QAAQ,MAAM,GAC3C,OAAO,SAAS,OAAO,CACzB;CAEA,MAAM,SAAS,SAAsB;EACnC,MAAM,QAAQ,MAAM,OAAO;EAE3B,IAAI,UAAU,KAAA,GAAW,MAAM,QAAQ,WAAW,KAAK,SAAS;EAEhE,OAAO;CACT;CAEA,MAAM,UAAU,UAAuB;EACrC,OAAO,MAAM,IAAI;EACjB,GAAG,OAAO,YAAY,OAAO,KAAK,cAAc,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;CACzF;CAEA,MAAM,EAAE,UAAU,GAAG,eAAe,SAAS,eAAe,gBAAgB;CAC5E,MAAM,YAAY;EAAE,UAAU,EAAE;EAAU,WAAW,EAAE;EAAW,QAAQ,OAAO;CAAG;CAEpF,MAAM,UAAU;EACd,OAAO,EAAE;EACT,IAAI,EAAE;EACN,QAAQ,EAAE;EACV,kBAAkB,EAAE;EACpB,iBAAiB,UAAmB,OAAO,GAAG,OAAO,EAAE,WAAW;EAClE,qBAAqB,EAAE;EACvB,mBAAmB,EAAE;EACrB,mBAAmB,EAAE;EACrB,yBAAyB,EAAE;EAC3B,4BAA4B,SAAS,KAAK,OAAO,IAAI,iBAAiB,IAAI,CAAC;CAC7E;CAEA,MAAM,6BAA6B;EACjC,GAAG,OAAO,aAAa;EACvB,WAAW;EACX,cAAc;EACd,UAAU;EACV,QAAQ;EACR,mBAAmB;EACnB,iBAAiB,UAAmB,UAAU;EAC9C,eAAe,SAAiB;GAAE,GAAG;GAAK,QAAQ;EAAK;EACvD,iBAAiB,cAAgC,EAAE,SAAS;CAC9D;CAEA,MAAM,mBAAmB;EAAE;EAAW;EAAS,YAAY,oBAAoB;CAAE;CAEjF,MAAM,QAAQ,OAAO,iBAAiB,KAAK;CAE3C,MAAM,gBAA2D;EAC/D,aAAa;EACb;EACA,SAAS;GAAE,OAAO,EAAE;GAAO,IAAI,EAAE;EAAG;EACpC;EACA,OAAO;GACL,GAAG,OAAO,QAAQ;GAClB,UAAU;GACV,SAAS;GACT,WAAW;GACX,SAAS;GACT,SAAS;GACT,eAAe;GACf,gBAAgB;GAChB,UAAU;GACV,WAAW;GACX,gBAAgB;GAChB,qBAAqB,CAAC;EACxB;CACF;CAEA,MAAM,kBAAgE;EACpE,MAAM,YAAY,iBAAsC;GACtD,UAAU,SAAS,MAAM,YAAY,QAAQ;GAC7C,eAAe,YAAY;EAC7B;EAEA,OAAO;GACL;GACA;GACA,qBAAqB,oBAAoB;GACzC,aAAa;GACb,eAAe;GACf,eAAe;GACf,sBAAsB;GACtB,kBAAkB,SAAS,KAAK,OAAO,IAAI,iBAAiB,IAAI,CAAC;GACjE,qBAAqB;GACrB,YAAY;IACV,OAAO,MAAM,aAAa;IAC1B,WAAW;IACX,OAAO;IACP,WAAW;IACX,YAAY;IACZ,iBAAiB;IACjB,YAAY,QAAQ,IAAI,WAAW;IACnC,sBAAsB,YAAY,WAAW,cAAc;KACzD,GAAG;KACH;KACA;KACA,YAAY;KACZ,QAAQ;IACV;GACF;GACA,YAAY;IACV,GAAG,OAAO,WAAW;IACrB,UAAU;IACV,WAAW;IACX,cAAc;IACd,oBAAoB;IACpB,iBAAiB;IACjB,UAAU;IACV,eAAe;IACf,eAAe,EAAE,aAAa,GAAG,WAAW;KAAE,GAAG;KAAK,GAAG,SAAS,WAAW;IAAE;IAC/E,iBAAiB,MAAM,qBAAqB;KAC1C,UAAU,SAAS,MAAM,IAAI;KAC7B;IACF;IACA,oBAAoB,EAAE,aAAa,GAAG,WAAW;KAAE,GAAG;KAAK,GAAG,SAAS,WAAW;IAAE;IACpF,SAAS,EAAE,UAAU,SAAS,KAAK,YAAY,iBAC7C,OAAO,IAAI,aAAa;KACtB,MAAM,KAAK,OAAO,EAAE,UAAU,IAAI,EAAE,GAAG;KACvC,MAAM,OAAO,OAAO,OAAO,qBAAqB,WAAW,QAAQ;KAEnE,OAAO,OAAO,OAAO,4BAA4B;MAC/C;MACA,UAAU;OACR,WAAW;OACX,kBAAkB,IAAI,EAAE;OACxB,aAAa,CACX;QACE,cAAc,WAAW;QACzB,UAAU,WAAW;OACvB,CACF;MACF;MACA,cAAc,WAAW;MACzB,oBAAoB,WAAW;MAC/B,iBAAiB,WAAW;MAC5B,UAAU;MACV,eAAe,WAAW;MAC1B,YAAY,OAAO,OAAO,iBAAiB;OACzC,WAAW,WAAW;OACtB,OAAO,WAAW;MACpB,CAAC;MACD,2BAA2B,WAAW;MACtC,GAAI,WAAW,eAAe,OAC1B,CAAC,IACD,EAAE,4BAA4B,OAAO,YAAY,WAAW,UAAU,EAAE;KAC9E,CAAC;IACH,CAAC;GACL;GACA;EACF;CACF;CAEA,MAAM,gBAAuD;EAC3D;EACA,SAAS;GAAE,GAAG;GAAS,mBAAmB,EAAE;EAAY;EACxD,aAAa;EACb,oBAAoB;EACpB,mBAAmB;EACnB;EACA,eAAe;EACf,eAAe;EACf,sBAAsB;EACtB,kBAAkB,SAAS,KAAK,OAAO,IAAI,iBAAiB,IAAI,CAAC;EACjE,qBAAqB;EACrB,4BAA4B;EAC5B,4BAA4B;EAC5B,qBAAqB;GACnB,GAAG,oBAAoB;GACvB,mBAAmB,cAAc;IAAE;IAAU,QAAQ;GAAK;GAC1D,mBAAmB,cAAc;IAAE;IAAU,QAAQ;GAAM;EAC7D;EACA,YAAY;GACV,OAAO,MAAM,aAAa;GAC1B,WAAW;GACX,OAAO;GACP,WAAW;GACX,YAAY;GACZ,iBAAiB;GACjB,YAAY,QAAQ,IAAI,WAAW,QAAQ,IAAI,eAAe;GAC9D,kBAAkB,QAAQ,IAAI,WAAW,QAAQ,IAAI,eAAe;GACpE,uBAAuB,EAAE,YAAY,WAAW,kBAAkB,uBAAuB;IACvF,GAAG;IACH;IACA,YAAY,QAAQ,gBAAgB;IACpC,UAAU;IACV,QAAQ;GACV;GACA,qBAAqB,EAAE,kBAAkB,uBAAuB;IAC9D,YAAY,QAAQ,gBAAgB;IACpC,UAAU;IACV,QAAQ;GACV;GACA,mBAAmB,EAAE,uBAAuB;IAAE,UAAU;IAAiB,QAAQ;GAAM;EACzF;EACA,YAAY;GACV,mBAAmB;GACnB,OAAO,MAAM,kBAAkB;GAC/B,UAAU;GACV,WAAW;GACX,cAAc;GACd,qBAAqB;GACrB,iBAAiB;GACjB,oBAAoB;GACpB,QAAQ;GACR,iBAAiB,UAAU,UAAU;GACrC,uBAAuB,EAAE,YAAY,GAAG,WAAW;IACjD,GAAG;IACH,qBAAqB,WAAW;IAChC,iBAAiB,WAAW;IAC5B,QAAQ;GACV;GACA,mBAAmB,EAAE,YAAY,0BAA0B;IACzD,qBAAqB,WAAW;IAChC,iBAAiB,WAAW;IAC5B;IACA,QAAQ;GACV;GACA,mBAAmB,EAAE,0BAA0B;IAAE;IAAoB,QAAQ;GAAM;GACnF,SAAS,EAAE,UAAU,SAAS,KAAK,YAAY,iBAC7C,OAAO,IAAI,aAAa;IACtB,OAAO,OAAO,OACZ,OAAO,OAAO,OAAO,KAAK,wBAAwB,QAAQ,CAAC,aAAa,CAAC,CAAC,GAC1E;KACE;KACA,YAAY;MAAE,WAAW,WAAW;MAAW,OAAO,WAAW;KAAM;KACvE,oBAAoB,WAAW;KAC/B,kBAAkB,OAAO,YAAY,WAAW,UAAU;KAC1D,cAAc,WAAW;KACzB,oBAAoB,WAAW;KAC/B,UAAU;MACR,WAAW,OAAO,EAAE,UAAU,IAAI,EAAE,GAAG;MACvC,kBAAkB,IAAI,EAAE;MACxB,aAAa,CACX;OACE,cAAc,WAAW;OACzB,UAAU,WAAW;MACvB,CACF;KACF;IACF,CACF;GACF,CAAC;EACL;CACF;CAEA,MAAM,WACJ,QACA,aACyF;EACzF,MAAM,SAAS,OAAO,eACpB,OAAO,OAAO;GACZ,QAAQ;GACR,SAAS;GACT,UAAU;GACV,WAAW,OAAO;GAClB,cAAc,OAAO,IAAI,MAAM,OAAO,cAAc,CAAC,CAAC;GACtD,QAAQ,OAAO;EACjB,CAAC,CACH;EAEA,OAAO;GACL,GAAG,UAAU;GACb;GACA;GACA,4BAA4B;GAC5B,aAAa,EAAE,eAAe,yBAAyB;GACvD,SAAS;IACP,OAAO,MAAM,SAAS;IACtB,UAAU;IACV,MAAM;IACN,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,WAAW;IACX,eAAe;IACf,UAAU;IACV,WAAW;IACX,cAAc;IACd,gBAAgB;IAChB,UAAU;IACV,gBAAgB,SAAS,QAAQ,SAAS,cAAc,IAAI,CAAC;IAC7D,iBAAiB,SAAS,KAAK,OAAO,IAAI,iBAAiB,IAAI,CAAC;IAChE,eAAe,WAAW;KACxB,GAAG;KACH,WAAW,QAAQ,SAAS,cAAc,MAAM,SAAS,CAAC;KAC1D,gBAAgB;KAChB,UAAU;IACZ;GACF;GACA,OAAO;IACL,SAAS,UACP,OAAO,aAAa,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,KACxC,OAAO,SAAS,UAAU,OAAO,aAAa,MAAM,CAAC,CAAC;KAAE,GAAG;KAAO,QAAQ;IAAM,CAAC,CAAC,GAClF,OAAO,SAAS,OAAO,CACzB;IACF,SAAS,UACP,OAAO,QAAQ,KAAK,CAAC,CAAC,KACpB,OAAO,SAAS,UACd,OAAO,QAAQ,MAAM,MAAM,CAAC,CAAC,KAC3B,OAAO,KAAK,aAAa;KAAE,GAAG;KAAO,QAAQ;IAAQ,EAAE,CACzD,CACF,CACF;GACJ;EACF;CACF;CAEA,MAAM,YACJ,QACA,aASG;EACH,MAAM,SAAS,OAAO,eACpB,OAAO,OAAO;GACZ,GAAG,gBAAgB;GACnB,QAAQ,OAAO;GACf,QAAQ;GACR,YAAY;GACZ,mBAAmB;EACrB,CAAC,CACH;EAEA,MAAM,aAAa,WAA6C;GAC9D,QAAQ,MAAM;GACd,kBAAkB,MAAM;GACxB,UAAU,QAAQ,SAAS,cAAc,MAAM,QAAQ,CAAC;GACxD,WAAW,QAAQ,SAAS,cAAc,MAAM,SAAS,CAAC;GAC1D,mBAAmB,QAAQ,SAAS,cAAc,MAAM,iBAAiB,CAAC;GAC1E,QAAQ,OAAO,WAAW,MAAM,CAAC,CAAC;IAChC,GAAG;IACH,QAAQ,OAAO,WAAW,MAAM,CAAC,CAAC,MAAM,MAAM;GAChD,CAAC;EACH;EAEA,MAAM,QAAQ,QAAQ,QAAQ,QAAQ;EAEtC,OAAO;GACL,GAAG,UAAU;GACb;GACA;GACA,4BAA4B;GAC5B,SAAS;IAAE,SAAS,MAAM;IAAS,OAAO,MAAM;GAAM;GACtD,aAAa;IACX,eAAe;IACf,eAAe;GACjB;GACA,WAAW;IACT,WAAW,OAAO,OAAO,QAAQ,EAAE;IACnC,YAAY,OAAO,OAAO,WAAW,EAAE;IACvC,QAAQ,OAAO;GACjB;GACA,SAAS;IACP,OAAO,MAAM,UAAU;IACvB,WAAW;IACX,WAAW;IACX,QAAQ;IACR,kBAAkB;IAClB,UAAU;IACV,WAAW;IACX,mBAAmB;IACnB,gBAAgB,SAAS,QAAQ,SAAS,cAAc,IAAI,CAAC;IAC7D,YAAY;IACZ,eAAe,OAAO,SAAS;KAAE,GAAG,UAAU,KAAK;KAAG,GAAG;IAAI;IAC7D,gBAAgB;IAChB,SAAS,QACP,OAAO,IAAI,aAAa;KACtB,MAAM,QAAQ,OAAO,OAAO,QAAQ,IAAI,MAAM,GAC5C,gBAAgB,OAAO,OAAO,QAAQ,MAAM,MAAM;KAEpD,OAAO;MACL,GAAG;MACH,UAAU,SAAS,WAAW,OAAO,YAAY,IAAI,QAAQ,CAAC;MAC9D,QAAQ;KACV;IACF,CAAC;GACL;EACF;CACF;CAEA,OAAO;EAAE;EAAO;EAAW;EAAQ;EAAW;EAAQ;EAAU;EAAS;CAAO;AAClF,CAAC"}
1
+ {"version":3,"file":"storage-mapping.mjs","names":[],"sources":["../../src/internal/storage-mapping.ts"],"sourcesContent":["import { EmailCredentialSnapshot } from \"@yielded/auth/Email\";\nimport { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport {\n PasswordCredentialSnapshot,\n EncodedPasswordHash,\n type PasswordReplacement,\n} from \"@yielded/auth/Password\";\nimport { TokenDigest } from \"@yielded/auth/Schema\";\nimport {\n SecurityRevision,\n AuthenticationEvidence,\n SessionId,\n SessionMetadata,\n SessionAuthenticationProvenance,\n SessionCredentialVersion,\n type StatefulSessionRecord,\n} from \"@yielded/auth/Sessions\";\nimport { Crypto, DateTime, Effect, Redacted, Schema, Struct } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport type { MappingInput } from \"./configuration\";\nimport { randomId } from \"./crypto\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport { requiredEmailAddressConstraints, type AnyEmailAddressMapping } from \"./models/email-model\";\nimport {\n requiredPasswordConstraints,\n type AnyPasswordPersistenceMapping,\n} from \"./models/password-model\";\nimport { requiredProofConstraints, type AnyProofPersistenceMapping } from \"./models/proof-model\";\nimport type { StatefulSessionMapping, PendingAuthenticationMapping } from \"./models/session-model\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport { exactSqlText } from \"./sql-change\";\nimport { makeStorageClock } from \"./storage-clock\";\nimport { storageTables, type StorageRole } from \"./storage-tables\";\nimport type { TableModel, SqlExpression } from \"./table-model\";\n\nconst failure = (cause: unknown) => PersistenceMappingError.make({ operation: \"decode\", cause });\n\nconst decode = <S extends Schema.Codec<unknown, unknown>>(schema: S, value: unknown) =>\n Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError(failure));\n\nconst string = (value: unknown) => Schema.decodeUnknownSync(Schema.String)(value);\n\n/** Derive shared row mappings from a managed or custom storage layout.\n * Acquire Effect Crypto once; the returned allocators retain that implementation.\n * Each factory requires its role tables to exist. Supplying native tables derives\n * batch commit predicates and subject policy columns. Adapter authors may refine\n * clocks and authority policy for explicit services.\n */\nexport const makeMappings = Effect.fnUntraced(function* (\n input: MappingInput,\n tables?: NativeSqlTables,\n) {\n const crypto = yield* Crypto.Crypto;\n const sql = (yield* SqlClient.SqlClient).withoutTransforms();\n\n const allocate = randomId.pipe(\n Effect.provideService(Crypto.Crypto, crypto),\n Effect.mapError(failure),\n );\n\n const table = (role: StorageRole) => {\n const found = input.tables[role];\n\n if (found === undefined) throw failure(`Missing ${role} mapping`);\n\n return found;\n };\n\n const mapped = (role: StorageRole) => ({\n table: table(role),\n ...Object.fromEntries(Object.keys(storageTables[role].columns).map((key) => [key, key])),\n });\n\n const { subjects: s, encodeInstant: instant, decodeInstant: readInstant } = input;\n const subjectId = { toNative: s.toNative, toSubject: s.toSubject, equals: Object.is };\n const identifierTable = tables?.(table(\"identifiers\"));\n\n const activeIdentifier =\n identifierTable === undefined\n ? undefined\n : sql`${identifierTable.column(\"active\")} = ${identifierTable.value(\"active\", true)}`;\n\n const subject = {\n table: s.table,\n id: s.id,\n status: s.status,\n securityRevision: s.securityRevision,\n // Policy callbacks may read any application column. Identity, status and\n // security revision have their own final checks and can be intentionally revised.\n ...(tables === undefined\n ? {}\n : {\n requirementColumns: tables(s.table).keys.filter(\n (key) => key !== s.id && key !== s.status && key !== s.securityRevision,\n ),\n }),\n isActiveStatus: (value: unknown) => Object.is(value, s.activeValue),\n d1ActiveStatusValue: s.activeValue,\n activeStatusValue: s.activeValue,\n decodeRequirement: s.requirements,\n decodeActionRequirement: s.actionRequirements,\n nextSecurityRevision: () => allocate.pipe(Effect.map(SecurityRevision.make)),\n };\n\n const authorityCredential = () => ({\n ...mapped(\"credentials\"),\n subjectId: \"subjectId\",\n credentialId: \"credentialId\",\n revision: \"revision\",\n status: \"active\",\n activeStatusValue: true,\n d1ActiveStatusValue: true,\n isActiveStatus: (value: unknown) => value === true,\n encodeInsert: (row: object) => ({ ...row, active: true }),\n encodeRevision: (revision: SecurityRevision) => ({ revision }),\n });\n\n const authority = () => ({ subjectId, subject, credential: authorityCredential() });\n\n const clock = yield* makeStorageClock(input);\n\n const proofs = (): AnyProofPersistenceMapping<SqlExpression> => ({\n constraints: requiredProofConstraints,\n subjectId,\n subject: { table: s.table, id: s.id },\n clock,\n proof: {\n ...mapped(\"proofs\"),\n moduleId: \"moduleId\",\n purpose: \"purpose\",\n seriesKey: \"seriesKey\",\n proofId: \"proofId\",\n binding: \"binding\",\n verifierKeyId: \"verifierKeyId\",\n verifierDigest: \"verifierDigest\",\n issuedAt: \"issuedAt\",\n expiresAt: \"expiresAt\",\n failedAttempts: \"failedAttempts\",\n encodeInsert: () => ({}),\n },\n });\n\n const passwords = (): AnyPasswordPersistenceMapping<SqlExpression> => {\n const verifier = (replacement: PasswordReplacement) => ({\n verifier: Redacted.value(replacement.verifier),\n normalization: replacement.normalization,\n });\n\n return {\n subjectId,\n subject,\n authorityCredential: authorityCredential(),\n constraints: requiredPasswordConstraints,\n encodeInstant: instant,\n decodeInstant: readInstant,\n allocateCredentialId: allocate,\n allocateRevision: allocate.pipe(Effect.map(SecurityRevision.make)),\n sessionInvalidation: \"same-authority-immediate\",\n identifier: {\n table: table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n verifiedAt: \"verifiedAt\",\n bindingRevision: \"revision\",\n isCurrent: (row) => row.active === true,\n ...(activeIdentifier === undefined\n ? {}\n : {\n d1CurrentCondition: () => activeIdentifier,\n }),\n encodeInitialInsert: (identifier, subjectId, revision) => ({\n ...identifier,\n subjectId,\n revision,\n verifiedAt: null,\n active: true,\n }),\n },\n credential: {\n ...mapped(\"passwords\"),\n moduleId: \"moduleId\",\n subjectId: \"subjectId\",\n credentialId: \"credentialId\",\n credentialRevision: \"credentialRevision\",\n verifierVersion: \"verifierVersion\",\n verifier: \"verifier\",\n normalization: \"normalization\",\n encodeInsert: ({ replacement, ...row }) => ({ ...row, ...verifier(replacement) }),\n encodeVerifier: (hash, verifierVersion) => ({\n verifier: Redacted.value(hash),\n verifierVersion,\n }),\n encodeReplacement: ({ replacement, ...row }) => ({ ...row, ...verifier(replacement) }),\n decode: ({ moduleId, subject: row, identifier, credential }) =>\n Effect.gen(function* () {\n const id = yield* s.toSubject(row[s.id]);\n const hash = yield* decode(EncodedPasswordHash, credential.verifier);\n\n return yield* decode(PasswordCredentialSnapshot, {\n moduleId,\n revision: {\n subjectId: id,\n securityRevision: row[s.securityRevision],\n credentials: [\n {\n credentialId: credential.credentialId,\n revision: credential.credentialRevision,\n },\n ],\n },\n credentialId: credential.credentialId,\n credentialRevision: credential.credentialRevision,\n verifierVersion: credential.verifierVersion,\n verifier: hash,\n normalization: credential.normalization,\n identifier: yield* decode(LoginIdentifier, {\n namespace: identifier.namespace,\n value: identifier.value,\n }),\n identifierBindingRevision: identifier.revision,\n ...(identifier.verifiedAt === null\n ? {}\n : { identifierVerifiedAtMillis: yield* readInstant(identifier.verifiedAt) }),\n });\n }),\n },\n clock,\n };\n };\n\n const emails = (): AnyEmailAddressMapping<SqlExpression> => ({\n subjectId,\n subject: { ...subject, activeStatusValue: s.activeValue },\n constraints: requiredEmailAddressConstraints,\n addressCardinality: \"single\",\n changeDisposition: \"retire-source\",\n clock,\n encodeInstant: instant,\n decodeInstant: readInstant,\n allocateCredentialId: allocate,\n allocateRevision: allocate.pipe(Effect.map(SecurityRevision.make)),\n sessionInvalidation: \"same-authority-immediate\",\n isIdentifierConflict: () => false,\n isCredentialConflict: () => false,\n authorityCredential: {\n ...authorityCredential(),\n encodeActivation: (revision) => ({ revision, active: true }),\n encodeRetirement: (revision) => ({ revision, active: false }),\n },\n identifier: {\n table: table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n verifiedAt: \"verifiedAt\",\n bindingRevision: \"revision\",\n isCurrent: (row) => row.active === true && row.verifiedAt !== null,\n isMutableTarget: (row) => row.active === true && row.verifiedAt === null,\n ...(identifierTable === undefined || activeIdentifier === undefined\n ? {}\n : {\n d1CurrentCondition: ({ bindingRevision }) =>\n sql`${activeIdentifier} and ${identifierTable.column(\"verifiedAt\")} is not null and ${exactSqlText(sql, identifierTable.column(\"revision\"), identifierTable.value(\"revision\", bindingRevision))}`,\n d1MutableTargetCondition: () =>\n sql`${activeIdentifier} and ${identifierTable.column(\"verifiedAt\")} is null`,\n }),\n encodeVerifiedInsert: ({ identifier, subjectId, verifiedAtMillis, bindingRevision }) => ({\n ...identifier,\n subjectId,\n verifiedAt: instant(verifiedAtMillis),\n revision: bindingRevision,\n active: true,\n }),\n encodeVerification: ({ verifiedAtMillis, bindingRevision }) => ({\n verifiedAt: instant(verifiedAtMillis),\n revision: bindingRevision,\n active: true,\n }),\n encodeRetirement: ({ bindingRevision }) => ({ revision: bindingRevision, active: false }),\n },\n credential: {\n activeStatusValue: true,\n table: table(\"emailCredentials\"),\n moduleId: \"moduleId\",\n subjectId: \"subjectId\",\n credentialId: \"credentialId\",\n identifierNamespace: \"identifierNamespace\",\n identifierValue: \"identifierValue\",\n credentialRevision: \"credentialRevision\",\n status: \"active\",\n isActiveStatus: (value) => value === true,\n encodeVerifiedInsert: ({ identifier, ...row }) => ({\n ...row,\n identifierNamespace: identifier.namespace,\n identifierValue: identifier.value,\n active: true,\n }),\n encodeActivation: ({ identifier, credentialRevision }) => ({\n identifierNamespace: identifier.namespace,\n identifierValue: identifier.value,\n credentialRevision,\n active: true,\n }),\n encodeRetirement: ({ credentialRevision }) => ({ credentialRevision, active: false }),\n decode: ({ moduleId, subject: row, identifier, credential }) =>\n Effect.gen(function* () {\n return yield* decode(\n Schema.Struct(Struct.omit(EmailCredentialSnapshot.fields, [\"requirement\"])),\n {\n moduleId,\n identifier: { namespace: identifier.namespace, value: identifier.value },\n identifierRevision: identifier.revision,\n verifiedAtMillis: yield* readInstant(identifier.verifiedAt),\n credentialId: credential.credentialId,\n credentialRevision: credential.credentialRevision,\n revision: {\n subjectId: yield* s.toSubject(row[s.id]),\n securityRevision: row[s.securityRevision],\n credentials: [\n {\n credentialId: credential.credentialId,\n revision: credential.credentialRevision,\n },\n ],\n },\n },\n );\n }),\n },\n });\n\n const pending = <C extends Schema.Codec<unknown, unknown, never, never>>(\n claims: C,\n moduleId: string,\n ): PendingAuthenticationMapping<C[\"Type\"], TableModel, TableModel, TableModel, unknown> => {\n const record = Schema.fromJsonString(\n Schema.Struct({\n digest: TokenDigest,\n version: SecurityRevision,\n evidence: AuthenticationEvidence,\n expiresAt: Schema.DateTimeUtcFromMillis,\n attemptLimit: Schema.Int.check(Schema.isGreaterThan(0)),\n claims: Schema.Unknown,\n }),\n );\n\n return {\n ...authority(),\n moduleId,\n clock,\n isConstraintConflict: () => false,\n constraints: { pendingDigest: \"unique(pending.digest)\" },\n pending: {\n table: table(\"pending\"),\n moduleId: \"moduleId\",\n kind: \"kind\",\n digest: \"digest\",\n version: \"version\",\n flowId: \"flowId\",\n subjectId: \"subjectId\",\n bindingDigest: \"bindingDigest\",\n snapshot: \"snapshot\",\n expiresAt: \"expiresAt\",\n attemptLimit: \"attemptLimit\",\n failedAttempts: \"failedAttempts\",\n consumed: \"consumed\",\n encodeInstant: (date) => instant(DateTime.toEpochMillis(date)),\n allocateVersion: allocate.pipe(Effect.map(SecurityRevision.make)),\n encodeInsert: (value) => ({\n ...value,\n expiresAt: instant(DateTime.toEpochMillis(value.expiresAt)),\n failedAttempts: 0,\n consumed: false,\n }),\n },\n login: {\n encode: (value) =>\n Schema.encodeEffect(claims)(value.claims).pipe(\n Effect.flatMap((saved) => Schema.encodeEffect(record)({ ...value, claims: saved })),\n Effect.mapError(failure),\n ),\n decode: (value) =>\n decode(record, value).pipe(\n Effect.flatMap((saved) =>\n decode(claims, saved.claims).pipe(\n Effect.map((decoded) => ({ ...saved, claims: decoded })),\n ),\n ),\n ),\n },\n };\n };\n\n const sessions = <C extends Schema.Codec<unknown, unknown, never, never>>(\n claims: C,\n moduleId: string,\n ): StatefulSessionMapping<\n C[\"Type\"],\n TableModel,\n TableModel,\n TableModel,\n TableModel,\n unknown,\n unknown\n > => {\n const record = Schema.fromJsonString(\n Schema.Struct({\n ...SessionMetadata.fields,\n claims: Schema.Unknown,\n digest: TokenDigest,\n provenance: SessionAuthenticationProvenance,\n credentialVersion: SessionCredentialVersion,\n }),\n );\n\n const encodeRow = (value: StatefulSessionRecord<C[\"Type\"]>) => ({\n digest: value.digest,\n securityRevision: value.securityRevision,\n issuedAt: instant(DateTime.toEpochMillis(value.issuedAt)),\n expiresAt: instant(DateTime.toEpochMillis(value.expiresAt)),\n absoluteExpiresAt: instant(DateTime.toEpochMillis(value.absoluteExpiresAt)),\n record: Schema.encodeSync(record)({\n ...value,\n claims: Schema.encodeSync(claims)(value.claims),\n }),\n });\n\n const login = pending(claims, moduleId);\n\n return {\n ...authority(),\n moduleId,\n clock,\n isConstraintConflict: () => false,\n pending: { pending: login.pending, login: login.login },\n constraints: {\n sessionDigest: \"unique(session.digest)\",\n pendingDigest: \"unique(pending.digest)\",\n },\n sessionId: {\n toNative: (id) => Effect.succeed(id),\n toSession: (id) => decode(SessionId, id),\n equals: Object.is,\n },\n session: {\n table: table(\"sessions\"),\n sessionId: \"sessionId\",\n subjectId: \"subjectId\",\n digest: \"digest\",\n securityRevision: \"securityRevision\",\n issuedAt: \"issuedAt\",\n expiresAt: \"expiresAt\",\n absoluteExpiresAt: \"absoluteExpiresAt\",\n encodeInstant: (date) => instant(DateTime.toEpochMillis(date)),\n allocateId: allocate,\n encodeInsert: (value, ids) => ({ ...encodeRow(value), ...ids }),\n encodeRotation: encodeRow,\n decode: (row) =>\n Effect.gen(function* () {\n const saved = yield* decode(record, row.record),\n decodedClaims = yield* decode(claims, saved.claims);\n\n return {\n ...saved,\n issuedAt: DateTime.makeUnsafe(yield* readInstant(row.issuedAt)),\n claims: decodedClaims,\n };\n }),\n },\n };\n };\n\n return { table, authority, proofs, passwords, emails, sessions, pending, string };\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@yielded/auth-persistence","version":"0.1.0-beta.29","dependencies":{"@yielded/auth":"0.1.0-beta.29"},"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","@yielded/crypto":"0.1.0-beta.29","@yielded/jose":"0.1.0-beta.29","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"},"./OAuthPersistence":{"types":"./dist/OAuthPersistence.d.mts","default":"./dist/OAuthPersistence.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.31","dependencies":{"@yielded/auth":"0.1.0-beta.31","@yielded/crypto":"0.1.0-beta.31"},"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","@yielded/jose":"0.1.0-beta.31","effect":"4.0.0","typescript":"7.0.2","vite":"npm:@voidzero-dev/vite-plus-core@1.1.0","vite-plus":"1.1.0","vitest":"5.0.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"},"./OAuthPersistence":{"types":"./dist/OAuthPersistence.d.mts","default":"./dist/OAuthPersistence.mjs"},"./Testing":{"types":"./dist/Testing.d.mts","default":"./dist/Testing.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"}}