@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.
Files changed (119) hide show
  1. package/README.md +9 -0
  2. package/dist/DrizzleD1.d.mts +9 -9
  3. package/dist/DrizzleLibsql.d.mts +25 -25
  4. package/dist/DrizzleLibsql.mjs +7 -22
  5. package/dist/DrizzleLibsql.mjs.map +1 -1
  6. package/dist/DrizzleMysql2.d.mts +15 -15
  7. package/dist/DrizzlePglite.d.mts +9 -9
  8. package/dist/DrizzlePostgres.d.mts +15 -15
  9. package/dist/DrizzleSqliteBun.d.mts +18 -18
  10. package/dist/DrizzleSqliteDo.d.mts +29 -29
  11. package/dist/DrizzleSqliteNode.d.mts +24 -24
  12. package/dist/DrizzleSqliteWasm.d.mts +24 -24
  13. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  14. package/dist/drizzle/D1BatchStatements.d.mts +1 -2
  15. package/dist/drizzle/SuppliedService.d.mts +1 -2
  16. package/dist/drizzle/d1-emails.d.mts +5 -6
  17. package/dist/drizzle/d1-identity.d.mts +2 -3
  18. package/dist/drizzle/d1-oauth.d.mts +10 -11
  19. package/dist/drizzle/d1-passkey.d.mts +5 -6
  20. package/dist/drizzle/d1-password-prepared.d.mts +2 -3
  21. package/dist/drizzle/d1-passwords.d.mts +4 -5
  22. package/dist/drizzle/d1-phone.d.mts +2 -3
  23. package/dist/drizzle/d1-planning.d.mts +1 -2
  24. package/dist/drizzle/d1-proofs.d.mts +2 -3
  25. package/dist/drizzle/d1-sessions.d.mts +10 -11
  26. package/dist/drizzle/d1-totp.d.mts +2 -3
  27. package/dist/drizzle/email-model.d.mts +30 -31
  28. package/dist/drizzle/email-registration.d.mts +1 -2
  29. package/dist/drizzle/email-target.d.mts +3 -4
  30. package/dist/drizzle/model.d.mts +42 -42
  31. package/dist/drizzle/model.mjs +4 -6
  32. package/dist/drizzle/model.mjs.map +1 -1
  33. package/dist/drizzle/mysql-emails.d.mts +7 -8
  34. package/dist/drizzle/mysql-identity.d.mts +2 -3
  35. package/dist/drizzle/mysql-password-prepared.d.mts +3 -4
  36. package/dist/drizzle/mysql-passwords.d.mts +6 -7
  37. package/dist/drizzle/mysql-proofs.d.mts +3 -4
  38. package/dist/drizzle/mysql-sessions.d.mts +15 -16
  39. package/dist/drizzle/mysql.d.mts +9 -10
  40. package/dist/drizzle/mysql.mjs +1 -1
  41. package/dist/drizzle/oauth-connected-model.d.mts +21 -22
  42. package/dist/drizzle/oauth-connected-reference.d.mts +1 -2
  43. package/dist/drizzle/oauth-connected-state.d.mts +1950 -7
  44. package/dist/drizzle/oauth-connected-target.d.mts +9 -10
  45. package/dist/drizzle/oauth-flow.d.mts +22 -2
  46. package/dist/drizzle/oauth-model.d.mts +45 -46
  47. package/dist/drizzle/oauth-owner.d.mts +10 -2
  48. package/dist/drizzle/oauth-target.d.mts +9 -10
  49. package/dist/drizzle/passkey-model.d.mts +34 -35
  50. package/dist/drizzle/passkey-registration-ceremony-model.d.mts +5 -6
  51. package/dist/drizzle/passkey-write-model.d.mts +13 -14
  52. package/dist/drizzle/password-model.d.mts +29 -30
  53. package/dist/drizzle/password-prepared-model.d.mts +10 -11
  54. package/dist/drizzle/password-prepared-target.d.mts +1 -2
  55. package/dist/drizzle/password-registration.d.mts +1 -2
  56. package/dist/drizzle/password-target.d.mts +2 -3
  57. package/dist/drizzle/pg-emails.d.mts +7 -8
  58. package/dist/drizzle/pg-password-prepared.d.mts +3 -4
  59. package/dist/drizzle/pg-passwords.d.mts +6 -7
  60. package/dist/drizzle/pg-proofs.d.mts +3 -4
  61. package/dist/drizzle/pg-sessions.d.mts +15 -16
  62. package/dist/drizzle/pg.d.mts +11 -12
  63. package/dist/drizzle/pg.mjs +1 -1
  64. package/dist/drizzle/phone-model.d.mts +9 -10
  65. package/dist/drizzle/phone-target.d.mts +1 -2
  66. package/dist/drizzle/proof-model.d.mts +25 -26
  67. package/dist/drizzle/proof-target.d.mts +1 -2
  68. package/dist/drizzle/session-model.d.mts +25 -26
  69. package/dist/drizzle/session-target.d.mts +4 -5
  70. package/dist/drizzle/sqlite.d.mts +9 -10
  71. package/dist/drizzle/sqlite.mjs +1 -1
  72. package/dist/drizzle/standalone-guard.mjs +3 -5
  73. package/dist/drizzle/standalone-guard.mjs.map +1 -1
  74. package/dist/drizzle/step-up-model.d.mts +6 -7
  75. package/dist/drizzle/totp-model.d.mts +7 -8
  76. package/dist/drizzle/totp-state.d.mts +2 -3
  77. package/dist/drizzle/totp-target.d.mts +1 -2
  78. package/dist/drizzle/transaction-mysql.mjs +1 -0
  79. package/dist/drizzle/transaction-mysql.mjs.map +1 -1
  80. package/dist/drizzle/transaction-owner.d.mts +3 -2
  81. package/dist/index.d.mts +3 -1
  82. package/dist/index.mjs +3 -1
  83. package/dist/internal/configuration.d.mts +19 -19
  84. package/dist/internal/mapping-error.d.mts +2 -3
  85. package/dist/internal/oauth-app.d.mts +11 -0
  86. package/dist/internal/oauth-app.mjs +57 -0
  87. package/dist/internal/oauth-app.mjs.map +1 -0
  88. package/dist/internal/oauth-server.d.mts +10 -0
  89. package/dist/internal/oauth-server.mjs +66 -0
  90. package/dist/internal/oauth-server.mjs.map +1 -0
  91. package/dist/internal/passkey/target.d.mts +2 -3
  92. package/dist/internal/passkeys.mjs +2 -1
  93. package/dist/internal/passkeys.mjs.map +1 -1
  94. package/dist/internal/persistence.mjs +3 -2
  95. package/dist/internal/persistence.mjs.map +1 -1
  96. package/dist/internal/sql-persistence.d.mts +1 -2
  97. package/dist/internal/sql-table.d.mts +6 -7
  98. package/dist/internal/sql-table.mjs +12 -2
  99. package/dist/internal/sql-table.mjs.map +1 -1
  100. package/dist/internal/standalone.mjs +13 -0
  101. package/dist/internal/standalone.mjs.map +1 -0
  102. package/dist/internal/storage-tables.d.mts +5 -6
  103. package/dist/internal/transaction-execution-kernel.d.mts +2 -3
  104. package/dist/internal/transaction-execution-kernel.mjs +3 -5
  105. package/dist/internal/transaction-execution-kernel.mjs.map +1 -1
  106. package/dist/internal/transaction-kernel.d.mts +49 -2
  107. package/package.json +1 -1
  108. package/src/DrizzleLibsql.ts +10 -54
  109. package/src/drizzle/model.ts +8 -10
  110. package/src/drizzle/standalone-guard.ts +4 -9
  111. package/src/drizzle/transaction-mysql.ts +2 -0
  112. package/src/index.ts +2 -0
  113. package/src/internal/oauth-app.ts +82 -0
  114. package/src/internal/oauth-server.ts +89 -0
  115. package/src/internal/passkeys.ts +2 -6
  116. package/src/internal/persistence.ts +3 -5
  117. package/src/internal/sql-table.ts +17 -2
  118. package/src/internal/standalone.ts +30 -0
  119. 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
- export { AuthPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
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
- export { AuthPersistence, PersistenceConfigurationError, PersistenceMappingError, StorageColumn, StorageTable };
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 { BoundPersistence, ClaimsCodec, ConfigId, Definition, MappingInput, PasskeyFeature, PasskeyRequirement$1 as PasskeyRequirement, PersistenceApi, PersistenceConfigurationError, Ports, Provisioning, ProvisioningId, ProvisioningRequirement, Roles, StorageLayout, Strategy, SubjectMapping, SubjectOptions, TimestampOptions };
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: () => Effect.serviceOption(client.transactionService).pipe(Effect.flatMap((value) => value._tag === "None" ? Effect.void : Effect.fail(unavailable())))
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":"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"}
@@ -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, Option, Schema } from "effect";
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) => Effect.serviceOption(client.transactionService).pipe(Effect.flatMap((value) => Option.isNone(value) ? Effect.void : Effect.fail(error())));
157
+ const standalone = (error) => requireStandalone(error, client);
157
158
  const native = database;
158
159
  const options = {
159
160
  mode: "interactive",