@yielded/auth-persistence-drizzle 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/D1.d.mts +963 -0
- package/dist/D1.mjs +29 -0
- package/dist/D1.mjs.map +1 -0
- package/dist/Libsql.d.mts +2134 -0
- package/dist/Libsql.mjs +77 -0
- package/dist/Libsql.mjs.map +1 -0
- package/dist/Mysql2.d.mts +1817 -0
- package/dist/Mysql2.mjs +55 -0
- package/dist/Mysql2.mjs.map +1 -0
- package/dist/Pglite.d.mts +1821 -0
- package/dist/Pglite.mjs +53 -0
- package/dist/Pglite.mjs.map +1 -0
- package/dist/Postgres.d.mts +1821 -0
- package/dist/Postgres.mjs +53 -0
- package/dist/Postgres.mjs.map +1 -0
- package/dist/SqliteBun.d.mts +2129 -0
- package/dist/SqliteBun.mjs +70 -0
- package/dist/SqliteBun.mjs.map +1 -0
- package/dist/SqliteDo.d.mts +2181 -0
- package/dist/SqliteDo.mjs +105 -0
- package/dist/SqliteDo.mjs.map +1 -0
- package/dist/SqliteNode.d.mts +2129 -0
- package/dist/SqliteNode.mjs +70 -0
- package/dist/SqliteNode.mjs.map +1 -0
- package/dist/SqliteWasm.d.mts +2132 -0
- package/dist/SqliteWasm.mjs +70 -0
- package/dist/SqliteWasm.mjs.map +1 -0
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/drizzle/D1BatchStatements.d.mts +10 -0
- package/dist/drizzle/D1BatchStatements.mjs +8 -0
- package/dist/drizzle/D1BatchStatements.mjs.map +1 -0
- package/dist/drizzle/SuppliedService.d.mts +9 -0
- package/dist/drizzle/d1-emails.d.mts +61 -0
- package/dist/drizzle/d1-emails.mjs +578 -0
- package/dist/drizzle/d1-emails.mjs.map +1 -0
- package/dist/drizzle/d1-generated-statement.mjs +79 -0
- package/dist/drizzle/d1-generated-statement.mjs.map +1 -0
- package/dist/drizzle/d1-identity.d.mts +30 -0
- package/dist/drizzle/d1-identity.mjs +118 -0
- package/dist/drizzle/d1-identity.mjs.map +1 -0
- package/dist/drizzle/d1-oauth.d.mts +300 -0
- package/dist/drizzle/d1-oauth.mjs +76 -0
- package/dist/drizzle/d1-oauth.mjs.map +1 -0
- package/dist/drizzle/d1-passkey.d.mts +47 -0
- package/dist/drizzle/d1-passkey.mjs +95 -0
- package/dist/drizzle/d1-passkey.mjs.map +1 -0
- package/dist/drizzle/d1-password-prepared.d.mts +24 -0
- package/dist/drizzle/d1-password-prepared.mjs +460 -0
- package/dist/drizzle/d1-password-prepared.mjs.map +1 -0
- package/dist/drizzle/d1-passwords.d.mts +86 -0
- package/dist/drizzle/d1-passwords.mjs +1003 -0
- package/dist/drizzle/d1-passwords.mjs.map +1 -0
- package/dist/drizzle/d1-phone.d.mts +23 -0
- package/dist/drizzle/d1-phone.mjs +30 -0
- package/dist/drizzle/d1-phone.mjs.map +1 -0
- package/dist/drizzle/d1-planning.d.mts +11 -0
- package/dist/drizzle/d1-planning.mjs +43 -0
- package/dist/drizzle/d1-planning.mjs.map +1 -0
- package/dist/drizzle/d1-proofs.d.mts +79 -0
- package/dist/drizzle/d1-proofs.mjs +829 -0
- package/dist/drizzle/d1-proofs.mjs.map +1 -0
- package/dist/drizzle/d1-sessions.d.mts +66 -0
- package/dist/drizzle/d1-sessions.mjs +965 -0
- package/dist/drizzle/d1-sessions.mjs.map +1 -0
- package/dist/drizzle/d1-totp.d.mts +23 -0
- package/dist/drizzle/d1-totp.mjs +27 -0
- package/dist/drizzle/d1-totp.mjs.map +1 -0
- package/dist/drizzle/email-model.d.mts +30 -0
- package/dist/drizzle/email-model.mjs +2 -0
- package/dist/drizzle/email-registration.d.mts +29 -0
- package/dist/drizzle/email-registration.mjs +236 -0
- package/dist/drizzle/email-registration.mjs.map +1 -0
- package/dist/drizzle/email-sql.d.mts +1 -0
- package/dist/drizzle/email-sql.mjs +9 -0
- package/dist/drizzle/email-sql.mjs.map +1 -0
- package/dist/drizzle/email-target.d.mts +19 -0
- package/dist/drizzle/email-target.mjs +72 -0
- package/dist/drizzle/email-target.mjs.map +1 -0
- package/dist/drizzle/model.d.mts +245 -0
- package/dist/drizzle/model.mjs +55 -0
- package/dist/drizzle/model.mjs.map +1 -0
- package/dist/drizzle/mysql-emails.d.mts +70 -0
- package/dist/drizzle/mysql-emails.mjs +38 -0
- package/dist/drizzle/mysql-emails.mjs.map +1 -0
- package/dist/drizzle/mysql-identity.d.mts +21 -0
- package/dist/drizzle/mysql-identity.mjs +93 -0
- package/dist/drizzle/mysql-identity.mjs.map +1 -0
- package/dist/drizzle/mysql-password-prepared.d.mts +29 -0
- package/dist/drizzle/mysql-password-prepared.mjs +16 -0
- package/dist/drizzle/mysql-password-prepared.mjs.map +1 -0
- package/dist/drizzle/mysql-passwords.d.mts +85 -0
- package/dist/drizzle/mysql-passwords.mjs +38 -0
- package/dist/drizzle/mysql-passwords.mjs.map +1 -0
- package/dist/drizzle/mysql-proofs.d.mts +74 -0
- package/dist/drizzle/mysql-proofs.mjs +23 -0
- package/dist/drizzle/mysql-proofs.mjs.map +1 -0
- package/dist/drizzle/mysql-sessions.d.mts +91 -0
- package/dist/drizzle/mysql-sessions.mjs +53 -0
- package/dist/drizzle/mysql-sessions.mjs.map +1 -0
- package/dist/drizzle/mysql.d.mts +69 -0
- package/dist/drizzle/mysql.mjs +218 -0
- package/dist/drizzle/mysql.mjs.map +1 -0
- package/dist/drizzle/oauth-accounts.mjs +358 -0
- package/dist/drizzle/oauth-accounts.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-access.mjs +210 -0
- package/dist/drizzle/oauth-connected-access.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-collection.mjs +202 -0
- package/dist/drizzle/oauth-connected-collection.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-custody.mjs +146 -0
- package/dist/drizzle/oauth-connected-custody.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-drivers.mjs +76 -0
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-flow.mjs +247 -0
- package/dist/drizzle/oauth-connected-flow.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-input.mjs +103 -0
- package/dist/drizzle/oauth-connected-input.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-maintenance.mjs +214 -0
- package/dist/drizzle/oauth-connected-maintenance.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-management.mjs +228 -0
- package/dist/drizzle/oauth-connected-management.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-model.d.mts +277 -0
- package/dist/drizzle/oauth-connected-model.mjs +22 -0
- package/dist/drizzle/oauth-connected-model.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-reference.d.mts +16 -0
- package/dist/drizzle/oauth-connected-reference.mjs +53 -0
- package/dist/drizzle/oauth-connected-reference.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-settlement.mjs +117 -0
- package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-state.d.mts +1954 -0
- package/dist/drizzle/oauth-connected-state.mjs +422 -0
- package/dist/drizzle/oauth-connected-state.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-target.d.mts +752 -0
- package/dist/drizzle/oauth-connected-target.mjs +91 -0
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -0
- package/dist/drizzle/oauth-drivers.mjs +51 -0
- package/dist/drizzle/oauth-drivers.mjs.map +1 -0
- package/dist/drizzle/oauth-flow.d.mts +22 -0
- package/dist/drizzle/oauth-flow.mjs +253 -0
- package/dist/drizzle/oauth-flow.mjs.map +1 -0
- package/dist/drizzle/oauth-input.mjs +127 -0
- package/dist/drizzle/oauth-input.mjs.map +1 -0
- package/dist/drizzle/oauth-model.d.mts +461 -0
- package/dist/drizzle/oauth-model.mjs +49 -0
- package/dist/drizzle/oauth-model.mjs.map +1 -0
- package/dist/drizzle/oauth-mysql.mjs +8 -0
- package/dist/drizzle/oauth-mysql.mjs.map +1 -0
- package/dist/drizzle/oauth-owner.d.mts +10 -0
- package/dist/drizzle/oauth-owner.mjs +10 -0
- package/dist/drizzle/oauth-owner.mjs.map +1 -0
- package/dist/drizzle/oauth-registration.d.mts +5 -0
- package/dist/drizzle/oauth-registration.mjs +374 -0
- package/dist/drizzle/oauth-registration.mjs.map +1 -0
- package/dist/drizzle/oauth-state.mjs +107 -0
- package/dist/drizzle/oauth-state.mjs.map +1 -0
- package/dist/drizzle/oauth-target.d.mts +109 -0
- package/dist/drizzle/oauth-target.mjs +246 -0
- package/dist/drizzle/oauth-target.mjs.map +1 -0
- package/dist/drizzle/passkey-drivers.mjs +34 -0
- package/dist/drizzle/passkey-drivers.mjs.map +1 -0
- package/dist/drizzle/passkey-kernel.mjs +8 -0
- package/dist/drizzle/passkey-kernel.mjs.map +1 -0
- package/dist/drizzle/passkey-model.d.mts +43 -0
- package/dist/drizzle/passkey-model.mjs +8 -0
- package/dist/drizzle/passkey-model.mjs.map +1 -0
- package/dist/drizzle/passkey-registration-ceremony-model.d.mts +12 -0
- package/dist/drizzle/passkey-registration-ceremony-model.mjs +2 -0
- package/dist/drizzle/passkey-state.mjs +7 -0
- package/dist/drizzle/passkey-state.mjs.map +1 -0
- package/dist/drizzle/passkey-target.d.mts +2 -0
- package/dist/drizzle/passkey-target.mjs +7 -0
- package/dist/drizzle/passkey-target.mjs.map +1 -0
- package/dist/drizzle/passkey-write-drivers.mjs +32 -0
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -0
- package/dist/drizzle/passkey-write-model.d.mts +20 -0
- package/dist/drizzle/passkey-write-model.mjs +9 -0
- package/dist/drizzle/passkey-write-model.mjs.map +1 -0
- package/dist/drizzle/passkey-write-target.d.mts +5 -0
- package/dist/drizzle/passkey-write-target.mjs +7 -0
- package/dist/drizzle/passkey-write-target.mjs.map +1 -0
- package/dist/drizzle/password-model.d.mts +24 -0
- package/dist/drizzle/password-model.mjs +2 -0
- package/dist/drizzle/password-prepared-model.d.mts +92 -0
- package/dist/drizzle/password-prepared-model.mjs +11 -0
- package/dist/drizzle/password-prepared-model.mjs.map +1 -0
- package/dist/drizzle/password-prepared-sql.mjs +389 -0
- package/dist/drizzle/password-prepared-sql.mjs.map +1 -0
- package/dist/drizzle/password-prepared-state.mjs +104 -0
- package/dist/drizzle/password-prepared-state.mjs.map +1 -0
- package/dist/drizzle/password-prepared-target.d.mts +11 -0
- package/dist/drizzle/password-prepared-target.mjs +56 -0
- package/dist/drizzle/password-prepared-target.mjs.map +1 -0
- package/dist/drizzle/password-registration.d.mts +7 -0
- package/dist/drizzle/password-registration.mjs +134 -0
- package/dist/drizzle/password-registration.mjs.map +1 -0
- package/dist/drizzle/password-sql.d.mts +1 -0
- package/dist/drizzle/password-sql.mjs +9 -0
- package/dist/drizzle/password-sql.mjs.map +1 -0
- package/dist/drizzle/password-target.d.mts +16 -0
- package/dist/drizzle/password-target.mjs +61 -0
- package/dist/drizzle/password-target.mjs.map +1 -0
- package/dist/drizzle/pg-emails.d.mts +71 -0
- package/dist/drizzle/pg-emails.mjs +38 -0
- package/dist/drizzle/pg-emails.mjs.map +1 -0
- package/dist/drizzle/pg-password-prepared.d.mts +30 -0
- package/dist/drizzle/pg-password-prepared.mjs +16 -0
- package/dist/drizzle/pg-password-prepared.mjs.map +1 -0
- package/dist/drizzle/pg-passwords.d.mts +86 -0
- package/dist/drizzle/pg-passwords.mjs +38 -0
- package/dist/drizzle/pg-passwords.mjs.map +1 -0
- package/dist/drizzle/pg-proofs.d.mts +75 -0
- package/dist/drizzle/pg-proofs.mjs +22 -0
- package/dist/drizzle/pg-proofs.mjs.map +1 -0
- package/dist/drizzle/pg-sessions.d.mts +92 -0
- package/dist/drizzle/pg-sessions.mjs +53 -0
- package/dist/drizzle/pg-sessions.mjs.map +1 -0
- package/dist/drizzle/pg.d.mts +80 -0
- package/dist/drizzle/pg.mjs +289 -0
- package/dist/drizzle/pg.mjs.map +1 -0
- package/dist/drizzle/phone-model.d.mts +113 -0
- package/dist/drizzle/phone-model.mjs +39 -0
- package/dist/drizzle/phone-model.mjs.map +1 -0
- package/dist/drizzle/phone-state.mjs +14 -0
- package/dist/drizzle/phone-state.mjs.map +1 -0
- package/dist/drizzle/phone-target.d.mts +14 -0
- package/dist/drizzle/phone-target.mjs +168 -0
- package/dist/drizzle/phone-target.mjs.map +1 -0
- package/dist/drizzle/proof-model.d.mts +21 -0
- package/dist/drizzle/proof-model.mjs +2 -0
- package/dist/drizzle/proof-sql.d.mts +1 -0
- package/dist/drizzle/proof-sql.mjs +8 -0
- package/dist/drizzle/proof-sql.mjs.map +1 -0
- package/dist/drizzle/proof-target.d.mts +11 -0
- package/dist/drizzle/proof-target.mjs +36 -0
- package/dist/drizzle/proof-target.mjs.map +1 -0
- package/dist/drizzle/query-operations.mjs +27 -0
- package/dist/drizzle/query-operations.mjs.map +1 -0
- package/dist/drizzle/session-model.d.mts +31 -0
- package/dist/drizzle/session-model.mjs +2 -0
- package/dist/drizzle/session-sql.mjs +8 -0
- package/dist/drizzle/session-sql.mjs.map +1 -0
- package/dist/drizzle/session-target.d.mts +27 -0
- package/dist/drizzle/session-target.mjs +46 -0
- package/dist/drizzle/session-target.mjs.map +1 -0
- package/dist/drizzle/sqlite-emails.mjs +45 -0
- package/dist/drizzle/sqlite-emails.mjs.map +1 -0
- package/dist/drizzle/sqlite-identity.mjs +90 -0
- package/dist/drizzle/sqlite-identity.mjs.map +1 -0
- package/dist/drizzle/sqlite-password-prepared.mjs +21 -0
- package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -0
- package/dist/drizzle/sqlite-passwords.mjs +49 -0
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -0
- package/dist/drizzle/sqlite-proofs.mjs +29 -0
- package/dist/drizzle/sqlite-proofs.mjs.map +1 -0
- package/dist/drizzle/sqlite-sessions.mjs +74 -0
- package/dist/drizzle/sqlite-sessions.mjs.map +1 -0
- package/dist/drizzle/sqlite.d.mts +77 -0
- package/dist/drizzle/sqlite.mjs +217 -0
- package/dist/drizzle/sqlite.mjs.map +1 -0
- package/dist/drizzle/standalone-guard.mjs +17 -0
- package/dist/drizzle/standalone-guard.mjs.map +1 -0
- package/dist/drizzle/step-up-model.d.mts +16 -0
- package/dist/drizzle/step-up-model.mjs +2 -0
- package/dist/drizzle/table-model.d.mts +11 -0
- package/dist/drizzle/totp-model.d.mts +82 -0
- package/dist/drizzle/totp-model.mjs +13 -0
- package/dist/drizzle/totp-model.mjs.map +1 -0
- package/dist/drizzle/totp-state.d.mts +37 -0
- package/dist/drizzle/totp-state.mjs +287 -0
- package/dist/drizzle/totp-state.mjs.map +1 -0
- package/dist/drizzle/totp-target.d.mts +14 -0
- package/dist/drizzle/totp-target.mjs +81 -0
- package/dist/drizzle/totp-target.mjs.map +1 -0
- package/dist/drizzle/transaction-execution.d.mts +2 -0
- package/dist/drizzle/transaction-execution.mjs +11 -0
- package/dist/drizzle/transaction-execution.mjs.map +1 -0
- package/dist/drizzle/transaction-mysql.mjs +47 -0
- package/dist/drizzle/transaction-mysql.mjs.map +1 -0
- package/dist/drizzle/transaction-owner.d.mts +2 -0
- package/dist/drizzle/transaction-owner.mjs +8 -0
- package/dist/drizzle/transaction-owner.mjs.map +1 -0
- package/dist/index.d.mts +27 -0
- package/dist/index.mjs +27 -0
- package/dist/internal/drizzle-migrations.mjs +19 -0
- package/dist/internal/drizzle-migrations.mjs.map +1 -0
- package/dist/internal/drizzle-postgres.mjs +37 -0
- package/dist/internal/drizzle-postgres.mjs.map +1 -0
- package/dist/internal/drizzle-sqlite.mjs +35 -0
- package/dist/internal/drizzle-sqlite.mjs.map +1 -0
- package/package.json +1 -0
- package/src/D1.ts +136 -0
- package/src/Libsql.ts +257 -0
- package/src/Mysql2.ts +184 -0
- package/src/Pglite.ts +174 -0
- package/src/Postgres.ts +174 -0
- package/src/SqliteBun.ts +258 -0
- package/src/SqliteDo.ts +473 -0
- package/src/SqliteNode.ts +259 -0
- package/src/SqliteWasm.ts +263 -0
- package/src/drizzle/D1BatchStatements.ts +10 -0
- package/src/drizzle/SuppliedService.ts +10 -0
- package/src/drizzle/d1-emails.ts +1829 -0
- package/src/drizzle/d1-generated-statement.ts +129 -0
- package/src/drizzle/d1-identity.ts +375 -0
- package/src/drizzle/d1-oauth.ts +340 -0
- package/src/drizzle/d1-passkey.ts +373 -0
- package/src/drizzle/d1-password-prepared.ts +1270 -0
- package/src/drizzle/d1-passwords.ts +2656 -0
- package/src/drizzle/d1-phone.ts +96 -0
- package/src/drizzle/d1-planning.ts +104 -0
- package/src/drizzle/d1-proofs.ts +2305 -0
- package/src/drizzle/d1-sessions.ts +2857 -0
- package/src/drizzle/d1-totp.ts +78 -0
- package/src/drizzle/email-model.ts +202 -0
- package/src/drizzle/email-registration.ts +698 -0
- package/src/drizzle/email-sql.ts +25 -0
- package/src/drizzle/email-target.ts +243 -0
- package/src/drizzle/model.ts +459 -0
- package/src/drizzle/mysql-emails.ts +321 -0
- package/src/drizzle/mysql-identity.ts +324 -0
- package/src/drizzle/mysql-password-prepared.ts +204 -0
- package/src/drizzle/mysql-passwords.ts +339 -0
- package/src/drizzle/mysql-proofs.ts +181 -0
- package/src/drizzle/mysql-sessions.ts +741 -0
- package/src/drizzle/mysql.ts +687 -0
- package/src/drizzle/oauth-accounts.ts +804 -0
- package/src/drizzle/oauth-connected-access.ts +354 -0
- package/src/drizzle/oauth-connected-collection.ts +324 -0
- package/src/drizzle/oauth-connected-custody.ts +277 -0
- package/src/drizzle/oauth-connected-drivers.ts +465 -0
- package/src/drizzle/oauth-connected-flow.ts +441 -0
- package/src/drizzle/oauth-connected-input.ts +127 -0
- package/src/drizzle/oauth-connected-maintenance.ts +345 -0
- package/src/drizzle/oauth-connected-management.ts +365 -0
- package/src/drizzle/oauth-connected-model.ts +347 -0
- package/src/drizzle/oauth-connected-reference.ts +112 -0
- package/src/drizzle/oauth-connected-settlement.ts +226 -0
- package/src/drizzle/oauth-connected-state.ts +845 -0
- package/src/drizzle/oauth-connected-target.ts +264 -0
- package/src/drizzle/oauth-drivers.ts +569 -0
- package/src/drizzle/oauth-flow.ts +462 -0
- package/src/drizzle/oauth-input.ts +201 -0
- package/src/drizzle/oauth-model.ts +617 -0
- package/src/drizzle/oauth-mysql.ts +10 -0
- package/src/drizzle/oauth-owner.ts +29 -0
- package/src/drizzle/oauth-registration.ts +640 -0
- package/src/drizzle/oauth-state.ts +215 -0
- package/src/drizzle/oauth-target.ts +750 -0
- package/src/drizzle/passkey-drivers.ts +385 -0
- package/src/drizzle/passkey-kernel.ts +4 -0
- package/src/drizzle/passkey-model.ts +153 -0
- package/src/drizzle/passkey-registration-ceremony-model.ts +32 -0
- package/src/drizzle/passkey-state.ts +3 -0
- package/src/drizzle/passkey-target.ts +23 -0
- package/src/drizzle/passkey-write-drivers.ts +395 -0
- package/src/drizzle/passkey-write-model.ts +103 -0
- package/src/drizzle/passkey-write-target.ts +9 -0
- package/src/drizzle/password-model.ts +169 -0
- package/src/drizzle/password-prepared-model.ts +259 -0
- package/src/drizzle/password-prepared-sql.ts +1191 -0
- package/src/drizzle/password-prepared-state.ts +231 -0
- package/src/drizzle/password-prepared-target.ts +160 -0
- package/src/drizzle/password-registration.ts +363 -0
- package/src/drizzle/password-sql.ts +13 -0
- package/src/drizzle/password-target.ts +224 -0
- package/src/drizzle/pg-emails.ts +321 -0
- package/src/drizzle/pg-password-prepared.ts +205 -0
- package/src/drizzle/pg-passwords.ts +338 -0
- package/src/drizzle/pg-proofs.ts +191 -0
- package/src/drizzle/pg-sessions.ts +750 -0
- package/src/drizzle/pg.ts +984 -0
- package/src/drizzle/phone-model.ts +190 -0
- package/src/drizzle/phone-state.ts +21 -0
- package/src/drizzle/phone-target.ts +472 -0
- package/src/drizzle/proof-model.ts +139 -0
- package/src/drizzle/proof-sql.ts +10 -0
- package/src/drizzle/proof-target.ts +122 -0
- package/src/drizzle/query-operations.ts +43 -0
- package/src/drizzle/session-model.ts +215 -0
- package/src/drizzle/session-sql.ts +14 -0
- package/src/drizzle/session-target.ts +338 -0
- package/src/drizzle/sqlite-emails.ts +366 -0
- package/src/drizzle/sqlite-identity.ts +344 -0
- package/src/drizzle/sqlite-password-prepared.ts +260 -0
- package/src/drizzle/sqlite-passwords.ts +497 -0
- package/src/drizzle/sqlite-proofs.ts +202 -0
- package/src/drizzle/sqlite-sessions.ts +971 -0
- package/src/drizzle/sqlite.ts +705 -0
- package/src/drizzle/standalone-guard.ts +32 -0
- package/src/drizzle/step-up-model.ts +73 -0
- package/src/drizzle/table-model.ts +9 -0
- package/src/drizzle/totp-model.ts +92 -0
- package/src/drizzle/totp-state.ts +525 -0
- package/src/drizzle/totp-target.ts +308 -0
- package/src/drizzle/transaction-execution.ts +13 -0
- package/src/drizzle/transaction-mysql.ts +106 -0
- package/src/drizzle/transaction-owner.ts +11 -0
- package/src/index.ts +378 -0
- package/src/internal/drizzle-migrations.ts +29 -0
- package/src/internal/drizzle-postgres.ts +83 -0
- package/src/internal/drizzle-sqlite.ts +81 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { PersistenceMappingError } from "./model.mjs";
|
|
2
|
+
import { SubjectId } from "@yielded/auth/Schema";
|
|
3
|
+
import { InferInsertModel, InferSelectModel, SQL, Table } from "drizzle-orm";
|
|
4
|
+
import { Effect, Layer } from "effect";
|
|
5
|
+
import { AuthenticationRequirement, PendingAuthenticationContext } from "@yielded/auth/Sessions";
|
|
6
|
+
import { TotpPersistence, TotpPolicy } from "@yielded/auth/Totp";
|
|
7
|
+
//#region src/drizzle/totp-model.d.ts
|
|
8
|
+
export type TotpColumn<T extends Table> = Extract<keyof T["_"]["columns"], string>;
|
|
9
|
+
export type TotpMappingSource<M, R = never> = M | Effect.Effect<M, PersistenceMappingError, R>;
|
|
10
|
+
export declare const requiredTotpConstraints: {
|
|
11
|
+
readonly factor: "unique(scope)";
|
|
12
|
+
readonly credential: "unique(credentialId)";
|
|
13
|
+
readonly subject: "unique(id)";
|
|
14
|
+
};
|
|
15
|
+
/** A dedicated encrypted factor row plus the shared authentication credential authority.
|
|
16
|
+
* factorEnabled is the consumer's TOTP requirement bit; central primary methods must
|
|
17
|
+
* read it when choosing their AuthenticationRequirement. Other factor policy is untouched.
|
|
18
|
+
* State JSON stores ciphertext and recovery digests only. The same table retains
|
|
19
|
+
* domain-separated management command tombstones; retain them while command IDs
|
|
20
|
+
* can be replayed. Encoders and current requirement decoding cannot suspend.
|
|
21
|
+
*/
|
|
22
|
+
export interface TotpMapping<S extends Table, F extends Table, C extends Table, N> {
|
|
23
|
+
readonly moduleId: string;
|
|
24
|
+
readonly policy: TotpPolicy;
|
|
25
|
+
readonly constraints: typeof requiredTotpConstraints;
|
|
26
|
+
readonly subjectIds: {
|
|
27
|
+
readonly toNative: (id: SubjectId) => N;
|
|
28
|
+
readonly toSubject: (id: N) => SubjectId;
|
|
29
|
+
};
|
|
30
|
+
readonly subject: {
|
|
31
|
+
readonly table: S;
|
|
32
|
+
readonly id: TotpColumn<S>;
|
|
33
|
+
readonly securityRevision: TotpColumn<S>;
|
|
34
|
+
readonly factorEnabled: TotpColumn<S>;
|
|
35
|
+
readonly activeCondition: SQL;
|
|
36
|
+
readonly encodeEnabled: (enabled: boolean) => unknown;
|
|
37
|
+
readonly decodeRequirement: (row: InferSelectModel<S>) => AuthenticationRequirement;
|
|
38
|
+
};
|
|
39
|
+
readonly factor: {
|
|
40
|
+
readonly table: F;
|
|
41
|
+
readonly scope: TotpColumn<F>;
|
|
42
|
+
readonly state: TotpColumn<F>;
|
|
43
|
+
readonly version: TotpColumn<F>;
|
|
44
|
+
readonly encodeInsert: (value: {
|
|
45
|
+
readonly scope: string;
|
|
46
|
+
readonly state: string;
|
|
47
|
+
readonly version: string;
|
|
48
|
+
}) => InferInsertModel<F>;
|
|
49
|
+
};
|
|
50
|
+
readonly credential: {
|
|
51
|
+
readonly table: C;
|
|
52
|
+
readonly id: TotpColumn<C>;
|
|
53
|
+
readonly subjectId: TotpColumn<C>;
|
|
54
|
+
readonly revision: TotpColumn<C>;
|
|
55
|
+
readonly status: TotpColumn<C>;
|
|
56
|
+
readonly activeCondition: SQL;
|
|
57
|
+
readonly encodeStatus: (active: boolean) => unknown;
|
|
58
|
+
readonly encodeInsert: (value: {
|
|
59
|
+
readonly credentialId: string;
|
|
60
|
+
readonly subjectId: N;
|
|
61
|
+
readonly revision: string;
|
|
62
|
+
readonly active: boolean;
|
|
63
|
+
}) => InferInsertModel<C>;
|
|
64
|
+
};
|
|
65
|
+
/** Unix epoch milliseconds, evaluated again at the final conditional write. */
|
|
66
|
+
readonly engineNowMillis: SQL;
|
|
67
|
+
/** Required for reset-with-recovery-code. Must assert the exact unconsumed,
|
|
68
|
+
* unexpired, unexhausted pending flow, binding digest and original credential
|
|
69
|
+
* revisions. No request-supplied SQL or external I/O is accepted. */
|
|
70
|
+
readonly pendingCondition?: (target: PendingAuthenticationContext, subjectId: N) => SQL;
|
|
71
|
+
}
|
|
72
|
+
export interface D1TotpMapping {
|
|
73
|
+
readonly d1: {
|
|
74
|
+
readonly primary: true;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export interface TotpPersistenceServices {
|
|
78
|
+
readonly totpPersistence: TotpPersistence["Service"];
|
|
79
|
+
}
|
|
80
|
+
export declare const totpPersistenceLayer: <E, R>(services: Effect.Effect<TotpPersistenceServices, E, R>) => Layer.Layer<TotpPersistence, E, Exclude<R, import("effect/Scope").Scope>>;
|
|
81
|
+
//#endregion
|
|
82
|
+
//# sourceMappingURL=totp-model.d.mts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Effect, Layer } from "effect";
|
|
2
|
+
import { TotpPersistence } from "@yielded/auth/Totp";
|
|
3
|
+
//#region src/drizzle/totp-model.ts
|
|
4
|
+
const requiredTotpConstraints = {
|
|
5
|
+
factor: "unique(scope)",
|
|
6
|
+
credential: "unique(credentialId)",
|
|
7
|
+
subject: "unique(id)"
|
|
8
|
+
};
|
|
9
|
+
const totpPersistenceLayer = (services) => Layer.effect(TotpPersistence, Effect.map(services, (value) => value.totpPersistence));
|
|
10
|
+
//#endregion
|
|
11
|
+
export { requiredTotpConstraints, totpPersistenceLayer };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=totp-model.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"totp-model.mjs","names":[],"sources":["../../src/drizzle/totp-model.ts"],"sourcesContent":["import type { SubjectId } from \"@yielded/auth/Schema\";\nimport type {\n AuthenticationRequirement,\n PendingAuthenticationContext,\n} from \"@yielded/auth/Sessions\";\nimport { type TotpPolicy, TotpPersistence } from \"@yielded/auth/Totp\";\nimport type { InferInsertModel, InferSelectModel, SQL, Table } from \"drizzle-orm\";\nimport { Effect, Layer } from \"effect\";\n\nimport type { PersistenceMappingError } from \"./model\";\nexport type TotpColumn<T extends Table> = Extract<keyof T[\"_\"][\"columns\"], string>;\nexport type TotpMappingSource<M, R = never> = M | Effect.Effect<M, PersistenceMappingError, R>;\n\nexport const requiredTotpConstraints = {\n factor: \"unique(scope)\",\n credential: \"unique(credentialId)\",\n subject: \"unique(id)\",\n} as const;\n\n/** A dedicated encrypted factor row plus the shared authentication credential authority.\n * factorEnabled is the consumer's TOTP requirement bit; central primary methods must\n * read it when choosing their AuthenticationRequirement. Other factor policy is untouched.\n * State JSON stores ciphertext and recovery digests only. The same table retains\n * domain-separated management command tombstones; retain them while command IDs\n * can be replayed. Encoders and current requirement decoding cannot suspend.\n */\nexport interface TotpMapping<S extends Table, F extends Table, C extends Table, N> {\n readonly moduleId: string;\n readonly policy: TotpPolicy;\n readonly constraints: typeof requiredTotpConstraints;\n readonly subjectIds: {\n readonly toNative: (id: SubjectId) => N;\n readonly toSubject: (id: N) => SubjectId;\n };\n readonly subject: {\n readonly table: S;\n readonly id: TotpColumn<S>;\n readonly securityRevision: TotpColumn<S>;\n readonly factorEnabled: TotpColumn<S>;\n readonly activeCondition: SQL;\n readonly encodeEnabled: (enabled: boolean) => unknown;\n readonly decodeRequirement: (row: InferSelectModel<S>) => AuthenticationRequirement;\n };\n readonly factor: {\n readonly table: F;\n readonly scope: TotpColumn<F>;\n readonly state: TotpColumn<F>;\n readonly version: TotpColumn<F>;\n readonly encodeInsert: (value: {\n readonly scope: string;\n readonly state: string;\n readonly version: string;\n }) => InferInsertModel<F>;\n };\n readonly credential: {\n readonly table: C;\n readonly id: TotpColumn<C>;\n readonly subjectId: TotpColumn<C>;\n readonly revision: TotpColumn<C>;\n readonly status: TotpColumn<C>;\n readonly activeCondition: SQL;\n readonly encodeStatus: (active: boolean) => unknown;\n readonly encodeInsert: (value: {\n readonly credentialId: string;\n readonly subjectId: N;\n readonly revision: string;\n readonly active: boolean;\n }) => InferInsertModel<C>;\n };\n /** Unix epoch milliseconds, evaluated again at the final conditional write. */\n readonly engineNowMillis: SQL;\n /** Required for reset-with-recovery-code. Must assert the exact unconsumed,\n * unexpired, unexhausted pending flow, binding digest and original credential\n * revisions. No request-supplied SQL or external I/O is accepted. */\n readonly pendingCondition?: (target: PendingAuthenticationContext, subjectId: N) => SQL;\n}\n\nexport interface D1TotpMapping {\n readonly d1: { readonly primary: true };\n}\n\nexport interface TotpPersistenceServices {\n readonly totpPersistence: TotpPersistence[\"Service\"];\n}\n\nexport const totpPersistenceLayer = <E, R>(\n services: Effect.Effect<TotpPersistenceServices, E, R>,\n) =>\n Layer.effect(\n TotpPersistence,\n Effect.map(services, (value) => value.totpPersistence),\n );\n"],"mappings":";;;AAaA,MAAa,0BAA0B;CACrC,QAAQ;CACR,YAAY;CACZ,SAAS;AACX;AAoEA,MAAa,wBACX,aAEA,MAAM,OACJ,iBACA,OAAO,IAAI,WAAW,UAAU,MAAM,eAAe,CACvD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import "./transaction-owner.mjs";
|
|
2
|
+
import { SQL } from "drizzle-orm";
|
|
3
|
+
import { Context, Effect } from "effect";
|
|
4
|
+
import { TotpRecord, TotpUnavailable } from "@yielded/auth/Totp";
|
|
5
|
+
//#region src/drizzle/totp-state.d.ts
|
|
6
|
+
export declare const encodeTotpRecord: (record: TotpRecord) => string;
|
|
7
|
+
export declare const decodeTotpRecord: (state: string) => {
|
|
8
|
+
readonly moduleId: string;
|
|
9
|
+
readonly subjectId: string & import("effect/Brand").Brand<"effect-auth/SubjectId">;
|
|
10
|
+
readonly credentialId: string;
|
|
11
|
+
readonly revision: string;
|
|
12
|
+
readonly version: string;
|
|
13
|
+
readonly secret: {
|
|
14
|
+
readonly keyId: string;
|
|
15
|
+
readonly nonce: string;
|
|
16
|
+
readonly ciphertext: string;
|
|
17
|
+
readonly revision: string;
|
|
18
|
+
} | null;
|
|
19
|
+
readonly pending: {
|
|
20
|
+
readonly revision: string;
|
|
21
|
+
readonly enrollmentId: string;
|
|
22
|
+
readonly secret: {
|
|
23
|
+
readonly keyId: string;
|
|
24
|
+
readonly nonce: string;
|
|
25
|
+
readonly ciphertext: string;
|
|
26
|
+
readonly revision: string;
|
|
27
|
+
};
|
|
28
|
+
readonly expiresAtMillis: number;
|
|
29
|
+
readonly failedAttempts: number;
|
|
30
|
+
} | null;
|
|
31
|
+
readonly recoveryDigests: readonly (string & import("effect/Brand").Brand<"effect-auth/TokenDigest">)[];
|
|
32
|
+
readonly acceptedStep: number;
|
|
33
|
+
readonly attemptWindow: number;
|
|
34
|
+
readonly failedAttempts: number;
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
//# sourceMappingURL=totp-state.d.mts.map
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { both, makeTransactionRows } from "./transaction-owner.mjs";
|
|
2
|
+
import { sql } from "drizzle-orm";
|
|
3
|
+
import { Context, Effect, Schema } from "effect";
|
|
4
|
+
import { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
|
|
5
|
+
import { TotpPolicy, TotpRecord, TotpUnavailable } from "@yielded/auth/Totp";
|
|
6
|
+
import { digest, randomId } from "@yielded/auth-crypto";
|
|
7
|
+
//#region src/drizzle/totp-state.ts
|
|
8
|
+
const unavailable = () => TotpUnavailable.make({});
|
|
9
|
+
const invariant = (condition) => {
|
|
10
|
+
if (!condition) throw unavailable();
|
|
11
|
+
};
|
|
12
|
+
var CurrentTotpTransaction = class extends Context.Service()("effect-auth/drizzle/CurrentTotpTransaction") {};
|
|
13
|
+
const { equal, col, copiedRow } = makeTransactionRows(unavailable);
|
|
14
|
+
const codec = Schema.fromJsonString(TotpRecord);
|
|
15
|
+
const encodeTotpRecord = (record) => Schema.encodeSync(codec)(record);
|
|
16
|
+
const decodeTotpRecord = (state) => Schema.decodeSync(codec)(state);
|
|
17
|
+
const scopeFor = (moduleId, subjectId) => digest(`effect-auth/totp/scope/v1/${moduleId.length}:${moduleId}/${subjectId}`);
|
|
18
|
+
const captureTotp = Effect.fn("TotpNative.capture")(function* (mapping, subjectId) {
|
|
19
|
+
const owner = yield* CurrentTotpTransaction, subject = mapping.subject, factor = mapping.factor, nativeId = mapping.subjectIds.toNative(subjectId);
|
|
20
|
+
invariant(mapping.subjectIds.toSubject(nativeId) === subjectId);
|
|
21
|
+
const subjectRow = (yield* owner.read(subject.table, equal(subject.table, { [subject.id]: nativeId }), { limit: 1 })).rows[0];
|
|
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];
|
|
24
|
+
const record = row === void 0 ? null : decodeTotpRecord(row[factor.state]);
|
|
25
|
+
invariant(record === null || (record.secret === null || record.secret.revision === record.revision) && (record.pending === null || record.pending.secret.revision === record.pending.revision));
|
|
26
|
+
invariant(record === null || record.moduleId === mapping.moduleId && record.subjectId === subjectId && record.version === row[factor.version]);
|
|
27
|
+
return {
|
|
28
|
+
nativeId,
|
|
29
|
+
subjectRow,
|
|
30
|
+
factorRow: row,
|
|
31
|
+
factorObservation: found,
|
|
32
|
+
scope,
|
|
33
|
+
snapshot: {
|
|
34
|
+
revision: {
|
|
35
|
+
subjectId,
|
|
36
|
+
securityRevision: SecurityRevision.make(subjectRow[subject.securityRevision]),
|
|
37
|
+
credentials: record === null || record.secret === null ? [] : [{
|
|
38
|
+
credentialId: record.credentialId,
|
|
39
|
+
revision: SecurityRevision.make(record.revision)
|
|
40
|
+
}]
|
|
41
|
+
},
|
|
42
|
+
record
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
const reject = { _tag: "Rejected" };
|
|
47
|
+
const mutateTotp = Effect.fn("TotpNative.mutate")(function* (mapping, input) {
|
|
48
|
+
const owner = yield* CurrentTotpTransaction;
|
|
49
|
+
invariant(input.moduleId === mapping.moduleId && Schema.encodeSync(Schema.fromJsonString(TotpPolicy))(input.policy) === Schema.encodeSync(Schema.fromJsonString(TotpPolicy))(mapping.policy));
|
|
50
|
+
const captured = yield* captureTotp(mapping, input.subjectId);
|
|
51
|
+
if (captured === void 0) return reject;
|
|
52
|
+
const { snapshot, subjectRow, factorRow, factorObservation, scope, nativeId } = captured, current = snapshot.record, policy = input.policy, action = input.action;
|
|
53
|
+
if (snapshot.revision.securityRevision !== input.snapshot.revision.securityRevision || (current?.version ?? null) !== (input.snapshot.record?.version ?? null)) return reject;
|
|
54
|
+
if (current === null !== (input.snapshot.record === null) || current !== null && encodeTotpRecord(current) !== encodeTotpRecord(input.snapshot.record)) return reject;
|
|
55
|
+
const now = yield* owner.now({ engineNowMillis: mapping.engineNowMillis });
|
|
56
|
+
const guards = [];
|
|
57
|
+
const credentialGuards = [];
|
|
58
|
+
const commandScope = digest(`effect-auth/totp/command/v1/${mapping.moduleId.length}:${mapping.moduleId}/${input.subjectId.length}:${input.subjectId}/${input.commandId}`);
|
|
59
|
+
const commandObservation = [
|
|
60
|
+
"Enroll",
|
|
61
|
+
"Confirm",
|
|
62
|
+
"Disable",
|
|
63
|
+
"Regenerate"
|
|
64
|
+
].includes(action._tag) ? yield* owner.read(mapping.factor.table, equal(mapping.factor.table, { [mapping.factor.scope]: commandScope }), { limit: 1 }) : void 0;
|
|
65
|
+
if (commandObservation !== void 0 && commandObservation.rows.length !== 0) return reject;
|
|
66
|
+
const timeGuards = [];
|
|
67
|
+
const timeBound = (start, end) => {
|
|
68
|
+
timeGuards.push(sql`${mapping.engineNowMillis} >= ${start} and ${mapping.engineNowMillis} < ${end}`);
|
|
69
|
+
};
|
|
70
|
+
if (action._tag === "Enroll" || action._tag === "Confirm" || action._tag === "Disable" || action._tag === "Regenerate") {
|
|
71
|
+
const authorization = input.authorization;
|
|
72
|
+
if (authorization === void 0) return reject;
|
|
73
|
+
const { challenge, evidence } = authorization;
|
|
74
|
+
const expectedAction = {
|
|
75
|
+
Enroll: "enroll",
|
|
76
|
+
Confirm: "confirm",
|
|
77
|
+
Disable: "disable",
|
|
78
|
+
Regenerate: "regenerate"
|
|
79
|
+
}[action._tag];
|
|
80
|
+
if (challenge.action !== expectedAction || challenge.moduleId !== mapping.moduleId || challenge.commandId !== input.commandId || challenge.revision.subjectId !== input.subjectId || challenge.revision.securityRevision !== snapshot.revision.securityRevision || evidence.flowId !== challenge.flowId || evidence.bindingDigest !== challenge.bindingDigest || evidence.revision.subjectId !== input.subjectId || evidence.revision.securityRevision !== snapshot.revision.securityRevision) return reject;
|
|
81
|
+
const auth = mapping.credential;
|
|
82
|
+
for (const revision of [...evidence.revision.credentials].sort((a, b) => a.credentialId.localeCompare(b.credentialId))) {
|
|
83
|
+
const row = (yield* owner.read(auth.table, equal(auth.table, {
|
|
84
|
+
[auth.id]: revision.credentialId,
|
|
85
|
+
[auth.subjectId]: nativeId
|
|
86
|
+
}), { limit: 1 })).rows[0];
|
|
87
|
+
if (row === void 0 || row[auth.revision] !== revision.revision) return reject;
|
|
88
|
+
const condition = sql`exists(select 1 from ${auth.table} where ${both(owner.exact(auth.table, row), auth.activeCondition)})`;
|
|
89
|
+
if (!(yield* owner.check(condition))) return reject;
|
|
90
|
+
credentialGuards.push({
|
|
91
|
+
credentialId: revision.credentialId,
|
|
92
|
+
condition
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const eligible = evidence.proofs.filter((proof) => evidence.revision.credentials.some((revision) => revision.credentialId === proof.credentialId));
|
|
96
|
+
if (eligible.length !== evidence.proofs.length || eligible.length === 0) return reject;
|
|
97
|
+
const requirements = [authorization.requirement, Schema.decodeSync(AuthenticationRequirement)(mapping.subject.decodeRequirement(copiedRow(subjectRow)))];
|
|
98
|
+
const maximumAge = Math.min(policy.maximumEvidenceAgeMillis, ...requirements.map((requirement) => requirement.maximumAgeMillis));
|
|
99
|
+
const evidenceFactors = new Set(eligible.flatMap((proof) => proof.factors));
|
|
100
|
+
const evidenceCredentials = new Set(eligible.map((proof) => proof.credentialId));
|
|
101
|
+
for (const requirement of requirements) if (!requirement.alternatives.some((alternative) => alternative.factors.every((factor) => evidenceFactors.has(factor)) && evidenceCredentials.size >= alternative.minimumCredentials && eligible.some((proof) => (!alternative.userVerified || proof.userVerified) && (!alternative.phishingResistant || proof.phishingResistant)))) return reject;
|
|
102
|
+
for (const proof of eligible) {
|
|
103
|
+
const verifiedAt = proof.verifiedAt.epochMilliseconds;
|
|
104
|
+
if (verifiedAt > now || now - verifiedAt >= maximumAge) return reject;
|
|
105
|
+
timeBound(verifiedAt, verifiedAt + maximumAge);
|
|
106
|
+
}
|
|
107
|
+
if (current !== null && current.secret !== null || action._tag === "Disable" || action._tag === "Regenerate") {
|
|
108
|
+
const factors = new Set(eligible.flatMap((proof) => proof.factors));
|
|
109
|
+
if (!(eligible.some((proof) => proof.userVerified && proof.phishingResistant && proof.factors.includes("possession")) || factors.has("knowledge") && factors.has("possession") && new Set(eligible.map((proof) => proof.credentialId)).size >= 2)) return reject;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (action._tag === "Recovery" && action.reset) {
|
|
113
|
+
const target = action.pending;
|
|
114
|
+
if (target === void 0 || mapping.pendingCondition === void 0 || target.revision.subjectId !== input.subjectId || target.revision.securityRevision !== snapshot.revision.securityRevision || target.expiresAtMillis <= now) return reject;
|
|
115
|
+
const condition = mapping.pendingCondition(target, nativeId);
|
|
116
|
+
if (!(yield* owner.check(condition))) return reject;
|
|
117
|
+
guards.push(condition);
|
|
118
|
+
timeBound(0, target.expiresAtMillis);
|
|
119
|
+
}
|
|
120
|
+
let next, semantic = false, accepted = true;
|
|
121
|
+
if (action._tag === "Enroll") {
|
|
122
|
+
const candidate = action.record;
|
|
123
|
+
if (candidate.subjectId !== input.subjectId || candidate.moduleId !== input.moduleId || candidate.pending === null || candidate.pending.expiresAtMillis <= now || candidate.pending.expiresAtMillis > now + policy.enrollmentLifetimeMillis || candidate.pending.failedAttempts !== 0 || candidate.pending.secret.revision !== candidate.pending.revision) return reject;
|
|
124
|
+
if (current !== null && current.pending !== null && current.pending.expiresAtMillis > now) return reject;
|
|
125
|
+
if (current !== null && (candidate.credentialId !== current.credentialId || encodeTotpRecord({
|
|
126
|
+
...candidate,
|
|
127
|
+
pending: current.pending
|
|
128
|
+
}) !== encodeTotpRecord(current))) return reject;
|
|
129
|
+
if (current === null && (candidate.secret !== null || candidate.recoveryDigests.length !== 0 || candidate.acceptedStep !== -1 || candidate.failedAttempts !== 0)) return reject;
|
|
130
|
+
next = candidate;
|
|
131
|
+
timeBound(0, candidate.pending.expiresAtMillis);
|
|
132
|
+
} else {
|
|
133
|
+
if (current === null) return reject;
|
|
134
|
+
next = { ...current };
|
|
135
|
+
if (action._tag === "Confirm") {
|
|
136
|
+
const pending = current.pending;
|
|
137
|
+
if (pending === null || pending.enrollmentId !== action.enrollmentId || pending.expiresAtMillis <= now || pending.failedAttempts >= policy.attemptLimit) return reject;
|
|
138
|
+
timeBound(0, pending.expiresAtMillis);
|
|
139
|
+
if (action.matchedStep === null || Math.abs(Math.floor(now / 3e4) - action.matchedStep) > policy.clockSkewSteps) {
|
|
140
|
+
next = {
|
|
141
|
+
...current,
|
|
142
|
+
pending: {
|
|
143
|
+
...pending,
|
|
144
|
+
failedAttempts: pending.failedAttempts + 1
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
accepted = false;
|
|
148
|
+
} else {
|
|
149
|
+
if (new Set(action.recoveryDigests).size !== 10) return reject;
|
|
150
|
+
next = {
|
|
151
|
+
...current,
|
|
152
|
+
secret: pending.secret,
|
|
153
|
+
revision: pending.secret.revision,
|
|
154
|
+
pending: null,
|
|
155
|
+
recoveryDigests: action.recoveryDigests,
|
|
156
|
+
acceptedStep: action.matchedStep,
|
|
157
|
+
attemptWindow: now,
|
|
158
|
+
failedAttempts: 0
|
|
159
|
+
};
|
|
160
|
+
semantic = true;
|
|
161
|
+
timeBound(Math.max(0, (action.matchedStep - policy.clockSkewSteps) * 3e4), (action.matchedStep + policy.clockSkewSteps + 1) * 3e4);
|
|
162
|
+
}
|
|
163
|
+
} else if (action._tag === "Verify" || action._tag === "Recovery") {
|
|
164
|
+
if (current.secret === null) return reject;
|
|
165
|
+
const expired = now >= current.attemptWindow + policy.attemptWindowMillis, attempts = expired ? 0 : current.failedAttempts, start = expired ? now : current.attemptWindow;
|
|
166
|
+
if (attempts >= policy.attemptLimit) return reject;
|
|
167
|
+
next = {
|
|
168
|
+
...current,
|
|
169
|
+
attemptWindow: start,
|
|
170
|
+
failedAttempts: attempts + 1
|
|
171
|
+
};
|
|
172
|
+
if (action._tag === "Verify") {
|
|
173
|
+
if (action.matchedStep === null || action.matchedStep <= current.acceptedStep || Math.abs(Math.floor(now / 3e4) - action.matchedStep) > policy.clockSkewSteps) accepted = false;
|
|
174
|
+
else {
|
|
175
|
+
next = {
|
|
176
|
+
...next,
|
|
177
|
+
acceptedStep: action.matchedStep,
|
|
178
|
+
failedAttempts: 0
|
|
179
|
+
};
|
|
180
|
+
timeBound(Math.max(0, (action.matchedStep - policy.clockSkewSteps) * 3e4), (action.matchedStep + policy.clockSkewSteps + 1) * 3e4);
|
|
181
|
+
}
|
|
182
|
+
} else if ((action.reset ? policy.lostFactorRecovery !== "reset-with-recovery-code" : !policy.allowRecoveryCodeForPending) || !current.recoveryDigests.includes(action.digest)) accepted = false;
|
|
183
|
+
else {
|
|
184
|
+
next = {
|
|
185
|
+
...next,
|
|
186
|
+
recoveryDigests: current.recoveryDigests.filter((value) => value !== action.digest),
|
|
187
|
+
failedAttempts: 0
|
|
188
|
+
};
|
|
189
|
+
if (action.reset) {
|
|
190
|
+
next = {
|
|
191
|
+
...next,
|
|
192
|
+
secret: null,
|
|
193
|
+
pending: null,
|
|
194
|
+
recoveryDigests: [],
|
|
195
|
+
revision: randomId()
|
|
196
|
+
};
|
|
197
|
+
semantic = true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
if (current.secret === null) return reject;
|
|
202
|
+
semantic = true;
|
|
203
|
+
if (action._tag === "Disable") next = {
|
|
204
|
+
...current,
|
|
205
|
+
secret: null,
|
|
206
|
+
pending: null,
|
|
207
|
+
recoveryDigests: [],
|
|
208
|
+
revision: randomId()
|
|
209
|
+
};
|
|
210
|
+
else {
|
|
211
|
+
if (new Set(action.recoveryDigests).size !== 10) return reject;
|
|
212
|
+
next = {
|
|
213
|
+
...current,
|
|
214
|
+
recoveryDigests: action.recoveryDigests
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
next = {
|
|
220
|
+
...next,
|
|
221
|
+
version: randomId()
|
|
222
|
+
};
|
|
223
|
+
const subject = mapping.subject, factor = mapping.factor, auth = mapping.credential;
|
|
224
|
+
const subjectKey = { [subject.id]: nativeId };
|
|
225
|
+
if (semantic) {
|
|
226
|
+
const revision = randomId(), updates = {
|
|
227
|
+
[subject.securityRevision]: revision,
|
|
228
|
+
[subject.factorEnabled]: subject.encodeEnabled(next.secret !== null)
|
|
229
|
+
};
|
|
230
|
+
yield* owner.update(subject.table, subjectKey, updates);
|
|
231
|
+
const idKey = {
|
|
232
|
+
[auth.id]: next.credentialId,
|
|
233
|
+
[auth.subjectId]: nativeId
|
|
234
|
+
};
|
|
235
|
+
const existing = yield* owner.read(auth.table, equal(auth.table, idKey), { limit: 1 });
|
|
236
|
+
if (existing.rows.length === 0) {
|
|
237
|
+
const values = {
|
|
238
|
+
...auth.encodeInsert({
|
|
239
|
+
credentialId: next.credentialId,
|
|
240
|
+
subjectId: nativeId,
|
|
241
|
+
revision: next.revision,
|
|
242
|
+
active: next.secret !== null
|
|
243
|
+
}),
|
|
244
|
+
[auth.id]: next.credentialId,
|
|
245
|
+
[auth.subjectId]: nativeId,
|
|
246
|
+
[auth.revision]: next.revision,
|
|
247
|
+
[auth.status]: auth.encodeStatus(next.secret !== null)
|
|
248
|
+
};
|
|
249
|
+
existing.rows = (yield* owner.insert(auth.table, values, { [auth.id]: next.credentialId })).rows;
|
|
250
|
+
} else yield* owner.update(auth.table, idKey, {
|
|
251
|
+
[auth.revision]: next.revision,
|
|
252
|
+
[auth.status]: auth.encodeStatus(next.secret !== null)
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
const state = encodeTotpRecord(next), values = {
|
|
256
|
+
[factor.state]: state,
|
|
257
|
+
[factor.version]: next.version
|
|
258
|
+
};
|
|
259
|
+
if (factorRow === void 0) {
|
|
260
|
+
const insert = factor.encodeInsert({
|
|
261
|
+
scope,
|
|
262
|
+
state,
|
|
263
|
+
version: next.version
|
|
264
|
+
});
|
|
265
|
+
invariant(insert[factor.scope] === scope && insert[factor.state] === state && insert[factor.version] === next.version);
|
|
266
|
+
factorObservation.rows = (yield* owner.insert(factor.table, insert, { [factor.scope]: scope })).rows;
|
|
267
|
+
} else yield* owner.update(factor.table, { [factor.scope]: scope }, values);
|
|
268
|
+
if (commandObservation !== void 0) {
|
|
269
|
+
const values = factor.encodeInsert({
|
|
270
|
+
scope: commandScope,
|
|
271
|
+
state: "totp-command/v1",
|
|
272
|
+
version: randomId()
|
|
273
|
+
});
|
|
274
|
+
invariant(values[factor.scope] === commandScope && values[factor.state] === "totp-command/v1");
|
|
275
|
+
commandObservation.rows = (yield* owner.insert(factor.table, values, { [factor.scope]: commandScope })).rows;
|
|
276
|
+
}
|
|
277
|
+
guards.push(sql`exists(select 1 from ${subject.table} where ${both(equal(subject.table, subjectKey), subject.activeCondition)})`);
|
|
278
|
+
owner.postconditions.push(...guards, ...timeGuards, ...credentialGuards.filter((guard) => !semantic || guard.credentialId !== next.credentialId).map((guard) => guard.condition));
|
|
279
|
+
return accepted ? {
|
|
280
|
+
_tag: "Accepted",
|
|
281
|
+
record: next
|
|
282
|
+
} : reject;
|
|
283
|
+
});
|
|
284
|
+
//#endregion
|
|
285
|
+
export { CurrentTotpTransaction, captureTotp, copiedRow, decodeTotpRecord, encodeTotpRecord, equal, invariant, mutateTotp, unavailable };
|
|
286
|
+
|
|
287
|
+
//# sourceMappingURL=totp-state.mjs.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PersistenceMappingError } from "./model.mjs";
|
|
2
|
+
import "./transaction-owner.mjs";
|
|
3
|
+
import { TransactionCoordinatorError } from "./transaction-execution.mjs";
|
|
4
|
+
import "./totp-model.mjs";
|
|
5
|
+
import "./SuppliedService.mjs";
|
|
6
|
+
import { Table } from "drizzle-orm";
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
9
|
+
import { TotpConfigurationError, TotpPersistence, TotpUnavailable } from "@yielded/auth/Totp";
|
|
10
|
+
import { Statement } from "effect/unstable/sql/Statement";
|
|
11
|
+
//#region src/drizzle/totp-target.d.ts
|
|
12
|
+
export type TotpCoordinatorError<E> = TransactionCoordinatorError<E, TotpUnavailable> | TotpConfigurationError | PersistenceMappingError;
|
|
13
|
+
//#endregion
|
|
14
|
+
//# sourceMappingURL=totp-target.d.mts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { coordinateTransactionOwner, makeTransactionExecution, sqlClientTransactionStandaloneGuard } from "./transaction-execution.mjs";
|
|
2
|
+
import { requiredTotpConstraints } from "./totp-model.mjs";
|
|
3
|
+
import { CurrentTotpTransaction, captureTotp, invariant, mutateTotp, unavailable } from "./totp-state.mjs";
|
|
4
|
+
import { Context, Effect, Schema } from "effect";
|
|
5
|
+
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
6
|
+
import { TotpConfigurationError, TotpMutation, TotpPersistence, TotpPolicy } from "@yielded/auth/Totp";
|
|
7
|
+
import { randomId } from "@yielded/auth-crypto";
|
|
8
|
+
//#region src/drizzle/totp-target.ts
|
|
9
|
+
const sqlClientTotpStandaloneGuard = (database) => sqlClientTransactionStandaloneGuard(unavailable, database);
|
|
10
|
+
const validateMapping = (original, configuration) => {
|
|
11
|
+
const mapping = original;
|
|
12
|
+
invariant(mapping.moduleId.length > 0);
|
|
13
|
+
Schema.decodeSync(TotpPolicy)(mapping.policy);
|
|
14
|
+
for (const [key, value] of Object.entries(requiredTotpConstraints)) invariant(mapping.constraints?.[key] === value);
|
|
15
|
+
if (configuration.mode === "batch") invariant(mapping.d1?.primary === true);
|
|
16
|
+
return Object.freeze({
|
|
17
|
+
...mapping,
|
|
18
|
+
policy: Object.freeze({ ...mapping.policy }),
|
|
19
|
+
subject: Object.freeze({ ...mapping.subject }),
|
|
20
|
+
factor: Object.freeze({ ...mapping.factor }),
|
|
21
|
+
credential: Object.freeze({ ...mapping.credential }),
|
|
22
|
+
subjectIds: Object.freeze({ ...mapping.subjectIds })
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const services = (mapping, execution, hooks) => ({ totpPersistence: TotpPersistence.of({
|
|
26
|
+
snapshot: Effect.fn("TotpNative.snapshot")(function* (input) {
|
|
27
|
+
const captured = { ...input };
|
|
28
|
+
invariant(captured.moduleId === mapping.moduleId);
|
|
29
|
+
yield* execution.admit;
|
|
30
|
+
return yield* execution.run(Effect.map(captureTotp(mapping, captured.subjectId), (value) => value?.snapshot), false).pipe(Effect.provideService(LifecycleHooks, hooks));
|
|
31
|
+
}, Effect.catchDefect(() => Effect.fail(unavailable()))),
|
|
32
|
+
mutate: (original, prepare) => Effect.suspend(() => {
|
|
33
|
+
const codec = Schema.toCodecIso(TotpMutation);
|
|
34
|
+
const input = Schema.decodeSync(codec)(Schema.encodeSync(codec)(original));
|
|
35
|
+
return execution.admit.pipe(Effect.andThen(execution.run(Effect.gen(function* () {
|
|
36
|
+
const decision = yield* mutateTotp(mapping, input), owner = yield* CurrentTotpTransaction;
|
|
37
|
+
owner.guards.push(owner.journal.prepare(void 0));
|
|
38
|
+
const receipt = prepare(decision, owner.journal);
|
|
39
|
+
invariant(receipt?._tag === "PreparedCommit" && Effect.isEffect(receipt.read));
|
|
40
|
+
owner.guards.push(receipt);
|
|
41
|
+
return receipt;
|
|
42
|
+
}))), Effect.provideService(LifecycleHooks, hooks));
|
|
43
|
+
}).pipe(Effect.catchDefect(() => Effect.fail(unavailable())))
|
|
44
|
+
}) });
|
|
45
|
+
const makeTargetTotpPersistence = (database, source, configuration) => Effect.gen(function* () {
|
|
46
|
+
const hooks = yield* LifecycleHooks;
|
|
47
|
+
const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);
|
|
48
|
+
const mapping = yield* Effect.try({
|
|
49
|
+
try: () => validateMapping(original, configuration),
|
|
50
|
+
catch: () => TotpConfigurationError.make({})
|
|
51
|
+
});
|
|
52
|
+
const execution = makeTransactionExecution(CurrentTotpTransaction, database, configuration, unavailable, randomId);
|
|
53
|
+
return services(mapping, execution, hooks);
|
|
54
|
+
});
|
|
55
|
+
const coordinateTargetTotp = (database, source, configuration, body) => Effect.gen(function* () {
|
|
56
|
+
const hooks = yield* LifecycleHooks;
|
|
57
|
+
const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);
|
|
58
|
+
const mapping = yield* Effect.try({
|
|
59
|
+
try: () => validateMapping(original, configuration),
|
|
60
|
+
catch: () => TotpConfigurationError.make({})
|
|
61
|
+
});
|
|
62
|
+
return yield* coordinateTransactionOwner(database, CurrentTotpTransaction, configuration, Effect.void, unavailable, randomId, (execution) => services(mapping, execution, hooks), body);
|
|
63
|
+
});
|
|
64
|
+
/** Concrete driver wrappers select transaction mode; cryptography always precedes these owners. */
|
|
65
|
+
const makeTotpTarget = (configuration) => {
|
|
66
|
+
function coordinateTotpPersistence(acquire, options, body) {
|
|
67
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetTotp(database, options.mapping, configuration, (transaction, services) => {
|
|
68
|
+
const provided = Context.make(TotpPersistence, services.totpPersistence);
|
|
69
|
+
const work = Effect.provideContext(body, provided);
|
|
70
|
+
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
makeTotpPersistenceServices: (database, mapping) => makeTargetTotpPersistence(database, mapping, configuration),
|
|
75
|
+
coordinateTotpPersistence
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
export { coordinateTargetTotp, makeTargetTotpPersistence, makeTotpTarget, sqlClientTotpStandaloneGuard };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=totp-target.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"totp-target.mjs","names":[],"sources":["../../src/drizzle/totp-target.ts"],"sourcesContent":["import { randomId } from \"@yielded/auth-crypto\";\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/unstable/sql/Statement\";\n\nimport type { PersistenceMappingError } from \"./model\";\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 database: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],\n) => sqlClientTransactionStandaloneGuard(unavailable, database);\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 = (\n mapping: any,\n execution: TransactionExecution<TotpUnavailable, CurrentTotpTransaction>,\n hooks: LifecycleHooks[\"Service\"],\n): TotpPersistenceServices => ({\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\nexport const makeTargetTotpPersistence = <\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n RSetup = never,\n>(\n database: TransactionNativeDatabase,\n source: TotpMappingSource<TotpMapping<S, F, C, N>, RSetup>,\n configuration: TotpTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const hooks = yield* LifecycleHooks;\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 const execution = makeTransactionExecution(\n CurrentTotpTransaction,\n database,\n configuration,\n unavailable,\n randomId,\n );\n\n return services(mapping, execution, hooks);\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> =>\n Effect.gen(function* () {\n const hooks = yield* LifecycleHooks;\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 return yield* coordinateTransactionOwner(\n database,\n CurrentTotpTransaction,\n configuration,\n Effect.void,\n unavailable,\n randomId,\n (execution) => services(mapping, execution, hooks),\n body,\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 D extends { readonly transaction: any },\n T extends Table,\n Extra = unknown,\n Synchronous extends boolean = false,\n>(\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(acquire, (database) =>\n coordinateTargetTotp(\n database as any,\n options.mapping,\n configuration,\n (transaction: TransactionOf<Database>, services) => {\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 ),\n );\n }\n\n return {\n makeTotpPersistenceServices: <\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n RSetup = never,\n >(\n database: Database,\n mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>,\n ) => makeTargetTotpPersistence(database as any, mapping, configuration),\n coordinateTotpPersistence,\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { makeTransactionOwner, reportTransactionFailure } from "./transaction-owner.mjs";
|
|
2
|
+
import { makeTransactionExecutionKernel } from "@yielded/auth-persistence/Adapter";
|
|
3
|
+
//#region src/drizzle/transaction-execution.ts
|
|
4
|
+
const { sqlClientTransactionStandaloneGuard, makeTransactionExecution, coordinateTransactionOwner } = makeTransactionExecutionKernel({
|
|
5
|
+
makeTransactionOwner,
|
|
6
|
+
reportTransactionFailure
|
|
7
|
+
});
|
|
8
|
+
//#endregion
|
|
9
|
+
export { coordinateTransactionOwner, makeTransactionExecution, sqlClientTransactionStandaloneGuard };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=transaction-execution.mjs.map
|