@yielded/auth-persistence 0.1.0-beta.7 → 0.1.0-beta.9
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 +9 -0
- package/dist/DrizzleD1.d.mts +9 -9
- package/dist/DrizzleLibsql.d.mts +25 -25
- package/dist/DrizzleLibsql.mjs +7 -22
- package/dist/DrizzleLibsql.mjs.map +1 -1
- package/dist/DrizzleMysql2.d.mts +15 -15
- package/dist/DrizzlePglite.d.mts +9 -9
- package/dist/DrizzlePostgres.d.mts +15 -15
- package/dist/DrizzleSqliteBun.d.mts +18 -18
- package/dist/DrizzleSqliteDo.d.mts +29 -29
- package/dist/DrizzleSqliteNode.d.mts +24 -24
- package/dist/DrizzleSqliteWasm.d.mts +24 -24
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/drizzle/D1BatchStatements.d.mts +1 -2
- package/dist/drizzle/SuppliedService.d.mts +1 -2
- package/dist/drizzle/d1-emails.d.mts +5 -6
- package/dist/drizzle/d1-identity.d.mts +2 -3
- package/dist/drizzle/d1-oauth.d.mts +10 -11
- package/dist/drizzle/d1-passkey.d.mts +5 -6
- package/dist/drizzle/d1-password-prepared.d.mts +2 -3
- package/dist/drizzle/d1-passwords.d.mts +4 -5
- package/dist/drizzle/d1-phone.d.mts +2 -3
- package/dist/drizzle/d1-planning.d.mts +1 -2
- package/dist/drizzle/d1-proofs.d.mts +2 -3
- package/dist/drizzle/d1-sessions.d.mts +10 -11
- package/dist/drizzle/d1-totp.d.mts +2 -3
- package/dist/drizzle/email-model.d.mts +30 -31
- package/dist/drizzle/email-registration.d.mts +1 -2
- package/dist/drizzle/email-target.d.mts +3 -4
- package/dist/drizzle/model.d.mts +42 -42
- package/dist/drizzle/model.mjs +4 -6
- package/dist/drizzle/model.mjs.map +1 -1
- package/dist/drizzle/mysql-emails.d.mts +7 -8
- package/dist/drizzle/mysql-identity.d.mts +2 -3
- package/dist/drizzle/mysql-password-prepared.d.mts +3 -4
- package/dist/drizzle/mysql-passwords.d.mts +6 -7
- package/dist/drizzle/mysql-proofs.d.mts +3 -4
- package/dist/drizzle/mysql-sessions.d.mts +15 -16
- package/dist/drizzle/mysql.d.mts +9 -10
- package/dist/drizzle/mysql.mjs +1 -1
- package/dist/drizzle/oauth-connected-model.d.mts +21 -22
- package/dist/drizzle/oauth-connected-reference.d.mts +1 -2
- package/dist/drizzle/oauth-connected-state.d.mts +1950 -7
- package/dist/drizzle/oauth-connected-target.d.mts +9 -10
- package/dist/drizzle/oauth-flow.d.mts +22 -2
- package/dist/drizzle/oauth-model.d.mts +45 -46
- package/dist/drizzle/oauth-owner.d.mts +10 -2
- package/dist/drizzle/oauth-target.d.mts +9 -10
- package/dist/drizzle/passkey-model.d.mts +34 -35
- package/dist/drizzle/passkey-registration-ceremony-model.d.mts +5 -6
- package/dist/drizzle/passkey-write-model.d.mts +13 -14
- package/dist/drizzle/password-model.d.mts +29 -30
- package/dist/drizzle/password-prepared-model.d.mts +10 -11
- package/dist/drizzle/password-prepared-target.d.mts +1 -2
- package/dist/drizzle/password-registration.d.mts +1 -2
- package/dist/drizzle/password-target.d.mts +2 -3
- package/dist/drizzle/pg-emails.d.mts +7 -8
- package/dist/drizzle/pg-password-prepared.d.mts +3 -4
- package/dist/drizzle/pg-passwords.d.mts +6 -7
- package/dist/drizzle/pg-proofs.d.mts +3 -4
- package/dist/drizzle/pg-sessions.d.mts +15 -16
- package/dist/drizzle/pg.d.mts +11 -12
- package/dist/drizzle/pg.mjs +1 -1
- package/dist/drizzle/phone-model.d.mts +9 -10
- package/dist/drizzle/phone-target.d.mts +1 -2
- package/dist/drizzle/proof-model.d.mts +25 -26
- package/dist/drizzle/proof-target.d.mts +1 -2
- package/dist/drizzle/session-model.d.mts +25 -26
- package/dist/drizzle/session-target.d.mts +4 -5
- package/dist/drizzle/sqlite.d.mts +9 -10
- package/dist/drizzle/sqlite.mjs +1 -1
- package/dist/drizzle/standalone-guard.mjs +3 -5
- package/dist/drizzle/standalone-guard.mjs.map +1 -1
- package/dist/drizzle/step-up-model.d.mts +6 -7
- package/dist/drizzle/totp-model.d.mts +7 -8
- package/dist/drizzle/totp-state.d.mts +2 -3
- package/dist/drizzle/totp-target.d.mts +1 -2
- package/dist/drizzle/transaction-mysql.mjs +1 -0
- package/dist/drizzle/transaction-mysql.mjs.map +1 -1
- package/dist/drizzle/transaction-owner.d.mts +3 -2
- package/dist/index.d.mts +3 -1
- package/dist/index.mjs +3 -1
- package/dist/internal/configuration.d.mts +19 -19
- package/dist/internal/mapping-error.d.mts +2 -3
- package/dist/internal/oauth-app.d.mts +11 -0
- package/dist/internal/oauth-app.mjs +57 -0
- package/dist/internal/oauth-app.mjs.map +1 -0
- package/dist/internal/oauth-server.d.mts +10 -0
- package/dist/internal/oauth-server.mjs +66 -0
- package/dist/internal/oauth-server.mjs.map +1 -0
- package/dist/internal/passkey/target.d.mts +2 -3
- package/dist/internal/passkeys.mjs +2 -1
- package/dist/internal/passkeys.mjs.map +1 -1
- package/dist/internal/persistence.mjs +3 -2
- package/dist/internal/persistence.mjs.map +1 -1
- package/dist/internal/sql-persistence.d.mts +1 -2
- package/dist/internal/sql-table.d.mts +6 -7
- package/dist/internal/sql-table.mjs +12 -2
- package/dist/internal/sql-table.mjs.map +1 -1
- package/dist/internal/standalone.mjs +13 -0
- package/dist/internal/standalone.mjs.map +1 -0
- package/dist/internal/storage-tables.d.mts +5 -6
- package/dist/internal/transaction-execution-kernel.d.mts +2 -3
- package/dist/internal/transaction-execution-kernel.mjs +3 -5
- package/dist/internal/transaction-execution-kernel.mjs.map +1 -1
- package/dist/internal/transaction-kernel.d.mts +49 -2
- package/package.json +1 -1
- package/src/DrizzleLibsql.ts +10 -54
- package/src/drizzle/model.ts +8 -10
- package/src/drizzle/standalone-guard.ts +4 -9
- package/src/drizzle/transaction-mysql.ts +2 -0
- package/src/index.ts +2 -0
- package/src/internal/oauth-app.ts +82 -0
- package/src/internal/oauth-server.ts +89 -0
- package/src/internal/passkeys.ts +2 -6
- package/src/internal/persistence.ts +3 -5
- package/src/internal/sql-table.ts +17 -2
- package/src/internal/standalone.ts +30 -0
- package/src/internal/transaction-execution-kernel.ts +3 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-mysql.mjs","names":[],"sources":["../../src/drizzle/transaction-mysql.ts"],"sourcesContent":["/* oxlint-disable no-explicit-any -- this private acquisition preserves the installed native transaction; public wrappers retain its exact type. */\nimport { EffectMysql2Transaction } from \"drizzle-orm/effect-mysql2\";\nimport { Effect } from \"effect\";\nimport { makeWithTransaction, type SqlClient } from \"effect/unstable/sql/SqlClient\";\n\n/** Locking discovery and later SQL policy predicates must see the same current\n * authority. MySQL's default repeatable-read snapshot is unsuitable after a\n * contended authority lock. Own one connection and one-shot transaction mode;\n * the pooled connection's session default is never changed. */\nexport const mysqlTransaction = <A, E, R, Failure>(\n unavailable: () => Failure,\n database: any,\n body: (transaction: any) => Effect.Effect<A, E, R>,\n) =>\n Effect.scoped(\n Effect.gen(function* () {\n const client: SqlClient = database.$client;\n const connection = yield* client.reserve;\n\n // Installed @effect/sql-mysql2 ConnectionImpl exposes its reserved native\n // PoolConnection as `conn`. Capture only its public disposal method; fail\n // before transaction work if an installed driver no longer provides it.\n const nativeConnection = (\n connection as {\n readonly conn?: { readonly destroy?: () => void; readonly release?: () => void };\n }\n ).conn;\n\n if (\n typeof nativeConnection?.destroy !== \"function\" ||\n typeof nativeConnection.release !== \"function\"\n )\n return yield* Effect.fail(unavailable());\n const destroy = nativeConnection.destroy.bind(nativeConnection);\n\n const defaults = yield* connection.executeUnprepared(\n \"select @@session.transaction_isolation as isolation\",\n [],\n undefined,\n );\n\n const isolation = String(defaults[0]?.isolation).replaceAll(\"-\", \" \").toUpperCase();\n\n if (\n ![\"READ UNCOMMITTED\", \"READ COMMITTED\", \"REPEATABLE READ\", \"SERIALIZABLE\"].includes(\n isolation,\n )\n )\n return yield* Effect.fail(unavailable());\n\n const statement = (source: string) =>\n Effect.asVoid(connection.executeUnprepared(source, [], undefined));\n\n const transaction = makeWithTransaction({\n transactionService: client.transactionService,\n spanAttributes: [\n [\"db.system\", \"mysql\"],\n [\"effect_auth.owner\", \"oauth\"],\n ],\n acquireConnection: Effect.succeed([undefined, connection] as const),\n begin: () =>\n statement(\"SET TRANSACTION ISOLATION LEVEL READ COMMITTED\").pipe(\n Effect.andThen(statement(\"BEGIN\")),\n ),\n commit: () => statement(\"COMMIT\"),\n rollback: () => statement(\"ROLLBACK\"),\n savepoint: (_connection, id) => statement(`SAVEPOINT effect_auth_oauth_${id}`),\n rollbackSavepoint: (_connection, id) =>\n statement(`ROLLBACK TO SAVEPOINT effect_auth_oauth_${id}`),\n });\n\n class NativeTransaction extends EffectMysql2Transaction<any, any> {\n override transaction<A2, E2, R2>(nested: (tx: any) => Effect.Effect<A2, E2, R2>) {\n return transaction(\n Effect.suspend(() =>\n nested(\n new NativeTransaction(database.dialect, database._.session, database._.relations),\n ),\n ),\n );\n }\n }\n\n const native = new NativeTransaction(\n database.dialect,\n database._.session,\n database._.relations,\n );\n\n const cleanup = statement(\"ROLLBACK\").pipe(\n Effect.andThen(statement(`SET TRANSACTION ISOLATION LEVEL ${isolation}`)),\n Effect.onExit((exit) => (exit._tag === \"Failure\" ? Effect.sync(destroy) : Effect.void)),\n Effect.orDie,\n );\n\n return yield* transaction(Effect.suspend(() => body(native))).pipe(\n // BEGIN/COMMIT acknowledgments can be lost after the server acted.\n // Roll back any surviving transaction before resetting one-shot mode.\n // Failed cleanup destroys the connection before its reserve is released;\n // the unknown owner result cannot release a prepared receipt.\n Effect.ensuring(cleanup),\n );\n }),\n );\n"],"mappings":";;;;;;;;AASA,MAAa,oBACX,aACA,UACA,SAEA,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,SAAoB,SAAS;CACnC,MAAM,aAAa,OAAO,OAAO;CAKjC,MAAM,mBACJ,WAGA;CAEF,IACE,OAAO,kBAAkB,YAAY,cACrC,OAAO,iBAAiB,YAAY,YAEpC,OAAO,OAAO,OAAO,KAAK,YAAY,CAAC;CACzC,MAAM,UAAU,iBAAiB,QAAQ,KAAK,gBAAgB;CAE9D,MAAM,WAAW,OAAO,WAAW,kBACjC,uDACA,CAAC,GACD,KAAA,CACF;CAEA,MAAM,YAAY,OAAO,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC,YAAY;CAElF,IACE,CAAC;EAAC;EAAoB;EAAkB;EAAmB;CAAc,CAAC,CAAC,SACzE,SACF,GAEA,OAAO,OAAO,OAAO,KAAK,YAAY,CAAC;CAEzC,MAAM,aAAa,WACjB,OAAO,OAAO,WAAW,kBAAkB,QAAQ,CAAC,GAAG,KAAA,CAAS,CAAC;CAEnE,MAAM,cAAc,oBAAoB;EACtC,oBAAoB,OAAO;EAC3B,gBAAgB,CACd,CAAC,aAAa,OAAO,GACrB,CAAC,qBAAqB,OAAO,CAC/B;EACA,mBAAmB,OAAO,QAAQ,CAAC,KAAA,GAAW,UAAU,CAAU;EAClE,aACE,UAAU,gDAAgD,CAAC,CAAC,KAC1D,OAAO,QAAQ,UAAU,OAAO,CAAC,CACnC;EACF,cAAc,UAAU,QAAQ;EAChC,gBAAgB,UAAU,UAAU;EACpC,YAAY,aAAa,OAAO,UAAU,+BAA+B,IAAI;EAC7E,oBAAoB,aAAa,OAC/B,UAAU,2CAA2C,IAAI;CAC7D,CAAC;CAED,MAAM,0BAA0B,wBAAkC;EAChE,YAAiC,QAAgD;GAC/E,OAAO,YACL,OAAO,cACL,OACE,IAAI,kBAAkB,SAAS,SAAS,SAAS,EAAE,SAAS,SAAS,EAAE,SAAS,CAClF,CACF,CACF;EACF;CACF;CAEA,MAAM,SAAS,IAAI,kBACjB,SAAS,SACT,SAAS,EAAE,SACX,SAAS,EAAE,SACb;CAEA,MAAM,UAAU,UAAU,UAAU,CAAC,CAAC,KACpC,OAAO,QAAQ,UAAU,mCAAmC,WAAW,CAAC,GACxE,OAAO,QAAQ,SAAU,KAAK,SAAS,YAAY,OAAO,KAAK,OAAO,IAAI,OAAO,IAAK,GACtF,OAAO,KACT;CAEA,OAAO,OAAO,YAAY,OAAO,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAK5D,OAAO,SAAS,OAAO,CACzB;AACF,CAAC,CACH"}
|
|
1
|
+
{"version":3,"file":"transaction-mysql.mjs","names":[],"sources":["../../src/drizzle/transaction-mysql.ts"],"sourcesContent":["/* oxlint-disable no-explicit-any -- this private acquisition preserves the installed native transaction; public wrappers retain its exact type. */\nimport { EffectMysql2Transaction } from \"drizzle-orm/effect-mysql2\";\nimport { Effect } from \"effect\";\nimport { makeWithTransaction, type SqlClient } from \"effect/unstable/sql/SqlClient\";\n\n/** Locking discovery and later SQL policy predicates must see the same current\n * authority. MySQL's default repeatable-read snapshot is unsuitable after a\n * contended authority lock. Own one connection and one-shot transaction mode;\n * the pooled connection's session default is never changed. */\nexport const mysqlTransaction = <A, E, R, Failure>(\n unavailable: () => Failure,\n database: any,\n body: (transaction: any) => Effect.Effect<A, E, R>,\n) =>\n Effect.scoped(\n Effect.gen(function* () {\n const client: SqlClient = database.$client;\n const connection = yield* client.reserve;\n\n // Installed @effect/sql-mysql2 ConnectionImpl exposes its reserved native\n // PoolConnection as `conn`. Capture only its public disposal method; fail\n // before transaction work if an installed driver no longer provides it.\n const nativeConnection = (\n connection as {\n readonly conn?: { readonly destroy?: () => void; readonly release?: () => void };\n }\n ).conn;\n\n if (\n typeof nativeConnection?.destroy !== \"function\" ||\n typeof nativeConnection.release !== \"function\"\n )\n return yield* Effect.fail(unavailable());\n const destroy = nativeConnection.destroy.bind(nativeConnection);\n\n const defaults = yield* connection.executeUnprepared(\n \"select @@session.transaction_isolation as isolation\",\n [],\n undefined,\n );\n\n const isolation = String(defaults[0]?.isolation).replaceAll(\"-\", \" \").toUpperCase();\n\n if (\n ![\"READ UNCOMMITTED\", \"READ COMMITTED\", \"REPEATABLE READ\", \"SERIALIZABLE\"].includes(\n isolation,\n )\n )\n return yield* Effect.fail(unavailable());\n\n const statement = (source: string) =>\n Effect.asVoid(connection.executeUnprepared(source, [], undefined));\n\n const transaction = makeWithTransaction({\n transactionService: client.transactionService,\n spanAttributes: [\n [\"db.system\", \"mysql\"],\n [\"effect_auth.owner\", \"oauth\"],\n ],\n acquireConnection: Effect.succeed([undefined, connection] as const),\n begin: () =>\n statement(\"SET TRANSACTION ISOLATION LEVEL READ COMMITTED\").pipe(\n Effect.andThen(statement(\"BEGIN\")),\n ),\n commit: () => statement(\"COMMIT\"),\n rollback: () => statement(\"ROLLBACK\"),\n savepoint: (_connection, id) => statement(`SAVEPOINT effect_auth_oauth_${id}`),\n releaseSavepoint: (_connection, id) =>\n statement(`RELEASE SAVEPOINT effect_auth_oauth_${id}`),\n rollbackSavepoint: (_connection, id) =>\n statement(`ROLLBACK TO SAVEPOINT effect_auth_oauth_${id}`),\n });\n\n class NativeTransaction extends EffectMysql2Transaction<any, any> {\n override transaction<A2, E2, R2>(nested: (tx: any) => Effect.Effect<A2, E2, R2>) {\n return transaction(\n Effect.suspend(() =>\n nested(\n new NativeTransaction(database.dialect, database._.session, database._.relations),\n ),\n ),\n );\n }\n }\n\n const native = new NativeTransaction(\n database.dialect,\n database._.session,\n database._.relations,\n );\n\n const cleanup = statement(\"ROLLBACK\").pipe(\n Effect.andThen(statement(`SET TRANSACTION ISOLATION LEVEL ${isolation}`)),\n Effect.onExit((exit) => (exit._tag === \"Failure\" ? Effect.sync(destroy) : Effect.void)),\n Effect.orDie,\n );\n\n return yield* transaction(Effect.suspend(() => body(native))).pipe(\n // BEGIN/COMMIT acknowledgments can be lost after the server acted.\n // Roll back any surviving transaction before resetting one-shot mode.\n // Failed cleanup destroys the connection before its reserve is released;\n // the unknown owner result cannot release a prepared receipt.\n Effect.ensuring(cleanup),\n );\n }),\n );\n"],"mappings":";;;;;;;;AASA,MAAa,oBACX,aACA,UACA,SAEA,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,SAAoB,SAAS;CACnC,MAAM,aAAa,OAAO,OAAO;CAKjC,MAAM,mBACJ,WAGA;CAEF,IACE,OAAO,kBAAkB,YAAY,cACrC,OAAO,iBAAiB,YAAY,YAEpC,OAAO,OAAO,OAAO,KAAK,YAAY,CAAC;CACzC,MAAM,UAAU,iBAAiB,QAAQ,KAAK,gBAAgB;CAE9D,MAAM,WAAW,OAAO,WAAW,kBACjC,uDACA,CAAC,GACD,KAAA,CACF;CAEA,MAAM,YAAY,OAAO,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC,YAAY;CAElF,IACE,CAAC;EAAC;EAAoB;EAAkB;EAAmB;CAAc,CAAC,CAAC,SACzE,SACF,GAEA,OAAO,OAAO,OAAO,KAAK,YAAY,CAAC;CAEzC,MAAM,aAAa,WACjB,OAAO,OAAO,WAAW,kBAAkB,QAAQ,CAAC,GAAG,KAAA,CAAS,CAAC;CAEnE,MAAM,cAAc,oBAAoB;EACtC,oBAAoB,OAAO;EAC3B,gBAAgB,CACd,CAAC,aAAa,OAAO,GACrB,CAAC,qBAAqB,OAAO,CAC/B;EACA,mBAAmB,OAAO,QAAQ,CAAC,KAAA,GAAW,UAAU,CAAU;EAClE,aACE,UAAU,gDAAgD,CAAC,CAAC,KAC1D,OAAO,QAAQ,UAAU,OAAO,CAAC,CACnC;EACF,cAAc,UAAU,QAAQ;EAChC,gBAAgB,UAAU,UAAU;EACpC,YAAY,aAAa,OAAO,UAAU,+BAA+B,IAAI;EAC7E,mBAAmB,aAAa,OAC9B,UAAU,uCAAuC,IAAI;EACvD,oBAAoB,aAAa,OAC/B,UAAU,2CAA2C,IAAI;CAC7D,CAAC;CAED,MAAM,0BAA0B,wBAAkC;EAChE,YAAiC,QAAgD;GAC/E,OAAO,YACL,OAAO,cACL,OACE,IAAI,kBAAkB,SAAS,SAAS,SAAS,EAAE,SAAS,SAAS,EAAE,SAAS,CAClF,CACF,CACF;EACF;CACF;CAEA,MAAM,SAAS,IAAI,kBACjB,SAAS,SACT,SAAS,EAAE,SACX,SAAS,EAAE,SACb;CAEA,MAAM,UAAU,UAAU,UAAU,CAAC,CAAC,KACpC,OAAO,QAAQ,UAAU,mCAAmC,WAAW,CAAC,GACxE,OAAO,QAAQ,SAAU,KAAK,SAAS,YAAY,OAAO,KAAK,OAAO,IAAI,OAAO,IAAK,GACtF,OAAO,KACT;CAEA,OAAO,OAAO,YAAY,OAAO,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAK5D,OAAO,SAAS,OAAO,CACzB;AACF,CAAC,CACH"}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import "../internal/transaction-kernel.mjs";
|
|
2
|
-
import "./transaction-owner.mjs";
|
|
1
|
+
import { GuardedUpdate, Observation, Row, TransactionOwner } from "../internal/transaction-kernel.mjs";
|
|
2
|
+
import "./transaction-owner.mjs";
|
|
3
|
+
export type { Row, TransactionOwner };
|
package/dist/index.d.mts
CHANGED
|
@@ -2,4 +2,6 @@ import { PersistenceMappingError } from "./internal/mapping-error.mjs";
|
|
|
2
2
|
import { StorageColumn, StorageTable } from "./internal/storage-tables.mjs";
|
|
3
3
|
import { PersistenceConfigurationError } from "./internal/configuration.mjs";
|
|
4
4
|
import { AuthPersistence } from "./internal/sql-persistence.mjs";
|
|
5
|
-
|
|
5
|
+
import { OAuthAppPersistence } from "./internal/oauth-app.mjs";
|
|
6
|
+
import { OAuthServerPersistence } from "./internal/oauth-server.mjs";
|
|
7
|
+
export { AuthPersistence, OAuthAppPersistence, OAuthServerPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
|
package/dist/index.mjs
CHANGED
|
@@ -2,4 +2,6 @@ import { PersistenceConfigurationError } from "./internal/configuration.mjs";
|
|
|
2
2
|
import { PersistenceMappingError } from "./internal/mapping-error.mjs";
|
|
3
3
|
import { StorageColumn, StorageTable } from "./internal/storage-tables.mjs";
|
|
4
4
|
import { AuthPersistence } from "./internal/sql-persistence.mjs";
|
|
5
|
-
|
|
5
|
+
import { OAuthAppPersistence } from "./internal/oauth-app.mjs";
|
|
6
|
+
import { OAuthServerPersistence } from "./internal/oauth-server.mjs";
|
|
7
|
+
export { AuthPersistence, OAuthAppPersistence, OAuthServerPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
|
|
@@ -14,16 +14,16 @@ import { LoginIdentifier } from "@yielded/auth/Identity";
|
|
|
14
14
|
declare const PersistenceConfigurationError_base: Schema.Class<PersistenceConfigurationError, Schema.TaggedStruct<"PersistenceConfigurationError", {
|
|
15
15
|
readonly reason: Schema.String;
|
|
16
16
|
}>, import("effect/Cause").YieldableError>;
|
|
17
|
-
declare class PersistenceConfigurationError extends PersistenceConfigurationError_base {}
|
|
18
|
-
type ClaimsCodec = Schema.Codec<unknown, unknown, never, never>;
|
|
19
|
-
interface PasskeyFeature {
|
|
17
|
+
export declare class PersistenceConfigurationError extends PersistenceConfigurationError_base {}
|
|
18
|
+
export type ClaimsCodec = Schema.Codec<unknown, unknown, never, never>;
|
|
19
|
+
export interface PasskeyFeature {
|
|
20
20
|
readonly kind: "passkey";
|
|
21
21
|
readonly moduleId: string;
|
|
22
22
|
readonly policy: Effect.Effect<PasskeyMethodPolicy, PasskeyConfigurationError, PasskeyConfig>;
|
|
23
23
|
readonly management?: boolean;
|
|
24
24
|
readonly managementPolicy?: PasskeyManagementPolicy;
|
|
25
25
|
}
|
|
26
|
-
interface Strategy {
|
|
26
|
+
export interface Strategy {
|
|
27
27
|
readonly strategy: object;
|
|
28
28
|
readonly persistence?: PasskeyFeature | {
|
|
29
29
|
readonly kind: "password" | "phone" | "email";
|
|
@@ -34,7 +34,7 @@ interface Strategy {
|
|
|
34
34
|
};
|
|
35
35
|
readonly RegistrationAuthority?: Context.Key<unknown, unknown>;
|
|
36
36
|
}
|
|
37
|
-
interface Definition<C extends ClaimsCodec, Id extends string> {
|
|
37
|
+
export interface Definition<C extends ClaimsCodec, Id extends string> {
|
|
38
38
|
readonly namespace: string;
|
|
39
39
|
readonly claims: C;
|
|
40
40
|
readonly sessionMode?: string;
|
|
@@ -74,11 +74,11 @@ type Registration<S> = RegistrationKey<S> extends Context.Key<infer _Id, infer S
|
|
|
74
74
|
} ? Input extends {
|
|
75
75
|
readonly registration: infer Value;
|
|
76
76
|
} ? Value : never : never : never;
|
|
77
|
-
interface ProvisioningId<Id extends string> {
|
|
77
|
+
export interface ProvisioningId<Id extends string> {
|
|
78
78
|
readonly authNamespace: Id;
|
|
79
79
|
readonly service: "PersistenceProvisioning";
|
|
80
80
|
}
|
|
81
|
-
type Provisioning<A extends {
|
|
81
|
+
export type Provisioning<A extends {
|
|
82
82
|
readonly strategies: Readonly<Record<string, Strategy>>;
|
|
83
83
|
}> = { readonly [K in keyof A["strategies"] as A["strategies"][K] extends {
|
|
84
84
|
persistence: {
|
|
@@ -89,7 +89,7 @@ type Provisioning<A extends {
|
|
|
89
89
|
readonly identifier: LoginIdentifier;
|
|
90
90
|
readonly registration: Registration<A["strategies"][K]>;
|
|
91
91
|
}) => Effect.Effect<SubjectId, PasswordUnavailable>; };
|
|
92
|
-
type ProvisioningRequirement<A extends {
|
|
92
|
+
export type ProvisioningRequirement<A extends {
|
|
93
93
|
readonly namespace: string;
|
|
94
94
|
readonly strategies: Readonly<Record<string, Strategy>>;
|
|
95
95
|
}> = ManagedPassword<A> extends never ? never : ProvisioningId<A["namespace"]>;
|
|
@@ -97,9 +97,9 @@ type ProofRoles = "proofRequests" | "proofSeries" | "proofGenerations" | "proofC
|
|
|
97
97
|
type UsesProofs<A extends {
|
|
98
98
|
readonly strategies: Readonly<Record<string, Strategy>>;
|
|
99
99
|
}> = Enabled<A, "phone"> | Enabled<A, "email"> | ManagedPassword<A>;
|
|
100
|
-
type Ports<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = AuthenticationAuthority | KeyId<A["sessions"]["StatefulSessionPersistence"]> | KeyId<A["sessions"]["SessionRepository"]> | (Enabled<A, "password"> extends never ? never : PasswordPersistence) | KeyId<RegistrationKey<ManagedPassword<A>>> | (Enabled<A, "passkey"> extends never ? never : PasskeyPersistence | PasskeyCredentials) | (ManagedPasskey<A> extends never ? never : PasskeyManagementPersistence | PasskeyEnrollmentContext) | (Enabled<A, "email"> extends never ? never : EmailAddressPersistence) | (UsesProofs<A> extends never ? never : ProofPersistence) | (Enabled<A, "phone"> extends never ? never : PhoneAdmission | PhoneSignInTargets);
|
|
101
|
-
type Roles<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = "identifiers" | "credentials" | "sessions" | "sessionFlows" | (Enabled<A, "password"> extends never ? never : "passwords" | "passwordAttempts" | "passwordScopes" | "passwordCharges" | "passwordCommands") | (ManagedPassword<A> extends never ? never : "passwordRegistrations") | (Enabled<A, "phone"> extends never ? never : "phoneState") | (Enabled<A, "email"> extends never ? never : "emailCredentials" | "emailCommands") | (Enabled<A, "passkey"> extends never ? never : "passkeyCredentials" | "passkeyOwnership" | "passkeyHandles" | "passkeyModules" | "passkeyFlows" | "passkeyAdmissions" | "passkeyCharges") | (ManagedPasskey<A> extends never ? never : "passkeyCommands") | (UsesProofs<A> extends never ? never : ProofRoles);
|
|
102
|
-
interface SubjectOptions<T extends object, NativeId> {
|
|
100
|
+
export type Ports<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = AuthenticationAuthority | KeyId<A["sessions"]["StatefulSessionPersistence"]> | KeyId<A["sessions"]["SessionRepository"]> | (Enabled<A, "password"> extends never ? never : PasswordPersistence) | KeyId<RegistrationKey<ManagedPassword<A>>> | (Enabled<A, "passkey"> extends never ? never : PasskeyPersistence | PasskeyCredentials) | (ManagedPasskey<A> extends never ? never : PasskeyManagementPersistence | PasskeyEnrollmentContext) | (Enabled<A, "email"> extends never ? never : EmailAddressPersistence) | (UsesProofs<A> extends never ? never : ProofPersistence) | (Enabled<A, "phone"> extends never ? never : PhoneAdmission | PhoneSignInTargets);
|
|
101
|
+
export type Roles<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = "identifiers" | "credentials" | "sessions" | "sessionFlows" | (Enabled<A, "password"> extends never ? never : "passwords" | "passwordAttempts" | "passwordScopes" | "passwordCharges" | "passwordCommands") | (ManagedPassword<A> extends never ? never : "passwordRegistrations") | (Enabled<A, "phone"> extends never ? never : "phoneState") | (Enabled<A, "email"> extends never ? never : "emailCredentials" | "emailCommands") | (Enabled<A, "passkey"> extends never ? never : "passkeyCredentials" | "passkeyOwnership" | "passkeyHandles" | "passkeyModules" | "passkeyFlows" | "passkeyAdmissions" | "passkeyCharges") | (ManagedPasskey<A> extends never ? never : "passkeyCommands") | (UsesProofs<A> extends never ? never : ProofRoles);
|
|
102
|
+
export interface SubjectOptions<T extends object, NativeId> {
|
|
103
103
|
readonly table: T;
|
|
104
104
|
readonly id: string;
|
|
105
105
|
readonly status: string;
|
|
@@ -111,7 +111,7 @@ interface SubjectOptions<T extends object, NativeId> {
|
|
|
111
111
|
readonly actionRequirements?: (row: Readonly<Record<string, unknown>>, action: PasswordAction | EmailAction | PasskeyActionChallenge["action"]) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;
|
|
112
112
|
}
|
|
113
113
|
/** Codecs at the application-owned subject and timestamp boundary. */
|
|
114
|
-
interface SubjectMapping {
|
|
114
|
+
export interface SubjectMapping {
|
|
115
115
|
readonly table: object;
|
|
116
116
|
readonly id: string;
|
|
117
117
|
readonly status: string;
|
|
@@ -124,26 +124,26 @@ interface SubjectMapping {
|
|
|
124
124
|
readonly toSubjectSync: (value: unknown) => SubjectId;
|
|
125
125
|
readonly toNativeSync: (value: SubjectId) => unknown;
|
|
126
126
|
}
|
|
127
|
-
interface MappingInput {
|
|
127
|
+
export interface MappingInput {
|
|
128
128
|
readonly tables: Partial<Record<StorageRole, object>>;
|
|
129
129
|
readonly subjects: SubjectMapping;
|
|
130
130
|
readonly encodeInstant: (millis: number) => unknown;
|
|
131
131
|
readonly decodeInstant: (value: unknown) => Effect.Effect<number, PersistenceMappingError>;
|
|
132
132
|
readonly decodeInstantSync: (value: unknown) => number;
|
|
133
133
|
}
|
|
134
|
-
interface StorageLayout<T extends object, Role extends StorageRole = StorageRole> extends MappingInput {
|
|
134
|
+
export interface StorageLayout<T extends object, Role extends StorageRole = StorageRole> extends MappingInput {
|
|
135
135
|
readonly namespace: string;
|
|
136
136
|
readonly schema: Readonly<Record<Role, T>>;
|
|
137
137
|
}
|
|
138
|
-
interface ConfigId<Id extends string> {
|
|
138
|
+
export interface ConfigId<Id extends string> {
|
|
139
139
|
readonly authNamespace: Id;
|
|
140
140
|
readonly service: "PersistenceConfig";
|
|
141
141
|
}
|
|
142
|
-
interface TimestampOptions<Instant> {
|
|
142
|
+
export interface TimestampOptions<Instant> {
|
|
143
143
|
readonly type: "text" | "integer";
|
|
144
144
|
readonly codec: Schema.Codec<number, Instant>;
|
|
145
145
|
}
|
|
146
|
-
interface BoundPersistence<T extends object, R, C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> {
|
|
146
|
+
export interface BoundPersistence<T extends object, R, C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> {
|
|
147
147
|
readonly Config: Context.Service<ConfigId<A["namespace"]>, StorageLayout<T, Roles<C, Id, A>>> & {
|
|
148
148
|
readonly layer: (value: StorageLayout<T, Roles<C, Id, A>>) => Layer.Layer<ConfigId<A["namespace"]>>;
|
|
149
149
|
};
|
|
@@ -166,9 +166,9 @@ interface BoundPersistence<T extends object, R, C extends ClaimsCodec, Id extend
|
|
|
166
166
|
}) => StorageLayout<T, Roles<C, Id, A>>;
|
|
167
167
|
}
|
|
168
168
|
/** Shared configuration shape. The backend chooses table types and service requirements. */
|
|
169
|
-
interface PersistenceApi<T extends object, R = never> {
|
|
169
|
+
export interface PersistenceApi<T extends object, R = never> {
|
|
170
170
|
readonly make: <C extends ClaimsCodec, const Id extends string, const A extends Definition<C, Id>>(auth: A & Definition<C, Id>) => BoundPersistence<T, R, C, Id, A>;
|
|
171
171
|
}
|
|
172
172
|
//#endregion
|
|
173
|
-
export {
|
|
173
|
+
export { PasskeyRequirement$1 as PasskeyRequirement };
|
|
174
174
|
//# sourceMappingURL=configuration.d.mts.map
|
|
@@ -4,8 +4,7 @@ declare const PersistenceMappingError_base: Schema.Class<PersistenceMappingError
|
|
|
4
4
|
readonly operation: Schema.NonEmptyString;
|
|
5
5
|
readonly cause: Schema.Defect;
|
|
6
6
|
}>, Cause.YieldableError>;
|
|
7
|
-
declare class PersistenceMappingError extends PersistenceMappingError_base {}
|
|
8
|
-
declare const isMappedConstraintConflict: (classify: (cause: unknown) => boolean, failure: unknown) => boolean;
|
|
7
|
+
export declare class PersistenceMappingError extends PersistenceMappingError_base {}
|
|
8
|
+
export declare const isMappedConstraintConflict: (classify: (cause: unknown) => boolean, failure: unknown) => boolean;
|
|
9
9
|
//#endregion
|
|
10
|
-
export { PersistenceMappingError, isMappedConstraintConflict };
|
|
11
10
|
//# sourceMappingURL=mapping-error.d.mts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
import { OAuthUnavailable } from "@yielded/auth/OAuth";
|
|
4
|
+
import { Persistence } from "@yielded/auth/OAuthApp";
|
|
5
|
+
//#region src/internal/oauth-app.d.ts
|
|
6
|
+
export declare const OAuthAppPersistence: {
|
|
7
|
+
layer: Layer.Layer<Persistence, OAuthUnavailable, SqlClient.SqlClient>;
|
|
8
|
+
migration: string;
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
//# sourceMappingURL=oauth-app.d.mts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { requireStandalone } from "./standalone.mjs";
|
|
2
|
+
import { Effect, Layer, Schema } from "effect";
|
|
3
|
+
import { SqlClient } from "effect/unstable/sql";
|
|
4
|
+
import { OAuthUnavailable } from "@yielded/auth/OAuth";
|
|
5
|
+
import { Persistence, Record } from "@yielded/auth/OAuthApp";
|
|
6
|
+
//#region src/internal/oauth-app.ts
|
|
7
|
+
const codec = Schema.fromJsonString(Record);
|
|
8
|
+
const Row = Schema.Struct({
|
|
9
|
+
payload: Schema.String,
|
|
10
|
+
version: Schema.String
|
|
11
|
+
});
|
|
12
|
+
const OAuthAppPersistence = {
|
|
13
|
+
layer: Layer.effect(Persistence, Effect.gen(function* () {
|
|
14
|
+
const sql = yield* SqlClient.SqlClient;
|
|
15
|
+
if (!sql.onDialectOrElse({
|
|
16
|
+
sqlite: () => true,
|
|
17
|
+
pg: () => true,
|
|
18
|
+
orElse: () => false
|
|
19
|
+
})) return yield* OAuthUnavailable.make({});
|
|
20
|
+
const noTransaction = requireStandalone(() => OAuthUnavailable.make({}), sql);
|
|
21
|
+
const failure = (effect) => effect.pipe(Effect.mapError(() => OAuthUnavailable.make({})));
|
|
22
|
+
return Persistence.of({
|
|
23
|
+
get: Effect.fn("OAuthAppPersistence.get")(function* (namespace, key) {
|
|
24
|
+
yield* noTransaction;
|
|
25
|
+
const rows = yield* sql`SELECT payload, version FROM yielded_oauth_app WHERE namespace = ${namespace} AND record_key = ${key}`;
|
|
26
|
+
if (rows.length === 0) return void 0;
|
|
27
|
+
if (rows.length !== 1) return yield* OAuthUnavailable.make({});
|
|
28
|
+
const row = yield* Schema.decodeEffect(Row)(rows[0]);
|
|
29
|
+
const value = yield* Schema.decodeEffect(codec)(row.payload);
|
|
30
|
+
if (value.version !== row.version) return yield* OAuthUnavailable.make({});
|
|
31
|
+
return value;
|
|
32
|
+
}, failure),
|
|
33
|
+
insert: Effect.fn("OAuthAppPersistence.insert")(function* (namespace, key, value) {
|
|
34
|
+
yield* noTransaction;
|
|
35
|
+
const payload = yield* Schema.encodeEffect(codec)(value);
|
|
36
|
+
return (yield* sql`INSERT INTO yielded_oauth_app (namespace, record_key, version, payload) VALUES (${namespace}, ${key}, ${value.version}, ${payload}) ON CONFLICT (namespace, record_key) DO NOTHING RETURNING version`).length === 1;
|
|
37
|
+
}, failure),
|
|
38
|
+
compareAndSet: Effect.fn("OAuthAppPersistence.compareAndSet")(function* (namespace, key, version, value) {
|
|
39
|
+
yield* noTransaction;
|
|
40
|
+
if (value.version === version) return yield* OAuthUnavailable.make({});
|
|
41
|
+
const payload = yield* Schema.encodeEffect(codec)(value);
|
|
42
|
+
return (yield* sql`UPDATE yielded_oauth_app SET version = ${value.version}, payload = ${payload} WHERE namespace = ${namespace} AND record_key = ${key} AND version = ${version} RETURNING version`).length === 1;
|
|
43
|
+
}, failure)
|
|
44
|
+
});
|
|
45
|
+
})),
|
|
46
|
+
migration: `CREATE TABLE yielded_oauth_app (
|
|
47
|
+
namespace TEXT NOT NULL,
|
|
48
|
+
record_key TEXT NOT NULL,
|
|
49
|
+
version TEXT NOT NULL,
|
|
50
|
+
payload TEXT NOT NULL,
|
|
51
|
+
PRIMARY KEY (namespace, record_key)
|
|
52
|
+
)`
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
export { OAuthAppPersistence };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=oauth-app.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-app.mjs","names":[],"sources":["../../src/internal/oauth-app.ts"],"sourcesContent":["import { OAuthUnavailable } from \"@yielded/auth/OAuth\";\nimport { Persistence, Record } from \"@yielded/auth/OAuthApp\";\nimport { Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/unstable/sql\";\n\nimport { requireStandalone } from \"./standalone\";\n\nconst codec = Schema.fromJsonString(Record);\nconst Row = Schema.Struct({ payload: Schema.String, version: Schema.String });\n\n/** Apply with the application's migrations. SQLite (including D1) and PostgreSQL.\n * Each transition is one conditional statement, so D1 needs no interactive\n * transaction and parallel workers share the same refresh/code claim.\n */\nconst migration = `CREATE TABLE yielded_oauth_app (\n namespace TEXT NOT NULL,\n record_key TEXT NOT NULL,\n version TEXT NOT NULL,\n payload TEXT NOT NULL,\n PRIMARY KEY (namespace, record_key)\n)`;\n\nconst layer = Layer.effect(\n Persistence,\n Effect.gen(function* () {\n const sql = yield* SqlClient.SqlClient;\n\n if (!sql.onDialectOrElse({ sqlite: () => true, pg: () => true, orElse: () => false }))\n return yield* OAuthUnavailable.make({});\n\n const noTransaction = requireStandalone(() => OAuthUnavailable.make({}), sql);\n\n const failure = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n effect.pipe(Effect.mapError(() => OAuthUnavailable.make({})));\n\n return Persistence.of({\n get: Effect.fn(\"OAuthAppPersistence.get\")(function* (namespace, key) {\n yield* noTransaction;\n\n const rows = yield* sql<{\n payload: string;\n version: string;\n }>`SELECT payload, version FROM yielded_oauth_app WHERE namespace = ${namespace} AND record_key = ${key}`;\n\n if (rows.length === 0) return undefined;\n if (rows.length !== 1) return yield* OAuthUnavailable.make({});\n const row = yield* Schema.decodeEffect(Row)(rows[0]);\n const value = yield* Schema.decodeEffect(codec)(row.payload);\n\n if (value.version !== row.version) return yield* OAuthUnavailable.make({});\n\n return value;\n }, failure),\n insert: Effect.fn(\"OAuthAppPersistence.insert\")(function* (namespace, key, value) {\n yield* noTransaction;\n const payload = yield* Schema.encodeEffect(codec)(value);\n\n const rows =\n yield* sql`INSERT INTO yielded_oauth_app (namespace, record_key, version, payload) VALUES (${namespace}, ${key}, ${value.version}, ${payload}) ON CONFLICT (namespace, record_key) DO NOTHING RETURNING version`;\n\n return rows.length === 1;\n }, failure),\n compareAndSet: Effect.fn(\"OAuthAppPersistence.compareAndSet\")(function* (\n namespace,\n key,\n version,\n value,\n ) {\n yield* noTransaction;\n if (value.version === version) return yield* OAuthUnavailable.make({});\n const payload = yield* Schema.encodeEffect(codec)(value);\n\n const rows =\n yield* sql`UPDATE yielded_oauth_app SET version = ${value.version}, payload = ${payload} WHERE namespace = ${namespace} AND record_key = ${key} AND version = ${version} RETURNING version`;\n\n return rows.length === 1;\n }, failure),\n });\n }),\n);\n\nexport const OAuthAppPersistence = { layer, migration };\n"],"mappings":";;;;;;AAOA,MAAM,QAAQ,OAAO,eAAe,MAAM;AAC1C,MAAM,MAAM,OAAO,OAAO;CAAE,SAAS,OAAO;CAAQ,SAAS,OAAO;AAAO,CAAC;AAyE5E,MAAa,sBAAsB;CAAE,OA3DvB,MAAM,OAClB,aACA,OAAO,IAAI,aAAa;EACtB,MAAM,MAAM,OAAO,UAAU;EAE7B,IAAI,CAAC,IAAI,gBAAgB;GAAE,cAAc;GAAM,UAAU;GAAM,cAAc;EAAM,CAAC,GAClF,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;EAExC,MAAM,gBAAgB,wBAAwB,iBAAiB,KAAK,CAAC,CAAC,GAAG,GAAG;EAE5E,MAAM,WAAoB,WACxB,OAAO,KAAK,OAAO,eAAe,iBAAiB,KAAK,CAAC,CAAC,CAAC,CAAC;EAE9D,OAAO,YAAY,GAAG;GACpB,KAAK,OAAO,GAAG,yBAAyB,CAAC,CAAC,WAAW,WAAW,KAAK;IACnE,OAAO;IAEP,MAAM,OAAO,OAAO,GAGlB,oEAAoE,UAAU,oBAAoB;IAEpG,IAAI,KAAK,WAAW,GAAG,OAAO,KAAA;IAC9B,IAAI,KAAK,WAAW,GAAG,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;IAC7D,MAAM,MAAM,OAAO,OAAO,aAAa,GAAG,CAAC,CAAC,KAAK,EAAE;IACnD,MAAM,QAAQ,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,IAAI,OAAO;IAE3D,IAAI,MAAM,YAAY,IAAI,SAAS,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;IAEzE,OAAO;GACT,GAAG,OAAO;GACV,QAAQ,OAAO,GAAG,4BAA4B,CAAC,CAAC,WAAW,WAAW,KAAK,OAAO;IAChF,OAAO;IACP,MAAM,UAAU,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,KAAK;IAKvD,QAAO,OAFE,GAAG,mFAAmF,UAAU,IAAI,IAAI,IAAI,MAAM,QAAQ,IAAI,QAAQ,oEAAA,CAEnI,WAAW;GACzB,GAAG,OAAO;GACV,eAAe,OAAO,GAAG,mCAAmC,CAAC,CAAC,WAC5D,WACA,KACA,SACA,OACA;IACA,OAAO;IACP,IAAI,MAAM,YAAY,SAAS,OAAO,OAAO,iBAAiB,KAAK,CAAC,CAAC;IACrE,MAAM,UAAU,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,KAAK;IAKvD,QAAO,OAFE,GAAG,0CAA0C,MAAM,QAAQ,cAAc,QAAQ,qBAAqB,UAAU,oBAAoB,IAAI,iBAAiB,QAAQ,oBAAA,CAE9J,WAAW;GACzB,GAAG,OAAO;EACZ,CAAC;CACH,CAAC,CAGkC;CAAO;;;;;;;AAAU"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
import { Persistence, Unavailable } from "@yielded/auth/OAuthServer";
|
|
4
|
+
//#region src/internal/oauth-server.d.ts
|
|
5
|
+
export declare const OAuthServerPersistence: {
|
|
6
|
+
migration: string;
|
|
7
|
+
layer: Layer.Layer<Persistence, Unavailable, SqlClient.SqlClient>;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
//# sourceMappingURL=oauth-server.d.mts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { requireStandalone } from "./standalone.mjs";
|
|
2
|
+
import { Effect, Layer, Schema } from "effect";
|
|
3
|
+
import { SqlClient } from "effect/unstable/sql";
|
|
4
|
+
import { Persistence, Record, Unavailable } from "@yielded/auth/OAuthServer";
|
|
5
|
+
//#region src/internal/oauth-server.ts
|
|
6
|
+
const codec = Schema.fromJsonString(Record);
|
|
7
|
+
const Row = Schema.Struct({
|
|
8
|
+
payload: Schema.String,
|
|
9
|
+
version: Schema.String,
|
|
10
|
+
revoked: Schema.Literals([0, 1])
|
|
11
|
+
});
|
|
12
|
+
const OAuthServerPersistence = {
|
|
13
|
+
migration: `CREATE TABLE yielded_oauth_server (
|
|
14
|
+
namespace TEXT NOT NULL,
|
|
15
|
+
grant_id TEXT NOT NULL,
|
|
16
|
+
version TEXT NOT NULL,
|
|
17
|
+
revoked INTEGER NOT NULL DEFAULT 0,
|
|
18
|
+
expires_at_millis BIGINT NOT NULL,
|
|
19
|
+
payload TEXT NOT NULL,
|
|
20
|
+
PRIMARY KEY (namespace, grant_id)
|
|
21
|
+
)`,
|
|
22
|
+
layer: Layer.effect(Persistence, Effect.gen(function* () {
|
|
23
|
+
const sql = yield* SqlClient.SqlClient;
|
|
24
|
+
if (!sql.onDialectOrElse({
|
|
25
|
+
sqlite: () => true,
|
|
26
|
+
pg: () => true,
|
|
27
|
+
orElse: () => false
|
|
28
|
+
})) return yield* Unavailable.make({});
|
|
29
|
+
const standalone = requireStandalone(() => Unavailable.make({}), sql);
|
|
30
|
+
const failure = (effect) => effect.pipe(Effect.mapError(() => Unavailable.make({})));
|
|
31
|
+
return Persistence.of({
|
|
32
|
+
get: Effect.fn("OAuthServerPersistence.get")(function* (namespace, id) {
|
|
33
|
+
yield* standalone;
|
|
34
|
+
const rows = yield* sql`SELECT payload, version, revoked FROM yielded_oauth_server WHERE namespace = ${namespace} AND grant_id = ${id}`;
|
|
35
|
+
if (rows.length === 0) return void 0;
|
|
36
|
+
if (rows.length !== 1) return yield* Unavailable.make({});
|
|
37
|
+
const row = yield* Schema.decodeUnknownEffect(Row)(rows[0]);
|
|
38
|
+
const record = yield* Schema.decodeEffect(codec)(row.payload);
|
|
39
|
+
if (record.version !== row.version) return yield* Unavailable.make({});
|
|
40
|
+
return row.revoked === 1 ? {
|
|
41
|
+
...record,
|
|
42
|
+
status: "Revoked"
|
|
43
|
+
} : record;
|
|
44
|
+
}, failure),
|
|
45
|
+
insert: Effect.fn("OAuthServerPersistence.insert")(function* (namespace, id, record) {
|
|
46
|
+
yield* standalone;
|
|
47
|
+
const payload = yield* Schema.encodeEffect(codec)(record);
|
|
48
|
+
return (yield* sql`INSERT INTO yielded_oauth_server (namespace, grant_id, version, revoked, expires_at_millis, payload) VALUES (${namespace}, ${id}, ${record.version}, ${record.status === "Revoked" ? 1 : 0}, ${record.expiresAtMillis}, ${payload}) ON CONFLICT (namespace, grant_id) DO NOTHING RETURNING version`).length === 1;
|
|
49
|
+
}, failure),
|
|
50
|
+
compareAndSet: Effect.fn("OAuthServerPersistence.compareAndSet")(function* (namespace, id, version, record) {
|
|
51
|
+
yield* standalone;
|
|
52
|
+
if (version === record.version) return yield* Unavailable.make({});
|
|
53
|
+
const payload = yield* Schema.encodeEffect(codec)(record);
|
|
54
|
+
return (yield* sql`UPDATE yielded_oauth_server SET version = ${record.version}, revoked = ${record.status === "Revoked" ? 1 : 0}, expires_at_millis = ${record.expiresAtMillis}, payload = ${payload} WHERE namespace = ${namespace} AND grant_id = ${id} AND version = ${version} AND revoked = 0 RETURNING version`).length === 1;
|
|
55
|
+
}, failure),
|
|
56
|
+
revoke: Effect.fn("OAuthServerPersistence.revoke")(function* (namespace, id) {
|
|
57
|
+
yield* standalone;
|
|
58
|
+
yield* sql`UPDATE yielded_oauth_server SET revoked = 1 WHERE namespace = ${namespace} AND grant_id = ${id}`;
|
|
59
|
+
}, failure)
|
|
60
|
+
});
|
|
61
|
+
}))
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { OAuthServerPersistence };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=oauth-server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-server.mjs","names":[],"sources":["../../src/internal/oauth-server.ts"],"sourcesContent":["import { Persistence, Record, Unavailable } from \"@yielded/auth/OAuthServer\";\nimport { Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/unstable/sql\";\n\nimport { requireStandalone } from \"./standalone\";\n\nconst codec = Schema.fromJsonString(Record);\n\nconst Row = Schema.Struct({\n payload: Schema.String,\n version: Schema.String,\n revoked: Schema.Literals([0, 1]),\n});\n\n/** SQLite (including D1) and PostgreSQL. Apply once through application migrations.\n * Expired records may be deleted when expires_at_millis <= the current time.\n * Revocation has its own monotonic column so it cannot lose a race with rotation.\n */\nconst migration = `CREATE TABLE yielded_oauth_server (\n namespace TEXT NOT NULL,\n grant_id TEXT NOT NULL,\n version TEXT NOT NULL,\n revoked INTEGER NOT NULL DEFAULT 0,\n expires_at_millis BIGINT NOT NULL,\n payload TEXT NOT NULL,\n PRIMARY KEY (namespace, grant_id)\n)`;\n\nconst layer = Layer.effect(\n Persistence,\n Effect.gen(function* () {\n const sql = yield* SqlClient.SqlClient;\n\n if (!sql.onDialectOrElse({ sqlite: () => true, pg: () => true, orElse: () => false }))\n return yield* Unavailable.make({});\n const standalone = requireStandalone(() => Unavailable.make({}), sql);\n\n const failure = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n effect.pipe(Effect.mapError(() => Unavailable.make({})));\n\n return Persistence.of({\n get: Effect.fn(\"OAuthServerPersistence.get\")(function* (namespace, id) {\n yield* standalone;\n\n const rows =\n yield* sql`SELECT payload, version, revoked FROM yielded_oauth_server WHERE namespace = ${namespace} AND grant_id = ${id}`;\n\n if (rows.length === 0) return undefined;\n if (rows.length !== 1) return yield* Unavailable.make({});\n const row = yield* Schema.decodeUnknownEffect(Row)(rows[0]);\n const record = yield* Schema.decodeEffect(codec)(row.payload);\n\n if (record.version !== row.version) return yield* Unavailable.make({});\n\n return row.revoked === 1 ? { ...record, status: \"Revoked\" as const } : record;\n }, failure),\n insert: Effect.fn(\"OAuthServerPersistence.insert\")(function* (namespace, id, record) {\n yield* standalone;\n const payload = yield* Schema.encodeEffect(codec)(record);\n\n const rows =\n yield* sql`INSERT INTO yielded_oauth_server (namespace, grant_id, version, revoked, expires_at_millis, payload) VALUES (${namespace}, ${id}, ${record.version}, ${record.status === \"Revoked\" ? 1 : 0}, ${record.expiresAtMillis}, ${payload}) ON CONFLICT (namespace, grant_id) DO NOTHING RETURNING version`;\n\n return rows.length === 1;\n }, failure),\n compareAndSet: Effect.fn(\"OAuthServerPersistence.compareAndSet\")(function* (\n namespace,\n id,\n version,\n record,\n ) {\n yield* standalone;\n if (version === record.version) return yield* Unavailable.make({});\n const payload = yield* Schema.encodeEffect(codec)(record);\n\n const rows =\n yield* sql`UPDATE yielded_oauth_server SET version = ${record.version}, revoked = ${record.status === \"Revoked\" ? 1 : 0}, expires_at_millis = ${record.expiresAtMillis}, payload = ${payload} WHERE namespace = ${namespace} AND grant_id = ${id} AND version = ${version} AND revoked = 0 RETURNING version`;\n\n return rows.length === 1;\n }, failure),\n revoke: Effect.fn(\"OAuthServerPersistence.revoke\")(function* (namespace, id) {\n yield* standalone;\n yield* sql`UPDATE yielded_oauth_server SET revoked = 1 WHERE namespace = ${namespace} AND grant_id = ${id}`;\n }, failure),\n });\n }),\n);\n\nexport const OAuthServerPersistence = { migration, layer };\n"],"mappings":";;;;;AAMA,MAAM,QAAQ,OAAO,eAAe,MAAM;AAE1C,MAAM,MAAM,OAAO,OAAO;CACxB,SAAS,OAAO;CAChB,SAAS,OAAO;CAChB,SAAS,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC;AACjC,CAAC;AA4ED,MAAa,yBAAyB;CAAE;;;;;;;;;CAAW,OA5DrC,MAAM,OAClB,aACA,OAAO,IAAI,aAAa;EACtB,MAAM,MAAM,OAAO,UAAU;EAE7B,IAAI,CAAC,IAAI,gBAAgB;GAAE,cAAc;GAAM,UAAU;GAAM,cAAc;EAAM,CAAC,GAClF,OAAO,OAAO,YAAY,KAAK,CAAC,CAAC;EACnC,MAAM,aAAa,wBAAwB,YAAY,KAAK,CAAC,CAAC,GAAG,GAAG;EAEpE,MAAM,WAAoB,WACxB,OAAO,KAAK,OAAO,eAAe,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC;EAEzD,OAAO,YAAY,GAAG;GACpB,KAAK,OAAO,GAAG,4BAA4B,CAAC,CAAC,WAAW,WAAW,IAAI;IACrE,OAAO;IAEP,MAAM,OACJ,OAAO,GAAG,gFAAgF,UAAU,kBAAkB;IAExH,IAAI,KAAK,WAAW,GAAG,OAAO,KAAA;IAC9B,IAAI,KAAK,WAAW,GAAG,OAAO,OAAO,YAAY,KAAK,CAAC,CAAC;IACxD,MAAM,MAAM,OAAO,OAAO,oBAAoB,GAAG,CAAC,CAAC,KAAK,EAAE;IAC1D,MAAM,SAAS,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,IAAI,OAAO;IAE5D,IAAI,OAAO,YAAY,IAAI,SAAS,OAAO,OAAO,YAAY,KAAK,CAAC,CAAC;IAErE,OAAO,IAAI,YAAY,IAAI;KAAE,GAAG;KAAQ,QAAQ;IAAmB,IAAI;GACzE,GAAG,OAAO;GACV,QAAQ,OAAO,GAAG,+BAA+B,CAAC,CAAC,WAAW,WAAW,IAAI,QAAQ;IACnF,OAAO;IACP,MAAM,UAAU,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,MAAM;IAKxD,QAAO,OAFE,GAAG,gHAAgH,UAAU,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAI,OAAO,WAAW,YAAY,IAAI,EAAE,IAAI,OAAO,gBAAgB,IAAI,QAAQ,kEAAA,CAEnO,WAAW;GACzB,GAAG,OAAO;GACV,eAAe,OAAO,GAAG,sCAAsC,CAAC,CAAC,WAC/D,WACA,IACA,SACA,QACA;IACA,OAAO;IACP,IAAI,YAAY,OAAO,SAAS,OAAO,OAAO,YAAY,KAAK,CAAC,CAAC;IACjE,MAAM,UAAU,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,MAAM;IAKxD,QAAO,OAFE,GAAG,6CAA6C,OAAO,QAAQ,cAAc,OAAO,WAAW,YAAY,IAAI,EAAE,wBAAwB,OAAO,gBAAgB,cAAc,QAAQ,qBAAqB,UAAU,kBAAkB,GAAG,iBAAiB,QAAQ,oCAAA,CAEhQ,WAAW;GACzB,GAAG,OAAO;GACV,QAAQ,OAAO,GAAG,+BAA+B,CAAC,CAAC,WAAW,WAAW,IAAI;IAC3E,OAAO;IACP,OAAO,GAAG,iEAAiE,UAAU,kBAAkB;GACzG,GAAG,OAAO;EACZ,CAAC;CACH,CAAC,CAGgD;AAAM"}
|
|
@@ -12,8 +12,7 @@ import { PasskeyConfigurationError, PasskeyPersistence, PasskeyUnavailable, Prep
|
|
|
12
12
|
import { LifecycleHooks, PreparedCommit } from "@yielded/auth/Hooks";
|
|
13
13
|
import { Statement } from "effect/unstable/sql/Statement";
|
|
14
14
|
//#region src/internal/passkey/target.d.ts
|
|
15
|
-
type PasskeyTargetConfiguration = TransactionTargetConfiguration<PasskeyUnavailable>;
|
|
16
|
-
type PasskeyCoordinatorError<E> = TransactionCoordinatorError<E, PasskeyUnavailable> | PasskeyConfigurationError | PersistenceMappingError;
|
|
15
|
+
export type PasskeyTargetConfiguration = TransactionTargetConfiguration<PasskeyUnavailable>;
|
|
16
|
+
export type PasskeyCoordinatorError<E> = TransactionCoordinatorError<E, PasskeyUnavailable> | PasskeyConfigurationError | PersistenceMappingError;
|
|
17
17
|
//#endregion
|
|
18
|
-
export { PasskeyCoordinatorError, PasskeyTargetConfiguration };
|
|
19
18
|
//# sourceMappingURL=target.d.mts.map
|
|
@@ -2,6 +2,7 @@ import { PersistenceConfigurationError } from "./configuration.mjs";
|
|
|
2
2
|
import { requiredPasskeyCredentialConstraints, requiredPasskeyPersistenceConstraints } from "../drizzle/passkey-model.mjs";
|
|
3
3
|
import { requiredPasskeyManagementConstraints } from "../drizzle/passkey-write-model.mjs";
|
|
4
4
|
import { PersistenceMappingError } from "./mapping-error.mjs";
|
|
5
|
+
import { requireStandalone } from "./standalone.mjs";
|
|
5
6
|
import { makePasskeyKernel } from "./passkey-kernel.mjs";
|
|
6
7
|
import { storageTables } from "./storage-tables.mjs";
|
|
7
8
|
import { Context, Effect, Schema } from "effect";
|
|
@@ -284,7 +285,7 @@ const makeComposedPasskeys = (operations) => {
|
|
|
284
285
|
mode: "interactive",
|
|
285
286
|
dialect,
|
|
286
287
|
locking: dialect === "pg",
|
|
287
|
-
standaloneGuard: () =>
|
|
288
|
+
standaloneGuard: () => requireStandalone(unavailable, client)
|
|
288
289
|
};
|
|
289
290
|
const native = database;
|
|
290
291
|
yield* client.withTransaction(Effect.gen(function* () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passkeys.mjs","names":[],"sources":["../../src/internal/passkeys.ts"],"sourcesContent":["import {\n PasskeyCredentials,\n PasskeyCredential,\n PasskeyEnrollmentContext,\n PasskeyManagementPersistence,\n PasskeyManagementPolicy,\n PasskeyMethodPolicy,\n PasskeyPersistence,\n PasskeyProfile,\n PasskeyRequirement,\n PasskeyUnavailable,\n} from \"@yielded/auth/Passkey\";\nimport { digest } from \"@yielded/auth/Persistence\";\nimport type { SQL, Table } from \"drizzle-orm\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/unstable/sql\";\n\nimport {\n requiredPasskeyCredentialConstraints,\n requiredPasskeyPersistenceConstraints,\n type PasskeyCredentialMapping,\n type PasskeyPersistenceMapping,\n} from \"../drizzle/passkey-model\";\nimport {\n requiredPasskeyManagementConstraints,\n type PasskeyManagementMapping,\n} from \"../drizzle/passkey-write-model\";\nimport {\n PersistenceConfigurationError,\n type MappingInput,\n type PasskeyFeature,\n} from \"./configuration\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport { makePasskeyKernel } from \"./passkey-kernel\";\nimport type { PasskeyTargetConfiguration } from \"./passkey/target\";\nimport type { Backend } from \"./persistence\";\nimport type { ProofSqlDatabase } from \"./proof-kernel\";\nimport type { QueryOperations } from \"./query-operations\";\nimport { storageTables, type StorageRole } from \"./storage-tables\";\n\nconst profileJson = Schema.fromJsonString(PasskeyProfile);\nconst policyJson = Schema.fromJsonString(PasskeyMethodPolicy);\n\nconst seedJson = Schema.fromJsonString(\n Schema.Struct({\n policy: PasskeyMethodPolicy,\n management: Schema.optionalKey(PasskeyManagementPolicy),\n }),\n);\n\nconst ModuleRow = Schema.Struct({\n active: Schema.Boolean,\n policy: Schema.String,\n policyRevision: Schema.String,\n});\n\nconst credentialData = PasskeyCredential.mapFields(\n ({ revision: _revision, active: _active, ...fields }) => fields,\n);\n\nconst unavailable = () => PasskeyUnavailable.make({});\nconst configurationError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\ntype ReadMapping = PasskeyCredentialMapping<Table, Table, Table, Table, Table, unknown>;\ntype BaseMapping = PasskeyPersistenceMapping<ReadMapping, Table, Table, Table, Table, unknown>;\ntype ManagementMapping = PasskeyManagementMapping<\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n unknown\n>;\n\n/** Share the same passkey algorithms across raw SQL and Drizzle compilers. */\nexport const makeComposedPasskeys = (\n operations: QueryOperations,\n): Backend<object, never>[\"passkeys\"] => {\n const { and, eq, getTableColumns, inArray, or, sql } = operations;\n const { target, writeTarget } = makePasskeyKernel(operations);\n\n const {\n makeTargetPasskeyCredentials,\n makeTargetPasskeyEnrollmentContext,\n makeTargetPasskeyPersistence,\n } = target;\n\n const { makeTargetPasskeyManagement } = writeTarget;\n\n const mappings = (\n storage: MappingInput,\n namespace: string,\n dialect: \"pg\" | \"sqlite\",\n passwordModules: ReadonlyArray<string>,\n signInProfiles: ReadonlyArray<PasskeyProfile>,\n ) => {\n const table = (role: StorageRole): Table => {\n const value = storage.tables[role];\n\n if (value === undefined) throw configurationError(`Missing ${role} mapping`);\n\n // Backend validation owns the foreign table shape. Row values are decoded below.\n return value as Table;\n };\n\n const mapped = <Role extends StorageRole>(role: Role) => ({\n table: table(role),\n ...(Object.fromEntries(Object.keys(storageTables[role].columns).map((key) => [key, key])) as {\n readonly [Key in keyof (typeof storageTables)[Role][\"columns\"]]: Key;\n }),\n });\n\n const column = (role: StorageRole, key: string) => getTableColumns(table(role))[key];\n const s = storage.subjects;\n const subject = s.table as Table;\n const sc = getTableColumns(subject);\n const active = (value: unknown) => value === true;\n const owned = (value: unknown) => value === \"owned\";\n\n const read: ReadMapping = {\n subject: {\n table: subject,\n id: s.id,\n status: s.status,\n securityRevision: s.securityRevision,\n decodeId: (row) => row[s.id],\n isActiveStatus: (value) => Object.is(value, s.activeValue),\n activeCondition: eq(sc[s.status], s.activeValue),\n },\n credential: {\n ...mapped(\"passkeyCredentials\"),\n status: \"active\",\n decode: (row) =>\n Schema.decodeUnknownSync(credentialData)({\n ...row,\n profile: Schema.decodeUnknownSync(profileJson)(row.profile),\n }),\n decodeSubjectId: (row) => row.subjectId,\n isActiveStatus: active,\n activeCondition: eq(column(\"passkeyCredentials\", \"active\"), true),\n },\n authority: {\n ...mapped(\"credentials\"),\n status: \"active\",\n isActiveStatus: active,\n activeCondition: eq(column(\"credentials\", \"active\"), true),\n },\n credentialOwnership: {\n ...mapped(\"passkeyOwnership\"),\n isOwnedState: owned,\n ownedCondition: eq(column(\"passkeyOwnership\", \"state\"), \"owned\"),\n decodeSubjectId: (row) => row.subjectId,\n },\n handleOwnership: {\n ...mapped(\"passkeyHandles\"),\n isOwnedState: owned,\n ownedCondition: eq(column(\"passkeyHandles\", \"state\"), \"owned\"),\n decodeSubjectId: (row) => row.subjectId,\n },\n subjectIds: { toNative: s.toNativeSync, toSubject: s.toSubjectSync, equals: Object.is },\n constraints: requiredPasskeyCredentialConstraints,\n };\n\n const base = (feature: PasskeyFeature): BaseMapping => ({\n moduleId: feature.moduleId,\n authorityScope: namespace,\n read,\n module: {\n ...mapped(\"passkeyModules\"),\n status: \"active\",\n policyColumns: [\"policy\", \"policyRevision\"],\n isActiveStatus: active,\n activeCondition: eq(column(\"passkeyModules\", \"active\"), true),\n decodeMethodPolicy: (row) => Schema.decodeUnknownSync(policyJson)(row.policy),\n },\n flow: {\n ...mapped(\"passkeyFlows\"),\n states: {\n Pending: \"Pending\",\n Claimed: \"Claimed\",\n Verified: \"Verified\",\n Rejected: \"Rejected\",\n Ambiguous: \"Ambiguous\",\n RegistrationAccepted: \"RegistrationAccepted\",\n ProvisioningPending: \"ProvisioningPending\",\n },\n encodeInsert: () => ({}),\n },\n admission: mapped(\"passkeyAdmissions\"),\n charge: { ...mapped(\"passkeyCharges\"), encodeInsert: () => ({}) },\n clock: {\n encodeInstant: storage.encodeInstant,\n decodeInstant: storage.decodeInstantSync,\n engineNowMillis:\n dialect === \"pg\"\n ? sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)`\n : sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`,\n toMillis: (expression) => expression,\n fromMillis: (expression) => expression,\n },\n telemetry: { lastUsedAt: \"lastUsedAt\", encodeBackupState: (value) => value },\n constraints: requiredPasskeyPersistenceConstraints,\n });\n\n const management = (feature: PasskeyFeature): ManagementMapping => {\n const policy = feature.managementPolicy;\n\n if (policy === undefined)\n throw configurationError(`Missing passkey management policy for ${feature.moduleId}`);\n const c = getTableColumns(table(\"passkeyCredentials\"));\n const f = getTableColumns(table(\"credentials\"));\n\n const metadata = (subjectId: unknown) =>\n sql`exists(select 1 from ${subject} where ${sc[s.id]} = ${subjectId} and ${sc[s.status]} = ${s.activeValue})`;\n\n return {\n ...base(feature),\n write: {\n credential: {\n name: \"name\",\n createdAt: \"createdAt\",\n encodeInsert: ({ credential, subjectId, summary, marker }) => ({\n credentialId: credential.credentialId,\n subjectId,\n rpId: credential.rpId,\n protocolCredentialId: credential.protocolCredentialId,\n userHandle: credential.userHandle,\n credentialKey: \"\",\n handleKey: \"\",\n publicKey: credential.publicKey,\n algorithm: credential.algorithm,\n profile: Schema.encodeSync(profileJson)(credential.profile),\n credentialRevision: marker,\n active: true,\n primarySignIn: credential.primarySignIn,\n enrollmentUserVerified: credential.enrollmentUserVerified,\n backupEligible: credential.backupEligible,\n backupState: credential.backupState,\n counter: credential.counter,\n maximumCounter: credential.maximumCounter,\n name: summary.name,\n createdAt: storage.encodeInstant(summary.createdAtMillis),\n }),\n encodePrimarySignIn: (value) => value,\n encodeEnrollmentUserVerified: (value) => value,\n encodeBackupEligible: (value) => value,\n activeStatus: true,\n removedStatus: false,\n },\n authority: {\n encodeInsert: ({ subjectId, credential, marker }) => ({\n subjectId,\n credentialId: credential.credentialId,\n revision: marker,\n active: true,\n }),\n activeStatus: true,\n removedStatus: false,\n },\n credentialOwnership: {\n encodeInsert: ({ credential, marker }) => ({\n credentialKey: \"\",\n rpId: credential.rpId,\n protocolCredentialId: credential.protocolCredentialId,\n state: \"owned\",\n version: marker,\n }),\n ownedState: \"owned\",\n removedState: \"removed\",\n },\n handleOwnership: {\n encodeInsert: ({ subjectId, rpId, userHandle, marker }) => ({\n subjectId,\n rpId,\n userHandle,\n handleKey: \"\",\n state: \"owned\",\n version: marker,\n }),\n ownedState: \"owned\",\n },\n policy: {\n subjectColumns: Object.keys(sc),\n management: () => policy,\n requirement: s.actionRequirements,\n metadata,\n action: metadata,\n remainingSignIn: (subjectId, excluded, row) =>\n Effect.gen(function* () {\n const requirement = yield* Schema.decodeUnknownEffect(PasskeyRequirement)(\n yield* s.requirements(row),\n );\n\n const alternatives: SQL[] = [];\n\n // Only retain complete sign-in paths enabled by this Auth definition.\n // More involved combinations require an explicit application's predicate.\n if (\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n alternative.factors.every((factor) => factor === \"possession\"),\n )\n ) {\n const profiles = signInProfiles.map((profile) =>\n Schema.encodeSync(profileJson)(profile),\n );\n\n alternatives.push(sql`exists(\n select 1 from ${table(\"passkeyCredentials\")} join ${table(\"credentials\")}\n on ${f.credentialId} = ${c.credentialId} and ${f.subjectId} = ${c.subjectId}\n and ${f.revision} = ${c.credentialRevision} and ${f.active} = ${true}\n where ${c.subjectId} = ${subjectId} and ${c.credentialId} <> ${excluded}\n and ${c.active} = ${true} and ${c.primarySignIn} = ${true}\n and ${c.enrollmentUserVerified} = ${true} and ${inArray(c.profile, profiles)}\n )`);\n }\n if (\n passwordModules.length > 0 &&\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n !alternative.userVerified &&\n !alternative.phishingResistant &&\n alternative.factors.every((factor) => factor === \"knowledge\"),\n )\n ) {\n const p = getTableColumns(table(\"passwords\"));\n const i = getTableColumns(table(\"identifiers\"));\n\n alternatives.push(sql`exists(\n select 1 from ${table(\"passwords\")} join ${table(\"credentials\")}\n on ${f.credentialId} = ${p.credentialId} and ${f.subjectId} = ${p.subjectId}\n and ${f.revision} = ${p.credentialRevision} and ${f.active} = ${true}\n join ${table(\"identifiers\")} on ${i.subjectId} = ${p.subjectId}\n and ${i.active} = ${true} and ${i.namespace} = 'email'\n where ${p.subjectId} = ${subjectId} and ${p.credentialId} <> ${excluded}\n and ${inArray(p.moduleId, passwordModules)}\n )`);\n }\n\n return or(...alternatives) ?? sql`false`;\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause }),\n ),\n ),\n },\n },\n command: { ...mapped(\"passkeyCommands\"), encodeInsert: (input) => ({ ...input }) },\n managementConstraints: requiredPasskeyManagementConstraints,\n invalidation: {\n window: {\n trigger: \"credential-change\",\n existingSessions: \"immediate\",\n maximumExposureMillis: 0,\n oldAuthenticationEvidence: \"rejected\",\n },\n mutations: [],\n postcondition: ({ subjectId, securityRevision }) =>\n sql`exists(select 1 from ${subject} where ${sc[s.id]} = ${subjectId} and ${sc[s.securityRevision]} = ${securityRevision})`,\n },\n };\n };\n\n return { read, base, management, table };\n };\n\n const make: Backend<object, never>[\"passkeys\"] = Effect.fn(\"AuthPersistence.passkeys\")(\n function* ({ database, storage, namespace, dialect, features, passwordModules }) {\n const client = yield* SqlClient.SqlClient;\n\n const policies = yield* Effect.forEach(features, (feature) =>\n Effect.map(feature.policy, (policy) => ({ feature, policy })),\n );\n\n const m = yield* Effect.try({\n try: () =>\n mappings(\n storage,\n namespace,\n dialect,\n passwordModules,\n policies.flatMap(({ feature, policy }) => (feature.management ? [] : policy.profiles)),\n ),\n catch: () => configurationError(\"Invalid passkey table mappings\"),\n });\n\n const configuration: PasskeyTargetConfiguration = {\n mode: \"interactive\",\n dialect,\n locking: dialect === \"pg\",\n standaloneGuard: () =>\n Effect.serviceOption(client.transactionService).pipe(\n Effect.flatMap((value) =>\n value._tag === \"None\" ? Effect.void : Effect.fail(unavailable()),\n ),\n ),\n };\n\n // The backend has already checked the native query builder; schemas check stored values.\n const native = database as ProofSqlDatabase;\n\n yield* client.withTransaction(\n Effect.gen(function* () {\n if (dialect === \"pg\")\n yield* client`select pg_advisory_xact_lock(hashtext(${`${namespace}/passkeys`}))`;\n for (const { feature, policy } of policies) {\n const encoded = yield* Schema.encodeEffect(policyJson)(policy);\n\n const policyRevision = digest(\n yield* Schema.encodeEffect(seedJson)({\n policy,\n ...(feature.managementPolicy === undefined\n ? {}\n : { management: feature.managementPolicy }),\n }),\n );\n\n const module = m.table(\"passkeyModules\");\n const columns = getTableColumns(module);\n\n yield* native\n .insert(module)\n .values({ moduleId: feature.moduleId, active: true, policy: encoded, policyRevision })\n .onConflictDoNothing();\n\n const rows = yield* native\n .select()\n .from(module)\n .where(eq(columns.moduleId, feature.moduleId));\n\n const row = yield* Schema.decodeUnknownEffect(ModuleRow)(rows[0]);\n\n if (!row.active)\n return yield* configurationError(`Passkey module ${feature.moduleId} is disabled`);\n if (row.policyRevision !== policyRevision) {\n const previous = yield* Schema.decodeEffect(policyJson)(row.policy);\n\n if (policy.generation <= previous.generation)\n return yield* configurationError(\n `Increase the passkey policy generation to change ${feature.moduleId}`,\n );\n yield* native\n .update(module)\n .set({ policy: encoded, policyRevision })\n .where(\n and(\n eq(columns.moduleId, feature.moduleId),\n eq(columns.policyRevision, row.policyRevision),\n eq(columns.active, true),\n ),\n );\n\n const updated = yield* native\n .select()\n .from(module)\n .where(eq(columns.moduleId, feature.moduleId));\n\n const applied = yield* Schema.decodeUnknownEffect(ModuleRow)(updated[0]);\n\n if (!applied.active || applied.policyRevision !== policyRevision)\n return yield* configurationError(\n `Passkey policy changed while configuring ${feature.moduleId}`,\n );\n }\n yield* native\n .insert(m.table(\"passkeyAdmissions\"))\n .values({\n authorityScope: namespace,\n moduleId: feature.moduleId,\n version: policyRevision,\n ownerMarker: policyRevision,\n })\n .onConflictDoNothing();\n }\n }),\n );\n\n const credential = yield* makeTargetPasskeyCredentials<ReadMapping, never>(\n database,\n m.read,\n configuration,\n );\n\n const persistence = new Map<string, PasskeyPersistence[\"Service\"]>();\n const managers = new Map<string, PasskeyManagementPersistence[\"Service\"]>();\n const enrollment = new Map<string, PasskeyEnrollmentContext[\"Service\"]>();\n\n for (const feature of features) {\n if (feature.management) {\n const mapping = yield* Effect.try({\n try: () => m.management(feature),\n catch: () =>\n configurationError(`Invalid passkey management mapping for ${feature.moduleId}`),\n });\n\n const services = yield* makeTargetPasskeyManagement<ManagementMapping, never>(\n database,\n mapping,\n configuration,\n );\n\n persistence.set(feature.moduleId, services.passkeyPersistence);\n managers.set(feature.moduleId, services.passkeyManagementPersistence);\n enrollment.set(\n feature.moduleId,\n (yield* makeTargetPasskeyEnrollmentContext<ManagementMapping, never>(\n database,\n mapping,\n configuration,\n )).passkeyEnrollmentContext,\n );\n } else {\n persistence.set(\n feature.moduleId,\n (yield* makeTargetPasskeyPersistence<BaseMapping, never>(\n database,\n m.base(feature),\n configuration,\n )).passkeyPersistence,\n );\n }\n }\n\n const service = <A>(services: ReadonlyMap<string, A>, moduleId: string) => {\n const value = services.get(moduleId);\n\n return value === undefined ? Effect.fail(unavailable()) : Effect.succeed(value);\n };\n\n let context: Context.Context<never> = Context.make(\n PasskeyCredentials,\n credential.passkeyCredentials,\n ).pipe(\n Context.add(PasskeyPersistence, {\n issue: (input, prepare) =>\n Effect.flatMap(service(persistence, input.ceremony.moduleId), (s) =>\n s.issue(input, prepare),\n ),\n context: (input) =>\n Effect.flatMap(service(persistence, input.moduleId), (s) => s.context(input)),\n claim: (input, prepare) =>\n Effect.flatMap(service(persistence, input.ceremony.moduleId), (s) =>\n s.claim(input, prepare),\n ),\n settle: (input, prepare) =>\n Effect.flatMap(service(persistence, input.claim.ceremony.moduleId), (s) =>\n s.settle(input, prepare),\n ),\n cleanup: (input, prepare) =>\n Effect.flatMap(service(persistence, input.moduleId), (s) => s.cleanup(input, prepare)),\n }),\n );\n\n if (managers.size > 0)\n context = context.pipe(\n Context.add(PasskeyEnrollmentContext, {\n capture: (input) =>\n Effect.flatMap(service(enrollment, input.moduleId), (s) => s.capture(input)),\n }),\n Context.add(PasskeyManagementPersistence, {\n issueEnrollment: (input, prepare) =>\n Effect.flatMap(service(managers, input.ceremony.moduleId), (s) =>\n s.issueEnrollment(input, prepare),\n ),\n completeEnrollment: (input, prepare) =>\n Effect.flatMap(service(managers, input.claim.ceremony.moduleId), (s) =>\n s.completeEnrollment(input, prepare),\n ),\n list: (input) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.list(input)),\n inspectRemove: (input) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.inspectRemove(input)),\n rename: (input, prepare) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.rename(input, prepare)),\n remove: (input, prepare) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.remove(input, prepare)),\n }),\n );\n\n return context;\n },\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : configurationError(\"Unable to configure passkey persistence\"),\n ),\n );\n\n return make;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"passkeys.mjs","names":[],"sources":["../../src/internal/passkeys.ts"],"sourcesContent":["import {\n PasskeyCredentials,\n PasskeyCredential,\n PasskeyEnrollmentContext,\n PasskeyManagementPersistence,\n PasskeyManagementPolicy,\n PasskeyMethodPolicy,\n PasskeyPersistence,\n PasskeyProfile,\n PasskeyRequirement,\n PasskeyUnavailable,\n} from \"@yielded/auth/Passkey\";\nimport { digest } from \"@yielded/auth/Persistence\";\nimport type { SQL, Table } from \"drizzle-orm\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/unstable/sql\";\n\nimport {\n requiredPasskeyCredentialConstraints,\n requiredPasskeyPersistenceConstraints,\n type PasskeyCredentialMapping,\n type PasskeyPersistenceMapping,\n} from \"../drizzle/passkey-model\";\nimport {\n requiredPasskeyManagementConstraints,\n type PasskeyManagementMapping,\n} from \"../drizzle/passkey-write-model\";\nimport {\n PersistenceConfigurationError,\n type MappingInput,\n type PasskeyFeature,\n} from \"./configuration\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport { makePasskeyKernel } from \"./passkey-kernel\";\nimport type { PasskeyTargetConfiguration } from \"./passkey/target\";\nimport type { Backend } from \"./persistence\";\nimport type { ProofSqlDatabase } from \"./proof-kernel\";\nimport type { QueryOperations } from \"./query-operations\";\nimport { requireStandalone } from \"./standalone\";\nimport { storageTables, type StorageRole } from \"./storage-tables\";\n\nconst profileJson = Schema.fromJsonString(PasskeyProfile);\nconst policyJson = Schema.fromJsonString(PasskeyMethodPolicy);\n\nconst seedJson = Schema.fromJsonString(\n Schema.Struct({\n policy: PasskeyMethodPolicy,\n management: Schema.optionalKey(PasskeyManagementPolicy),\n }),\n);\n\nconst ModuleRow = Schema.Struct({\n active: Schema.Boolean,\n policy: Schema.String,\n policyRevision: Schema.String,\n});\n\nconst credentialData = PasskeyCredential.mapFields(\n ({ revision: _revision, active: _active, ...fields }) => fields,\n);\n\nconst unavailable = () => PasskeyUnavailable.make({});\nconst configurationError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\ntype ReadMapping = PasskeyCredentialMapping<Table, Table, Table, Table, Table, unknown>;\ntype BaseMapping = PasskeyPersistenceMapping<ReadMapping, Table, Table, Table, Table, unknown>;\ntype ManagementMapping = PasskeyManagementMapping<\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n Table,\n unknown\n>;\n\n/** Share the same passkey algorithms across raw SQL and Drizzle compilers. */\nexport const makeComposedPasskeys = (\n operations: QueryOperations,\n): Backend<object, never>[\"passkeys\"] => {\n const { and, eq, getTableColumns, inArray, or, sql } = operations;\n const { target, writeTarget } = makePasskeyKernel(operations);\n\n const {\n makeTargetPasskeyCredentials,\n makeTargetPasskeyEnrollmentContext,\n makeTargetPasskeyPersistence,\n } = target;\n\n const { makeTargetPasskeyManagement } = writeTarget;\n\n const mappings = (\n storage: MappingInput,\n namespace: string,\n dialect: \"pg\" | \"sqlite\",\n passwordModules: ReadonlyArray<string>,\n signInProfiles: ReadonlyArray<PasskeyProfile>,\n ) => {\n const table = (role: StorageRole): Table => {\n const value = storage.tables[role];\n\n if (value === undefined) throw configurationError(`Missing ${role} mapping`);\n\n // Backend validation owns the foreign table shape. Row values are decoded below.\n return value as Table;\n };\n\n const mapped = <Role extends StorageRole>(role: Role) => ({\n table: table(role),\n ...(Object.fromEntries(Object.keys(storageTables[role].columns).map((key) => [key, key])) as {\n readonly [Key in keyof (typeof storageTables)[Role][\"columns\"]]: Key;\n }),\n });\n\n const column = (role: StorageRole, key: string) => getTableColumns(table(role))[key];\n const s = storage.subjects;\n const subject = s.table as Table;\n const sc = getTableColumns(subject);\n const active = (value: unknown) => value === true;\n const owned = (value: unknown) => value === \"owned\";\n\n const read: ReadMapping = {\n subject: {\n table: subject,\n id: s.id,\n status: s.status,\n securityRevision: s.securityRevision,\n decodeId: (row) => row[s.id],\n isActiveStatus: (value) => Object.is(value, s.activeValue),\n activeCondition: eq(sc[s.status], s.activeValue),\n },\n credential: {\n ...mapped(\"passkeyCredentials\"),\n status: \"active\",\n decode: (row) =>\n Schema.decodeUnknownSync(credentialData)({\n ...row,\n profile: Schema.decodeUnknownSync(profileJson)(row.profile),\n }),\n decodeSubjectId: (row) => row.subjectId,\n isActiveStatus: active,\n activeCondition: eq(column(\"passkeyCredentials\", \"active\"), true),\n },\n authority: {\n ...mapped(\"credentials\"),\n status: \"active\",\n isActiveStatus: active,\n activeCondition: eq(column(\"credentials\", \"active\"), true),\n },\n credentialOwnership: {\n ...mapped(\"passkeyOwnership\"),\n isOwnedState: owned,\n ownedCondition: eq(column(\"passkeyOwnership\", \"state\"), \"owned\"),\n decodeSubjectId: (row) => row.subjectId,\n },\n handleOwnership: {\n ...mapped(\"passkeyHandles\"),\n isOwnedState: owned,\n ownedCondition: eq(column(\"passkeyHandles\", \"state\"), \"owned\"),\n decodeSubjectId: (row) => row.subjectId,\n },\n subjectIds: { toNative: s.toNativeSync, toSubject: s.toSubjectSync, equals: Object.is },\n constraints: requiredPasskeyCredentialConstraints,\n };\n\n const base = (feature: PasskeyFeature): BaseMapping => ({\n moduleId: feature.moduleId,\n authorityScope: namespace,\n read,\n module: {\n ...mapped(\"passkeyModules\"),\n status: \"active\",\n policyColumns: [\"policy\", \"policyRevision\"],\n isActiveStatus: active,\n activeCondition: eq(column(\"passkeyModules\", \"active\"), true),\n decodeMethodPolicy: (row) => Schema.decodeUnknownSync(policyJson)(row.policy),\n },\n flow: {\n ...mapped(\"passkeyFlows\"),\n states: {\n Pending: \"Pending\",\n Claimed: \"Claimed\",\n Verified: \"Verified\",\n Rejected: \"Rejected\",\n Ambiguous: \"Ambiguous\",\n RegistrationAccepted: \"RegistrationAccepted\",\n ProvisioningPending: \"ProvisioningPending\",\n },\n encodeInsert: () => ({}),\n },\n admission: mapped(\"passkeyAdmissions\"),\n charge: { ...mapped(\"passkeyCharges\"), encodeInsert: () => ({}) },\n clock: {\n encodeInstant: storage.encodeInstant,\n decodeInstant: storage.decodeInstantSync,\n engineNowMillis:\n dialect === \"pg\"\n ? sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)`\n : sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`,\n toMillis: (expression) => expression,\n fromMillis: (expression) => expression,\n },\n telemetry: { lastUsedAt: \"lastUsedAt\", encodeBackupState: (value) => value },\n constraints: requiredPasskeyPersistenceConstraints,\n });\n\n const management = (feature: PasskeyFeature): ManagementMapping => {\n const policy = feature.managementPolicy;\n\n if (policy === undefined)\n throw configurationError(`Missing passkey management policy for ${feature.moduleId}`);\n const c = getTableColumns(table(\"passkeyCredentials\"));\n const f = getTableColumns(table(\"credentials\"));\n\n const metadata = (subjectId: unknown) =>\n sql`exists(select 1 from ${subject} where ${sc[s.id]} = ${subjectId} and ${sc[s.status]} = ${s.activeValue})`;\n\n return {\n ...base(feature),\n write: {\n credential: {\n name: \"name\",\n createdAt: \"createdAt\",\n encodeInsert: ({ credential, subjectId, summary, marker }) => ({\n credentialId: credential.credentialId,\n subjectId,\n rpId: credential.rpId,\n protocolCredentialId: credential.protocolCredentialId,\n userHandle: credential.userHandle,\n credentialKey: \"\",\n handleKey: \"\",\n publicKey: credential.publicKey,\n algorithm: credential.algorithm,\n profile: Schema.encodeSync(profileJson)(credential.profile),\n credentialRevision: marker,\n active: true,\n primarySignIn: credential.primarySignIn,\n enrollmentUserVerified: credential.enrollmentUserVerified,\n backupEligible: credential.backupEligible,\n backupState: credential.backupState,\n counter: credential.counter,\n maximumCounter: credential.maximumCounter,\n name: summary.name,\n createdAt: storage.encodeInstant(summary.createdAtMillis),\n }),\n encodePrimarySignIn: (value) => value,\n encodeEnrollmentUserVerified: (value) => value,\n encodeBackupEligible: (value) => value,\n activeStatus: true,\n removedStatus: false,\n },\n authority: {\n encodeInsert: ({ subjectId, credential, marker }) => ({\n subjectId,\n credentialId: credential.credentialId,\n revision: marker,\n active: true,\n }),\n activeStatus: true,\n removedStatus: false,\n },\n credentialOwnership: {\n encodeInsert: ({ credential, marker }) => ({\n credentialKey: \"\",\n rpId: credential.rpId,\n protocolCredentialId: credential.protocolCredentialId,\n state: \"owned\",\n version: marker,\n }),\n ownedState: \"owned\",\n removedState: \"removed\",\n },\n handleOwnership: {\n encodeInsert: ({ subjectId, rpId, userHandle, marker }) => ({\n subjectId,\n rpId,\n userHandle,\n handleKey: \"\",\n state: \"owned\",\n version: marker,\n }),\n ownedState: \"owned\",\n },\n policy: {\n subjectColumns: Object.keys(sc),\n management: () => policy,\n requirement: s.actionRequirements,\n metadata,\n action: metadata,\n remainingSignIn: (subjectId, excluded, row) =>\n Effect.gen(function* () {\n const requirement = yield* Schema.decodeUnknownEffect(PasskeyRequirement)(\n yield* s.requirements(row),\n );\n\n const alternatives: SQL[] = [];\n\n // Only retain complete sign-in paths enabled by this Auth definition.\n // More involved combinations require an explicit application's predicate.\n if (\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n alternative.factors.every((factor) => factor === \"possession\"),\n )\n ) {\n const profiles = signInProfiles.map((profile) =>\n Schema.encodeSync(profileJson)(profile),\n );\n\n alternatives.push(sql`exists(\n select 1 from ${table(\"passkeyCredentials\")} join ${table(\"credentials\")}\n on ${f.credentialId} = ${c.credentialId} and ${f.subjectId} = ${c.subjectId}\n and ${f.revision} = ${c.credentialRevision} and ${f.active} = ${true}\n where ${c.subjectId} = ${subjectId} and ${c.credentialId} <> ${excluded}\n and ${c.active} = ${true} and ${c.primarySignIn} = ${true}\n and ${c.enrollmentUserVerified} = ${true} and ${inArray(c.profile, profiles)}\n )`);\n }\n if (\n passwordModules.length > 0 &&\n requirement.alternatives.some(\n (alternative) =>\n alternative.minimumCredentials === 1 &&\n !alternative.userVerified &&\n !alternative.phishingResistant &&\n alternative.factors.every((factor) => factor === \"knowledge\"),\n )\n ) {\n const p = getTableColumns(table(\"passwords\"));\n const i = getTableColumns(table(\"identifiers\"));\n\n alternatives.push(sql`exists(\n select 1 from ${table(\"passwords\")} join ${table(\"credentials\")}\n on ${f.credentialId} = ${p.credentialId} and ${f.subjectId} = ${p.subjectId}\n and ${f.revision} = ${p.credentialRevision} and ${f.active} = ${true}\n join ${table(\"identifiers\")} on ${i.subjectId} = ${p.subjectId}\n and ${i.active} = ${true} and ${i.namespace} = 'email'\n where ${p.subjectId} = ${subjectId} and ${p.credentialId} <> ${excluded}\n and ${inArray(p.moduleId, passwordModules)}\n )`);\n }\n\n return or(...alternatives) ?? sql`false`;\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause }),\n ),\n ),\n },\n },\n command: { ...mapped(\"passkeyCommands\"), encodeInsert: (input) => ({ ...input }) },\n managementConstraints: requiredPasskeyManagementConstraints,\n invalidation: {\n window: {\n trigger: \"credential-change\",\n existingSessions: \"immediate\",\n maximumExposureMillis: 0,\n oldAuthenticationEvidence: \"rejected\",\n },\n mutations: [],\n postcondition: ({ subjectId, securityRevision }) =>\n sql`exists(select 1 from ${subject} where ${sc[s.id]} = ${subjectId} and ${sc[s.securityRevision]} = ${securityRevision})`,\n },\n };\n };\n\n return { read, base, management, table };\n };\n\n const make: Backend<object, never>[\"passkeys\"] = Effect.fn(\"AuthPersistence.passkeys\")(\n function* ({ database, storage, namespace, dialect, features, passwordModules }) {\n const client = yield* SqlClient.SqlClient;\n\n const policies = yield* Effect.forEach(features, (feature) =>\n Effect.map(feature.policy, (policy) => ({ feature, policy })),\n );\n\n const m = yield* Effect.try({\n try: () =>\n mappings(\n storage,\n namespace,\n dialect,\n passwordModules,\n policies.flatMap(({ feature, policy }) => (feature.management ? [] : policy.profiles)),\n ),\n catch: () => configurationError(\"Invalid passkey table mappings\"),\n });\n\n const configuration: PasskeyTargetConfiguration = {\n mode: \"interactive\",\n dialect,\n locking: dialect === \"pg\",\n standaloneGuard: () => requireStandalone(unavailable, client),\n };\n\n // The backend has already checked the native query builder; schemas check stored values.\n const native = database as ProofSqlDatabase;\n\n yield* client.withTransaction(\n Effect.gen(function* () {\n if (dialect === \"pg\")\n yield* client`select pg_advisory_xact_lock(hashtext(${`${namespace}/passkeys`}))`;\n for (const { feature, policy } of policies) {\n const encoded = yield* Schema.encodeEffect(policyJson)(policy);\n\n const policyRevision = digest(\n yield* Schema.encodeEffect(seedJson)({\n policy,\n ...(feature.managementPolicy === undefined\n ? {}\n : { management: feature.managementPolicy }),\n }),\n );\n\n const module = m.table(\"passkeyModules\");\n const columns = getTableColumns(module);\n\n yield* native\n .insert(module)\n .values({ moduleId: feature.moduleId, active: true, policy: encoded, policyRevision })\n .onConflictDoNothing();\n\n const rows = yield* native\n .select()\n .from(module)\n .where(eq(columns.moduleId, feature.moduleId));\n\n const row = yield* Schema.decodeUnknownEffect(ModuleRow)(rows[0]);\n\n if (!row.active)\n return yield* configurationError(`Passkey module ${feature.moduleId} is disabled`);\n if (row.policyRevision !== policyRevision) {\n const previous = yield* Schema.decodeEffect(policyJson)(row.policy);\n\n if (policy.generation <= previous.generation)\n return yield* configurationError(\n `Increase the passkey policy generation to change ${feature.moduleId}`,\n );\n yield* native\n .update(module)\n .set({ policy: encoded, policyRevision })\n .where(\n and(\n eq(columns.moduleId, feature.moduleId),\n eq(columns.policyRevision, row.policyRevision),\n eq(columns.active, true),\n ),\n );\n\n const updated = yield* native\n .select()\n .from(module)\n .where(eq(columns.moduleId, feature.moduleId));\n\n const applied = yield* Schema.decodeUnknownEffect(ModuleRow)(updated[0]);\n\n if (!applied.active || applied.policyRevision !== policyRevision)\n return yield* configurationError(\n `Passkey policy changed while configuring ${feature.moduleId}`,\n );\n }\n yield* native\n .insert(m.table(\"passkeyAdmissions\"))\n .values({\n authorityScope: namespace,\n moduleId: feature.moduleId,\n version: policyRevision,\n ownerMarker: policyRevision,\n })\n .onConflictDoNothing();\n }\n }),\n );\n\n const credential = yield* makeTargetPasskeyCredentials<ReadMapping, never>(\n database,\n m.read,\n configuration,\n );\n\n const persistence = new Map<string, PasskeyPersistence[\"Service\"]>();\n const managers = new Map<string, PasskeyManagementPersistence[\"Service\"]>();\n const enrollment = new Map<string, PasskeyEnrollmentContext[\"Service\"]>();\n\n for (const feature of features) {\n if (feature.management) {\n const mapping = yield* Effect.try({\n try: () => m.management(feature),\n catch: () =>\n configurationError(`Invalid passkey management mapping for ${feature.moduleId}`),\n });\n\n const services = yield* makeTargetPasskeyManagement<ManagementMapping, never>(\n database,\n mapping,\n configuration,\n );\n\n persistence.set(feature.moduleId, services.passkeyPersistence);\n managers.set(feature.moduleId, services.passkeyManagementPersistence);\n enrollment.set(\n feature.moduleId,\n (yield* makeTargetPasskeyEnrollmentContext<ManagementMapping, never>(\n database,\n mapping,\n configuration,\n )).passkeyEnrollmentContext,\n );\n } else {\n persistence.set(\n feature.moduleId,\n (yield* makeTargetPasskeyPersistence<BaseMapping, never>(\n database,\n m.base(feature),\n configuration,\n )).passkeyPersistence,\n );\n }\n }\n\n const service = <A>(services: ReadonlyMap<string, A>, moduleId: string) => {\n const value = services.get(moduleId);\n\n return value === undefined ? Effect.fail(unavailable()) : Effect.succeed(value);\n };\n\n let context: Context.Context<never> = Context.make(\n PasskeyCredentials,\n credential.passkeyCredentials,\n ).pipe(\n Context.add(PasskeyPersistence, {\n issue: (input, prepare) =>\n Effect.flatMap(service(persistence, input.ceremony.moduleId), (s) =>\n s.issue(input, prepare),\n ),\n context: (input) =>\n Effect.flatMap(service(persistence, input.moduleId), (s) => s.context(input)),\n claim: (input, prepare) =>\n Effect.flatMap(service(persistence, input.ceremony.moduleId), (s) =>\n s.claim(input, prepare),\n ),\n settle: (input, prepare) =>\n Effect.flatMap(service(persistence, input.claim.ceremony.moduleId), (s) =>\n s.settle(input, prepare),\n ),\n cleanup: (input, prepare) =>\n Effect.flatMap(service(persistence, input.moduleId), (s) => s.cleanup(input, prepare)),\n }),\n );\n\n if (managers.size > 0)\n context = context.pipe(\n Context.add(PasskeyEnrollmentContext, {\n capture: (input) =>\n Effect.flatMap(service(enrollment, input.moduleId), (s) => s.capture(input)),\n }),\n Context.add(PasskeyManagementPersistence, {\n issueEnrollment: (input, prepare) =>\n Effect.flatMap(service(managers, input.ceremony.moduleId), (s) =>\n s.issueEnrollment(input, prepare),\n ),\n completeEnrollment: (input, prepare) =>\n Effect.flatMap(service(managers, input.claim.ceremony.moduleId), (s) =>\n s.completeEnrollment(input, prepare),\n ),\n list: (input) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.list(input)),\n inspectRemove: (input) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.inspectRemove(input)),\n rename: (input, prepare) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.rename(input, prepare)),\n remove: (input, prepare) =>\n Effect.flatMap(service(managers, input.moduleId), (s) => s.remove(input, prepare)),\n }),\n );\n\n return context;\n },\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : configurationError(\"Unable to configure passkey persistence\"),\n ),\n );\n\n return make;\n};\n"],"mappings":";;;;;;;;;;;;AAyCA,MAAM,cAAc,OAAO,eAAe,cAAc;AACxD,MAAM,aAAa,OAAO,eAAe,mBAAmB;AAE5D,MAAM,WAAW,OAAO,eACtB,OAAO,OAAO;CACZ,QAAQ;CACR,YAAY,OAAO,YAAY,uBAAuB;AACxD,CAAC,CACH;AAEA,MAAM,YAAY,OAAO,OAAO;CAC9B,QAAQ,OAAO;CACf,QAAQ,OAAO;CACf,gBAAgB,OAAO;AACzB,CAAC;AAED,MAAM,iBAAiB,kBAAkB,WACtC,EAAE,UAAU,WAAW,QAAQ,SAAS,GAAG,aAAa,MAC3D;AAEA,MAAM,oBAAoB,mBAAmB,KAAK,CAAC,CAAC;AACpD,MAAM,sBAAsB,WAAmB,8BAA8B,KAAK,EAAE,OAAO,CAAC;;AAmB5F,MAAa,wBACX,eACuC;CACvC,MAAM,EAAE,KAAK,IAAI,iBAAiB,SAAS,IAAI,QAAQ;CACvD,MAAM,EAAE,QAAQ,gBAAgB,kBAAkB,UAAU;CAE5D,MAAM,EACJ,8BACA,oCACA,iCACE;CAEJ,MAAM,EAAE,gCAAgC;CAExC,MAAM,YACJ,SACA,WACA,SACA,iBACA,mBACG;EACH,MAAM,SAAS,SAA6B;GAC1C,MAAM,QAAQ,QAAQ,OAAO;GAE7B,IAAI,UAAU,KAAA,GAAW,MAAM,mBAAmB,WAAW,KAAK,SAAS;GAG3E,OAAO;EACT;EAEA,MAAM,UAAoC,UAAgB;GACxD,OAAO,MAAM,IAAI;GACjB,GAAI,OAAO,YAAY,OAAO,KAAK,cAAc,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;EAG1F;EAEA,MAAM,UAAU,MAAmB,QAAgB,gBAAgB,MAAM,IAAI,CAAC,CAAC,CAAC;EAChF,MAAM,IAAI,QAAQ;EAClB,MAAM,UAAU,EAAE;EAClB,MAAM,KAAK,gBAAgB,OAAO;EAClC,MAAM,UAAU,UAAmB,UAAU;EAC7C,MAAM,SAAS,UAAmB,UAAU;EAE5C,MAAM,OAAoB;GACxB,SAAS;IACP,OAAO;IACP,IAAI,EAAE;IACN,QAAQ,EAAE;IACV,kBAAkB,EAAE;IACpB,WAAW,QAAQ,IAAI,EAAE;IACzB,iBAAiB,UAAU,OAAO,GAAG,OAAO,EAAE,WAAW;IACzD,iBAAiB,GAAG,GAAG,EAAE,SAAS,EAAE,WAAW;GACjD;GACA,YAAY;IACV,GAAG,OAAO,oBAAoB;IAC9B,QAAQ;IACR,SAAS,QACP,OAAO,kBAAkB,cAAc,CAAC,CAAC;KACvC,GAAG;KACH,SAAS,OAAO,kBAAkB,WAAW,CAAC,CAAC,IAAI,OAAO;IAC5D,CAAC;IACH,kBAAkB,QAAQ,IAAI;IAC9B,gBAAgB;IAChB,iBAAiB,GAAG,OAAO,sBAAsB,QAAQ,GAAG,IAAI;GAClE;GACA,WAAW;IACT,GAAG,OAAO,aAAa;IACvB,QAAQ;IACR,gBAAgB;IAChB,iBAAiB,GAAG,OAAO,eAAe,QAAQ,GAAG,IAAI;GAC3D;GACA,qBAAqB;IACnB,GAAG,OAAO,kBAAkB;IAC5B,cAAc;IACd,gBAAgB,GAAG,OAAO,oBAAoB,OAAO,GAAG,OAAO;IAC/D,kBAAkB,QAAQ,IAAI;GAChC;GACA,iBAAiB;IACf,GAAG,OAAO,gBAAgB;IAC1B,cAAc;IACd,gBAAgB,GAAG,OAAO,kBAAkB,OAAO,GAAG,OAAO;IAC7D,kBAAkB,QAAQ,IAAI;GAChC;GACA,YAAY;IAAE,UAAU,EAAE;IAAc,WAAW,EAAE;IAAe,QAAQ,OAAO;GAAG;GACtF,aAAa;EACf;EAEA,MAAM,QAAQ,aAA0C;GACtD,UAAU,QAAQ;GAClB,gBAAgB;GAChB;GACA,QAAQ;IACN,GAAG,OAAO,gBAAgB;IAC1B,QAAQ;IACR,eAAe,CAAC,UAAU,gBAAgB;IAC1C,gBAAgB;IAChB,iBAAiB,GAAG,OAAO,kBAAkB,QAAQ,GAAG,IAAI;IAC5D,qBAAqB,QAAQ,OAAO,kBAAkB,UAAU,CAAC,CAAC,IAAI,MAAM;GAC9E;GACA,MAAM;IACJ,GAAG,OAAO,cAAc;IACxB,QAAQ;KACN,SAAS;KACT,SAAS;KACT,UAAU;KACV,UAAU;KACV,WAAW;KACX,sBAAsB;KACtB,qBAAqB;IACvB;IACA,qBAAqB,CAAC;GACxB;GACA,WAAW,OAAO,mBAAmB;GACrC,QAAQ;IAAE,GAAG,OAAO,gBAAgB;IAAG,qBAAqB,CAAC;GAAG;GAChE,OAAO;IACL,eAAe,QAAQ;IACvB,eAAe,QAAQ;IACvB,iBACE,YAAY,OACR,GAAG,iEACH,GAAG;IACT,WAAW,eAAe;IAC1B,aAAa,eAAe;GAC9B;GACA,WAAW;IAAE,YAAY;IAAc,oBAAoB,UAAU;GAAM;GAC3E,aAAa;EACf;EAEA,MAAM,cAAc,YAA+C;GACjE,MAAM,SAAS,QAAQ;GAEvB,IAAI,WAAW,KAAA,GACb,MAAM,mBAAmB,yCAAyC,QAAQ,UAAU;GACtF,MAAM,IAAI,gBAAgB,MAAM,oBAAoB,CAAC;GACrD,MAAM,IAAI,gBAAgB,MAAM,aAAa,CAAC;GAE9C,MAAM,YAAY,cAChB,GAAG,wBAAwB,QAAQ,SAAS,GAAG,EAAE,IAAI,KAAK,UAAU,OAAO,GAAG,EAAE,QAAQ,KAAK,EAAE,YAAY;GAE7G,OAAO;IACL,GAAG,KAAK,OAAO;IACf,OAAO;KACL,YAAY;MACV,MAAM;MACN,WAAW;MACX,eAAe,EAAE,YAAY,WAAW,SAAS,cAAc;OAC7D,cAAc,WAAW;OACzB;OACA,MAAM,WAAW;OACjB,sBAAsB,WAAW;OACjC,YAAY,WAAW;OACvB,eAAe;OACf,WAAW;OACX,WAAW,WAAW;OACtB,WAAW,WAAW;OACtB,SAAS,OAAO,WAAW,WAAW,CAAC,CAAC,WAAW,OAAO;OAC1D,oBAAoB;OACpB,QAAQ;OACR,eAAe,WAAW;OAC1B,wBAAwB,WAAW;OACnC,gBAAgB,WAAW;OAC3B,aAAa,WAAW;OACxB,SAAS,WAAW;OACpB,gBAAgB,WAAW;OAC3B,MAAM,QAAQ;OACd,WAAW,QAAQ,cAAc,QAAQ,eAAe;MAC1D;MACA,sBAAsB,UAAU;MAChC,+BAA+B,UAAU;MACzC,uBAAuB,UAAU;MACjC,cAAc;MACd,eAAe;KACjB;KACA,WAAW;MACT,eAAe,EAAE,WAAW,YAAY,cAAc;OACpD;OACA,cAAc,WAAW;OACzB,UAAU;OACV,QAAQ;MACV;MACA,cAAc;MACd,eAAe;KACjB;KACA,qBAAqB;MACnB,eAAe,EAAE,YAAY,cAAc;OACzC,eAAe;OACf,MAAM,WAAW;OACjB,sBAAsB,WAAW;OACjC,OAAO;OACP,SAAS;MACX;MACA,YAAY;MACZ,cAAc;KAChB;KACA,iBAAiB;MACf,eAAe,EAAE,WAAW,MAAM,YAAY,cAAc;OAC1D;OACA;OACA;OACA,WAAW;OACX,OAAO;OACP,SAAS;MACX;MACA,YAAY;KACd;KACA,QAAQ;MACN,gBAAgB,OAAO,KAAK,EAAE;MAC9B,kBAAkB;MAClB,aAAa,EAAE;MACf;MACA,QAAQ;MACR,kBAAkB,WAAW,UAAU,QACrC,OAAO,IAAI,aAAa;OACtB,MAAM,cAAc,OAAO,OAAO,oBAAoB,kBAAkB,CAAC,CACvE,OAAO,EAAE,aAAa,GAAG,CAC3B;OAEA,MAAM,eAAsB,CAAC;OAI7B,IACE,YAAY,aAAa,MACtB,gBACC,YAAY,uBAAuB,KACnC,YAAY,QAAQ,OAAO,WAAW,WAAW,YAAY,CACjE,GACA;QACA,MAAM,WAAW,eAAe,KAAK,YACnC,OAAO,WAAW,WAAW,CAAC,CAAC,OAAO,CACxC;QAEA,aAAa,KAAK,GAAG;kCACL,MAAM,oBAAoB,EAAE,QAAQ,MAAM,aAAa,EAAE;uBACpE,EAAE,aAAa,KAAK,EAAE,aAAa,OAAO,EAAE,UAAU,KAAK,EAAE,UAAU;0BACpE,EAAE,SAAS,KAAK,EAAE,mBAAmB,OAAO,EAAE,OAAO,KAAK,KAAK;0BAC/D,EAAE,UAAU,KAAK,UAAU,OAAO,EAAE,aAAa,MAAM,SAAS;0BAChE,EAAE,OAAO,KAAK,KAAK,OAAO,EAAE,cAAc,KAAK,KAAK;0BACpD,EAAE,uBAAuB,KAAK,KAAK,OAAO,QAAQ,EAAE,SAAS,QAAQ,EAAE;kBAC/E;OACF;OACA,IACE,gBAAgB,SAAS,KACzB,YAAY,aAAa,MACtB,gBACC,YAAY,uBAAuB,KACnC,CAAC,YAAY,gBACb,CAAC,YAAY,qBACb,YAAY,QAAQ,OAAO,WAAW,WAAW,WAAW,CAChE,GACA;QACA,MAAM,IAAI,gBAAgB,MAAM,WAAW,CAAC;QAC5C,MAAM,IAAI,gBAAgB,MAAM,aAAa,CAAC;QAE9C,aAAa,KAAK,GAAG;kCACL,MAAM,WAAW,EAAE,QAAQ,MAAM,aAAa,EAAE;uBAC3D,EAAE,aAAa,KAAK,EAAE,aAAa,OAAO,EAAE,UAAU,KAAK,EAAE,UAAU;0BACpE,EAAE,SAAS,KAAK,EAAE,mBAAmB,OAAO,EAAE,OAAO,KAAK,KAAK;yBAChE,MAAM,aAAa,EAAE,MAAM,EAAE,UAAU,KAAK,EAAE,UAAU;0BACvD,EAAE,OAAO,KAAK,KAAK,OAAO,EAAE,UAAU;0BACtC,EAAE,UAAU,KAAK,UAAU,OAAO,EAAE,aAAa,MAAM,SAAS;0BAChE,QAAQ,EAAE,UAAU,eAAe,EAAE;kBAC7C;OACF;OAEA,OAAO,GAAG,GAAG,YAAY,KAAK,GAAG;MACnC,CAAC,CAAC,CAAC,KACD,OAAO,UAAU,UACf,wBAAwB,KAAK;OAAE,WAAW;OAAW;MAAM,CAAC,CAC9D,CACF;KACJ;IACF;IACA,SAAS;KAAE,GAAG,OAAO,iBAAiB;KAAG,eAAe,WAAW,EAAE,GAAG,MAAM;IAAG;IACjF,uBAAuB;IACvB,cAAc;KACZ,QAAQ;MACN,SAAS;MACT,kBAAkB;MAClB,uBAAuB;MACvB,2BAA2B;KAC7B;KACA,WAAW,CAAC;KACZ,gBAAgB,EAAE,WAAW,uBAC3B,GAAG,wBAAwB,QAAQ,SAAS,GAAG,EAAE,IAAI,KAAK,UAAU,OAAO,GAAG,EAAE,kBAAkB,KAAK,iBAAiB;IAC5H;GACF;EACF;EAEA,OAAO;GAAE;GAAM;GAAM;GAAY;EAAM;CACzC;CA2NA,OAzNiD,OAAO,GAAG,0BAA0B,CAAC,CACpF,WAAW,EAAE,UAAU,SAAS,WAAW,SAAS,UAAU,mBAAmB;EAC/E,MAAM,SAAS,OAAO,UAAU;EAEhC,MAAM,WAAW,OAAO,OAAO,QAAQ,WAAW,YAChD,OAAO,IAAI,QAAQ,SAAS,YAAY;GAAE;GAAS;EAAO,EAAE,CAC9D;EAEA,MAAM,IAAI,OAAO,OAAO,IAAI;GAC1B,WACE,SACE,SACA,WACA,SACA,iBACA,SAAS,SAAS,EAAE,SAAS,aAAc,QAAQ,aAAa,CAAC,IAAI,OAAO,QAAS,CACvF;GACF,aAAa,mBAAmB,gCAAgC;EAClE,CAAC;EAED,MAAM,gBAA4C;GAChD,MAAM;GACN;GACA,SAAS,YAAY;GACrB,uBAAuB,kBAAkB,aAAa,MAAM;EAC9D;EAGA,MAAM,SAAS;EAEf,OAAO,OAAO,gBACZ,OAAO,IAAI,aAAa;GACtB,IAAI,YAAY,MACd,OAAO,MAAM,yCAAyC,GAAG,UAAU,WAAW;GAChF,KAAK,MAAM,EAAE,SAAS,YAAY,UAAU;IAC1C,MAAM,UAAU,OAAO,OAAO,aAAa,UAAU,CAAC,CAAC,MAAM;IAE7D,MAAM,iBAAiB,OACrB,OAAO,OAAO,aAAa,QAAQ,CAAC,CAAC;KACnC;KACA,GAAI,QAAQ,qBAAqB,KAAA,IAC7B,CAAC,IACD,EAAE,YAAY,QAAQ,iBAAiB;IAC7C,CAAC,CACH;IAEA,MAAM,SAAS,EAAE,MAAM,gBAAgB;IACvC,MAAM,UAAU,gBAAgB,MAAM;IAEtC,OAAO,OACJ,OAAO,MAAM,CAAC,CACd,OAAO;KAAE,UAAU,QAAQ;KAAU,QAAQ;KAAM,QAAQ;KAAS;IAAe,CAAC,CAAC,CACrF,oBAAoB;IAEvB,MAAM,OAAO,OAAO,OACjB,OAAO,CAAC,CACR,KAAK,MAAM,CAAC,CACZ,MAAM,GAAG,QAAQ,UAAU,QAAQ,QAAQ,CAAC;IAE/C,MAAM,MAAM,OAAO,OAAO,oBAAoB,SAAS,CAAC,CAAC,KAAK,EAAE;IAEhE,IAAI,CAAC,IAAI,QACP,OAAO,OAAO,mBAAmB,kBAAkB,QAAQ,SAAS,aAAa;IACnF,IAAI,IAAI,mBAAmB,gBAAgB;KACzC,MAAM,WAAW,OAAO,OAAO,aAAa,UAAU,CAAC,CAAC,IAAI,MAAM;KAElE,IAAI,OAAO,cAAc,SAAS,YAChC,OAAO,OAAO,mBACZ,oDAAoD,QAAQ,UAC9D;KACF,OAAO,OACJ,OAAO,MAAM,CAAC,CACd,IAAI;MAAE,QAAQ;MAAS;KAAe,CAAC,CAAC,CACxC,MACC,IACE,GAAG,QAAQ,UAAU,QAAQ,QAAQ,GACrC,GAAG,QAAQ,gBAAgB,IAAI,cAAc,GAC7C,GAAG,QAAQ,QAAQ,IAAI,CACzB,CACF;KAEF,MAAM,UAAU,OAAO,OACpB,OAAO,CAAC,CACR,KAAK,MAAM,CAAC,CACZ,MAAM,GAAG,QAAQ,UAAU,QAAQ,QAAQ,CAAC;KAE/C,MAAM,UAAU,OAAO,OAAO,oBAAoB,SAAS,CAAC,CAAC,QAAQ,EAAE;KAEvE,IAAI,CAAC,QAAQ,UAAU,QAAQ,mBAAmB,gBAChD,OAAO,OAAO,mBACZ,4CAA4C,QAAQ,UACtD;IACJ;IACA,OAAO,OACJ,OAAO,EAAE,MAAM,mBAAmB,CAAC,CAAC,CACpC,OAAO;KACN,gBAAgB;KAChB,UAAU,QAAQ;KAClB,SAAS;KACT,aAAa;IACf,CAAC,CAAC,CACD,oBAAoB;GACzB;EACF,CAAC,CACH;EAEA,MAAM,aAAa,OAAO,6BACxB,UACA,EAAE,MACF,aACF;EAEA,MAAM,8BAAc,IAAI,IAA2C;EACnE,MAAM,2BAAW,IAAI,IAAqD;EAC1E,MAAM,6BAAa,IAAI,IAAiD;EAExE,KAAK,MAAM,WAAW,UACpB,IAAI,QAAQ,YAAY;GACtB,MAAM,UAAU,OAAO,OAAO,IAAI;IAChC,WAAW,EAAE,WAAW,OAAO;IAC/B,aACE,mBAAmB,0CAA0C,QAAQ,UAAU;GACnF,CAAC;GAED,MAAM,WAAW,OAAO,4BACtB,UACA,SACA,aACF;GAEA,YAAY,IAAI,QAAQ,UAAU,SAAS,kBAAkB;GAC7D,SAAS,IAAI,QAAQ,UAAU,SAAS,4BAA4B;GACpE,WAAW,IACT,QAAQ,WACP,OAAO,mCACN,UACA,SACA,aACF,EAAA,CAAG,wBACL;EACF,OACE,YAAY,IACV,QAAQ,WACP,OAAO,6BACN,UACA,EAAE,KAAK,OAAO,GACd,aACF,EAAA,CAAG,kBACL;EAIJ,MAAM,WAAc,UAAkC,aAAqB;GACzE,MAAM,QAAQ,SAAS,IAAI,QAAQ;GAEnC,OAAO,UAAU,KAAA,IAAY,OAAO,KAAK,YAAY,CAAC,IAAI,OAAO,QAAQ,KAAK;EAChF;EAEA,IAAI,UAAkC,QAAQ,KAC5C,oBACA,WAAW,kBACb,CAAC,CAAC,KACA,QAAQ,IAAI,oBAAoB;GAC9B,QAAQ,OAAO,YACb,OAAO,QAAQ,QAAQ,aAAa,MAAM,SAAS,QAAQ,IAAI,MAC7D,EAAE,MAAM,OAAO,OAAO,CACxB;GACF,UAAU,UACR,OAAO,QAAQ,QAAQ,aAAa,MAAM,QAAQ,IAAI,MAAM,EAAE,QAAQ,KAAK,CAAC;GAC9E,QAAQ,OAAO,YACb,OAAO,QAAQ,QAAQ,aAAa,MAAM,SAAS,QAAQ,IAAI,MAC7D,EAAE,MAAM,OAAO,OAAO,CACxB;GACF,SAAS,OAAO,YACd,OAAO,QAAQ,QAAQ,aAAa,MAAM,MAAM,SAAS,QAAQ,IAAI,MACnE,EAAE,OAAO,OAAO,OAAO,CACzB;GACF,UAAU,OAAO,YACf,OAAO,QAAQ,QAAQ,aAAa,MAAM,QAAQ,IAAI,MAAM,EAAE,QAAQ,OAAO,OAAO,CAAC;EACzF,CAAC,CACH;EAEA,IAAI,SAAS,OAAO,GAClB,UAAU,QAAQ,KAChB,QAAQ,IAAI,0BAA0B,EACpC,UAAU,UACR,OAAO,QAAQ,QAAQ,YAAY,MAAM,QAAQ,IAAI,MAAM,EAAE,QAAQ,KAAK,CAAC,EAC/E,CAAC,GACD,QAAQ,IAAI,8BAA8B;GACxC,kBAAkB,OAAO,YACvB,OAAO,QAAQ,QAAQ,UAAU,MAAM,SAAS,QAAQ,IAAI,MAC1D,EAAE,gBAAgB,OAAO,OAAO,CAClC;GACF,qBAAqB,OAAO,YAC1B,OAAO,QAAQ,QAAQ,UAAU,MAAM,MAAM,SAAS,QAAQ,IAAI,MAChE,EAAE,mBAAmB,OAAO,OAAO,CACrC;GACF,OAAO,UACL,OAAO,QAAQ,QAAQ,UAAU,MAAM,QAAQ,IAAI,MAAM,EAAE,KAAK,KAAK,CAAC;GACxE,gBAAgB,UACd,OAAO,QAAQ,QAAQ,UAAU,MAAM,QAAQ,IAAI,MAAM,EAAE,cAAc,KAAK,CAAC;GACjF,SAAS,OAAO,YACd,OAAO,QAAQ,QAAQ,UAAU,MAAM,QAAQ,IAAI,MAAM,EAAE,OAAO,OAAO,OAAO,CAAC;GACnF,SAAS,OAAO,YACd,OAAO,QAAQ,QAAQ,UAAU,MAAM,QAAQ,IAAI,MAAM,EAAE,OAAO,OAAO,OAAO,CAAC;EACrF,CAAC,CACH;EAEF,OAAO;CACT,GACA,OAAO,UAAU,UACf,OAAO,GAAG,6BAA6B,CAAC,CAAC,KAAK,IAC1C,QACA,mBAAmB,yCAAyC,CAClE,CAGQ;AACZ"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PersistenceConfigurationError } from "./configuration.mjs";
|
|
2
2
|
import { PersistenceMappingError } from "./mapping-error.mjs";
|
|
3
|
+
import { requireStandalone } from "./standalone.mjs";
|
|
3
4
|
import { makeTransactionKernel } from "./transaction-kernel.mjs";
|
|
4
5
|
import { makeTransactionExecutionKernel } from "./transaction-execution-kernel.mjs";
|
|
5
6
|
import { storageTables, tableDefinition } from "./storage-tables.mjs";
|
|
@@ -11,7 +12,7 @@ import { makeRegistrationAuthority } from "./registration.mjs";
|
|
|
11
12
|
import { makeSessionKernel } from "./session-kernel.mjs";
|
|
12
13
|
import { makeMappings } from "./storage-mapping.mjs";
|
|
13
14
|
import { validateStorage } from "./storage-validation.mjs";
|
|
14
|
-
import { Context, Effect, Layer,
|
|
15
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
15
16
|
import { SqlClient } from "effect/unstable/sql";
|
|
16
17
|
import { digest, hooksLayer, randomId } from "@yielded/auth/Persistence";
|
|
17
18
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
@@ -153,7 +154,7 @@ const createPersistence = (backend) => {
|
|
|
153
154
|
}
|
|
154
155
|
yield* validateStorage(client, dialect, backend.describe(storage.subjects.table), [[storage.subjects.id]]);
|
|
155
156
|
const mappings = makeMappings(storage);
|
|
156
|
-
const standalone = (error) =>
|
|
157
|
+
const standalone = (error) => requireStandalone(error, client);
|
|
157
158
|
const native = database;
|
|
158
159
|
const options = {
|
|
159
160
|
mode: "interactive",
|