@effect-auth/core 0.1.0-alpha.18 → 0.1.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.md +4 -5
  2. package/dist/DevEmail.d.ts +44 -0
  3. package/dist/DevEmail.d.ts.map +1 -0
  4. package/dist/DevEmail.js +115 -0
  5. package/dist/DevEmail.js.map +1 -0
  6. package/dist/DevelopmentSeed.d.ts +47 -0
  7. package/dist/DevelopmentSeed.d.ts.map +1 -0
  8. package/dist/DevelopmentSeed.js +337 -0
  9. package/dist/DevelopmentSeed.js.map +1 -0
  10. package/dist/DrizzleBunSqliteStorage.d.ts +1 -1
  11. package/dist/DrizzleBunSqliteStorage.d.ts.map +1 -1
  12. package/dist/DrizzleD1SqliteStorage.d.ts +1 -1
  13. package/dist/DrizzleD1SqliteStorage.d.ts.map +1 -1
  14. package/dist/DrizzleEffectSqliteStorage.d.ts +1 -1
  15. package/dist/DrizzleEffectSqliteStorage.d.ts.map +1 -1
  16. package/dist/DrizzleNodeSqliteStorage.d.ts +1 -1
  17. package/dist/DrizzleNodeSqliteStorage.d.ts.map +1 -1
  18. package/dist/DrizzlePostgresStorage.d.ts +26 -0
  19. package/dist/DrizzlePostgresStorage.d.ts.map +1 -0
  20. package/dist/DrizzlePostgresStorage.js +14 -0
  21. package/dist/DrizzlePostgresStorage.js.map +1 -0
  22. package/dist/EffectQbPostgresStorage.d.ts +8 -1
  23. package/dist/EffectQbPostgresStorage.d.ts.map +1 -1
  24. package/dist/EffectQbPostgresStorage.js +359 -2
  25. package/dist/EffectQbPostgresStorage.js.map +1 -1
  26. package/dist/EffectQbSqliteStorage.d.ts +42 -2
  27. package/dist/EffectQbSqliteStorage.d.ts.map +1 -1
  28. package/dist/EffectQbSqliteStorage.js +337 -1
  29. package/dist/EffectQbSqliteStorage.js.map +1 -1
  30. package/dist/HttpApi/Api.d.ts +151 -98
  31. package/dist/HttpApi/Api.d.ts.map +1 -1
  32. package/dist/HttpApi/Api.js +122 -72
  33. package/dist/HttpApi/Api.js.map +1 -1
  34. package/dist/HttpApi/ClientApi.d.ts +136 -136
  35. package/dist/HttpApi/Endpoints.d.ts +33 -1
  36. package/dist/HttpApi/Endpoints.d.ts.map +1 -1
  37. package/dist/HttpApi/Endpoints.js +31 -2
  38. package/dist/HttpApi/Endpoints.js.map +1 -1
  39. package/dist/HttpApi/Errors.d.ts +11 -3
  40. package/dist/HttpApi/Errors.d.ts.map +1 -1
  41. package/dist/HttpApi/Errors.js +16 -0
  42. package/dist/HttpApi/Errors.js.map +1 -1
  43. package/dist/HttpApi/Middleware.d.ts +12 -0
  44. package/dist/HttpApi/Middleware.d.ts.map +1 -1
  45. package/dist/HttpApi/Middleware.js +8 -0
  46. package/dist/HttpApi/Middleware.js.map +1 -1
  47. package/dist/HttpApi/OAuthDeviceAuthorization.d.ts +106 -0
  48. package/dist/HttpApi/OAuthDeviceAuthorization.d.ts.map +1 -0
  49. package/dist/HttpApi/OAuthDeviceAuthorization.js +415 -0
  50. package/dist/HttpApi/OAuthDeviceAuthorization.js.map +1 -0
  51. package/dist/HttpApi/OAuthToken.d.ts +1 -1
  52. package/dist/HttpApi/OAuthToken.d.ts.map +1 -1
  53. package/dist/HttpApi/OAuthToken.js +1 -1
  54. package/dist/HttpApi/OAuthToken.js.map +1 -1
  55. package/dist/HttpApi/Operations/OAuthDeviceAuthorization.d.ts +23 -0
  56. package/dist/HttpApi/Operations/OAuthDeviceAuthorization.d.ts.map +1 -0
  57. package/dist/HttpApi/Operations/OAuthDeviceAuthorization.js +7 -0
  58. package/dist/HttpApi/Operations/OAuthDeviceAuthorization.js.map +1 -0
  59. package/dist/HttpApi/Operations/OAuthToken.d.ts +10 -0
  60. package/dist/HttpApi/Operations/OAuthToken.d.ts.map +1 -1
  61. package/dist/HttpApi/Operations/OAuthToken.js +4 -0
  62. package/dist/HttpApi/Operations/OAuthToken.js.map +1 -1
  63. package/dist/HttpApi/Operations/index.d.ts +1 -0
  64. package/dist/HttpApi/Operations/index.d.ts.map +1 -1
  65. package/dist/HttpApi/Operations/index.js +1 -0
  66. package/dist/HttpApi/Operations/index.js.map +1 -1
  67. package/dist/HttpApi/PasswordContract.d.ts +9 -9
  68. package/dist/HttpApi/Schemas.d.ts +38 -0
  69. package/dist/HttpApi/Schemas.d.ts.map +1 -1
  70. package/dist/HttpApi/Schemas.js +36 -1
  71. package/dist/HttpApi/Schemas.js.map +1 -1
  72. package/dist/HttpApi/index.d.ts +3 -1
  73. package/dist/HttpApi/index.d.ts.map +1 -1
  74. package/dist/HttpApi/index.js +3 -1
  75. package/dist/HttpApi/index.js.map +1 -1
  76. package/dist/OAuth.d.ts +46 -1
  77. package/dist/OAuth.d.ts.map +1 -1
  78. package/dist/OAuth.js +118 -4
  79. package/dist/OAuth.js.map +1 -1
  80. package/dist/OAuthDeviceAuthorization.d.ts +378 -0
  81. package/dist/OAuthDeviceAuthorization.d.ts.map +1 -0
  82. package/dist/OAuthDeviceAuthorization.js +860 -0
  83. package/dist/OAuthDeviceAuthorization.js.map +1 -0
  84. package/dist/OAuthDeviceClient.d.ts +76 -0
  85. package/dist/OAuthDeviceClient.d.ts.map +1 -0
  86. package/dist/OAuthDeviceClient.js +362 -0
  87. package/dist/OAuthDeviceClient.js.map +1 -0
  88. package/dist/PostgresStorageMigrations.d.ts +2 -1
  89. package/dist/PostgresStorageMigrations.d.ts.map +1 -1
  90. package/dist/PostgresStorageMigrations.js +54 -0
  91. package/dist/PostgresStorageMigrations.js.map +1 -1
  92. package/dist/Retention.d.ts +6 -1
  93. package/dist/Retention.d.ts.map +1 -1
  94. package/dist/Retention.js +49 -12
  95. package/dist/Retention.js.map +1 -1
  96. package/dist/SqliteStorageSchemaData.d.ts +2 -0
  97. package/dist/SqliteStorageSchemaData.d.ts.map +1 -0
  98. package/dist/SqliteStorageSchemaData.js +508 -0
  99. package/dist/SqliteStorageSchemaData.js.map +1 -0
  100. package/dist/StorageMigrations.d.ts +2 -1
  101. package/dist/StorageMigrations.d.ts.map +1 -1
  102. package/dist/StorageMigrations.js +32 -0
  103. package/dist/StorageMigrations.js.map +1 -1
  104. package/dist/StorageSchemaGenerator.d.ts +70 -12
  105. package/dist/StorageSchemaGenerator.d.ts.map +1 -1
  106. package/dist/StorageSchemaGenerator.js +478 -82
  107. package/dist/StorageSchemaGenerator.js.map +1 -1
  108. package/migrations/0029_auth_oauth_device_authorization.sql +28 -0
  109. package/migrations/postgres/0010_auth_oauth_device_authorization.sql +50 -0
  110. package/package.json +24 -16
  111. package/dist/DrizzleDurableObjectSqliteStorage.d.ts +0 -19
  112. package/dist/DrizzleDurableObjectSqliteStorage.d.ts.map +0 -1
  113. package/dist/DrizzleDurableObjectSqliteStorage.js +0 -14
  114. package/dist/DrizzleDurableObjectSqliteStorage.js.map +0 -1
  115. package/dist/DrizzleWasmSqliteStorage.d.ts +0 -23
  116. package/dist/DrizzleWasmSqliteStorage.d.ts.map +0 -1
  117. package/dist/DrizzleWasmSqliteStorage.js +0 -15
  118. package/dist/DrizzleWasmSqliteStorage.js.map +0 -1
@@ -13,6 +13,7 @@ import { JwtError, JwtRevocationStore } from "./Jwt.js";
13
13
  import { LoginApprovalReviewError, LoginApprovalReviewStore, } from "./LoginApproval.js";
14
14
  import { LoginRiskContext, LoginRiskHistory, LoginRiskHistoryError, LoginRiskSignal, maxLoginRiskLevel, } from "./LoginRisk.js";
15
15
  import { OAuthAccountStore, OAuthAccountStoreError, OAuthIdentityBridgeConflictError, OAuthIdentityBridgeStore, OAuthIdentityBridgeStoreError, OAuthAuthorizationCodeStore, OAuthAuthorizationCodeStoreError, OAuthClientStore, OAuthClientStoreError, OAuthConsentStore, OAuthConsentStoreError, OAuthClientSecretHash, OAuthClientSecretPrefix, OAuthClientSecretStore, OAuthClientSecretStoreError, OAuthCodeChallenge, OAuthProviderModeTokenStore, OAuthProviderModeTokenStoreError, OAuthProviderTokenVault, OAuthProviderTokenVaultError, } from "./OAuth.js";
16
+ import { OAuthDeviceAuthorizationId, OAuthDeviceAuthorizationStore, OAuthDeviceAuthorizationStoreError, OAuthDeviceCodeTokenCommitStore, OAuthDeviceCodeTokenCommitStoreError, } from "./OAuthDeviceAuthorization.js";
16
17
  import { PasskeyCredentialId, PasskeyCredentialStore, PasskeyCredentialStoreError, } from "./Passkey.js";
17
18
  import { canonicalPermissionScope, normalizePermissionDefinitionListLimit, PermissionStore, PermissionStoreError, } from "./Permission.js";
18
19
  import { RecoveryCodeHash, RecoveryCodeLoginCommitStore, RecoveryCodeLoginCommitStoreError, RecoveryCodeStore, RecoveryCodeStoreError, RecoveryCodeSessionRotateStore, RecoveryCodeSessionRotateStoreError, } from "./RecoveryCode.js";
@@ -277,6 +278,25 @@ const makeAuthOAuthAuthorizationCodeTable = (name) => Table.make(name, {
277
278
  consumed_at: Column.int().pipe(Column.nullable),
278
279
  metadata: Column.text().pipe(Column.nullable),
279
280
  });
281
+ const makeAuthOAuthDeviceAuthorizationTable = (name) => Table.make(name, {
282
+ id: Column.text().pipe(Column.primaryKey),
283
+ device_code_hash: Column.text().pipe(Column.unique),
284
+ user_code_hash: Column.text().pipe(Column.unique),
285
+ client_id: Column.text(),
286
+ requested_scopes: Column.text(),
287
+ granted_scopes: Column.text().pipe(Column.nullable),
288
+ subject: Column.text().pipe(Column.nullable),
289
+ status: Column.text(),
290
+ issued_at: Column.int(),
291
+ expires_at: Column.int(),
292
+ poll_interval_seconds: Column.int(),
293
+ next_poll_at: Column.int(),
294
+ last_polled_at: Column.int().pipe(Column.nullable),
295
+ approved_at: Column.int().pipe(Column.nullable),
296
+ denied_at: Column.int().pipe(Column.nullable),
297
+ consumed_at: Column.int().pipe(Column.nullable),
298
+ metadata: Column.text().pipe(Column.nullable),
299
+ });
280
300
  const makeAuthOAuthClientSecretTable = (name) => Table.make(name, {
281
301
  prefix: Column.text(),
282
302
  client_id: Column.text(),
@@ -439,6 +459,16 @@ const queryChanges = () => Query.call("changes");
439
459
  const queryChangedOne = () => queryEq(queryChanges(), 1);
440
460
  const queryWithoutNullRefinement = (value) => Query.cast(value, value[Scalar.TypeId].dbType);
441
461
  const queryIn = (value, first, ...rest) => Query.in(value, first, ...rest);
462
+ const sqliteCastLike = (value, column) => Query.cast(value, column[Scalar.TypeId].dbType);
463
+ const sqliteIncrementByFive = (value) => Query.call("length", Query.concat(Query.call("printf", "%.*c", value, "x"), "xxxxx"));
464
+ const sqliteUnixMillisAfterSeconds = (now, seconds, textColumn, millisColumn) => {
465
+ const secondsText = sqliteCastLike(seconds, textColumn);
466
+ const modifier = Query.concat("+", secondsText, " seconds");
467
+ const epochSeconds = Query.call("strftime", "%s", new Date(Number(now)).toISOString(), modifier);
468
+ const fractionalSeconds = Query.call("strftime", "%f", new Date(Number(now)).toISOString(), modifier);
469
+ const milliseconds = Query.call("substr", fractionalSeconds, -3);
470
+ return sqliteCastLike(Query.concat(epochSeconds, milliseconds), millisColumn);
471
+ };
442
472
  const aliasTable = (table, alias) => Table.alias(table, alias);
443
473
  const aliasColumn = (table, column) => table[boundColumnName(column)];
444
474
  const queryAstTypeId = Symbol.for("effect-qb/QueryAst");
@@ -923,6 +953,42 @@ const decodeDefaultOAuthAuthorizationCodeRow = (row) => omitUndefined({
923
953
  const decodeOAuthAuthorizationCodeRow = (tables, row) => tables.oauthAuthorizationCode.decode === undefined
924
954
  ? decodeDefaultOAuthAuthorizationCodeRow(row)
925
955
  : tables.oauthAuthorizationCode.decode(row);
956
+ const decodeDefaultOAuthDeviceAuthorizationRow = (row) => {
957
+ const base = omitUndefined({
958
+ id: OAuthDeviceAuthorizationId(row.id),
959
+ deviceCodeHash: row.deviceCodeHash,
960
+ userCodeHash: row.userCodeHash,
961
+ clientId: OAuthClientId(row.clientId),
962
+ requestedScopes: decodeStringArray(row.requestedScopes),
963
+ issuedAt: UnixMillis(Number(row.issuedAt)),
964
+ expiresAt: UnixMillis(Number(row.expiresAt)),
965
+ pollIntervalSeconds: Number(row.pollIntervalSeconds),
966
+ nextPollAt: UnixMillis(Number(row.nextPollAt)),
967
+ lastPolledAt: optionalUnixMillis(row.lastPolledAt),
968
+ metadata: jsonDecode(row.metadata),
969
+ });
970
+ if (row.status === "approved") {
971
+ return {
972
+ ...base,
973
+ status: "approved",
974
+ subject: row.subject ?? "",
975
+ grantedScopes: decodeStringArray(row.grantedScopes),
976
+ approvedAt: UnixMillis(Number(row.approvedAt)),
977
+ ...omitUndefined({ consumedAt: optionalUnixMillis(row.consumedAt) }),
978
+ };
979
+ }
980
+ if (row.status === "denied") {
981
+ return {
982
+ ...base,
983
+ status: "denied",
984
+ deniedAt: UnixMillis(Number(row.deniedAt)),
985
+ };
986
+ }
987
+ return { ...base, status: "pending" };
988
+ };
989
+ const decodeOAuthDeviceAuthorizationRow = (table, row) => table.decode === undefined
990
+ ? decodeDefaultOAuthDeviceAuthorizationRow(row)
991
+ : table.decode(row);
926
992
  const decodeDefaultOAuthClientSecretRow = (row) => omitUndefined({
927
993
  prefix: OAuthClientSecretPrefix(row.prefix),
928
994
  clientId: OAuthClientId(row.clientId),
@@ -1526,6 +1592,37 @@ const oauthAuthorizationCodeValues = (record) => ({
1526
1592
  const oauthAuthorizationCodeMarkConsumed = (input) => ({
1527
1593
  consumed_at: Number(input.consumedAt),
1528
1594
  });
1595
+ const oauthDeviceAuthorizationValues = (record) => ({
1596
+ id: record.id,
1597
+ device_code_hash: record.deviceCodeHash,
1598
+ user_code_hash: record.userCodeHash,
1599
+ client_id: record.clientId,
1600
+ requested_scopes: JSON.stringify(record.requestedScopes),
1601
+ granted_scopes: null,
1602
+ subject: null,
1603
+ status: "pending",
1604
+ issued_at: Number(record.issuedAt),
1605
+ expires_at: Number(record.expiresAt),
1606
+ poll_interval_seconds: record.pollIntervalSeconds,
1607
+ next_poll_at: Number(record.nextPollAt),
1608
+ last_polled_at: record.lastPolledAt === undefined ? null : Number(record.lastPolledAt),
1609
+ approved_at: null,
1610
+ denied_at: null,
1611
+ consumed_at: null,
1612
+ metadata: jsonEncode(record.metadata),
1613
+ });
1614
+ const oauthDeviceAuthorizationApprove = (input) => omitUndefined({
1615
+ status: "approved",
1616
+ subject: input.subject,
1617
+ granted_scopes: JSON.stringify(input.grantedScopes),
1618
+ approved_at: Number(input.decidedAt),
1619
+ metadata: input.metadata === undefined ? undefined : jsonEncode(input.metadata),
1620
+ });
1621
+ const oauthDeviceAuthorizationDeny = (input) => omitUndefined({
1622
+ status: "denied",
1623
+ denied_at: Number(input.decidedAt),
1624
+ metadata: input.metadata === undefined ? undefined : jsonEncode(input.metadata),
1625
+ });
1529
1626
  const oauthClientSecretValues = (record) => ({
1530
1627
  prefix: record.prefix,
1531
1628
  client_id: record.clientId,
@@ -1767,6 +1864,7 @@ const makeInternalAuthSqliteTables = (names = {}) => {
1767
1864
  const oauthClient = makeAuthOAuthClientTable(authSqliteTableName(names.oauthClient, "auth_oauth_client"));
1768
1865
  const oauthConsent = makeAuthOAuthConsentTable(authSqliteTableName(names.oauthConsent, "auth_oauth_consent"));
1769
1866
  const oauthAuthorizationCode = makeAuthOAuthAuthorizationCodeTable(authSqliteTableName(names.oauthAuthorizationCode, "auth_oauth_authorization_code"));
1867
+ const oauthDeviceAuthorization = makeAuthOAuthDeviceAuthorizationTable(authSqliteTableName(names.oauthDeviceAuthorization, "auth_oauth_device_authorization"));
1770
1868
  const oauthClientSecret = makeAuthOAuthClientSecretTable(authSqliteTableName(names.oauthClientSecret, "auth_oauth_client_secret"));
1771
1869
  const oauthProviderModeToken = makeAuthOAuthProviderModeTokenTable(authSqliteTableName(names.oauthProviderModeToken, "auth_oauth_provider_mode_token"));
1772
1870
  const oauthProviderTokenVault = makeAuthOAuthProviderTokenVaultTable(names.oauthProviderTokenVault ?? "auth_oauth_provider_token_vault");
@@ -2123,6 +2221,31 @@ const makeInternalAuthSqliteTables = (names = {}) => {
2123
2221
  update: oauthAuthorizationCodeValues,
2124
2222
  markConsumed: oauthAuthorizationCodeMarkConsumed,
2125
2223
  },
2224
+ oauthDeviceAuthorization: {
2225
+ table: oauthDeviceAuthorization,
2226
+ select: {
2227
+ id: oauthDeviceAuthorization.id,
2228
+ deviceCodeHash: oauthDeviceAuthorization.device_code_hash,
2229
+ userCodeHash: oauthDeviceAuthorization.user_code_hash,
2230
+ clientId: oauthDeviceAuthorization.client_id,
2231
+ requestedScopes: oauthDeviceAuthorization.requested_scopes,
2232
+ grantedScopes: oauthDeviceAuthorization.granted_scopes,
2233
+ subject: oauthDeviceAuthorization.subject,
2234
+ status: oauthDeviceAuthorization.status,
2235
+ issuedAt: oauthDeviceAuthorization.issued_at,
2236
+ expiresAt: oauthDeviceAuthorization.expires_at,
2237
+ pollIntervalSeconds: oauthDeviceAuthorization.poll_interval_seconds,
2238
+ nextPollAt: oauthDeviceAuthorization.next_poll_at,
2239
+ lastPolledAt: oauthDeviceAuthorization.last_polled_at,
2240
+ approvedAt: oauthDeviceAuthorization.approved_at,
2241
+ deniedAt: oauthDeviceAuthorization.denied_at,
2242
+ consumedAt: oauthDeviceAuthorization.consumed_at,
2243
+ metadata: oauthDeviceAuthorization.metadata,
2244
+ },
2245
+ insert: oauthDeviceAuthorizationValues,
2246
+ approve: oauthDeviceAuthorizationApprove,
2247
+ deny: oauthDeviceAuthorizationDeny,
2248
+ },
2126
2249
  oauthClientSecret: {
2127
2250
  table: oauthClientSecret,
2128
2251
  select: {
@@ -2355,6 +2478,8 @@ const selectOAuthAccountColumns = (tables) => tables.oauthAccount.select;
2355
2478
  const selectOAuthClientColumns = (tables) => tables.oauthClient.select;
2356
2479
  const selectOAuthConsentColumns = (tables) => tables.oauthConsent.select;
2357
2480
  const selectOAuthAuthorizationCodeColumns = (tables) => tables.oauthAuthorizationCode.select;
2481
+ const oauthDeviceAuthorizationTable = (tables) => tables.oauthDeviceAuthorization ?? authSqliteTables.oauthDeviceAuthorization;
2482
+ const selectOAuthDeviceAuthorizationColumns = (tables) => oauthDeviceAuthorizationTable(tables).select;
2358
2483
  const selectOAuthClientSecretColumns = (tables) => tables.oauthClientSecret.select;
2359
2484
  const selectOAuthProviderModeTokenColumns = (tables) => tables.oauthProviderModeToken.select;
2360
2485
  const selectOAuthProviderTokenVaultColumns = (tables) => tables.oauthProviderTokenVault.select;
@@ -2441,6 +2566,11 @@ const oauthAuthorizationCodeStoreError = (operation, cause) => new OAuthAuthoriz
2441
2566
  message: `OAuth authorization code ${operation} failed`,
2442
2567
  cause,
2443
2568
  });
2569
+ const oauthDeviceAuthorizationStoreError = (operation, cause) => new OAuthDeviceAuthorizationStoreError({
2570
+ operation,
2571
+ message: `OAuth device authorization ${operation} failed`,
2572
+ cause,
2573
+ });
2444
2574
  const oauthClientSecretStoreError = (operation, cause) => new OAuthClientSecretStoreError({
2445
2575
  operation,
2446
2576
  message: `OAuth client secret ${operation} failed`,
@@ -3791,6 +3921,210 @@ export const makeEffectQbSqliteOAuthAuthorizationCodeStore = (executor, options
3791
3921
  })),
3792
3922
  });
3793
3923
  };
3924
+ export const makeEffectQbSqliteOAuthDeviceAuthorizationStore = (executor, atomic, options = {}) => {
3925
+ const tables = options.tables ?? authSqliteTables;
3926
+ const mapping = oauthDeviceAuthorizationTable(tables);
3927
+ const selection = selectOAuthDeviceAuthorizationColumns(tables);
3928
+ const decode = (row) => decodeOAuthDeviceAuthorizationRow(mapping, row);
3929
+ const find = (column, value, operation) => executePlan(executor, Query.select(selection).pipe(Query.from(mapping.table), Query.where(queryEq(column, value)))).pipe(Effect.mapError((cause) => oauthDeviceAuthorizationStoreError(operation, cause)), Effect.flatMap((rows) => Effect.try({
3930
+ try: () => rows[0] === undefined
3931
+ ? Option.none()
3932
+ : Option.some(decode(rows[0])),
3933
+ catch: (cause) => oauthDeviceAuthorizationStoreError(operation, cause),
3934
+ })));
3935
+ return OAuthDeviceAuthorizationStore.of({
3936
+ insert: (record) => executePlan(executor, queryInsert(mapping.table, mutationValues(mapping.insert(record))).pipe(Query.returning({ id: mapping.select.id }))).pipe(Effect.as(true), Effect.catch((error) => sqliteConstraintDiscriminator(error)
3937
+ ? Effect.succeed(false)
3938
+ : Effect.fail(oauthDeviceAuthorizationStoreError("insert", error)))),
3939
+ findByDeviceCodeHash: (input) => find(mapping.select.deviceCodeHash, input.deviceCodeHash, "find-by-device-code-hash"),
3940
+ findByUserCodeHash: (input) => find(mapping.select.userCodeHash, input.userCodeHash, "find-by-user-code-hash"),
3941
+ findById: (id) => find(mapping.select.id, id, "find-by-id"),
3942
+ decide: (input) => {
3943
+ const updatePlan = queryUpdate(mapping.table, mutationValues(input.decision === "approve"
3944
+ ? mapping.approve(input)
3945
+ : mapping.deny(input))).pipe(Query.where(queryEq(mapping.select.id, input.id)), Query.where(queryEq(mapping.select.status, "pending")), Query.where(queryGt(mapping.select.expiresAt, Number(input.decidedAt))), Query.returning(selection));
3946
+ const classifyPlan = Query.select(selection).pipe(Query.from(mapping.table), Query.where(queryEq(mapping.select.id, input.id)));
3947
+ return executeAtomicPlans(atomic, [
3948
+ updatePlan,
3949
+ classifyPlan,
3950
+ ]).pipe(Effect.mapError((cause) => oauthDeviceAuthorizationStoreError("decide", cause)), Effect.flatMap(([updated, selected]) => Effect.try({
3951
+ try: () => {
3952
+ const changed = updated[0];
3953
+ if (changed !== undefined) {
3954
+ const record = decode(changed);
3955
+ return record.status === "approved"
3956
+ ? { status: "approved", record }
3957
+ : {
3958
+ status: "denied",
3959
+ record: record,
3960
+ };
3961
+ }
3962
+ const row = selected[0];
3963
+ if (row === undefined) {
3964
+ return { status: "missing" };
3965
+ }
3966
+ const record = decode(row);
3967
+ if (Number(input.decidedAt) >= Number(record.expiresAt)) {
3968
+ return { status: "expired", record };
3969
+ }
3970
+ if (record.status === "pending") {
3971
+ return { status: "expired", record };
3972
+ }
3973
+ return { status: "already_decided", record };
3974
+ },
3975
+ catch: (cause) => oauthDeviceAuthorizationStoreError("decide", cause),
3976
+ })));
3977
+ },
3978
+ poll: (input) => {
3979
+ const active = [
3980
+ queryEq(mapping.select.deviceCodeHash, input.deviceCodeHash),
3981
+ queryEq(mapping.select.clientId, input.clientId),
3982
+ queryGt(mapping.select.expiresAt, Number(input.now)),
3983
+ queryIsNull(mapping.select.consumedAt),
3984
+ queryIn(mapping.select.status, "pending", "approved"),
3985
+ ];
3986
+ const intervalColumn = boundColumnName(mapping.select.pollIntervalSeconds);
3987
+ const nextPollColumn = boundColumnName(mapping.select.nextPollAt);
3988
+ const lastPolledColumn = boundColumnName(mapping.select.lastPolledAt);
3989
+ const slowedInterval = sqliteIncrementByFive(mapping.select.pollIntervalSeconds);
3990
+ const slowPlan = queryUpdate(mapping.table, {
3991
+ [intervalColumn]: slowedInterval,
3992
+ [nextPollColumn]: sqliteUnixMillisAfterSeconds(input.now, slowedInterval, mapping.select.status, mapping.select.nextPollAt),
3993
+ [lastPolledColumn]: Number(input.now),
3994
+ }).pipe(Query.where(active[0]), Query.where(active[1]), Query.where(active[2]), Query.where(active[3]), Query.where(active[4]), Query.where(queryEq(mapping.select.status, "pending")), Query.where(queryGt(mapping.select.nextPollAt, Number(input.now))), Query.returning({
3995
+ ...selection,
3996
+ consumedAt: queryWithoutNullRefinement(mapping.select.consumedAt),
3997
+ }));
3998
+ const pendingPlan = queryUpdate(mapping.table, {
3999
+ [nextPollColumn]: sqliteUnixMillisAfterSeconds(input.now, mapping.select.pollIntervalSeconds, mapping.select.status, mapping.select.nextPollAt),
4000
+ [lastPolledColumn]: Number(input.now),
4001
+ }).pipe(Query.where(active[0]), Query.where(active[1]), Query.where(active[2]), Query.where(active[3]), Query.where(active[4]), Query.where(queryEq(mapping.select.status, "pending")), Query.where(queryLte(mapping.select.nextPollAt, Number(input.now))), Query.returning(selection));
4002
+ const classifyPlan = Query.select(selection).pipe(Query.from(mapping.table), Query.where(queryEq(mapping.select.deviceCodeHash, input.deviceCodeHash)), Query.where(queryEq(mapping.select.clientId, input.clientId)));
4003
+ return executeAtomicPlans(atomic, [
4004
+ slowPlan,
4005
+ pendingPlan,
4006
+ classifyPlan,
4007
+ ]).pipe(Effect.mapError((cause) => oauthDeviceAuthorizationStoreError("poll", cause)), Effect.flatMap(([slowed, pending, selected]) => Effect.try({
4008
+ try: () => {
4009
+ const slowRow = slowed[0];
4010
+ if (slowRow !== undefined) {
4011
+ const record = decode(slowRow);
4012
+ return {
4013
+ status: "slow_down",
4014
+ record,
4015
+ interval: record.pollIntervalSeconds,
4016
+ };
4017
+ }
4018
+ const pendingRow = pending[0];
4019
+ if (pendingRow !== undefined) {
4020
+ return {
4021
+ status: "pending",
4022
+ record: decode(pendingRow),
4023
+ };
4024
+ }
4025
+ const row = selected[0];
4026
+ if (row === undefined) {
4027
+ return { status: "missing" };
4028
+ }
4029
+ const record = decode(row);
4030
+ if (record.status === "approved" &&
4031
+ record.consumedAt !== undefined) {
4032
+ return {
4033
+ status: "already_consumed",
4034
+ record: record,
4035
+ };
4036
+ }
4037
+ if (Number(input.now) >= Number(record.expiresAt)) {
4038
+ return { status: "expired", record };
4039
+ }
4040
+ if (record.status === "denied") {
4041
+ return { status: "denied", record };
4042
+ }
4043
+ if (record.status === "approved") {
4044
+ return {
4045
+ status: "approved",
4046
+ record: record,
4047
+ };
4048
+ }
4049
+ return { status: "missing" };
4050
+ },
4051
+ catch: (cause) => oauthDeviceAuthorizationStoreError("poll", cause),
4052
+ })));
4053
+ },
4054
+ deleteExpired: (input) => executePlan(executor, Query.delete(mapping.table).pipe(Query.where(queryLte(mapping.select.expiresAt, Number(input.beforeExpiresAt))), Query.returning({ id: mapping.select.id }))).pipe(Effect.mapError((cause) => oauthDeviceAuthorizationStoreError("delete-expired", cause)), Effect.map((rows) => rows.length)),
4055
+ });
4056
+ };
4057
+ export const makeEffectQbSqliteOAuthDeviceCodeTokenCommitStore = (atomic, options = {}) => {
4058
+ const tables = options.tables ?? authSqliteTables;
4059
+ const authorizationTable = oauthDeviceAuthorizationTable(tables);
4060
+ const authorizationSelection = selectOAuthDeviceAuthorizationColumns(tables);
4061
+ const decodeAuthorization = (row) => decodeOAuthDeviceAuthorizationRow(authorizationTable, row);
4062
+ return OAuthDeviceCodeTokenCommitStore.of({
4063
+ commit: (input) => {
4064
+ const { authorization } = input;
4065
+ const nextPollColumn = boundColumnName(authorizationTable.select.nextPollAt);
4066
+ const lastPolledColumn = boundColumnName(authorizationTable.select.lastPolledAt);
4067
+ const consumedColumn = boundColumnName(authorizationTable.select.consumedAt);
4068
+ const consumePlan = queryUpdate(authorizationTable.table, {
4069
+ [consumedColumn]: Number(input.consumedAt),
4070
+ [lastPolledColumn]: Number(input.consumedAt),
4071
+ [nextPollColumn]: sqliteUnixMillisAfterSeconds(input.consumedAt, authorizationTable.select.pollIntervalSeconds, authorizationTable.select.status, authorizationTable.select.nextPollAt),
4072
+ }).pipe(Query.where(queryEq(authorizationTable.select.id, authorization.id)), Query.where(queryEq(authorizationTable.select.deviceCodeHash, authorization.deviceCodeHash)), Query.where(queryEq(authorizationTable.select.userCodeHash, authorization.userCodeHash)), Query.where(queryEq(authorizationTable.select.clientId, authorization.clientId)), Query.where(queryEq(authorizationTable.select.requestedScopes, JSON.stringify(authorization.requestedScopes))), Query.where(queryEq(authorizationTable.select.status, "approved")), Query.where(queryEq(authorizationTable.select.subject, authorization.subject)), Query.where(queryEq(authorizationTable.select.grantedScopes, JSON.stringify(authorization.grantedScopes))), Query.where(queryEq(authorizationTable.select.issuedAt, Number(authorization.issuedAt))), Query.where(queryEq(authorizationTable.select.expiresAt, Number(authorization.expiresAt))), Query.where(queryEq(authorizationTable.select.pollIntervalSeconds, authorization.pollIntervalSeconds)), Query.where(queryEq(authorizationTable.select.nextPollAt, Number(authorization.nextPollAt))), Query.where(queryIsNotDistinctFrom(authorizationTable.select.lastPolledAt, authorization.lastPolledAt === undefined
4073
+ ? null
4074
+ : Number(authorization.lastPolledAt))), Query.where(queryEq(authorizationTable.select.approvedAt, Number(authorization.approvedAt))), Query.where(queryIsNotDistinctFrom(authorizationTable.select.metadata, jsonEncode(authorization.metadata))), Query.where(queryIsNull(authorizationTable.select.consumedAt)), Query.where(queryGt(authorizationTable.select.expiresAt, Number(input.consumedAt))), Query.returning({
4075
+ ...authorizationSelection,
4076
+ lastPolledAt: queryWithoutNullRefinement(authorizationTable.select.lastPolledAt),
4077
+ consumedAt: queryWithoutNullRefinement(authorizationTable.select.consumedAt),
4078
+ }));
4079
+ const tokenPlans = input.tokenRecords.map((record) => queryInsertWhere(tables.oauthProviderModeToken.table, mutationValues(tables.oauthProviderModeToken.insert(record)), queryChangedOne()).pipe(Query.returning({
4080
+ tokenHash: tables.oauthProviderModeToken.select.tokenHash,
4081
+ })));
4082
+ const classifyPlan = Query.select(authorizationSelection).pipe(Query.from(authorizationTable.table), Query.where(queryEq(authorizationTable.select.id, authorization.id)));
4083
+ const plans = [
4084
+ consumePlan,
4085
+ ...tokenPlans,
4086
+ classifyPlan,
4087
+ ];
4088
+ return executeAtomicPlans(atomic, plans).pipe(Effect.mapError((cause) => new OAuthDeviceCodeTokenCommitStoreError({
4089
+ operation: "commit",
4090
+ message: "Atomic OAuth device token commit failed",
4091
+ cause,
4092
+ })), Effect.flatMap((results) => Effect.try({
4093
+ try: () => {
4094
+ const changed = results[0]?.[0];
4095
+ if (changed !== undefined) {
4096
+ return {
4097
+ status: "committed",
4098
+ record: decodeAuthorization(changed),
4099
+ };
4100
+ }
4101
+ const selected = results.at(-1)?.[0];
4102
+ if (selected === undefined) {
4103
+ return { status: "missing" };
4104
+ }
4105
+ const record = decodeAuthorization(selected);
4106
+ if (record.status === "approved" &&
4107
+ record.consumedAt !== undefined) {
4108
+ return {
4109
+ status: "already_consumed",
4110
+ record: record,
4111
+ };
4112
+ }
4113
+ if (record.status === "approved" &&
4114
+ Number(input.consumedAt) >= Number(record.expiresAt)) {
4115
+ return { status: "expired", record };
4116
+ }
4117
+ return { status: "missing" };
4118
+ },
4119
+ catch: (cause) => new OAuthDeviceCodeTokenCommitStoreError({
4120
+ operation: "commit",
4121
+ message: "Failed to decode OAuth device token commit result",
4122
+ cause,
4123
+ }),
4124
+ })));
4125
+ },
4126
+ });
4127
+ };
3794
4128
  export const makeEffectQbSqliteOAuthClientSecretStore = (executor, options = {}) => {
3795
4129
  const tables = options.tables ?? authSqliteTables;
3796
4130
  return OAuthClientSecretStore.of({
@@ -4283,6 +4617,8 @@ export const makeEffectQbSqliteStorage = (executor, atomic, options = {}) => ({
4283
4617
  oauthClientStore: makeEffectQbSqliteOAuthClientStore(executor, options),
4284
4618
  oauthConsentStore: makeEffectQbSqliteOAuthConsentStore(executor, options),
4285
4619
  oauthAuthorizationCodeStore: makeEffectQbSqliteOAuthAuthorizationCodeStore(executor, options),
4620
+ oauthDeviceAuthorizationStore: makeEffectQbSqliteOAuthDeviceAuthorizationStore(executor, atomic, options),
4621
+ oauthDeviceCodeTokenCommitStore: makeEffectQbSqliteOAuthDeviceCodeTokenCommitStore(atomic, options),
4286
4622
  oauthClientSecretStore: makeEffectQbSqliteOAuthClientSecretStore(executor, options),
4287
4623
  oauthProviderModeTokenStore: makeEffectQbSqliteOAuthProviderModeTokenStore(executor, options),
4288
4624
  oauthProviderTokenVault: makeEffectQbSqliteOAuthProviderTokenVault(executor, options),
@@ -4292,7 +4628,7 @@ export const makeEffectQbSqliteStorage = (executor, atomic, options = {}) => ({
4292
4628
  webhookReplayStore: makeEffectQbSqliteWebhookReplayStore(executor, options),
4293
4629
  permissionStore: makeEffectQbSqlitePermissionStore(executor, options),
4294
4630
  });
4295
- export const EffectQbSqliteAuthStorageLive = (executor, atomic, options = {}) => Layer.mergeAll(Layer.succeed(UserStore)(makeEffectQbSqliteUserStore(executor, options)), Layer.succeed(IdentityStore)(makeEffectQbSqliteIdentityStore(executor, atomic, options)), Layer.succeed(RegistrationStore)(makeEffectQbSqliteRegistrationStore(executor, atomic, options)), Layer.succeed(CredentialStore)(makeEffectQbSqliteCredentialStore(executor, options)), Layer.succeed(SessionStore)(makeEffectQbSqliteSessionStore(executor, options)), Layer.succeed(VerificationStore)(makeEffectQbSqliteVerificationStore(executor, options)), Layer.succeed(AuditLogStore)(makeEffectQbSqliteAuditLogStore(executor, options)), Layer.succeed(LoginApprovalReviewStore)(makeEffectQbSqliteLoginApprovalReviewStore(executor, options)), Layer.succeed(LoginRiskHistory)(makeEffectQbSqliteLoginRiskHistoryStore(executor, options)), Layer.succeed(TrustedDeviceStore)(makeEffectQbSqliteTrustedDeviceStore(executor, options)), Layer.succeed(PasskeyCredentialStore)(makeEffectQbSqlitePasskeyCredentialStore(executor, options)), Layer.succeed(TotpFactorStore)(makeEffectQbSqliteTotpFactorStore(executor, options)), Layer.succeed(TotpSessionRotateStore)(makeEffectQbSqliteTotpSessionRotateStore(executor, atomic, options)), Layer.succeed(TotpLoginCommitStore)(makeEffectQbSqliteTotpLoginCommitStore(atomic, options)), Layer.succeed(RecoveryCodeStore)(makeEffectQbSqliteRecoveryCodeStore(executor, atomic, options)), Layer.succeed(RecoveryCodeSessionRotateStore)(makeEffectQbSqliteRecoveryCodeSessionRotateStore(executor, atomic, options)), Layer.succeed(RecoveryCodeLoginCommitStore)(makeEffectQbSqliteRecoveryCodeLoginCommitStore(atomic, options)), Layer.succeed(ApiKeyStore)(makeEffectQbSqliteApiKeyStore(executor, options)), Layer.succeed(RefreshTokenStore)(makeEffectQbSqliteRefreshTokenStore(executor, atomic, options)), Layer.succeed(JwtRevocationStore)(makeEffectQbSqliteJwtRevocationStore(executor, options)), Layer.succeed(OAuthAccountStore)(makeEffectQbSqliteOAuthAccountStore(executor, options)), Layer.succeed(OAuthIdentityBridgeStore)(makeEffectQbSqliteOAuthIdentityBridgeStore(executor, atomic, options)), Layer.succeed(OAuthClientStore)(makeEffectQbSqliteOAuthClientStore(executor, options)), Layer.succeed(OAuthConsentStore)(makeEffectQbSqliteOAuthConsentStore(executor, options)), Layer.succeed(OAuthAuthorizationCodeStore)(makeEffectQbSqliteOAuthAuthorizationCodeStore(executor, options)), Layer.succeed(OAuthClientSecretStore)(makeEffectQbSqliteOAuthClientSecretStore(executor, options)), Layer.succeed(OAuthProviderModeTokenStore)(makeEffectQbSqliteOAuthProviderModeTokenStore(executor, options)), Layer.succeed(OAuthProviderTokenVault)(makeEffectQbSqliteOAuthProviderTokenVault(executor, options)), Layer.succeed(DomainVerificationStore)(makeEffectQbSqliteDomainVerificationStore(executor, options)), Layer.succeed(SecurityTimelineStore)(makeEffectQbSqliteSecurityTimelineStore(executor, options)), Layer.succeed(WebhookOutboxStore)(makeEffectQbSqliteWebhookOutboxStore(executor, options)), Layer.succeed(WebhookReplayStore)(makeEffectQbSqliteWebhookReplayStore(executor, options)), Layer.succeed(PermissionStore)(makeEffectQbSqlitePermissionStore(executor, options)));
4631
+ export const EffectQbSqliteAuthStorageLive = (executor, atomic, options = {}) => Layer.mergeAll(Layer.succeed(UserStore)(makeEffectQbSqliteUserStore(executor, options)), Layer.succeed(IdentityStore)(makeEffectQbSqliteIdentityStore(executor, atomic, options)), Layer.succeed(RegistrationStore)(makeEffectQbSqliteRegistrationStore(executor, atomic, options)), Layer.succeed(CredentialStore)(makeEffectQbSqliteCredentialStore(executor, options)), Layer.succeed(SessionStore)(makeEffectQbSqliteSessionStore(executor, options)), Layer.succeed(VerificationStore)(makeEffectQbSqliteVerificationStore(executor, options)), Layer.succeed(AuditLogStore)(makeEffectQbSqliteAuditLogStore(executor, options)), Layer.succeed(LoginApprovalReviewStore)(makeEffectQbSqliteLoginApprovalReviewStore(executor, options)), Layer.succeed(LoginRiskHistory)(makeEffectQbSqliteLoginRiskHistoryStore(executor, options)), Layer.succeed(TrustedDeviceStore)(makeEffectQbSqliteTrustedDeviceStore(executor, options)), Layer.succeed(PasskeyCredentialStore)(makeEffectQbSqlitePasskeyCredentialStore(executor, options)), Layer.succeed(TotpFactorStore)(makeEffectQbSqliteTotpFactorStore(executor, options)), Layer.succeed(TotpSessionRotateStore)(makeEffectQbSqliteTotpSessionRotateStore(executor, atomic, options)), Layer.succeed(TotpLoginCommitStore)(makeEffectQbSqliteTotpLoginCommitStore(atomic, options)), Layer.succeed(RecoveryCodeStore)(makeEffectQbSqliteRecoveryCodeStore(executor, atomic, options)), Layer.succeed(RecoveryCodeSessionRotateStore)(makeEffectQbSqliteRecoveryCodeSessionRotateStore(executor, atomic, options)), Layer.succeed(RecoveryCodeLoginCommitStore)(makeEffectQbSqliteRecoveryCodeLoginCommitStore(atomic, options)), Layer.succeed(ApiKeyStore)(makeEffectQbSqliteApiKeyStore(executor, options)), Layer.succeed(RefreshTokenStore)(makeEffectQbSqliteRefreshTokenStore(executor, atomic, options)), Layer.succeed(JwtRevocationStore)(makeEffectQbSqliteJwtRevocationStore(executor, options)), Layer.succeed(OAuthAccountStore)(makeEffectQbSqliteOAuthAccountStore(executor, options)), Layer.succeed(OAuthIdentityBridgeStore)(makeEffectQbSqliteOAuthIdentityBridgeStore(executor, atomic, options)), Layer.succeed(OAuthClientStore)(makeEffectQbSqliteOAuthClientStore(executor, options)), Layer.succeed(OAuthConsentStore)(makeEffectQbSqliteOAuthConsentStore(executor, options)), Layer.succeed(OAuthAuthorizationCodeStore)(makeEffectQbSqliteOAuthAuthorizationCodeStore(executor, options)), Layer.succeed(OAuthDeviceAuthorizationStore)(makeEffectQbSqliteOAuthDeviceAuthorizationStore(executor, atomic, options)), Layer.succeed(OAuthDeviceCodeTokenCommitStore)(makeEffectQbSqliteOAuthDeviceCodeTokenCommitStore(atomic, options)), Layer.succeed(OAuthClientSecretStore)(makeEffectQbSqliteOAuthClientSecretStore(executor, options)), Layer.succeed(OAuthProviderModeTokenStore)(makeEffectQbSqliteOAuthProviderModeTokenStore(executor, options)), Layer.succeed(OAuthProviderTokenVault)(makeEffectQbSqliteOAuthProviderTokenVault(executor, options)), Layer.succeed(DomainVerificationStore)(makeEffectQbSqliteDomainVerificationStore(executor, options)), Layer.succeed(SecurityTimelineStore)(makeEffectQbSqliteSecurityTimelineStore(executor, options)), Layer.succeed(WebhookOutboxStore)(makeEffectQbSqliteWebhookOutboxStore(executor, options)), Layer.succeed(WebhookReplayStore)(makeEffectQbSqliteWebhookReplayStore(executor, options)), Layer.succeed(PermissionStore)(makeEffectQbSqlitePermissionStore(executor, options)));
4296
4632
  export const makeD1EffectQbSqliteExecutor = (database) => Executor.make({
4297
4633
  driver: Executor.driver((query) => Effect.tryPromise({
4298
4634
  try: () => database