@yielded/auth-persistence-drizzle 0.1.0-beta.18 → 0.1.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/D1.d.mts +8 -8
- package/dist/Libsql.d.mts +44 -44
- package/dist/Mysql2.d.mts +44 -44
- package/dist/Pglite.d.mts +44 -44
- package/dist/Postgres.d.mts +44 -44
- package/dist/SqliteBun.d.mts +44 -44
- package/dist/SqliteDo.d.mts +112 -134
- package/dist/SqliteDo.mjs +30 -45
- package/dist/SqliteDo.mjs.map +1 -1
- package/dist/SqliteNode.d.mts +38 -38
- package/dist/SqliteWasm.d.mts +38 -38
- package/dist/drizzle/crypto.mjs +11 -0
- package/dist/drizzle/crypto.mjs.map +1 -0
- package/dist/drizzle/d1-identity.mjs +2 -2
- package/dist/drizzle/d1-identity.mjs.map +1 -1
- package/dist/drizzle/d1-oauth.d.mts +11 -11
- package/dist/drizzle/d1-oauth.mjs.map +1 -1
- package/dist/drizzle/d1-passkey.d.mts +6 -6
- package/dist/drizzle/d1-passkey.mjs.map +1 -1
- package/dist/drizzle/d1-passwords.d.mts +1 -1
- package/dist/drizzle/d1-phone.d.mts +3 -3
- package/dist/drizzle/d1-phone.mjs.map +1 -1
- package/dist/drizzle/d1-proofs.d.mts +1 -1
- package/dist/drizzle/d1-sessions.d.mts +1 -1
- package/dist/drizzle/d1-totp.d.mts +3 -3
- package/dist/drizzle/d1-totp.mjs.map +1 -1
- package/dist/drizzle/mysql-identity.mjs +2 -2
- package/dist/drizzle/mysql-identity.mjs.map +1 -1
- package/dist/drizzle/oauth-accounts.mjs +9 -8
- package/dist/drizzle/oauth-accounts.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-collection.mjs +1 -1
- package/dist/drizzle/oauth-connected-collection.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-custody.mjs +5 -4
- package/dist/drizzle/oauth-connected-custody.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-flow.mjs +8 -7
- package/dist/drizzle/oauth-connected-flow.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-management.mjs +3 -2
- package/dist/drizzle/oauth-connected-management.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-reference.mjs +8 -4
- package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-settlement.mjs +4 -4
- package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-sign-in.mjs +11 -10
- package/dist/drizzle/oauth-connected-sign-in.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-state.d.mts +13 -13
- package/dist/drizzle/oauth-connected-state.mjs +23 -20
- package/dist/drizzle/oauth-connected-state.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-target.d.mts +7 -7
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
- package/dist/drizzle/oauth-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-flow.mjs +1 -1
- package/dist/drizzle/oauth-flow.mjs.map +1 -1
- package/dist/drizzle/oauth-model.d.mts +4 -4
- package/dist/drizzle/oauth-model.mjs.map +1 -1
- package/dist/drizzle/oauth-registration.mjs +2 -2
- package/dist/drizzle/oauth-registration.mjs.map +1 -1
- package/dist/drizzle/oauth-state.mjs +11 -12
- package/dist/drizzle/oauth-state.mjs.map +1 -1
- package/dist/drizzle/oauth-target.d.mts +4 -4
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/passkey-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-target.d.mts +1 -1
- package/dist/drizzle/password-prepared-state.mjs +1 -1
- package/dist/drizzle/pg-identity.mjs +2 -2
- package/dist/drizzle/pg-identity.mjs.map +1 -1
- package/dist/drizzle/phone-model.d.mts +2 -2
- package/dist/drizzle/phone-model.mjs +3 -3
- package/dist/drizzle/phone-model.mjs.map +1 -1
- package/dist/drizzle/phone-target.d.mts +1 -1
- package/dist/drizzle/phone-target.mjs +2 -2
- package/dist/drizzle/phone-target.mjs.map +1 -1
- package/dist/drizzle/sqlite-do-database.d.mts +29 -0
- package/dist/drizzle/sqlite-do-database.mjs +45 -0
- package/dist/drizzle/sqlite-do-database.mjs.map +1 -0
- package/dist/drizzle/sqlite-emails.mjs.map +1 -1
- package/dist/drizzle/sqlite-identity.mjs +2 -2
- package/dist/drizzle/sqlite-identity.mjs.map +1 -1
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
- package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
- package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
- package/dist/drizzle/storage-validation.mjs +17 -9
- package/dist/drizzle/storage-validation.mjs.map +1 -1
- package/dist/drizzle/totp-state.mjs +8 -8
- package/dist/drizzle/totp-state.mjs.map +1 -1
- package/dist/drizzle/totp-target.d.mts +1 -1
- package/dist/drizzle/totp-target.mjs +2 -2
- package/dist/drizzle/totp-target.mjs.map +1 -1
- package/package.json +1 -1
- package/src/SqliteDo.ts +63 -70
- package/src/drizzle/crypto.ts +14 -0
- package/src/drizzle/d1-identity.ts +2 -2
- package/src/drizzle/d1-oauth.ts +14 -5
- package/src/drizzle/d1-passkey.ts +5 -1
- package/src/drizzle/d1-phone.ts +2 -1
- package/src/drizzle/d1-totp.ts +6 -2
- package/src/drizzle/mysql-identity.ts +2 -2
- package/src/drizzle/oauth-accounts.ts +14 -13
- package/src/drizzle/oauth-connected-collection.ts +1 -1
- package/src/drizzle/oauth-connected-custody.ts +8 -6
- package/src/drizzle/oauth-connected-drivers.ts +9 -3
- package/src/drizzle/oauth-connected-flow.ts +6 -6
- package/src/drizzle/oauth-connected-management.ts +1 -1
- package/src/drizzle/oauth-connected-reference.ts +14 -9
- package/src/drizzle/oauth-connected-settlement.ts +4 -4
- package/src/drizzle/oauth-connected-sign-in.ts +11 -10
- package/src/drizzle/oauth-connected-state.ts +40 -25
- package/src/drizzle/oauth-connected-target.ts +9 -5
- package/src/drizzle/oauth-drivers.ts +13 -5
- package/src/drizzle/oauth-flow.ts +1 -1
- package/src/drizzle/oauth-model.ts +4 -4
- package/src/drizzle/oauth-registration.ts +2 -2
- package/src/drizzle/oauth-state.ts +17 -15
- package/src/drizzle/oauth-target.ts +11 -3
- package/src/drizzle/passkey-drivers.ts +7 -3
- package/src/drizzle/passkey-write-drivers.ts +11 -2
- package/src/drizzle/pg-identity.ts +2 -2
- package/src/drizzle/phone-model.ts +3 -3
- package/src/drizzle/phone-target.ts +11 -4
- package/src/drizzle/sqlite-do-database.ts +87 -0
- package/src/drizzle/sqlite-emails.ts +1 -1
- package/src/drizzle/sqlite-identity.ts +2 -2
- package/src/drizzle/sqlite-passwords.ts +1 -1
- package/src/drizzle/sqlite-proofs.ts +2 -2
- package/src/drizzle/sqlite-sessions.ts +2 -2
- package/src/drizzle/storage-validation.ts +15 -6
- package/src/drizzle/totp-state.ts +8 -8
- package/src/drizzle/totp-target.ts +11 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-validation.mjs","names":["getPgTableConfig","getMysqlTableConfig"],"sources":["../../src/drizzle/storage-validation.ts"],"sourcesContent":["import {\n NativeDatabase,\n PersistenceMappingError,\n validateStorage,\n} from \"@yielded/auth-persistence/Adapter\";\nimport { getTableColumns, getTableName, is, Table } from \"drizzle-orm\";\nimport { getTableConfig as getMysqlTableConfig, MySqlTable } from \"drizzle-orm/mysql-core\";\nimport { getTableConfig as getPgTableConfig, PgTable } from \"drizzle-orm/pg-core\";\nimport { Effect, Predicate, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\n\n// These are mapping contracts, not a parser for arbitrary constraint declarations.\n// Role aliases are explicit because their documentation names differ from mapping fields.\nconst uniquePlans: Readonly<Record<string, readonly [string, ReadonlyArray<string>]>> = {\n \"unique(abuseEvent.moduleId,abuseEvent.action,abuseEvent.scopeKind,abuseEvent.scopeKey,abuseEvent.commandId)\":\n [\"abuseEvent\", [\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\", \"commandId\"]],\n \"unique(admission.moduleId)\": [\"admission\", [\"moduleId\"]],\n \"unique(attempt.moduleId,attempt.attemptId)\": [\"attempt\", [\"moduleId\", \"attemptId\"]],\n \"unique(authority.subjectId,authority.credentialId)\": [\n \"authority\",\n [\"subjectId\", \"credentialId\"],\n ],\n \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\": [\n \"authorityCredential\",\n [\"subjectId\", \"credentialId\"],\n ],\n \"unique(charge.moduleId,charge.action,charge.scopeKind,charge.scopeKey,charge.attemptId)\": [\n \"charge\",\n [\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\", \"attemptId\"],\n ],\n \"unique(command.moduleId,command.commandId)\": [\"command\", [\"moduleId\", \"commandId\"]],\n \"unique(connectedAdmission.admissionId)\": [\"admission\", [\"admissionId\"]],\n \"unique(connectedClient.clientKey)\": [\"client\", [\"clientKey\"]],\n \"unique(connectedCohort.cohortKey)\": [\"cohort\", [\"cohortKey\"]],\n \"unique(connectedCommand.moduleId,connectedCommand.commandId)\": [\n \"command\",\n [\"moduleId\", \"commandId\"],\n ],\n \"unique(connectedFlow.moduleId,connectedFlow.commandId)\": [\"flow\", [\"moduleId\", \"commandId\"]],\n \"unique(connectedFlow.moduleId,connectedFlow.flowId)\": [\"flow\", [\"moduleId\", \"flowId\"]],\n \"unique(connectedFlow.stateDigest)\": [\"flow\", [\"stateDigest\"]],\n \"unique(connectedGrant.moduleId,connectedGrant.grantId)\": [\"grant\", [\"moduleId\", \"grantId\"]],\n \"unique(connectedGrant.moduleId,connectedGrant.subjectId,connectedGrant.profileKey,connectedGrant.activeIdentityKey)\":\n [\"grant\", [\"moduleId\", \"subjectId\", \"profileKey\", \"activeIdentityKey\"]],\n \"unique(connectedRevocation.jobId)\": [\"job\", [\"jobId\"]],\n \"unique(continuation.moduleId,continuation.continuationId)\": [\n \"continuation\",\n [\"moduleId\", \"continuationId\"],\n ],\n \"unique(continuation.moduleId,continuation.digest)\": [\"continuation\", [\"moduleId\", \"digest\"]],\n \"unique(credential.credentialId)\": [\"credential\", [\"credentialId\"]],\n \"unique(credential.identityKey)\": [\"credential\", [\"identityKey\"]],\n \"unique(credential.moduleId,credential.credentialId)\": [\n \"credential\",\n [\"moduleId\", \"credentialId\"],\n ],\n \"unique(credential.moduleId,credential.subjectId)\": [\"credential\", [\"moduleId\", \"subjectId\"]],\n \"unique(emailCommand.moduleId,emailCommand.commandId)\": [\"command\", [\"moduleId\", \"commandId\"]],\n \"unique(emailCredential.moduleId,emailCredential.credentialId)\": [\n \"credential\",\n [\"moduleId\", \"credentialId\"],\n ],\n \"unique(emailCredential.moduleId,emailCredential.identifierNamespace,emailCredential.identifierValue)\":\n [\"credential\", [\"moduleId\", \"identifierNamespace\", \"identifierValue\"]],\n \"unique(emailRegistration.moduleId,emailRegistration.commandId)\": [\n \"registration\",\n [\"moduleId\", \"commandId\"],\n ],\n \"unique(emailRegistration.pendingReference)\": [\"registration\", [\"pendingReference\"]],\n \"unique(failureEvent.moduleId,failureEvent.seriesKey,failureEvent.commandId)\": [\n \"failureEvent\",\n [\"moduleId\", \"seriesKey\", \"commandId\"],\n ],\n \"unique(flow.flowId)\": [\"flow\", [\"flowId\"]],\n \"unique(flow.moduleId,flow.commandId)\": [\"flow\", [\"moduleId\", \"commandId\"]],\n \"unique(flow.moduleId,flow.flowId)\": [\"flow\", [\"moduleId\", \"flowId\"]],\n \"unique(flow.stateDigest)\": [\"flow\", [\"stateDigest\"]],\n \"unique(generation.moduleId,generation.deliveryId)\": [\"generation\", [\"moduleId\", \"deliveryId\"]],\n \"unique(generation.moduleId,generation.proofId)\": [\"generation\", [\"moduleId\", \"proofId\"]],\n \"unique(identifier.namespace,identifier.value)\": [\"identifier\", [\"namespace\", \"value\"]],\n \"unique(intent.digest)\": [\"intent\", [\"digest\"]],\n \"unique(intent.flowId)\": [\"intent\", [\"flowId\"]],\n \"unique(intent.moduleId,intent.commandId)\": [\"intent\", [\"moduleId\", \"commandId\"]],\n \"unique(intent.moduleId,intent.flowId)\": [\"intent\", [\"moduleId\", \"flowId\"]],\n \"unique(intent.moduleId,intent.intentId)\": [\"intent\", [\"moduleId\", \"intentId\"]],\n \"unique(intent.moduleId,intent.reference)\": [\"intent\", [\"moduleId\", \"reference\"]],\n \"unique(ownership.identityKey)\": [\"ownership\", [\"identityKey\"]],\n \"unique(pending.digest)\": [\"pending\", [\"digest\"]],\n \"unique(pending.flowId)\": [\"pending\", [\"flowId\"]],\n \"unique(rateScope.moduleId,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)\": [\n \"rateScope\",\n [\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\"],\n ],\n \"unique(rateScope.moduleId,rateScope.purpose,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)\":\n [\"rateScope\", [\"moduleId\", \"purpose\", \"action\", \"scopeKind\", \"scopeKey\"]],\n \"unique(registration.moduleId,registration.requestId)\": [\n \"registration\",\n [\"moduleId\", \"requestId\"],\n ],\n \"unique(registration.recoveryReference)\": [\"registration\", [\"recoveryReference\"]],\n \"unique(registrationCommand.moduleId,registrationCommand.commandId)\": [\n \"command\",\n [\"moduleId\", \"commandId\"],\n ],\n \"unique(request.moduleId,request.requestId)\": [\"request\", [\"moduleId\", \"requestId\"]],\n \"unique(series.moduleId,series.purpose,series.scopeKey)\": [\n \"series\",\n [\"moduleId\", \"purpose\", \"scopeKey\"],\n ],\n \"unique(session.digest)\": [\"session\", [\"digest\"]],\n \"unique(tombstone.subjectId,tombstone.sessionId)\": [\"tombstone\", [\"subjectId\", \"sessionId\"]],\n \"unique(tuple.identityKey)\": [\"ownership.tuple\", [\"identityKey\"]],\n \"unique(unlinkCommand.moduleId,unlinkCommand.commandId)\": [\"command\", [\"moduleId\", \"commandId\"]],\n};\n\nconst arrayRoles: Readonly<Record<string, string>> = {\n credentialId: \"credential\",\n factor: \"authority\",\n credentialOwnership: \"credentialOwnership\",\n handleOwnership: \"handleOwnership\",\n boundSubjectHandle: \"handleOwnership\",\n flow: \"flow\",\n command: \"flow\",\n admission: \"admission\",\n charge: \"charge\",\n intentFlow: \"intent\",\n intentCommand: \"intent\",\n handle: \"handle\",\n};\n\nconst nestedMappings = [\n \"read\",\n \"signIn\",\n \"password\",\n \"proof\",\n \"proofs\",\n \"revocation\",\n \"pending\",\n \"session\",\n \"source\",\n];\n\nconst constraintGroups = [\n \"constraints\",\n \"tupleConstraints\",\n \"registrationConstraints\",\n \"managementConstraints\",\n];\n\nconst MappingRecord = Schema.Record(Schema.String, Schema.Unknown);\nconst record = Schema.decodeUnknownSync(MappingRecord);\n\nconst plans = (mapping: Readonly<Record<string, unknown>>) => {\n const result: Array<{ readonly table: Table; readonly keys: ReadonlyArray<string> }> = [];\n\n for (const group of constraintGroups) {\n if (mapping[group] === undefined) continue;\n for (const [name, declaration] of Object.entries(record(mapping[group]))) {\n if (declaration === \"notNull(provisioningRequest.subjectId)\") continue;\n let role: string;\n let keys: ReadonlyArray<string>;\n\n if (typeof declaration === \"string\") {\n const plan = uniquePlans[declaration];\n\n if (plan !== undefined) [role, keys] = plan;\n else if (declaration === \"unique(id)\") {\n role = \"subject\";\n keys = [\"id\"];\n } else if (declaration === \"unique(scope)\") {\n role = name;\n keys = [\"scope\"];\n } else if (declaration === \"unique(credentialId)\") {\n role = \"credential\";\n keys = [\"id\"];\n } else if (declaration === \"unique(namespace,value)\") {\n role = \"identifier\";\n keys = [\"namespace\", \"value\"];\n } else if (declaration === \"unique(provider,issuer,subject)\") {\n role = \"externalIdentity\";\n keys = [\"provider\", \"issuer\", \"subject\"];\n } else if (declaration === \"unique(requestId)\") {\n role = \"provisioningRequest\";\n keys = [\"requestId\"];\n } else throw new Error(\"Unknown storage constraint\");\n } else if (Array.isArray(declaration) && declaration.every(Predicate.isString)) {\n const mappedRole =\n group === \"managementConstraints\" && name === \"command\" ? \"command\" : arrayRoles[name];\n\n if (mappedRole === undefined) throw new Error(\"Unknown storage constraint\");\n role = mappedRole;\n keys = declaration;\n } else throw new Error(\"Invalid storage constraint\");\n\n let target: unknown = mapping;\n\n for (const segment of role.split(\".\")) target = record(target)[segment];\n // Session authority places its pending tables in one nested mapping.\n if (target === undefined && Schema.is(MappingRecord)(mapping.pending))\n target = mapping.pending[role];\n let mapped = record(target);\n\n if (role === \"pending\" && mapped.table === undefined) mapped = record(mapped.pending);\n // OAuth ownership can be integrated into its tuple authority or separate.\n if (role === \"ownership\" && mapped.table === undefined)\n mapped = record(mapped.external ?? mapped.tuple);\n if (!is(mapped.table, Table)) throw new Error(\"Missing storage table\");\n const columns = getTableColumns(mapped.table);\n\n result.push({\n table: mapped.table,\n keys: keys.map((key) => {\n const value = mapped[key];\n\n if (typeof value !== \"string\" || columns[value] === undefined)\n throw new Error(\"Missing mapped key\");\n\n return value;\n }),\n });\n }\n }\n for (const nested of nestedMappings) {\n const value = mapping[nested];\n\n if (Schema.is(MappingRecord)(value) && value.table === undefined) result.push(...plans(value));\n }\n\n return result;\n};\n\n/** Validate at acquisition using the root database supplied by the adapter. */\nexport const validateDrizzleStorage = Effect.fnUntraced(\n function* (mapping: unknown) {\n const physical = yield* Effect.try({\n try: () => plans(record(mapping)),\n catch: () =>\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Invalid storage key mapping\",\n }),\n });\n\n const { $client: client } = yield* NativeDatabase;\n\n for (const plan of physical) {\n const pg = is(plan.table, PgTable);\n const mysql = is(plan.table, MySqlTable);\n\n const schema = pg\n ? getPgTableConfig(plan.table).schema\n : mysql\n ? getMysqlTableConfig(plan.table).schema\n : undefined;\n\n const columns = getTableColumns(plan.table);\n\n yield* validateStorage(\n pg ? \"pg\" : mysql ? \"mysql\" : \"sqlite\",\n {\n name: getTableName(plan.table),\n ...(schema === undefined ? {} : { schema }),\n columns: Object.fromEntries(plan.keys.map((key) => [key, { name: columns[key]!.name }])),\n },\n [plan.keys],\n ).pipe(\n Effect.provideService(SqlClient, client),\n Effect.mapError(() =>\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Required SQL storage key is unavailable\",\n }),\n ),\n );\n }\n },\n Effect.catchDefect(() =>\n Effect.fail(\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Cannot inspect SQL storage metadata\",\n }),\n ),\n ),\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage-validation.mjs","names":["getPgTableConfig","getMysqlTableConfig"],"sources":["../../src/drizzle/storage-validation.ts"],"sourcesContent":["import {\n NativeDatabase,\n PersistenceMappingError,\n validateStorageBatch,\n type StorageValidation,\n} from \"@yielded/auth-persistence/Adapter\";\nimport { getTableColumns, getTableName, is, Table } from \"drizzle-orm\";\nimport { getTableConfig as getMysqlTableConfig, MySqlTable } from \"drizzle-orm/mysql-core\";\nimport { getTableConfig as getPgTableConfig, PgTable } from \"drizzle-orm/pg-core\";\nimport { Effect, Predicate, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\n\n// These are mapping contracts, not a parser for arbitrary constraint declarations.\n// Role aliases are explicit because their documentation names differ from mapping fields.\nconst uniquePlans: Readonly<Record<string, readonly [string, ReadonlyArray<string>]>> = {\n \"unique(abuseEvent.moduleId,abuseEvent.action,abuseEvent.scopeKind,abuseEvent.scopeKey,abuseEvent.commandId)\":\n [\"abuseEvent\", [\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\", \"commandId\"]],\n \"unique(admission.moduleId)\": [\"admission\", [\"moduleId\"]],\n \"unique(attempt.moduleId,attempt.attemptId)\": [\"attempt\", [\"moduleId\", \"attemptId\"]],\n \"unique(authority.subjectId,authority.credentialId)\": [\n \"authority\",\n [\"subjectId\", \"credentialId\"],\n ],\n \"unique(authorityCredential.subjectId,authorityCredential.credentialId)\": [\n \"authorityCredential\",\n [\"subjectId\", \"credentialId\"],\n ],\n \"unique(charge.moduleId,charge.action,charge.scopeKind,charge.scopeKey,charge.attemptId)\": [\n \"charge\",\n [\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\", \"attemptId\"],\n ],\n \"unique(command.moduleId,command.commandId)\": [\"command\", [\"moduleId\", \"commandId\"]],\n \"unique(connectedAdmission.admissionId)\": [\"admission\", [\"admissionId\"]],\n \"unique(connectedClient.clientKey)\": [\"client\", [\"clientKey\"]],\n \"unique(connectedCohort.cohortKey)\": [\"cohort\", [\"cohortKey\"]],\n \"unique(connectedCommand.moduleId,connectedCommand.commandId)\": [\n \"command\",\n [\"moduleId\", \"commandId\"],\n ],\n \"unique(connectedFlow.moduleId,connectedFlow.commandId)\": [\"flow\", [\"moduleId\", \"commandId\"]],\n \"unique(connectedFlow.moduleId,connectedFlow.flowId)\": [\"flow\", [\"moduleId\", \"flowId\"]],\n \"unique(connectedFlow.stateDigest)\": [\"flow\", [\"stateDigest\"]],\n \"unique(connectedGrant.moduleId,connectedGrant.grantId)\": [\"grant\", [\"moduleId\", \"grantId\"]],\n \"unique(connectedGrant.moduleId,connectedGrant.subjectId,connectedGrant.profileKey,connectedGrant.activeIdentityKey)\":\n [\"grant\", [\"moduleId\", \"subjectId\", \"profileKey\", \"activeIdentityKey\"]],\n \"unique(connectedRevocation.jobId)\": [\"job\", [\"jobId\"]],\n \"unique(continuation.moduleId,continuation.continuationId)\": [\n \"continuation\",\n [\"moduleId\", \"continuationId\"],\n ],\n \"unique(continuation.moduleId,continuation.digest)\": [\"continuation\", [\"moduleId\", \"digest\"]],\n \"unique(credential.credentialId)\": [\"credential\", [\"credentialId\"]],\n \"unique(credential.identityKey)\": [\"credential\", [\"identityKey\"]],\n \"unique(credential.moduleId,credential.credentialId)\": [\n \"credential\",\n [\"moduleId\", \"credentialId\"],\n ],\n \"unique(credential.moduleId,credential.subjectId)\": [\"credential\", [\"moduleId\", \"subjectId\"]],\n \"unique(emailCommand.moduleId,emailCommand.commandId)\": [\"command\", [\"moduleId\", \"commandId\"]],\n \"unique(emailCredential.moduleId,emailCredential.credentialId)\": [\n \"credential\",\n [\"moduleId\", \"credentialId\"],\n ],\n \"unique(emailCredential.moduleId,emailCredential.identifierNamespace,emailCredential.identifierValue)\":\n [\"credential\", [\"moduleId\", \"identifierNamespace\", \"identifierValue\"]],\n \"unique(emailRegistration.moduleId,emailRegistration.commandId)\": [\n \"registration\",\n [\"moduleId\", \"commandId\"],\n ],\n \"unique(emailRegistration.pendingReference)\": [\"registration\", [\"pendingReference\"]],\n \"unique(failureEvent.moduleId,failureEvent.seriesKey,failureEvent.commandId)\": [\n \"failureEvent\",\n [\"moduleId\", \"seriesKey\", \"commandId\"],\n ],\n \"unique(flow.flowId)\": [\"flow\", [\"flowId\"]],\n \"unique(flow.moduleId,flow.commandId)\": [\"flow\", [\"moduleId\", \"commandId\"]],\n \"unique(flow.moduleId,flow.flowId)\": [\"flow\", [\"moduleId\", \"flowId\"]],\n \"unique(flow.stateDigest)\": [\"flow\", [\"stateDigest\"]],\n \"unique(generation.moduleId,generation.deliveryId)\": [\"generation\", [\"moduleId\", \"deliveryId\"]],\n \"unique(generation.moduleId,generation.proofId)\": [\"generation\", [\"moduleId\", \"proofId\"]],\n \"unique(identifier.namespace,identifier.value)\": [\"identifier\", [\"namespace\", \"value\"]],\n \"unique(intent.digest)\": [\"intent\", [\"digest\"]],\n \"unique(intent.flowId)\": [\"intent\", [\"flowId\"]],\n \"unique(intent.moduleId,intent.commandId)\": [\"intent\", [\"moduleId\", \"commandId\"]],\n \"unique(intent.moduleId,intent.flowId)\": [\"intent\", [\"moduleId\", \"flowId\"]],\n \"unique(intent.moduleId,intent.intentId)\": [\"intent\", [\"moduleId\", \"intentId\"]],\n \"unique(intent.moduleId,intent.reference)\": [\"intent\", [\"moduleId\", \"reference\"]],\n \"unique(ownership.identityKey)\": [\"ownership\", [\"identityKey\"]],\n \"unique(pending.digest)\": [\"pending\", [\"digest\"]],\n \"unique(pending.flowId)\": [\"pending\", [\"flowId\"]],\n \"unique(rateScope.moduleId,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)\": [\n \"rateScope\",\n [\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\"],\n ],\n \"unique(rateScope.moduleId,rateScope.purpose,rateScope.action,rateScope.scopeKind,rateScope.scopeKey)\":\n [\"rateScope\", [\"moduleId\", \"purpose\", \"action\", \"scopeKind\", \"scopeKey\"]],\n \"unique(registration.moduleId,registration.requestId)\": [\n \"registration\",\n [\"moduleId\", \"requestId\"],\n ],\n \"unique(registration.recoveryReference)\": [\"registration\", [\"recoveryReference\"]],\n \"unique(registrationCommand.moduleId,registrationCommand.commandId)\": [\n \"command\",\n [\"moduleId\", \"commandId\"],\n ],\n \"unique(request.moduleId,request.requestId)\": [\"request\", [\"moduleId\", \"requestId\"]],\n \"unique(series.moduleId,series.purpose,series.scopeKey)\": [\n \"series\",\n [\"moduleId\", \"purpose\", \"scopeKey\"],\n ],\n \"unique(session.digest)\": [\"session\", [\"digest\"]],\n \"unique(tombstone.subjectId,tombstone.sessionId)\": [\"tombstone\", [\"subjectId\", \"sessionId\"]],\n \"unique(tuple.identityKey)\": [\"ownership.tuple\", [\"identityKey\"]],\n \"unique(unlinkCommand.moduleId,unlinkCommand.commandId)\": [\"command\", [\"moduleId\", \"commandId\"]],\n};\n\nconst arrayRoles: Readonly<Record<string, string>> = {\n credentialId: \"credential\",\n factor: \"authority\",\n credentialOwnership: \"credentialOwnership\",\n handleOwnership: \"handleOwnership\",\n boundSubjectHandle: \"handleOwnership\",\n flow: \"flow\",\n command: \"flow\",\n admission: \"admission\",\n charge: \"charge\",\n intentFlow: \"intent\",\n intentCommand: \"intent\",\n handle: \"handle\",\n};\n\nconst nestedMappings = [\n \"read\",\n \"signIn\",\n \"password\",\n \"proof\",\n \"proofs\",\n \"revocation\",\n \"pending\",\n \"session\",\n \"source\",\n];\n\nconst constraintGroups = [\n \"constraints\",\n \"tupleConstraints\",\n \"registrationConstraints\",\n \"managementConstraints\",\n];\n\nconst MappingRecord = Schema.Record(Schema.String, Schema.Unknown);\nconst record = Schema.decodeUnknownSync(MappingRecord);\n\nconst plans = (mapping: Readonly<Record<string, unknown>>) => {\n const result: Array<{ readonly table: Table; readonly keys: ReadonlyArray<string> }> = [];\n\n for (const group of constraintGroups) {\n if (mapping[group] === undefined) continue;\n for (const [name, declaration] of Object.entries(record(mapping[group]))) {\n if (declaration === \"notNull(provisioningRequest.subjectId)\") continue;\n let role: string;\n let keys: ReadonlyArray<string>;\n\n if (typeof declaration === \"string\") {\n const plan = uniquePlans[declaration];\n\n if (plan !== undefined) [role, keys] = plan;\n else if (declaration === \"unique(id)\") {\n role = \"subject\";\n keys = [\"id\"];\n } else if (declaration === \"unique(scope)\") {\n role = name;\n keys = [\"scope\"];\n } else if (declaration === \"unique(credentialId)\") {\n role = \"credential\";\n keys = [\"id\"];\n } else if (declaration === \"unique(namespace,value)\") {\n role = \"identifier\";\n keys = [\"namespace\", \"value\"];\n } else if (declaration === \"unique(provider,issuer,subject)\") {\n role = \"externalIdentity\";\n keys = [\"provider\", \"issuer\", \"subject\"];\n } else if (declaration === \"unique(requestId)\") {\n role = \"provisioningRequest\";\n keys = [\"requestId\"];\n } else throw new Error(\"Unknown storage constraint\");\n } else if (Array.isArray(declaration) && declaration.every(Predicate.isString)) {\n const mappedRole =\n group === \"managementConstraints\" && name === \"command\" ? \"command\" : arrayRoles[name];\n\n if (mappedRole === undefined) throw new Error(\"Unknown storage constraint\");\n role = mappedRole;\n keys = declaration;\n } else throw new Error(\"Invalid storage constraint\");\n\n let target: unknown = mapping;\n\n for (const segment of role.split(\".\")) target = record(target)[segment];\n // Session authority places its pending tables in one nested mapping.\n if (target === undefined && Schema.is(MappingRecord)(mapping.pending))\n target = mapping.pending[role];\n let mapped = record(target);\n\n if (role === \"pending\" && mapped.table === undefined) mapped = record(mapped.pending);\n // OAuth ownership can be integrated into its tuple authority or separate.\n if (role === \"ownership\" && mapped.table === undefined)\n mapped = record(mapped.external ?? mapped.tuple);\n if (!is(mapped.table, Table)) throw new Error(\"Missing storage table\");\n const columns = getTableColumns(mapped.table);\n\n result.push({\n table: mapped.table,\n keys: keys.map((key) => {\n const value = mapped[key];\n\n if (typeof value !== \"string\" || columns[value] === undefined)\n throw new Error(\"Missing mapped key\");\n\n return value;\n }),\n });\n }\n }\n for (const nested of nestedMappings) {\n const value = mapping[nested];\n\n if (Schema.is(MappingRecord)(value) && value.table === undefined) result.push(...plans(value));\n }\n\n return result;\n};\n\n/** Validate at acquisition using the root database supplied by the adapter. */\nexport const validateDrizzleStorage = Effect.fnUntraced(\n function* (mapping: unknown) {\n const physical = yield* Effect.try({\n try: () => plans(record(mapping)),\n catch: () =>\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Invalid storage key mapping\",\n }),\n });\n\n const { $client: client } = yield* NativeDatabase;\n\n const batches = new Map<\"pg\" | \"mysql\" | \"sqlite\", StorageValidation[]>();\n\n for (const plan of physical) {\n const pg = is(plan.table, PgTable);\n const mysql = is(plan.table, MySqlTable);\n\n const schema = pg\n ? getPgTableConfig(plan.table).schema\n : mysql\n ? getMysqlTableConfig(plan.table).schema\n : undefined;\n\n const columns = getTableColumns(plan.table);\n\n const dialect = pg ? \"pg\" : mysql ? \"mysql\" : \"sqlite\";\n const batch = batches.get(dialect) ?? [];\n\n batch.push({\n table: {\n name: getTableName(plan.table),\n ...(schema === undefined ? {} : { schema }),\n columns: Object.fromEntries(plan.keys.map((key) => [key, { name: columns[key]!.name }])),\n },\n required: [plan.keys],\n });\n batches.set(dialect, batch);\n }\n for (const [dialect, requirements] of batches) {\n yield* validateStorageBatch(dialect, requirements).pipe(\n Effect.provideService(SqlClient, client),\n Effect.mapError(() =>\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Required SQL storage key is unavailable\",\n }),\n ),\n );\n }\n },\n Effect.catchDefect(() =>\n Effect.fail(\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Cannot inspect SQL storage metadata\",\n }),\n ),\n ),\n);\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { digest, randomId } from "./crypto.mjs";
|
|
1
2
|
import { both, makeTransactionRows } from "./transaction-owner.mjs";
|
|
2
3
|
import { sql } from "drizzle-orm";
|
|
3
4
|
import { Context, Effect, Schema } from "effect";
|
|
4
5
|
import { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
|
|
5
6
|
import { TotpPolicy, TotpRecord, TotpUnavailable } from "@yielded/auth/Totp";
|
|
6
|
-
import { digest, randomId } from "@yielded/auth-crypto";
|
|
7
7
|
//#region src/drizzle/totp-state.ts
|
|
8
8
|
const unavailable = () => TotpUnavailable.make({});
|
|
9
9
|
const invariant = (condition) => {
|
|
@@ -20,7 +20,7 @@ const captureTotp = Effect.fn("TotpNative.capture")(function* (mapping, subjectI
|
|
|
20
20
|
invariant(mapping.subjectIds.toSubject(nativeId) === subjectId);
|
|
21
21
|
const subjectRow = (yield* owner.read(subject.table, equal(subject.table, { [subject.id]: nativeId }), { limit: 1 })).rows[0];
|
|
22
22
|
if (subjectRow === void 0 || !(yield* owner.check(sql`exists(select 1 from ${subject.table} where ${both(owner.exact(subject.table, subjectRow), subject.activeCondition)})`))) return void 0;
|
|
23
|
-
const scope = scopeFor(mapping.moduleId, subjectId), found = yield* owner.read(factor.table, equal(factor.table, { [factor.scope]: scope }), { limit: 1 }), row = found.rows[0];
|
|
23
|
+
const scope = yield* scopeFor(mapping.moduleId, subjectId), found = yield* owner.read(factor.table, equal(factor.table, { [factor.scope]: scope }), { limit: 1 }), row = found.rows[0];
|
|
24
24
|
const record = row === void 0 ? null : decodeTotpRecord(row[factor.state]);
|
|
25
25
|
invariant(record === null || (record.secret === null || record.secret.revision === record.revision) && (record.pending === null || record.pending.secret.revision === record.pending.revision));
|
|
26
26
|
invariant(record === null || record.moduleId === mapping.moduleId && record.subjectId === subjectId && record.version === row[factor.version]);
|
|
@@ -55,7 +55,7 @@ const mutateTotp = Effect.fn("TotpNative.mutate")(function* (mapping, input) {
|
|
|
55
55
|
const now = yield* owner.now({ engineNowMillis: mapping.engineNowMillis });
|
|
56
56
|
const guards = [];
|
|
57
57
|
const credentialGuards = [];
|
|
58
|
-
const commandScope = digest(`effect-auth/totp/command/v1/${mapping.moduleId.length}:${mapping.moduleId}/${input.subjectId.length}:${input.subjectId}/${input.commandId}`);
|
|
58
|
+
const commandScope = yield* digest(`effect-auth/totp/command/v1/${mapping.moduleId.length}:${mapping.moduleId}/${input.subjectId.length}:${input.subjectId}/${input.commandId}`);
|
|
59
59
|
const commandObservation = [
|
|
60
60
|
"Enroll",
|
|
61
61
|
"Confirm",
|
|
@@ -192,7 +192,7 @@ const mutateTotp = Effect.fn("TotpNative.mutate")(function* (mapping, input) {
|
|
|
192
192
|
secret: null,
|
|
193
193
|
pending: null,
|
|
194
194
|
recoveryDigests: [],
|
|
195
|
-
revision: randomId
|
|
195
|
+
revision: yield* randomId
|
|
196
196
|
};
|
|
197
197
|
semantic = true;
|
|
198
198
|
}
|
|
@@ -205,7 +205,7 @@ const mutateTotp = Effect.fn("TotpNative.mutate")(function* (mapping, input) {
|
|
|
205
205
|
secret: null,
|
|
206
206
|
pending: null,
|
|
207
207
|
recoveryDigests: [],
|
|
208
|
-
revision: randomId
|
|
208
|
+
revision: yield* randomId
|
|
209
209
|
};
|
|
210
210
|
else {
|
|
211
211
|
if (new Set(action.recoveryDigests).size !== 10) return reject;
|
|
@@ -218,12 +218,12 @@ const mutateTotp = Effect.fn("TotpNative.mutate")(function* (mapping, input) {
|
|
|
218
218
|
}
|
|
219
219
|
next = {
|
|
220
220
|
...next,
|
|
221
|
-
version: randomId
|
|
221
|
+
version: yield* randomId
|
|
222
222
|
};
|
|
223
223
|
const subject = mapping.subject, factor = mapping.factor, auth = mapping.credential;
|
|
224
224
|
const subjectKey = { [subject.id]: nativeId };
|
|
225
225
|
if (semantic) {
|
|
226
|
-
const revision = randomId
|
|
226
|
+
const revision = yield* randomId, updates = {
|
|
227
227
|
[subject.securityRevision]: revision,
|
|
228
228
|
[subject.factorEnabled]: subject.encodeEnabled(next.secret !== null)
|
|
229
229
|
};
|
|
@@ -269,7 +269,7 @@ const mutateTotp = Effect.fn("TotpNative.mutate")(function* (mapping, input) {
|
|
|
269
269
|
const values = factor.encodeInsert({
|
|
270
270
|
scope: commandScope,
|
|
271
271
|
state: "totp-command/v1",
|
|
272
|
-
version: randomId
|
|
272
|
+
version: yield* randomId
|
|
273
273
|
});
|
|
274
274
|
invariant(values[factor.scope] === commandScope && values[factor.state] === "totp-command/v1");
|
|
275
275
|
commandObservation.rows = (yield* owner.insert(factor.table, values, { [factor.scope]: commandScope })).rows;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"totp-state.mjs","names":[],"sources":["../../src/drizzle/totp-state.ts"],"sourcesContent":["import { randomId, digest } from \"@yielded/auth-crypto\";\nimport { AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport {\n TotpUnavailable,\n type TotpMutation,\n TotpPolicy,\n TotpRecord,\n type TotpDecision,\n} from \"@yielded/auth/Totp\";\n/* oxlint-disable no-explicit-any -- private native driver bridge; public makers preserve table and ID types. */\nimport { sql, type SQL } from \"drizzle-orm\";\nimport { Context, Effect, Schema } from \"effect\";\n\nimport { both, makeTransactionRows, type TransactionOwner } from \"./transaction-owner\";\nexport const unavailable = () => TotpUnavailable.make({});\n\nexport const invariant: (condition: unknown) => asserts condition = (condition) => {\n if (!condition) throw unavailable();\n};\n\nexport class CurrentTotpTransaction extends Context.Service<\n CurrentTotpTransaction,\n TransactionOwner<TotpUnavailable>\n>()(\"effect-auth/drizzle/CurrentTotpTransaction\") {}\n\nexport const { equal, col, copiedRow } = makeTransactionRows(unavailable);\nconst codec = Schema.fromJsonString(TotpRecord);\n\nexport const encodeTotpRecord = (record: TotpRecord) => Schema.encodeSync(codec)(record);\nexport const decodeTotpRecord = (state: string) => Schema.decodeSync(codec)(state);\n\nconst scopeFor = (moduleId: string, subjectId: string) =>\n digest(`effect-auth/totp/scope/v1/${moduleId.length}:${moduleId}/${subjectId}`);\n\nexport const captureTotp = Effect.fn(\"TotpNative.capture\")(function* (\n mapping: any,\n subjectId: typeof TotpRecord.Type.subjectId,\n) {\n const owner = yield* CurrentTotpTransaction,\n subject = mapping.subject,\n factor = mapping.factor,\n nativeId = mapping.subjectIds.toNative(subjectId);\n\n invariant(mapping.subjectIds.toSubject(nativeId) === subjectId);\n\n const selected = yield* owner.read(\n subject.table,\n equal(subject.table, { [subject.id]: nativeId }),\n { limit: 1 },\n );\n\n const subjectRow = selected.rows[0];\n\n if (\n subjectRow === undefined ||\n !(yield* owner.check(\n sql`exists(select 1 from ${subject.table} where ${both(owner.exact(subject.table, subjectRow), subject.activeCondition)})`,\n ))\n )\n return undefined;\n\n const scope = scopeFor(mapping.moduleId, subjectId),\n found = yield* owner.read(factor.table, equal(factor.table, { [factor.scope]: scope }), {\n limit: 1,\n }),\n row = found.rows[0];\n\n const record = row === undefined ? null : decodeTotpRecord(row[factor.state] as string);\n\n invariant(\n record === null ||\n ((record.secret === null || record.secret.revision === record.revision) &&\n (record.pending === null || record.pending.secret.revision === record.pending.revision)),\n );\n invariant(\n record === null ||\n (record.moduleId === mapping.moduleId &&\n record.subjectId === subjectId &&\n record.version === row![factor.version]),\n );\n\n return {\n nativeId,\n subjectRow,\n factorRow: row,\n factorObservation: found,\n scope,\n snapshot: {\n revision: {\n subjectId,\n securityRevision: SecurityRevision.make(subjectRow[subject.securityRevision] as string),\n credentials:\n record === null || record.secret === null\n ? []\n : [\n {\n credentialId: record.credentialId,\n revision: SecurityRevision.make(record.revision),\n },\n ],\n },\n record,\n },\n };\n});\n\nconst reject: TotpDecision = { _tag: \"Rejected\" };\n\nexport const mutateTotp = Effect.fn(\"TotpNative.mutate\")(function* (\n mapping: any,\n input: TotpMutation,\n) {\n const owner = yield* CurrentTotpTransaction;\n\n invariant(\n input.moduleId === mapping.moduleId &&\n Schema.encodeSync(Schema.fromJsonString(TotpPolicy))(input.policy) ===\n Schema.encodeSync(Schema.fromJsonString(TotpPolicy))(mapping.policy),\n );\n const captured = yield* captureTotp(mapping, input.subjectId);\n\n if (captured === undefined) return reject;\n\n const { snapshot, subjectRow, factorRow, factorObservation, scope, nativeId } = captured,\n current = snapshot.record,\n policy = input.policy,\n action = input.action;\n\n if (\n snapshot.revision.securityRevision !== input.snapshot.revision.securityRevision ||\n (current?.version ?? null) !== (input.snapshot.record?.version ?? null)\n )\n return reject;\n if (\n (current === null) !== (input.snapshot.record === null) ||\n (current !== null && encodeTotpRecord(current) !== encodeTotpRecord(input.snapshot.record!))\n )\n return reject;\n const now = yield* owner.now({ engineNowMillis: mapping.engineNowMillis });\n const guards: SQL[] = [];\n const credentialGuards: { credentialId: string; condition: SQL }[] = [];\n\n const commandScope = digest(\n `effect-auth/totp/command/v1/${mapping.moduleId.length}:${mapping.moduleId}/${input.subjectId.length}:${input.subjectId}/${input.commandId}`,\n );\n\n const management = [\"Enroll\", \"Confirm\", \"Disable\", \"Regenerate\"].includes(action._tag);\n\n const commandObservation = management\n ? yield* owner.read(\n mapping.factor.table,\n equal(mapping.factor.table, { [mapping.factor.scope]: commandScope }),\n { limit: 1 },\n )\n : undefined;\n\n if (commandObservation !== undefined && commandObservation.rows.length !== 0) return reject;\n const timeGuards: SQL[] = [];\n\n const timeBound = (start: number, end: number) => {\n timeGuards.push(\n sql`${mapping.engineNowMillis} >= ${start} and ${mapping.engineNowMillis} < ${end}`,\n );\n };\n\n if (\n action._tag === \"Enroll\" ||\n action._tag === \"Confirm\" ||\n action._tag === \"Disable\" ||\n action._tag === \"Regenerate\"\n ) {\n const authorization = input.authorization;\n\n if (authorization === undefined) return reject;\n const { challenge, evidence } = authorization;\n\n const expectedAction = {\n Enroll: \"enroll\",\n Confirm: \"confirm\",\n Disable: \"disable\",\n Regenerate: \"regenerate\",\n }[action._tag];\n\n if (\n challenge.action !== expectedAction ||\n challenge.moduleId !== mapping.moduleId ||\n challenge.commandId !== input.commandId ||\n challenge.revision.subjectId !== input.subjectId ||\n challenge.revision.securityRevision !== snapshot.revision.securityRevision ||\n evidence.flowId !== challenge.flowId ||\n evidence.bindingDigest !== challenge.bindingDigest ||\n evidence.revision.subjectId !== input.subjectId ||\n evidence.revision.securityRevision !== snapshot.revision.securityRevision\n )\n return reject;\n const auth = mapping.credential;\n\n for (const revision of [...evidence.revision.credentials].sort((a, b) =>\n a.credentialId.localeCompare(b.credentialId),\n )) {\n const found = yield* owner.read(\n auth.table,\n equal(auth.table, { [auth.id]: revision.credentialId, [auth.subjectId]: nativeId }),\n { limit: 1 },\n );\n\n const row = found.rows[0];\n\n if (row === undefined || row[auth.revision] !== revision.revision) return reject;\n const condition = sql`exists(select 1 from ${auth.table} where ${both(owner.exact(auth.table, row), auth.activeCondition)})`;\n\n if (!(yield* owner.check(condition))) return reject;\n credentialGuards.push({ credentialId: revision.credentialId, condition });\n }\n\n const eligible = evidence.proofs.filter((proof) =>\n evidence.revision.credentials.some(\n (revision) => revision.credentialId === proof.credentialId,\n ),\n );\n\n if (eligible.length !== evidence.proofs.length || eligible.length === 0) return reject;\n\n const requirements = [\n authorization.requirement,\n Schema.decodeSync(AuthenticationRequirement)(\n mapping.subject.decodeRequirement(copiedRow(subjectRow)),\n ),\n ];\n\n const maximumAge = Math.min(\n policy.maximumEvidenceAgeMillis,\n ...requirements.map((requirement) => requirement.maximumAgeMillis),\n );\n\n const evidenceFactors = new Set(eligible.flatMap((proof) => proof.factors));\n const evidenceCredentials = new Set(eligible.map((proof) => proof.credentialId));\n\n for (const requirement of requirements) {\n if (\n !requirement.alternatives.some(\n (alternative) =>\n alternative.factors.every((factor) => evidenceFactors.has(factor)) &&\n evidenceCredentials.size >= alternative.minimumCredentials &&\n eligible.some(\n (proof) =>\n (!alternative.userVerified || proof.userVerified) &&\n (!alternative.phishingResistant || proof.phishingResistant),\n ),\n )\n )\n return reject;\n }\n for (const proof of eligible) {\n const verifiedAt = proof.verifiedAt.epochMilliseconds;\n\n if (verifiedAt > now || now - verifiedAt >= maximumAge) return reject;\n timeBound(verifiedAt, verifiedAt + maximumAge);\n }\n if (\n (current !== null && current.secret !== null) ||\n action._tag === \"Disable\" ||\n action._tag === \"Regenerate\"\n ) {\n const factors = new Set(eligible.flatMap((proof) => proof.factors));\n\n if (\n !(\n eligible.some(\n (proof) =>\n proof.userVerified && proof.phishingResistant && proof.factors.includes(\"possession\"),\n ) ||\n (factors.has(\"knowledge\") &&\n factors.has(\"possession\") &&\n new Set(eligible.map((proof) => proof.credentialId)).size >= 2)\n )\n )\n return reject;\n }\n }\n if (action._tag === \"Recovery\" && action.reset) {\n const target = action.pending;\n\n if (\n target === undefined ||\n mapping.pendingCondition === undefined ||\n target.revision.subjectId !== input.subjectId ||\n target.revision.securityRevision !== snapshot.revision.securityRevision ||\n target.expiresAtMillis <= now\n )\n return reject;\n const condition = mapping.pendingCondition(target, nativeId);\n\n if (!(yield* owner.check(condition))) return reject;\n guards.push(condition);\n timeBound(0, target.expiresAtMillis);\n }\n\n let next: TotpRecord,\n semantic = false,\n accepted = true;\n\n if (action._tag === \"Enroll\") {\n const candidate = action.record;\n\n if (\n candidate.subjectId !== input.subjectId ||\n candidate.moduleId !== input.moduleId ||\n candidate.pending === null ||\n candidate.pending.expiresAtMillis <= now ||\n candidate.pending.expiresAtMillis > now + policy.enrollmentLifetimeMillis ||\n candidate.pending.failedAttempts !== 0 ||\n candidate.pending.secret.revision !== candidate.pending.revision\n )\n return reject;\n // Reissuing cannot erase the confirmation budget during its current enrollment lifetime.\n if (current !== null && current.pending !== null && current.pending.expiresAtMillis > now)\n return reject;\n if (\n current !== null &&\n (candidate.credentialId !== current.credentialId ||\n encodeTotpRecord({ ...candidate, pending: current.pending }) !== encodeTotpRecord(current))\n )\n return reject;\n if (\n current === null &&\n (candidate.secret !== null ||\n candidate.recoveryDigests.length !== 0 ||\n candidate.acceptedStep !== -1 ||\n candidate.failedAttempts !== 0)\n )\n return reject;\n next = candidate;\n timeBound(0, candidate.pending.expiresAtMillis);\n } else {\n if (current === null) return reject;\n next = { ...current };\n if (action._tag === \"Confirm\") {\n const pending = current.pending;\n\n if (\n pending === null ||\n pending.enrollmentId !== action.enrollmentId ||\n pending.expiresAtMillis <= now ||\n pending.failedAttempts >= policy.attemptLimit\n )\n return reject;\n timeBound(0, pending.expiresAtMillis);\n if (\n action.matchedStep === null ||\n Math.abs(Math.floor(now / 30000) - action.matchedStep) > policy.clockSkewSteps\n ) {\n next = { ...current, pending: { ...pending, failedAttempts: pending.failedAttempts + 1 } };\n accepted = false;\n } else {\n if (new Set(action.recoveryDigests).size !== 10) return reject;\n next = {\n ...current,\n secret: pending.secret,\n revision: pending.secret.revision,\n pending: null,\n recoveryDigests: action.recoveryDigests,\n acceptedStep: action.matchedStep,\n attemptWindow: now,\n failedAttempts: 0,\n };\n semantic = true;\n timeBound(\n Math.max(0, (action.matchedStep - policy.clockSkewSteps) * 30000),\n (action.matchedStep + policy.clockSkewSteps + 1) * 30000,\n );\n }\n } else if (action._tag === \"Verify\" || action._tag === \"Recovery\") {\n if (current.secret === null) return reject;\n\n const expired = now >= current.attemptWindow + policy.attemptWindowMillis,\n attempts = expired ? 0 : current.failedAttempts,\n start = expired ? now : current.attemptWindow;\n\n if (attempts >= policy.attemptLimit) return reject;\n next = { ...current, attemptWindow: start, failedAttempts: attempts + 1 };\n if (action._tag === \"Verify\") {\n if (\n action.matchedStep === null ||\n action.matchedStep <= current.acceptedStep ||\n Math.abs(Math.floor(now / 30000) - action.matchedStep) > policy.clockSkewSteps\n )\n accepted = false;\n else {\n next = { ...next, acceptedStep: action.matchedStep, failedAttempts: 0 };\n timeBound(\n Math.max(0, (action.matchedStep - policy.clockSkewSteps) * 30000),\n (action.matchedStep + policy.clockSkewSteps + 1) * 30000,\n );\n }\n } else {\n if (\n (action.reset\n ? policy.lostFactorRecovery !== \"reset-with-recovery-code\"\n : !policy.allowRecoveryCodeForPending) ||\n !current.recoveryDigests.includes(action.digest)\n )\n accepted = false;\n else {\n next = {\n ...next,\n recoveryDigests: current.recoveryDigests.filter((value) => value !== action.digest),\n failedAttempts: 0,\n };\n if (action.reset) {\n next = {\n ...next,\n secret: null,\n pending: null,\n recoveryDigests: [],\n revision: randomId(),\n };\n semantic = true;\n }\n }\n }\n } else {\n if (current.secret === null) return reject;\n semantic = true;\n if (action._tag === \"Disable\")\n next = {\n ...current,\n secret: null,\n pending: null,\n recoveryDigests: [],\n revision: randomId(),\n };\n else {\n if (new Set(action.recoveryDigests).size !== 10) return reject;\n next = { ...current, recoveryDigests: action.recoveryDigests };\n }\n }\n }\n next = { ...next, version: randomId() };\n\n const subject = mapping.subject,\n factor = mapping.factor,\n auth = mapping.credential;\n\n const subjectKey = { [subject.id]: nativeId };\n\n if (semantic) {\n const revision = randomId(),\n updates = {\n [subject.securityRevision]: revision,\n [subject.factorEnabled]: subject.encodeEnabled(next.secret !== null),\n };\n\n yield* owner.update(subject.table, subjectKey, updates);\n const idKey = { [auth.id]: next.credentialId, [auth.subjectId]: nativeId };\n const existing = yield* owner.read(auth.table, equal(auth.table, idKey), { limit: 1 });\n\n if (existing.rows.length === 0) {\n const values = {\n ...auth.encodeInsert({\n credentialId: next.credentialId,\n subjectId: nativeId,\n revision: next.revision,\n active: next.secret !== null,\n }),\n [auth.id]: next.credentialId,\n [auth.subjectId]: nativeId,\n [auth.revision]: next.revision,\n [auth.status]: auth.encodeStatus(next.secret !== null),\n };\n\n existing.rows = (yield* owner.insert(auth.table, values, {\n [auth.id]: next.credentialId,\n })).rows;\n } else\n yield* owner.update(auth.table, idKey, {\n [auth.revision]: next.revision,\n [auth.status]: auth.encodeStatus(next.secret !== null),\n });\n // Management proof observations precede its own credential/revision mutation.\n // Retain all unrelated credential authority checks at final commit.\n }\n\n const state = encodeTotpRecord(next),\n values = { [factor.state]: state, [factor.version]: next.version };\n\n if (factorRow === undefined) {\n const insert = factor.encodeInsert({ scope, state, version: next.version });\n\n invariant(\n insert[factor.scope] === scope &&\n insert[factor.state] === state &&\n insert[factor.version] === next.version,\n );\n factorObservation.rows = (yield* owner.insert(factor.table, insert, {\n [factor.scope]: scope,\n })).rows;\n } else yield* owner.update(factor.table, { [factor.scope]: scope }, values);\n if (commandObservation !== undefined) {\n const values = factor.encodeInsert({\n scope: commandScope,\n state: \"totp-command/v1\",\n version: randomId(),\n });\n\n invariant(values[factor.scope] === commandScope && values[factor.state] === \"totp-command/v1\");\n commandObservation.rows = (yield* owner.insert(factor.table, values, {\n [factor.scope]: commandScope,\n })).rows;\n }\n // Exact pre-write observations plus final readback are asserted by the common owner.\n // Include active subject and native time at finalization, including on rejection commits.\n guards.push(\n sql`exists(select 1 from ${subject.table} where ${both(equal(subject.table, subjectKey), subject.activeCondition)})`,\n );\n owner.postconditions.push(\n ...guards,\n ...timeGuards,\n ...credentialGuards\n .filter((guard) => !semantic || guard.credentialId !== next.credentialId)\n .map((guard) => guard.condition),\n );\n\n return accepted ? { _tag: \"Accepted\" as const, record: next } : reject;\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"totp-state.mjs","names":[],"sources":["../../src/drizzle/totp-state.ts"],"sourcesContent":["import { AuthenticationRequirement, SecurityRevision } from \"@yielded/auth/Sessions\";\nimport {\n TotpUnavailable,\n type TotpMutation,\n TotpPolicy,\n TotpRecord,\n type TotpDecision,\n} from \"@yielded/auth/Totp\";\n/* oxlint-disable no-explicit-any -- private native driver bridge; public makers preserve table and ID types. */\nimport { sql, type SQL } from \"drizzle-orm\";\nimport { Context, Effect, Schema } from \"effect\";\n\nimport { randomId, digest } from \"./crypto\";\nimport { both, makeTransactionRows, type TransactionOwner } from \"./transaction-owner\";\nexport const unavailable = () => TotpUnavailable.make({});\n\nexport const invariant: (condition: unknown) => asserts condition = (condition) => {\n if (!condition) throw unavailable();\n};\n\nexport class CurrentTotpTransaction extends Context.Service<\n CurrentTotpTransaction,\n TransactionOwner<TotpUnavailable>\n>()(\"effect-auth/drizzle/CurrentTotpTransaction\") {}\n\nexport const { equal, col, copiedRow } = makeTransactionRows(unavailable);\nconst codec = Schema.fromJsonString(TotpRecord);\n\nexport const encodeTotpRecord = (record: TotpRecord) => Schema.encodeSync(codec)(record);\nexport const decodeTotpRecord = (state: string) => Schema.decodeSync(codec)(state);\n\nconst scopeFor = (moduleId: string, subjectId: string) =>\n digest(`effect-auth/totp/scope/v1/${moduleId.length}:${moduleId}/${subjectId}`);\n\nexport const captureTotp = Effect.fn(\"TotpNative.capture\")(function* (\n mapping: any,\n subjectId: typeof TotpRecord.Type.subjectId,\n) {\n const owner = yield* CurrentTotpTransaction,\n subject = mapping.subject,\n factor = mapping.factor,\n nativeId = mapping.subjectIds.toNative(subjectId);\n\n invariant(mapping.subjectIds.toSubject(nativeId) === subjectId);\n\n const selected = yield* owner.read(\n subject.table,\n equal(subject.table, { [subject.id]: nativeId }),\n { limit: 1 },\n );\n\n const subjectRow = selected.rows[0];\n\n if (\n subjectRow === undefined ||\n !(yield* owner.check(\n sql`exists(select 1 from ${subject.table} where ${both(owner.exact(subject.table, subjectRow), subject.activeCondition)})`,\n ))\n )\n return undefined;\n\n const scope = yield* scopeFor(mapping.moduleId, subjectId),\n found = yield* owner.read(factor.table, equal(factor.table, { [factor.scope]: scope }), {\n limit: 1,\n }),\n row = found.rows[0];\n\n const record = row === undefined ? null : decodeTotpRecord(row[factor.state] as string);\n\n invariant(\n record === null ||\n ((record.secret === null || record.secret.revision === record.revision) &&\n (record.pending === null || record.pending.secret.revision === record.pending.revision)),\n );\n invariant(\n record === null ||\n (record.moduleId === mapping.moduleId &&\n record.subjectId === subjectId &&\n record.version === row![factor.version]),\n );\n\n return {\n nativeId,\n subjectRow,\n factorRow: row,\n factorObservation: found,\n scope,\n snapshot: {\n revision: {\n subjectId,\n securityRevision: SecurityRevision.make(subjectRow[subject.securityRevision] as string),\n credentials:\n record === null || record.secret === null\n ? []\n : [\n {\n credentialId: record.credentialId,\n revision: SecurityRevision.make(record.revision),\n },\n ],\n },\n record,\n },\n };\n});\n\nconst reject: TotpDecision = { _tag: \"Rejected\" };\n\nexport const mutateTotp = Effect.fn(\"TotpNative.mutate\")(function* (\n mapping: any,\n input: TotpMutation,\n) {\n const owner = yield* CurrentTotpTransaction;\n\n invariant(\n input.moduleId === mapping.moduleId &&\n Schema.encodeSync(Schema.fromJsonString(TotpPolicy))(input.policy) ===\n Schema.encodeSync(Schema.fromJsonString(TotpPolicy))(mapping.policy),\n );\n const captured = yield* captureTotp(mapping, input.subjectId);\n\n if (captured === undefined) return reject;\n\n const { snapshot, subjectRow, factorRow, factorObservation, scope, nativeId } = captured,\n current = snapshot.record,\n policy = input.policy,\n action = input.action;\n\n if (\n snapshot.revision.securityRevision !== input.snapshot.revision.securityRevision ||\n (current?.version ?? null) !== (input.snapshot.record?.version ?? null)\n )\n return reject;\n if (\n (current === null) !== (input.snapshot.record === null) ||\n (current !== null && encodeTotpRecord(current) !== encodeTotpRecord(input.snapshot.record!))\n )\n return reject;\n const now = yield* owner.now({ engineNowMillis: mapping.engineNowMillis });\n const guards: SQL[] = [];\n const credentialGuards: { credentialId: string; condition: SQL }[] = [];\n\n const commandScope = yield* digest(\n `effect-auth/totp/command/v1/${mapping.moduleId.length}:${mapping.moduleId}/${input.subjectId.length}:${input.subjectId}/${input.commandId}`,\n );\n\n const management = [\"Enroll\", \"Confirm\", \"Disable\", \"Regenerate\"].includes(action._tag);\n\n const commandObservation = management\n ? yield* owner.read(\n mapping.factor.table,\n equal(mapping.factor.table, { [mapping.factor.scope]: commandScope }),\n { limit: 1 },\n )\n : undefined;\n\n if (commandObservation !== undefined && commandObservation.rows.length !== 0) return reject;\n const timeGuards: SQL[] = [];\n\n const timeBound = (start: number, end: number) => {\n timeGuards.push(\n sql`${mapping.engineNowMillis} >= ${start} and ${mapping.engineNowMillis} < ${end}`,\n );\n };\n\n if (\n action._tag === \"Enroll\" ||\n action._tag === \"Confirm\" ||\n action._tag === \"Disable\" ||\n action._tag === \"Regenerate\"\n ) {\n const authorization = input.authorization;\n\n if (authorization === undefined) return reject;\n const { challenge, evidence } = authorization;\n\n const expectedAction = {\n Enroll: \"enroll\",\n Confirm: \"confirm\",\n Disable: \"disable\",\n Regenerate: \"regenerate\",\n }[action._tag];\n\n if (\n challenge.action !== expectedAction ||\n challenge.moduleId !== mapping.moduleId ||\n challenge.commandId !== input.commandId ||\n challenge.revision.subjectId !== input.subjectId ||\n challenge.revision.securityRevision !== snapshot.revision.securityRevision ||\n evidence.flowId !== challenge.flowId ||\n evidence.bindingDigest !== challenge.bindingDigest ||\n evidence.revision.subjectId !== input.subjectId ||\n evidence.revision.securityRevision !== snapshot.revision.securityRevision\n )\n return reject;\n const auth = mapping.credential;\n\n for (const revision of [...evidence.revision.credentials].sort((a, b) =>\n a.credentialId.localeCompare(b.credentialId),\n )) {\n const found = yield* owner.read(\n auth.table,\n equal(auth.table, { [auth.id]: revision.credentialId, [auth.subjectId]: nativeId }),\n { limit: 1 },\n );\n\n const row = found.rows[0];\n\n if (row === undefined || row[auth.revision] !== revision.revision) return reject;\n const condition = sql`exists(select 1 from ${auth.table} where ${both(owner.exact(auth.table, row), auth.activeCondition)})`;\n\n if (!(yield* owner.check(condition))) return reject;\n credentialGuards.push({ credentialId: revision.credentialId, condition });\n }\n\n const eligible = evidence.proofs.filter((proof) =>\n evidence.revision.credentials.some(\n (revision) => revision.credentialId === proof.credentialId,\n ),\n );\n\n if (eligible.length !== evidence.proofs.length || eligible.length === 0) return reject;\n\n const requirements = [\n authorization.requirement,\n Schema.decodeSync(AuthenticationRequirement)(\n mapping.subject.decodeRequirement(copiedRow(subjectRow)),\n ),\n ];\n\n const maximumAge = Math.min(\n policy.maximumEvidenceAgeMillis,\n ...requirements.map((requirement) => requirement.maximumAgeMillis),\n );\n\n const evidenceFactors = new Set(eligible.flatMap((proof) => proof.factors));\n const evidenceCredentials = new Set(eligible.map((proof) => proof.credentialId));\n\n for (const requirement of requirements) {\n if (\n !requirement.alternatives.some(\n (alternative) =>\n alternative.factors.every((factor) => evidenceFactors.has(factor)) &&\n evidenceCredentials.size >= alternative.minimumCredentials &&\n eligible.some(\n (proof) =>\n (!alternative.userVerified || proof.userVerified) &&\n (!alternative.phishingResistant || proof.phishingResistant),\n ),\n )\n )\n return reject;\n }\n for (const proof of eligible) {\n const verifiedAt = proof.verifiedAt.epochMilliseconds;\n\n if (verifiedAt > now || now - verifiedAt >= maximumAge) return reject;\n timeBound(verifiedAt, verifiedAt + maximumAge);\n }\n if (\n (current !== null && current.secret !== null) ||\n action._tag === \"Disable\" ||\n action._tag === \"Regenerate\"\n ) {\n const factors = new Set(eligible.flatMap((proof) => proof.factors));\n\n if (\n !(\n eligible.some(\n (proof) =>\n proof.userVerified && proof.phishingResistant && proof.factors.includes(\"possession\"),\n ) ||\n (factors.has(\"knowledge\") &&\n factors.has(\"possession\") &&\n new Set(eligible.map((proof) => proof.credentialId)).size >= 2)\n )\n )\n return reject;\n }\n }\n if (action._tag === \"Recovery\" && action.reset) {\n const target = action.pending;\n\n if (\n target === undefined ||\n mapping.pendingCondition === undefined ||\n target.revision.subjectId !== input.subjectId ||\n target.revision.securityRevision !== snapshot.revision.securityRevision ||\n target.expiresAtMillis <= now\n )\n return reject;\n const condition = mapping.pendingCondition(target, nativeId);\n\n if (!(yield* owner.check(condition))) return reject;\n guards.push(condition);\n timeBound(0, target.expiresAtMillis);\n }\n\n let next: TotpRecord,\n semantic = false,\n accepted = true;\n\n if (action._tag === \"Enroll\") {\n const candidate = action.record;\n\n if (\n candidate.subjectId !== input.subjectId ||\n candidate.moduleId !== input.moduleId ||\n candidate.pending === null ||\n candidate.pending.expiresAtMillis <= now ||\n candidate.pending.expiresAtMillis > now + policy.enrollmentLifetimeMillis ||\n candidate.pending.failedAttempts !== 0 ||\n candidate.pending.secret.revision !== candidate.pending.revision\n )\n return reject;\n // Reissuing cannot erase the confirmation budget during its current enrollment lifetime.\n if (current !== null && current.pending !== null && current.pending.expiresAtMillis > now)\n return reject;\n if (\n current !== null &&\n (candidate.credentialId !== current.credentialId ||\n encodeTotpRecord({ ...candidate, pending: current.pending }) !== encodeTotpRecord(current))\n )\n return reject;\n if (\n current === null &&\n (candidate.secret !== null ||\n candidate.recoveryDigests.length !== 0 ||\n candidate.acceptedStep !== -1 ||\n candidate.failedAttempts !== 0)\n )\n return reject;\n next = candidate;\n timeBound(0, candidate.pending.expiresAtMillis);\n } else {\n if (current === null) return reject;\n next = { ...current };\n if (action._tag === \"Confirm\") {\n const pending = current.pending;\n\n if (\n pending === null ||\n pending.enrollmentId !== action.enrollmentId ||\n pending.expiresAtMillis <= now ||\n pending.failedAttempts >= policy.attemptLimit\n )\n return reject;\n timeBound(0, pending.expiresAtMillis);\n if (\n action.matchedStep === null ||\n Math.abs(Math.floor(now / 30000) - action.matchedStep) > policy.clockSkewSteps\n ) {\n next = { ...current, pending: { ...pending, failedAttempts: pending.failedAttempts + 1 } };\n accepted = false;\n } else {\n if (new Set(action.recoveryDigests).size !== 10) return reject;\n next = {\n ...current,\n secret: pending.secret,\n revision: pending.secret.revision,\n pending: null,\n recoveryDigests: action.recoveryDigests,\n acceptedStep: action.matchedStep,\n attemptWindow: now,\n failedAttempts: 0,\n };\n semantic = true;\n timeBound(\n Math.max(0, (action.matchedStep - policy.clockSkewSteps) * 30000),\n (action.matchedStep + policy.clockSkewSteps + 1) * 30000,\n );\n }\n } else if (action._tag === \"Verify\" || action._tag === \"Recovery\") {\n if (current.secret === null) return reject;\n\n const expired = now >= current.attemptWindow + policy.attemptWindowMillis,\n attempts = expired ? 0 : current.failedAttempts,\n start = expired ? now : current.attemptWindow;\n\n if (attempts >= policy.attemptLimit) return reject;\n next = { ...current, attemptWindow: start, failedAttempts: attempts + 1 };\n if (action._tag === \"Verify\") {\n if (\n action.matchedStep === null ||\n action.matchedStep <= current.acceptedStep ||\n Math.abs(Math.floor(now / 30000) - action.matchedStep) > policy.clockSkewSteps\n )\n accepted = false;\n else {\n next = { ...next, acceptedStep: action.matchedStep, failedAttempts: 0 };\n timeBound(\n Math.max(0, (action.matchedStep - policy.clockSkewSteps) * 30000),\n (action.matchedStep + policy.clockSkewSteps + 1) * 30000,\n );\n }\n } else {\n if (\n (action.reset\n ? policy.lostFactorRecovery !== \"reset-with-recovery-code\"\n : !policy.allowRecoveryCodeForPending) ||\n !current.recoveryDigests.includes(action.digest)\n )\n accepted = false;\n else {\n next = {\n ...next,\n recoveryDigests: current.recoveryDigests.filter((value) => value !== action.digest),\n failedAttempts: 0,\n };\n if (action.reset) {\n next = {\n ...next,\n secret: null,\n pending: null,\n recoveryDigests: [],\n revision: yield* randomId,\n };\n semantic = true;\n }\n }\n }\n } else {\n if (current.secret === null) return reject;\n semantic = true;\n if (action._tag === \"Disable\")\n next = {\n ...current,\n secret: null,\n pending: null,\n recoveryDigests: [],\n revision: yield* randomId,\n };\n else {\n if (new Set(action.recoveryDigests).size !== 10) return reject;\n next = { ...current, recoveryDigests: action.recoveryDigests };\n }\n }\n }\n next = { ...next, version: yield* randomId };\n\n const subject = mapping.subject,\n factor = mapping.factor,\n auth = mapping.credential;\n\n const subjectKey = { [subject.id]: nativeId };\n\n if (semantic) {\n const revision = yield* randomId,\n updates = {\n [subject.securityRevision]: revision,\n [subject.factorEnabled]: subject.encodeEnabled(next.secret !== null),\n };\n\n yield* owner.update(subject.table, subjectKey, updates);\n const idKey = { [auth.id]: next.credentialId, [auth.subjectId]: nativeId };\n const existing = yield* owner.read(auth.table, equal(auth.table, idKey), { limit: 1 });\n\n if (existing.rows.length === 0) {\n const values = {\n ...auth.encodeInsert({\n credentialId: next.credentialId,\n subjectId: nativeId,\n revision: next.revision,\n active: next.secret !== null,\n }),\n [auth.id]: next.credentialId,\n [auth.subjectId]: nativeId,\n [auth.revision]: next.revision,\n [auth.status]: auth.encodeStatus(next.secret !== null),\n };\n\n existing.rows = (yield* owner.insert(auth.table, values, {\n [auth.id]: next.credentialId,\n })).rows;\n } else\n yield* owner.update(auth.table, idKey, {\n [auth.revision]: next.revision,\n [auth.status]: auth.encodeStatus(next.secret !== null),\n });\n // Management proof observations precede its own credential/revision mutation.\n // Retain all unrelated credential authority checks at final commit.\n }\n\n const state = encodeTotpRecord(next),\n values = { [factor.state]: state, [factor.version]: next.version };\n\n if (factorRow === undefined) {\n const insert = factor.encodeInsert({ scope, state, version: next.version });\n\n invariant(\n insert[factor.scope] === scope &&\n insert[factor.state] === state &&\n insert[factor.version] === next.version,\n );\n factorObservation.rows = (yield* owner.insert(factor.table, insert, {\n [factor.scope]: scope,\n })).rows;\n } else yield* owner.update(factor.table, { [factor.scope]: scope }, values);\n if (commandObservation !== undefined) {\n const values = factor.encodeInsert({\n scope: commandScope,\n state: \"totp-command/v1\",\n version: yield* randomId,\n });\n\n invariant(values[factor.scope] === commandScope && values[factor.state] === \"totp-command/v1\");\n commandObservation.rows = (yield* owner.insert(factor.table, values, {\n [factor.scope]: commandScope,\n })).rows;\n }\n // Exact pre-write observations plus final readback are asserted by the common owner.\n // Include active subject and native time at finalization, including on rejection commits.\n guards.push(\n sql`exists(select 1 from ${subject.table} where ${both(equal(subject.table, subjectKey), subject.activeCondition)})`,\n );\n owner.postconditions.push(\n ...guards,\n ...timeGuards,\n ...credentialGuards\n .filter((guard) => !semantic || guard.credentialId !== next.credentialId)\n .map((guard) => guard.condition),\n );\n\n return accepted ? { _tag: \"Accepted\" as const, record: next } : reject;\n});\n"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import "./totp-model.mjs";
|
|
|
5
5
|
import "./SuppliedService.mjs";
|
|
6
6
|
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
7
7
|
import { Table } from "drizzle-orm";
|
|
8
|
-
import { Context, Effect } from "effect";
|
|
8
|
+
import { Context, Crypto, Effect } from "effect";
|
|
9
9
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
10
10
|
import { TotpConfigurationError, TotpPersistence, TotpUnavailable } from "@yielded/auth/Totp";
|
|
11
11
|
import { Statement } from "effect/sql/Statement";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { validateDrizzleStorage } from "./storage-validation.mjs";
|
|
2
|
+
import { randomId } from "./crypto.mjs";
|
|
2
3
|
import { coordinateTransactionOwner, makeTransactionExecution, sqlClientTransactionStandaloneGuard } from "./transaction-execution.mjs";
|
|
3
4
|
import { requiredTotpConstraints } from "./totp-model.mjs";
|
|
4
5
|
import { CurrentTotpTransaction, captureTotp, invariant, mutateTotp, unavailable } from "./totp-state.mjs";
|
|
@@ -7,7 +8,6 @@ import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
|
7
8
|
import { Context, Effect, Schema } from "effect";
|
|
8
9
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
9
10
|
import { TotpConfigurationError, TotpMutation, TotpPersistence, TotpPolicy } from "@yielded/auth/Totp";
|
|
10
|
-
import { randomId } from "@yielded/auth-crypto";
|
|
11
11
|
//#region src/drizzle/totp-target.ts
|
|
12
12
|
const sqlClientTotpStandaloneGuard = (service) => sqlClientTransactionStandaloneGuard(unavailable, service);
|
|
13
13
|
const validateMapping = (original, configuration) => {
|
|
@@ -67,7 +67,7 @@ const coordinateTargetTotp = (database, source, configuration, body) => Effect.g
|
|
|
67
67
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(() => TotpConfigurationError.make({})));
|
|
68
68
|
return yield* coordinateTransactionOwner(database, CurrentTotpTransaction, configuration, Effect.void, unavailable, randomId, (execution) => services(mapping, execution), (transaction, acquireServices, append) => Effect.flatMap(acquireServices, (boundServices) => body(transaction, boundServices, append)));
|
|
69
69
|
});
|
|
70
|
-
/** Concrete driver wrappers select transaction mode
|
|
70
|
+
/** Concrete driver wrappers select transaction mode. */
|
|
71
71
|
const makeTotpTarget = (databaseService, configuration) => {
|
|
72
72
|
function coordinateTotpPersistence(acquire, options, body) {
|
|
73
73
|
return Effect.flatMap(nativeDatabase(acquire), (database) => coordinateTargetTotp(database, options.mapping, configuration, (transaction, services) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"totp-target.mjs","names":[],"sources":["../../src/drizzle/totp-target.ts"],"sourcesContent":["import { randomId } from \"@yielded/auth-crypto\";\nimport { NativeDatabase } from \"@yielded/auth-persistence/Adapter\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n TotpConfigurationError,\n type TotpUnavailable,\n TotpMutation,\n TotpPolicy,\n TotpPersistence,\n} from \"@yielded/auth/Totp\";\nimport type { Table } from \"drizzle-orm\";\n/* oxlint-disable no-explicit-any -- shared native implementation; driver entrypoints retain exact database and table types. */\nimport { Context, Effect, Schema } from \"effect\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport type { PersistenceMappingError } from \"./model\";\nimport { nativeDatabase } from \"./native-database\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\nimport type { SuppliedService } from \"./SuppliedService\";\nimport {\n type TotpMapping,\n type TotpMappingSource,\n type TotpPersistenceServices,\n requiredTotpConstraints,\n} from \"./totp-model\";\nimport {\n captureTotp,\n CurrentTotpTransaction,\n invariant,\n mutateTotp,\n unavailable,\n} from \"./totp-state\";\nimport {\n coordinateTransactionOwner,\n makeTransactionExecution,\n sqlClientTransactionStandaloneGuard,\n type TransactionExecution,\n type TransactionTargetConfiguration,\n type TransactionCoordinatorError,\n} from \"./transaction-execution\";\nimport type { TransactionNativeDatabase } from \"./transaction-owner\";\nexport type TotpTargetConfiguration = TransactionTargetConfiguration<TotpUnavailable>;\n\nexport type TotpCoordinatorError<E> =\n | TransactionCoordinatorError<E, TotpUnavailable>\n | TotpConfigurationError\n | PersistenceMappingError;\n\nexport const sqlClientTotpStandaloneGuard = (\n service: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],\n) => sqlClientTransactionStandaloneGuard(unavailable, service);\n\nconst validateMapping = <M>(original: M, configuration: TotpTargetConfiguration): M => {\n const mapping = original as any;\n\n invariant(mapping.moduleId.length > 0);\n Schema.decodeSync(TotpPolicy)(mapping.policy);\n for (const [key, value] of Object.entries(requiredTotpConstraints))\n invariant(mapping.constraints?.[key] === value);\n if (configuration.mode === \"batch\") invariant(mapping.d1?.primary === true);\n\n return Object.freeze({\n ...mapping,\n policy: Object.freeze({ ...mapping.policy }),\n subject: Object.freeze({ ...mapping.subject }),\n factor: Object.freeze({ ...mapping.factor }),\n credential: Object.freeze({ ...mapping.credential }),\n subjectIds: Object.freeze({ ...mapping.subjectIds }),\n });\n};\n\nconst services = Effect.fnUntraced(function* (\n mapping: any,\n execution: TransactionExecution<TotpUnavailable, CurrentTotpTransaction>,\n): Effect.fn.Return<TotpPersistenceServices, never, LifecycleHooks> {\n const hooks = yield* LifecycleHooks;\n\n return {\n totpPersistence: TotpPersistence.of({\n snapshot: Effect.fn(\"TotpNative.snapshot\")(\n function* (input) {\n const captured = { ...input };\n\n invariant(captured.moduleId === mapping.moduleId);\n yield* execution.admit;\n\n return yield* execution\n .run(\n Effect.map(captureTotp(mapping, captured.subjectId), (value) => value?.snapshot),\n false,\n )\n .pipe(Effect.provideService(LifecycleHooks, hooks));\n },\n Effect.catchDefect(() => Effect.fail(unavailable())),\n ),\n mutate: (original, prepare) =>\n Effect.suspend(() => {\n // Detach caller-owned payloads before any driver or hook can suspend.\n const codec = Schema.toCodecIso(TotpMutation);\n const input = Schema.decodeSync(codec)(Schema.encodeSync(codec)(original));\n\n return execution.admit.pipe(\n Effect.andThen(\n execution.run(\n Effect.gen(function* () {\n const decision = yield* mutateTotp(mapping, input),\n owner = yield* CurrentTotpTransaction;\n\n owner.guards.push(owner.journal.prepare(undefined));\n const receipt = prepare(decision, owner.journal);\n\n invariant(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n owner.guards.push(receipt as any);\n\n return receipt;\n }),\n ),\n ),\n Effect.provideService(LifecycleHooks, hooks),\n );\n }).pipe(Effect.catchDefect(() => Effect.fail(unavailable()))),\n }),\n };\n});\n\nexport const makeTargetTotpPersistence = <\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n RSetup = never,\n>(\n source: TotpMappingSource<TotpMapping<S, F, C, N>, RSetup>,\n configuration: TotpTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n const execution = yield* makeTransactionExecution(\n CurrentTotpTransaction,\n configuration,\n unavailable,\n randomId,\n );\n\n return yield* services(mapping, execution);\n });\n\nexport const coordinateTargetTotp = <M, A, E, R, RSetup = never>(\n database: TransactionNativeDatabase,\n source: TotpMappingSource<M, RSetup>,\n configuration: TotpTargetConfiguration,\n body: (\n transaction: any,\n services: TotpPersistenceServices,\n append: (statement: Statement<any>) => void,\n ) => Effect.Effect<A, E, R>,\n): Effect.Effect<A, TotpCoordinatorError<E>, R | RSetup | LifecycleHooks | NativeDatabase> =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n return yield* coordinateTransactionOwner(\n database,\n CurrentTotpTransaction,\n configuration,\n Effect.void,\n unavailable,\n randomId,\n (execution) => services(mapping, execution),\n (transaction, acquireServices, append) =>\n Effect.flatMap(acquireServices, (boundServices) =>\n body(transaction, boundServices, append),\n ),\n );\n });\n\ntype TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => any }\n ? Parameters<Parameters<D[\"transaction\"]>[0]>[0]\n : never;\n\n/** Concrete driver wrappers select transaction mode; cryptography always precedes these owners. */\nexport const makeTotpTarget = <\n DatabaseId,\n D extends { readonly transaction: any },\n T extends Table,\n Extra = unknown,\n Synchronous extends boolean = false,\n>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: TotpTargetConfiguration,\n) => {\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence>)\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence | TxId> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence | TxId>)\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n Exclude<R, TotpPersistence> | LifecycleHooks | RSetup | DatabaseRequirements\n > {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateTargetTotp(\n database as any,\n options.mapping,\n configuration,\n (\n transaction: TransactionOf<Database>,\n services,\n ): Effect.Effect<A, E, Exclude<R, TotpPersistence>> => {\n const provided = Context.make(TotpPersistence, services.totpPersistence);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ).pipe(Effect.provideService(NativeDatabase, database)),\n );\n }\n\n return {\n makeTotpPersistenceServices: <S extends T, F extends T, C extends T, N, RSetup = never>(\n mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>,\n ) =>\n makeTargetTotpPersistence(mapping, configuration).pipe(\n Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),\n ),\n coordinateTotpPersistence,\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"totp-target.mjs","names":[],"sources":["../../src/drizzle/totp-target.ts"],"sourcesContent":["import { NativeDatabase } from \"@yielded/auth-persistence/Adapter\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n TotpConfigurationError,\n type TotpUnavailable,\n TotpMutation,\n TotpPolicy,\n TotpPersistence,\n} from \"@yielded/auth/Totp\";\nimport type { Table } from \"drizzle-orm\";\n/* oxlint-disable no-explicit-any -- shared native implementation; driver entrypoints retain exact database and table types. */\nimport { type Crypto, Context, Effect, Schema } from \"effect\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport { randomId } from \"./crypto\";\nimport type { PersistenceMappingError } from \"./model\";\nimport { nativeDatabase } from \"./native-database\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\nimport type { SuppliedService } from \"./SuppliedService\";\nimport {\n type TotpMapping,\n type TotpMappingSource,\n type TotpPersistenceServices,\n requiredTotpConstraints,\n} from \"./totp-model\";\nimport {\n captureTotp,\n CurrentTotpTransaction,\n invariant,\n mutateTotp,\n unavailable,\n} from \"./totp-state\";\nimport {\n coordinateTransactionOwner,\n makeTransactionExecution,\n sqlClientTransactionStandaloneGuard,\n type TransactionExecution,\n type TransactionTargetConfiguration,\n type TransactionCoordinatorError,\n} from \"./transaction-execution\";\nimport type { TransactionNativeDatabase } from \"./transaction-owner\";\nexport type TotpTargetConfiguration = TransactionTargetConfiguration<TotpUnavailable>;\n\nexport type TotpCoordinatorError<E> =\n | TransactionCoordinatorError<E, TotpUnavailable>\n | TotpConfigurationError\n | PersistenceMappingError;\n\nexport const sqlClientTotpStandaloneGuard = (\n service: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],\n) => sqlClientTransactionStandaloneGuard(unavailable, service);\n\nconst validateMapping = <M>(original: M, configuration: TotpTargetConfiguration): M => {\n const mapping = original as any;\n\n invariant(mapping.moduleId.length > 0);\n Schema.decodeSync(TotpPolicy)(mapping.policy);\n for (const [key, value] of Object.entries(requiredTotpConstraints))\n invariant(mapping.constraints?.[key] === value);\n if (configuration.mode === \"batch\") invariant(mapping.d1?.primary === true);\n\n return Object.freeze({\n ...mapping,\n policy: Object.freeze({ ...mapping.policy }),\n subject: Object.freeze({ ...mapping.subject }),\n factor: Object.freeze({ ...mapping.factor }),\n credential: Object.freeze({ ...mapping.credential }),\n subjectIds: Object.freeze({ ...mapping.subjectIds }),\n });\n};\n\nconst services = Effect.fnUntraced(function* (\n mapping: any,\n execution: TransactionExecution<TotpUnavailable, CurrentTotpTransaction>,\n): Effect.fn.Return<TotpPersistenceServices, never, LifecycleHooks> {\n const hooks = yield* LifecycleHooks;\n\n return {\n totpPersistence: TotpPersistence.of({\n snapshot: Effect.fn(\"TotpNative.snapshot\")(\n function* (input) {\n const captured = { ...input };\n\n invariant(captured.moduleId === mapping.moduleId);\n yield* execution.admit;\n\n return yield* execution\n .run(\n Effect.map(captureTotp(mapping, captured.subjectId), (value) => value?.snapshot),\n false,\n )\n .pipe(Effect.provideService(LifecycleHooks, hooks));\n },\n Effect.catchDefect(() => Effect.fail(unavailable())),\n ),\n mutate: (original, prepare) =>\n Effect.suspend(() => {\n // Detach caller-owned payloads before any driver or hook can suspend.\n const codec = Schema.toCodecIso(TotpMutation);\n const input = Schema.decodeSync(codec)(Schema.encodeSync(codec)(original));\n\n return execution.admit.pipe(\n Effect.andThen(\n execution.run(\n Effect.gen(function* () {\n const decision = yield* mutateTotp(mapping, input),\n owner = yield* CurrentTotpTransaction;\n\n owner.guards.push(owner.journal.prepare(undefined));\n const receipt = prepare(decision, owner.journal);\n\n invariant(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n owner.guards.push(receipt as any);\n\n return receipt;\n }),\n ),\n ),\n Effect.provideService(LifecycleHooks, hooks),\n );\n }).pipe(Effect.catchDefect(() => Effect.fail(unavailable()))),\n }),\n };\n});\n\nexport const makeTargetTotpPersistence = <\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n RSetup = never,\n>(\n source: TotpMappingSource<TotpMapping<S, F, C, N>, RSetup>,\n configuration: TotpTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n const execution = yield* makeTransactionExecution(\n CurrentTotpTransaction,\n configuration,\n unavailable,\n randomId,\n );\n\n return yield* services(mapping, execution);\n });\n\nexport const coordinateTargetTotp = <M, A, E, R, RSetup = never>(\n database: TransactionNativeDatabase,\n source: TotpMappingSource<M, RSetup>,\n configuration: TotpTargetConfiguration,\n body: (\n transaction: any,\n services: TotpPersistenceServices,\n append: (statement: Statement<any>) => void,\n ) => Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n TotpCoordinatorError<E>,\n R | RSetup | Crypto.Crypto | LifecycleHooks | NativeDatabase\n> =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n return yield* coordinateTransactionOwner(\n database,\n CurrentTotpTransaction,\n configuration,\n Effect.void,\n unavailable,\n randomId,\n (execution) => services(mapping, execution),\n (transaction, acquireServices, append) =>\n Effect.flatMap(acquireServices, (boundServices) =>\n body(transaction, boundServices, append),\n ),\n );\n });\n\ntype TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => any }\n ? Parameters<Parameters<D[\"transaction\"]>[0]>[0]\n : never;\n\n/** Concrete driver wrappers select transaction mode. */\nexport const makeTotpTarget = <\n DatabaseId,\n D extends { readonly transaction: any },\n T extends Table,\n Extra = unknown,\n Synchronous extends boolean = false,\n>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: TotpTargetConfiguration,\n) => {\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence>)\n | Crypto.Crypto\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence | TxId> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence | TxId>)\n | Crypto.Crypto\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n Exclude<R, TotpPersistence> | Crypto.Crypto | LifecycleHooks | RSetup | DatabaseRequirements\n > {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateTargetTotp(\n database as any,\n options.mapping,\n configuration,\n (\n transaction: TransactionOf<Database>,\n services,\n ): Effect.Effect<A, E, Exclude<R, TotpPersistence>> => {\n const provided = Context.make(TotpPersistence, services.totpPersistence);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ).pipe(Effect.provideService(NativeDatabase, database)),\n );\n }\n\n return {\n makeTotpPersistenceServices: <S extends T, F extends T, C extends T, N, RSetup = never>(\n mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>,\n ) =>\n makeTargetTotpPersistence(mapping, configuration).pipe(\n Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),\n ),\n coordinateTotpPersistence,\n };\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@yielded/auth-persistence-drizzle","version":"0.1.0-beta.
|
|
1
|
+
{"name":"@yielded/auth-persistence-drizzle","version":"0.1.0-beta.19","dependencies":{"@yielded/auth":"0.1.0-beta.19","@yielded/auth-persistence":"0.1.0-beta.19"},"devDependencies":{"@effect/platform-bun":"4.0.0","@effect/platform-node":"4.0.0","@effect/sql-d1":"4.0.0","@effect/sql-libsql":"4.0.0","@effect/sql-mysql2":"4.0.0","@effect/sql-pg":"4.0.0","@effect/sql-pglite":"4.0.0","@effect/sql-sqlite-bun":"4.0.0","@effect/sql-sqlite-do":"4.0.0","@effect/sql-sqlite-node":"4.0.0","@effect/sql-sqlite-wasm":"4.0.0","@effect/vitest":"4.0.0","@yielded/crypto":"0.1.0-beta.19","drizzle-orm":"1.0.0-rc.4","effect":"4.0.0","typescript":"7.0.2","vite-plus":"0.3.3"},"peerDependencies":{"@effect/sql-d1":">=4.0.0","@effect/sql-libsql":">=4.0.0","@effect/sql-mysql2":">=4.0.0","@effect/sql-pg":">=4.0.0","@effect/sql-pglite":">=4.0.0","@effect/sql-sqlite-bun":">=4.0.0","@effect/sql-sqlite-do":">=4.0.0","@effect/sql-sqlite-node":">=4.0.0","@effect/sql-sqlite-wasm":">=4.0.0","drizzle-orm":">=1.0.0-rc.4","effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./D1":{"types":"./dist/D1.d.mts","default":"./dist/D1.mjs"},"./Libsql":{"types":"./dist/Libsql.d.mts","default":"./dist/Libsql.mjs"},"./Mysql2":{"types":"./dist/Mysql2.d.mts","default":"./dist/Mysql2.mjs"},"./Pglite":{"types":"./dist/Pglite.d.mts","default":"./dist/Pglite.mjs"},"./Postgres":{"types":"./dist/Postgres.d.mts","default":"./dist/Postgres.mjs"},"./SqliteBun":{"types":"./dist/SqliteBun.d.mts","default":"./dist/SqliteBun.mjs"},"./SqliteDo":{"types":"./dist/SqliteDo.d.mts","default":"./dist/SqliteDo.mjs"},"./SqliteNode":{"types":"./dist/SqliteNode.d.mts","default":"./dist/SqliteNode.mjs"},"./SqliteWasm":{"types":"./dist/SqliteWasm.d.mts","default":"./dist/SqliteWasm.mjs"}},"description":"Drizzle persistence, table mappings, and migration adapters 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-drizzle"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests","example:totp":"bun test/fixtures/totp-sqlite-bun.ts"},"peerDependenciesMeta":{"@effect/sql-d1":{"optional":true},"@effect/sql-libsql":{"optional":true},"@effect/sql-mysql2":{"optional":true},"@effect/sql-pg":{"optional":true},"@effect/sql-pglite":{"optional":true},"@effect/sql-sqlite-bun":{"optional":true},"@effect/sql-sqlite-do":{"optional":true},"@effect/sql-sqlite-node":{"optional":true},"@effect/sql-sqlite-wasm":{"optional":true}}}
|