@effect-auth/core 0.1.0-alpha.10 → 0.1.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -4
- package/dist/AuditLog.d.ts +60 -0
- package/dist/AuditLog.d.ts.map +1 -1
- package/dist/AuditLog.js +105 -0
- package/dist/AuditLog.js.map +1 -1
- package/dist/AuthKernel.d.ts +1 -1
- package/dist/Client.d.ts +72 -1
- package/dist/Client.d.ts.map +1 -1
- package/dist/Client.js +218 -1
- package/dist/Client.js.map +1 -1
- package/dist/DomainVerification.d.ts +200 -0
- package/dist/DomainVerification.d.ts.map +1 -0
- package/dist/DomainVerification.js +304 -0
- package/dist/DomainVerification.js.map +1 -0
- package/dist/EffectQbSqliteStorage.d.ts +389 -4
- package/dist/EffectQbSqliteStorage.d.ts.map +1 -1
- package/dist/EffectQbSqliteStorage.js +1191 -4
- package/dist/EffectQbSqliteStorage.js.map +1 -1
- package/dist/EmailOtp.d.ts +2 -2
- package/dist/HttpApi/Api.d.ts +477 -23
- package/dist/HttpApi/Api.d.ts.map +1 -1
- package/dist/HttpApi/Api.js +705 -4
- package/dist/HttpApi/Api.js.map +1 -1
- package/dist/HttpApi/Endpoints.d.ts +133 -5
- package/dist/HttpApi/Endpoints.d.ts.map +1 -1
- package/dist/HttpApi/Endpoints.js +57 -2
- package/dist/HttpApi/Endpoints.js.map +1 -1
- package/dist/HttpApi/Errors.d.ts +32 -0
- package/dist/HttpApi/Errors.d.ts.map +1 -1
- package/dist/HttpApi/Errors.js +46 -0
- package/dist/HttpApi/Errors.js.map +1 -1
- package/dist/HttpApi/Schemas.d.ts +149 -8
- package/dist/HttpApi/Schemas.d.ts.map +1 -1
- package/dist/HttpApi/Schemas.js +128 -0
- package/dist/HttpApi/Schemas.js.map +1 -1
- package/dist/Identifiers.d.ts +3 -0
- package/dist/Identifiers.d.ts.map +1 -1
- package/dist/Identifiers.js +2 -0
- package/dist/Identifiers.js.map +1 -1
- package/dist/IncidentAction.d.ts +80 -0
- package/dist/IncidentAction.d.ts.map +1 -0
- package/dist/IncidentAction.js +158 -0
- package/dist/IncidentAction.js.map +1 -0
- package/dist/Jwt.d.ts +10 -0
- package/dist/Jwt.d.ts.map +1 -1
- package/dist/Jwt.js +209 -0
- package/dist/Jwt.js.map +1 -1
- package/dist/LoginNotification.d.ts +1 -1
- package/dist/LoginRisk.d.ts +272 -1
- package/dist/LoginRisk.d.ts.map +1 -1
- package/dist/LoginRisk.js +427 -0
- package/dist/LoginRisk.js.map +1 -1
- package/dist/MachineAuth.d.ts +73 -0
- package/dist/MachineAuth.d.ts.map +1 -0
- package/dist/MachineAuth.js +147 -0
- package/dist/MachineAuth.js.map +1 -0
- package/dist/MagicLink.d.ts +2 -2
- package/dist/OAuth.d.ts +957 -1
- package/dist/OAuth.d.ts.map +1 -1
- package/dist/OAuth.js +1403 -1
- package/dist/OAuth.js.map +1 -1
- package/dist/Password.d.ts +2 -2
- package/dist/Retention.d.ts +98 -0
- package/dist/Retention.d.ts.map +1 -0
- package/dist/Retention.js +204 -0
- package/dist/Retention.js.map +1 -0
- package/dist/SecurityTimeline.d.ts +8 -2
- package/dist/SecurityTimeline.d.ts.map +1 -1
- package/dist/SecurityTimeline.js +75 -0
- package/dist/SecurityTimeline.js.map +1 -1
- package/dist/StorageMigrations.d.ts +11 -1
- package/dist/StorageMigrations.d.ts.map +1 -1
- package/dist/StorageMigrations.js +206 -0
- package/dist/StorageMigrations.js.map +1 -1
- package/dist/Webhook.d.ts +310 -2
- package/dist/Webhook.d.ts.map +1 -1
- package/dist/Webhook.js +511 -1
- package/dist/Webhook.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/migrations/0014_auth_webhook_outbox.sql +16 -0
- package/migrations/0015_auth_webhook_replay.sql +7 -0
- package/migrations/0016_auth_login_risk_history.sql +23 -0
- package/migrations/0017_auth_audit_log.sql +17 -0
- package/migrations/0018_auth_domain_verification.sql +18 -0
- package/migrations/0019_auth_oauth_authorization_code.sql +17 -0
- package/migrations/0020_auth_oauth_provider_mode_token.sql +24 -0
- package/migrations/0021_auth_oauth_client_secret.sql +14 -0
- package/migrations/0022_auth_oauth_client.sql +15 -0
- package/migrations/0023_auth_oauth_consent.sql +15 -0
- package/package.json +18 -2
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { Data, Effect, Layer, Option, Redacted } from "effect";
|
|
2
2
|
import { Column, Executor, Query, Scalar, Table } from "effect-qb/sqlite";
|
|
3
|
+
import { AuditLogStore, AuditLogStoreError, auditEventActorUserId, auditEventUserId, filterAuditLogEvents, } from "./AuditLog.js";
|
|
3
4
|
import { ApiKeyId, ApiKeyPrefix, ApiKeySecretHash, ApiKeyStore, ApiKeyStoreError, } from "./ApiKey.js";
|
|
4
|
-
import {
|
|
5
|
+
import { DomainName, DomainVerificationId, DomainVerificationProofToken, DomainVerificationStore, DomainVerificationStoreError, } from "./DomainVerification.js";
|
|
6
|
+
import { AuthFlowId, ChallengeId, CredentialId, Email, OAuthAccountId, OAuthClientId, OAuthProviderId, SessionId, UnixMillis, UserId, } from "./Identifiers.js";
|
|
7
|
+
import { currentUnixMillis } from "./Internal.js";
|
|
5
8
|
import { JwtError, JwtRevocationStore } from "./Jwt.js";
|
|
6
9
|
import { LoginApprovalReviewError, LoginApprovalReviewStore, } from "./LoginApproval.js";
|
|
7
|
-
import { LoginRiskContext, LoginRiskSignal } from "./LoginRisk.js";
|
|
8
|
-
import { OAuthAccountStore, OAuthAccountStoreError, OAuthProviderTokenVault, OAuthProviderTokenVaultError, } from "./OAuth.js";
|
|
10
|
+
import { LoginRiskContext, LoginRiskHistory, LoginRiskHistoryError, LoginRiskSignal, maxLoginRiskLevel, } from "./LoginRisk.js";
|
|
11
|
+
import { OAuthAccountStore, OAuthAccountStoreError, OAuthAuthorizationCodeStore, OAuthAuthorizationCodeStoreError, OAuthClientStore, OAuthClientStoreError, OAuthConsentStore, OAuthConsentStoreError, OAuthClientSecretHash, OAuthClientSecretPrefix, OAuthClientSecretStore, OAuthClientSecretStoreError, OAuthCodeChallenge, OAuthProviderModeTokenStore, OAuthProviderModeTokenStoreError, OAuthProviderTokenVault, OAuthProviderTokenVaultError, } from "./OAuth.js";
|
|
9
12
|
import { PasskeyCredentialId, PasskeyCredentialStore, PasskeyCredentialStoreError, } from "./Passkey.js";
|
|
10
13
|
import { RecoveryCodeHash, RecoveryCodeStore, RecoveryCodeStoreError, } from "./RecoveryCode.js";
|
|
11
14
|
import { RefreshTokenFamilyId, RefreshTokenId, RefreshTokenSecretHash, RefreshTokenStore, RefreshTokenStoreError, } from "./RefreshToken.js";
|
|
@@ -13,6 +16,7 @@ import { filterSecurityTimelineEvents, SecurityTimelineEventId, SecurityTimeline
|
|
|
13
16
|
import { CredentialStore, SessionStore, StorageError, UserStore, VerificationStore, } from "./Storage.js";
|
|
14
17
|
import { TotpFactorStore, TotpFactorStoreError, TotpSecret, } from "./Totp.js";
|
|
15
18
|
import { filterTrustedDevicesForUser, TrustedDeviceError, TrustedDeviceStore, } from "./TrustedDevice.js";
|
|
19
|
+
import { filterDueWebhookOutboxRecords, WebhookOutboxItemId, WebhookOutboxStore, WebhookOutboxStoreError, WebhookReplayStore, WebhookReplayStoreError, } from "./Webhook.js";
|
|
16
20
|
export class D1EffectQbError extends Data.TaggedError("D1EffectQbError") {
|
|
17
21
|
}
|
|
18
22
|
const makeAuthUserTable = (name) => Table.make(name, {
|
|
@@ -59,6 +63,17 @@ const makeAuthVerificationTable = (name) => Table.make(name, {
|
|
|
59
63
|
metadata: Column.text().pipe(Column.nullable),
|
|
60
64
|
consumed_at: Column.int().pipe(Column.nullable),
|
|
61
65
|
});
|
|
66
|
+
const makeAuthAuditLogTable = (name) => Table.make(name, {
|
|
67
|
+
id: Column.text().pipe(Column.nullable),
|
|
68
|
+
type: Column.text(),
|
|
69
|
+
user_id: Column.text().pipe(Column.nullable),
|
|
70
|
+
actor_user_id: Column.text().pipe(Column.nullable),
|
|
71
|
+
occurred_at: Column.int(),
|
|
72
|
+
request_ip_hash: Column.text().pipe(Column.nullable),
|
|
73
|
+
request_user_agent_hash: Column.text().pipe(Column.nullable),
|
|
74
|
+
event: Column.text(),
|
|
75
|
+
created_at: Column.int(),
|
|
76
|
+
});
|
|
62
77
|
const makeAuthLoginApprovalReviewTable = (name) => Table.make(name, {
|
|
63
78
|
approval_challenge_id: Column.text().pipe(Column.primaryKey),
|
|
64
79
|
flow_id: Column.text(),
|
|
@@ -77,6 +92,24 @@ const makeAuthLoginApprovalReviewTable = (name) => Table.make(name, {
|
|
|
77
92
|
metadata: Column.text().pipe(Column.nullable),
|
|
78
93
|
review_metadata: Column.text().pipe(Column.nullable),
|
|
79
94
|
});
|
|
95
|
+
const makeAuthLoginRiskHistoryTable = (name) => Table.make(name, {
|
|
96
|
+
id: Column.text().pipe(Column.primaryKey),
|
|
97
|
+
user_id: Column.text(),
|
|
98
|
+
occurred_at: Column.int(),
|
|
99
|
+
outcome: Column.text(),
|
|
100
|
+
method: Column.text(),
|
|
101
|
+
amr: Column.text(),
|
|
102
|
+
aal: Column.text(),
|
|
103
|
+
device_status: Column.text(),
|
|
104
|
+
device_key: Column.text().pipe(Column.nullable),
|
|
105
|
+
location_key: Column.text().pipe(Column.nullable),
|
|
106
|
+
country: Column.text().pipe(Column.nullable),
|
|
107
|
+
region: Column.text().pipe(Column.nullable),
|
|
108
|
+
latitude_micro: Column.int().pipe(Column.nullable),
|
|
109
|
+
longitude_micro: Column.int().pipe(Column.nullable),
|
|
110
|
+
risk_level: Column.text().pipe(Column.nullable),
|
|
111
|
+
created_at: Column.int(),
|
|
112
|
+
});
|
|
80
113
|
const makeAuthTrustedDeviceTable = (name) => Table.make(name, {
|
|
81
114
|
user_id: Column.text(),
|
|
82
115
|
token_hash: Column.text(),
|
|
@@ -179,6 +212,84 @@ const makeAuthOAuthProviderTokenVaultTable = (name) => Table.make(name, {
|
|
|
179
212
|
revoked_at: Column.int().pipe(Column.nullable),
|
|
180
213
|
revocation_reason: Column.text().pipe(Column.nullable),
|
|
181
214
|
});
|
|
215
|
+
const makeAuthOAuthClientTable = (name) => Table.make(name, {
|
|
216
|
+
id: Column.text().pipe(Column.primaryKey),
|
|
217
|
+
type: Column.text(),
|
|
218
|
+
status: Column.text(),
|
|
219
|
+
name: Column.text().pipe(Column.nullable),
|
|
220
|
+
redirect_uris: Column.text(),
|
|
221
|
+
allowed_grant_types: Column.text(),
|
|
222
|
+
allowed_response_types: Column.text(),
|
|
223
|
+
allowed_scopes: Column.text().pipe(Column.nullable),
|
|
224
|
+
created_at: Column.int().pipe(Column.nullable),
|
|
225
|
+
updated_at: Column.int().pipe(Column.nullable),
|
|
226
|
+
metadata: Column.text().pipe(Column.nullable),
|
|
227
|
+
});
|
|
228
|
+
const makeAuthOAuthConsentTable = (name) => Table.make(name, {
|
|
229
|
+
id: Column.text().pipe(Column.primaryKey),
|
|
230
|
+
user_id: Column.text(),
|
|
231
|
+
client_id: Column.text(),
|
|
232
|
+
scopes: Column.text(),
|
|
233
|
+
granted_at: Column.int(),
|
|
234
|
+
expires_at: Column.int().pipe(Column.nullable),
|
|
235
|
+
revoked_at: Column.int().pipe(Column.nullable),
|
|
236
|
+
metadata: Column.text().pipe(Column.nullable),
|
|
237
|
+
});
|
|
238
|
+
const makeAuthOAuthAuthorizationCodeTable = (name) => Table.make(name, {
|
|
239
|
+
code_hash: Column.text().pipe(Column.primaryKey),
|
|
240
|
+
client_id: Column.text(),
|
|
241
|
+
subject: Column.text(),
|
|
242
|
+
redirect_uri: Column.text(),
|
|
243
|
+
scopes: Column.text(),
|
|
244
|
+
code_challenge: Column.text().pipe(Column.nullable),
|
|
245
|
+
code_challenge_method: Column.text().pipe(Column.nullable),
|
|
246
|
+
issued_at: Column.int(),
|
|
247
|
+
expires_at: Column.int(),
|
|
248
|
+
consumed_at: Column.int().pipe(Column.nullable),
|
|
249
|
+
metadata: Column.text().pipe(Column.nullable),
|
|
250
|
+
});
|
|
251
|
+
const makeAuthOAuthClientSecretTable = (name) => Table.make(name, {
|
|
252
|
+
prefix: Column.text().pipe(Column.primaryKey),
|
|
253
|
+
client_id: Column.text(),
|
|
254
|
+
secret_hash: Column.text(),
|
|
255
|
+
authentication_methods: Column.text(),
|
|
256
|
+
created_at: Column.int(),
|
|
257
|
+
expires_at: Column.int().pipe(Column.nullable),
|
|
258
|
+
last_used_at: Column.int().pipe(Column.nullable),
|
|
259
|
+
revoked_at: Column.int().pipe(Column.nullable),
|
|
260
|
+
metadata: Column.text().pipe(Column.nullable),
|
|
261
|
+
});
|
|
262
|
+
const makeAuthOAuthProviderModeTokenTable = (name) => Table.make(name, {
|
|
263
|
+
token_hash: Column.text().pipe(Column.primaryKey),
|
|
264
|
+
token_type: Column.text(),
|
|
265
|
+
client_id: Column.text(),
|
|
266
|
+
subject: Column.text(),
|
|
267
|
+
scopes: Column.text(),
|
|
268
|
+
issued_at: Column.int(),
|
|
269
|
+
expires_at: Column.int(),
|
|
270
|
+
issuer: Column.text().pipe(Column.nullable),
|
|
271
|
+
audience: Column.text().pipe(Column.nullable),
|
|
272
|
+
jwt_id: Column.text().pipe(Column.nullable),
|
|
273
|
+
revoked_at: Column.int().pipe(Column.nullable),
|
|
274
|
+
revocation_reason: Column.text().pipe(Column.nullable),
|
|
275
|
+
rotated_at: Column.int().pipe(Column.nullable),
|
|
276
|
+
replaced_by_token_hash: Column.text().pipe(Column.nullable),
|
|
277
|
+
metadata: Column.text().pipe(Column.nullable),
|
|
278
|
+
});
|
|
279
|
+
const makeAuthDomainVerificationTable = (name) => Table.make(name, {
|
|
280
|
+
id: Column.text().pipe(Column.primaryKey),
|
|
281
|
+
owner_id: Column.text(),
|
|
282
|
+
domain: Column.text(),
|
|
283
|
+
proof_method: Column.text(),
|
|
284
|
+
proof_token: Column.text(),
|
|
285
|
+
status: Column.text(),
|
|
286
|
+
created_at: Column.int(),
|
|
287
|
+
expires_at: Column.int(),
|
|
288
|
+
verified_at: Column.int().pipe(Column.nullable),
|
|
289
|
+
revoked_at: Column.int().pipe(Column.nullable),
|
|
290
|
+
last_checked_at: Column.int().pipe(Column.nullable),
|
|
291
|
+
metadata: Column.text().pipe(Column.nullable),
|
|
292
|
+
});
|
|
182
293
|
const makeAuthSecurityTimelineTable = (name) => Table.make(name, {
|
|
183
294
|
id: Column.text().pipe(Column.primaryKey),
|
|
184
295
|
user_id: Column.text(),
|
|
@@ -191,6 +302,23 @@ const makeAuthSecurityTimelineTable = (name) => Table.make(name, {
|
|
|
191
302
|
request: Column.text().pipe(Column.nullable),
|
|
192
303
|
metadata: Column.text().pipe(Column.nullable),
|
|
193
304
|
});
|
|
305
|
+
const makeAuthWebhookOutboxTable = (name) => Table.make(name, {
|
|
306
|
+
id: Column.text().pipe(Column.primaryKey),
|
|
307
|
+
endpoint_key: Column.text(),
|
|
308
|
+
event: Column.text(),
|
|
309
|
+
status: Column.text(),
|
|
310
|
+
attempts: Column.int(),
|
|
311
|
+
next_attempt_at: Column.int(),
|
|
312
|
+
created_at: Column.int(),
|
|
313
|
+
updated_at: Column.int(),
|
|
314
|
+
delivered_at: Column.int().pipe(Column.nullable),
|
|
315
|
+
last_error: Column.text().pipe(Column.nullable),
|
|
316
|
+
});
|
|
317
|
+
const makeAuthWebhookReplayTable = (name) => Table.make(name, {
|
|
318
|
+
id: Column.text().pipe(Column.primaryKey),
|
|
319
|
+
expires_at: Column.int(),
|
|
320
|
+
created_at: Column.int(),
|
|
321
|
+
});
|
|
194
322
|
const authSqliteTablesTypeId = Symbol.for("@effect-auth/core/EffectQbSqliteStorage/AuthSqliteTables");
|
|
195
323
|
const jsonEncode = (value) => value === undefined ? null : JSON.stringify(value);
|
|
196
324
|
const jsonDecode = (value) => {
|
|
@@ -220,6 +348,7 @@ const queryInsert = (table, values) => Query.insert(table, values);
|
|
|
220
348
|
const queryUpdate = (table, values) => Query.update(table, values);
|
|
221
349
|
const queryEq = (left, right) => Query.eq(left, right);
|
|
222
350
|
const queryGt = (left, right) => Query.gt(left, right);
|
|
351
|
+
const queryLt = (left, right) => Query.lt(left, right);
|
|
223
352
|
const queryLte = (left, right) => Query.lte(left, right);
|
|
224
353
|
const queryIsNull = (value) => Query.isNull(value);
|
|
225
354
|
const queryIn = (value, first, ...rest) => Query.in(value, first, ...rest);
|
|
@@ -353,6 +482,10 @@ const decodeDefaultVerificationRow = (row) => omitUndefined({
|
|
|
353
482
|
const decodeVerificationRow = (tables, row) => tables.verification.decode === undefined
|
|
354
483
|
? decodeDefaultVerificationRow(row)
|
|
355
484
|
: tables.verification.decode(row);
|
|
485
|
+
const decodeDefaultAuditLogEvent = (row) => jsonDecode(row.event);
|
|
486
|
+
const decodeAuditLogEvent = (tables, row) => tables.auditLog.decode === undefined
|
|
487
|
+
? decodeDefaultAuditLogEvent(row)
|
|
488
|
+
: tables.auditLog.decode(row);
|
|
356
489
|
const decodeDefaultLoginApprovalReviewRow = (row) => omitUndefined({
|
|
357
490
|
approvalChallengeId: ChallengeId(row.approvalChallengeId),
|
|
358
491
|
flowId: AuthFlowId(row.flowId),
|
|
@@ -376,6 +509,29 @@ const decodeDefaultLoginApprovalReviewRow = (row) => omitUndefined({
|
|
|
376
509
|
const decodeLoginApprovalReviewRow = (tables, row) => tables.loginApprovalReview.decode === undefined
|
|
377
510
|
? decodeDefaultLoginApprovalReviewRow(row)
|
|
378
511
|
: tables.loginApprovalReview.decode(row);
|
|
512
|
+
const decodeDefaultLoginRiskHistoryRecord = (row) => omitUndefined({
|
|
513
|
+
id: row.id,
|
|
514
|
+
userId: UserId(row.userId),
|
|
515
|
+
occurredAt: UnixMillis(Number(row.occurredAt)),
|
|
516
|
+
outcome: row.outcome,
|
|
517
|
+
method: row.method,
|
|
518
|
+
amr: decodeAmr(row.amr),
|
|
519
|
+
aal: row.aal,
|
|
520
|
+
device: { status: row.deviceStatus },
|
|
521
|
+
deviceKey: row.deviceKey ?? undefined,
|
|
522
|
+
locationKey: row.locationKey ?? undefined,
|
|
523
|
+
country: row.country ?? undefined,
|
|
524
|
+
region: row.region ?? undefined,
|
|
525
|
+
latitude: row.latitudeMicro === null ? undefined : Number(row.latitudeMicro) / 1_000_000,
|
|
526
|
+
longitude: row.longitudeMicro === null
|
|
527
|
+
? undefined
|
|
528
|
+
: Number(row.longitudeMicro) / 1_000_000,
|
|
529
|
+
riskLevel: row.riskLevel === null ? undefined : row.riskLevel,
|
|
530
|
+
createdAt: UnixMillis(Number(row.createdAt)),
|
|
531
|
+
});
|
|
532
|
+
const decodeLoginRiskHistoryRecord = (tables, row) => tables.loginRiskHistory.decode === undefined
|
|
533
|
+
? decodeDefaultLoginRiskHistoryRecord(row)
|
|
534
|
+
: tables.loginRiskHistory.decode(row);
|
|
379
535
|
const decodeDefaultTrustedDeviceRow = (row) => omitUndefined({
|
|
380
536
|
userId: UserId(row.userId),
|
|
381
537
|
tokenHash: row.tokenHash,
|
|
@@ -525,6 +681,134 @@ const decodeDefaultOAuthProviderTokenVaultRow = (row) => omitUndefined({
|
|
|
525
681
|
const decodeOAuthProviderTokenVaultRow = (tables, row) => tables.oauthProviderTokenVault.decode === undefined
|
|
526
682
|
? decodeDefaultOAuthProviderTokenVaultRow(row)
|
|
527
683
|
: tables.oauthProviderTokenVault.decode(row);
|
|
684
|
+
const decodeDefaultOAuthClientRow = (row) => omitUndefined({
|
|
685
|
+
id: OAuthClientId(row.id),
|
|
686
|
+
type: row.type,
|
|
687
|
+
status: row.status,
|
|
688
|
+
name: row.name ?? undefined,
|
|
689
|
+
redirectUris: decodeStringArray(row.redirectUris),
|
|
690
|
+
allowedGrantTypes: decodeStringArray(row.allowedGrantTypes),
|
|
691
|
+
allowedResponseTypes: decodeStringArray(row.allowedResponseTypes),
|
|
692
|
+
allowedScopes: decodeOptionalStringArray(row.allowedScopes),
|
|
693
|
+
createdAt: optionalUnixMillis(row.createdAt),
|
|
694
|
+
updatedAt: optionalUnixMillis(row.updatedAt),
|
|
695
|
+
metadata: jsonDecode(row.metadata),
|
|
696
|
+
});
|
|
697
|
+
const decodeOAuthClientRow = (tables, row) => tables.oauthClient.decode === undefined
|
|
698
|
+
? decodeDefaultOAuthClientRow(row)
|
|
699
|
+
: tables.oauthClient.decode(row);
|
|
700
|
+
const decodeDefaultOAuthConsentRow = (row) => omitUndefined({
|
|
701
|
+
userId: UserId(row.userId),
|
|
702
|
+
clientId: OAuthClientId(row.clientId),
|
|
703
|
+
scopes: decodeStringArray(row.scopes),
|
|
704
|
+
grantedAt: UnixMillis(Number(row.grantedAt)),
|
|
705
|
+
expiresAt: optionalUnixMillis(row.expiresAt),
|
|
706
|
+
revokedAt: optionalUnixMillis(row.revokedAt),
|
|
707
|
+
metadata: jsonDecode(row.metadata),
|
|
708
|
+
});
|
|
709
|
+
const decodeOAuthConsentRow = (tables, row) => tables.oauthConsent.decode === undefined
|
|
710
|
+
? decodeDefaultOAuthConsentRow(row)
|
|
711
|
+
: tables.oauthConsent.decode(row);
|
|
712
|
+
const oauthConsentCoversScopes = (record, scopes = []) => scopes.every((scope) => record.scopes.includes(scope));
|
|
713
|
+
const isOAuthConsentActive = (record, input) => record.revokedAt === undefined &&
|
|
714
|
+
(record.expiresAt === undefined || Number(record.expiresAt) > Number(input.now)) &&
|
|
715
|
+
oauthConsentCoversScopes(record, input.scopes);
|
|
716
|
+
const oauthClientRedirectUriValidationResult = (client, input) => {
|
|
717
|
+
if (client === undefined) {
|
|
718
|
+
return { valid: false, reason: "unknown_client" };
|
|
719
|
+
}
|
|
720
|
+
if (client.status !== "active") {
|
|
721
|
+
return { valid: false, reason: "disabled_client" };
|
|
722
|
+
}
|
|
723
|
+
const responseType = input.responseType ?? "code";
|
|
724
|
+
if (!client.allowedResponseTypes.includes(responseType)) {
|
|
725
|
+
return { valid: false, reason: "unsupported_response_type" };
|
|
726
|
+
}
|
|
727
|
+
if (input.grantType !== undefined &&
|
|
728
|
+
!client.allowedGrantTypes.includes(input.grantType)) {
|
|
729
|
+
return { valid: false, reason: "unsupported_grant_type" };
|
|
730
|
+
}
|
|
731
|
+
if (!client.redirectUris.includes(input.redirectUri)) {
|
|
732
|
+
return { valid: false, reason: "redirect_uri_mismatch" };
|
|
733
|
+
}
|
|
734
|
+
return { valid: true, client };
|
|
735
|
+
};
|
|
736
|
+
const decodeDefaultOAuthAuthorizationCodeRow = (row) => omitUndefined({
|
|
737
|
+
codeHash: row.codeHash,
|
|
738
|
+
clientId: OAuthClientId(row.clientId),
|
|
739
|
+
subject: row.subject,
|
|
740
|
+
redirectUri: row.redirectUri,
|
|
741
|
+
scopes: decodeStringArray(row.scopes),
|
|
742
|
+
codeChallenge: row.codeChallenge === null ? undefined : OAuthCodeChallenge(row.codeChallenge),
|
|
743
|
+
codeChallengeMethod: row.codeChallengeMethod === null
|
|
744
|
+
? undefined
|
|
745
|
+
: row.codeChallengeMethod,
|
|
746
|
+
issuedAt: UnixMillis(Number(row.issuedAt)),
|
|
747
|
+
expiresAt: UnixMillis(Number(row.expiresAt)),
|
|
748
|
+
consumedAt: optionalUnixMillis(row.consumedAt),
|
|
749
|
+
metadata: jsonDecode(row.metadata),
|
|
750
|
+
});
|
|
751
|
+
const decodeOAuthAuthorizationCodeRow = (tables, row) => tables.oauthAuthorizationCode.decode === undefined
|
|
752
|
+
? decodeDefaultOAuthAuthorizationCodeRow(row)
|
|
753
|
+
: tables.oauthAuthorizationCode.decode(row);
|
|
754
|
+
const decodeDefaultOAuthClientSecretRow = (row) => omitUndefined({
|
|
755
|
+
prefix: OAuthClientSecretPrefix(row.prefix),
|
|
756
|
+
clientId: OAuthClientId(row.clientId),
|
|
757
|
+
secretHash: OAuthClientSecretHash(row.secretHash),
|
|
758
|
+
authenticationMethods: decodeStringArray(row.authenticationMethods),
|
|
759
|
+
createdAt: UnixMillis(Number(row.createdAt)),
|
|
760
|
+
expiresAt: optionalUnixMillis(row.expiresAt),
|
|
761
|
+
lastUsedAt: optionalUnixMillis(row.lastUsedAt),
|
|
762
|
+
revokedAt: optionalUnixMillis(row.revokedAt),
|
|
763
|
+
metadata: jsonDecode(row.metadata),
|
|
764
|
+
});
|
|
765
|
+
const decodeOAuthClientSecretRow = (tables, row) => tables.oauthClientSecret.decode === undefined
|
|
766
|
+
? decodeDefaultOAuthClientSecretRow(row)
|
|
767
|
+
: tables.oauthClientSecret.decode(row);
|
|
768
|
+
const decodeOAuthProviderModeTokenAudience = (value) => {
|
|
769
|
+
const decoded = jsonDecode(value);
|
|
770
|
+
if (typeof decoded === "string") {
|
|
771
|
+
return decoded;
|
|
772
|
+
}
|
|
773
|
+
return Array.isArray(decoded) ? decoded.map(String) : undefined;
|
|
774
|
+
};
|
|
775
|
+
const decodeDefaultOAuthProviderModeTokenRow = (row) => omitUndefined({
|
|
776
|
+
tokenHash: row.tokenHash,
|
|
777
|
+
tokenType: row.tokenType,
|
|
778
|
+
clientId: OAuthClientId(row.clientId),
|
|
779
|
+
subject: row.subject,
|
|
780
|
+
scopes: decodeStringArray(row.scopes),
|
|
781
|
+
issuedAt: UnixMillis(Number(row.issuedAt)),
|
|
782
|
+
expiresAt: UnixMillis(Number(row.expiresAt)),
|
|
783
|
+
issuer: row.issuer ?? undefined,
|
|
784
|
+
audience: decodeOAuthProviderModeTokenAudience(row.audience),
|
|
785
|
+
jwtId: row.jwtId ?? undefined,
|
|
786
|
+
revokedAt: optionalUnixMillis(row.revokedAt),
|
|
787
|
+
revocationReason: row.revocationReason ?? undefined,
|
|
788
|
+
rotatedAt: optionalUnixMillis(row.rotatedAt),
|
|
789
|
+
replacedByTokenHash: row.replacedByTokenHash ?? undefined,
|
|
790
|
+
metadata: jsonDecode(row.metadata),
|
|
791
|
+
});
|
|
792
|
+
const decodeOAuthProviderModeTokenRow = (tables, row) => tables.oauthProviderModeToken.decode === undefined
|
|
793
|
+
? decodeDefaultOAuthProviderModeTokenRow(row)
|
|
794
|
+
: tables.oauthProviderModeToken.decode(row);
|
|
795
|
+
const decodeDefaultDomainVerificationRecord = (row) => omitUndefined({
|
|
796
|
+
id: DomainVerificationId(row.id),
|
|
797
|
+
ownerId: row.ownerId,
|
|
798
|
+
domain: DomainName(row.domain),
|
|
799
|
+
proofMethod: row.proofMethod,
|
|
800
|
+
proofToken: DomainVerificationProofToken(row.proofToken),
|
|
801
|
+
status: row.status,
|
|
802
|
+
createdAt: UnixMillis(Number(row.createdAt)),
|
|
803
|
+
expiresAt: UnixMillis(Number(row.expiresAt)),
|
|
804
|
+
verifiedAt: optionalUnixMillis(row.verifiedAt),
|
|
805
|
+
revokedAt: optionalUnixMillis(row.revokedAt),
|
|
806
|
+
lastCheckedAt: optionalUnixMillis(row.lastCheckedAt),
|
|
807
|
+
metadata: jsonDecode(row.metadata),
|
|
808
|
+
});
|
|
809
|
+
const decodeDomainVerificationRecord = (tables, row) => tables.domainVerification.decode === undefined
|
|
810
|
+
? decodeDefaultDomainVerificationRecord(row)
|
|
811
|
+
: tables.domainVerification.decode(row);
|
|
528
812
|
const decodeDefaultSecurityTimelineEvent = (row) => omitUndefined({
|
|
529
813
|
id: SecurityTimelineEventId(row.id),
|
|
530
814
|
userId: UserId(row.userId),
|
|
@@ -540,6 +824,21 @@ const decodeDefaultSecurityTimelineEvent = (row) => omitUndefined({
|
|
|
540
824
|
const decodeSecurityTimelineEvent = (tables, row) => tables.securityTimeline.decode === undefined
|
|
541
825
|
? decodeDefaultSecurityTimelineEvent(row)
|
|
542
826
|
: tables.securityTimeline.decode(row);
|
|
827
|
+
const decodeDefaultWebhookOutboxRecord = (row) => omitUndefined({
|
|
828
|
+
id: WebhookOutboxItemId(row.id),
|
|
829
|
+
endpointKey: row.endpointKey,
|
|
830
|
+
event: jsonDecode(row.event),
|
|
831
|
+
status: row.status,
|
|
832
|
+
attempts: Number(row.attempts),
|
|
833
|
+
nextAttemptAt: UnixMillis(Number(row.nextAttemptAt)),
|
|
834
|
+
createdAt: UnixMillis(Number(row.createdAt)),
|
|
835
|
+
updatedAt: UnixMillis(Number(row.updatedAt)),
|
|
836
|
+
deliveredAt: optionalUnixMillis(row.deliveredAt),
|
|
837
|
+
lastError: row.lastError ?? undefined,
|
|
838
|
+
});
|
|
839
|
+
const decodeWebhookOutboxRecord = (tables, row) => tables.webhookOutbox.decode === undefined
|
|
840
|
+
? decodeDefaultWebhookOutboxRecord(row)
|
|
841
|
+
: tables.webhookOutbox.decode(row);
|
|
543
842
|
const providerTokenVaultTokens = (record) => omitUndefined({
|
|
544
843
|
accessTokenCiphertext: record.accessTokenCiphertext,
|
|
545
844
|
refreshTokenCiphertext: record.refreshTokenCiphertext,
|
|
@@ -596,6 +895,17 @@ const verificationInsert = (row) => ({
|
|
|
596
895
|
metadata: jsonEncode(row.metadata),
|
|
597
896
|
consumed_at: null,
|
|
598
897
|
});
|
|
898
|
+
const auditLogInsert = (event, createdAt) => ({
|
|
899
|
+
id: event.id ?? null,
|
|
900
|
+
type: event.type,
|
|
901
|
+
user_id: auditEventUserId(event) ?? null,
|
|
902
|
+
actor_user_id: auditEventActorUserId(event) ?? null,
|
|
903
|
+
occurred_at: Number(event.occurredAt),
|
|
904
|
+
request_ip_hash: event.request?.ipHash ?? null,
|
|
905
|
+
request_user_agent_hash: event.request?.userAgentHash ?? null,
|
|
906
|
+
event: JSON.stringify(event),
|
|
907
|
+
created_at: Number(createdAt),
|
|
908
|
+
});
|
|
599
909
|
const loginApprovalReviewInsert = (row) => ({
|
|
600
910
|
approval_challenge_id: row.approvalChallengeId,
|
|
601
911
|
flow_id: row.flowId,
|
|
@@ -614,6 +924,27 @@ const loginApprovalReviewInsert = (row) => ({
|
|
|
614
924
|
metadata: jsonEncode(row.metadata),
|
|
615
925
|
review_metadata: jsonEncode(row.reviewMetadata),
|
|
616
926
|
});
|
|
927
|
+
const coordinateMicro = (value) => value === undefined || !Number.isFinite(value)
|
|
928
|
+
? null
|
|
929
|
+
: Math.round(value * 1_000_000);
|
|
930
|
+
const loginRiskHistoryInsert = (row) => ({
|
|
931
|
+
id: row.id,
|
|
932
|
+
user_id: row.userId,
|
|
933
|
+
occurred_at: Number(row.occurredAt),
|
|
934
|
+
outcome: row.outcome,
|
|
935
|
+
method: row.method,
|
|
936
|
+
amr: JSON.stringify(row.amr),
|
|
937
|
+
aal: row.aal,
|
|
938
|
+
device_status: row.device.status,
|
|
939
|
+
device_key: row.deviceKey ?? null,
|
|
940
|
+
location_key: row.locationKey ?? null,
|
|
941
|
+
country: row.country ?? null,
|
|
942
|
+
region: row.region ?? null,
|
|
943
|
+
latitude_micro: coordinateMicro(row.latitude),
|
|
944
|
+
longitude_micro: coordinateMicro(row.longitude),
|
|
945
|
+
risk_level: row.riskLevel ?? null,
|
|
946
|
+
created_at: Number(row.createdAt),
|
|
947
|
+
});
|
|
617
948
|
const userMarkEmailVerifiedUpdate = (input) => ({
|
|
618
949
|
email_verified: 1,
|
|
619
950
|
updated_at: Number(input.updatedAt),
|
|
@@ -825,6 +1156,119 @@ const oauthProviderTokenVaultMarkRevoked = (input) => ({
|
|
|
825
1156
|
revoked_at: Number(input.revokedAt),
|
|
826
1157
|
revocation_reason: input.reason,
|
|
827
1158
|
});
|
|
1159
|
+
const oauthClientValues = (record) => ({
|
|
1160
|
+
id: record.id,
|
|
1161
|
+
type: record.type,
|
|
1162
|
+
status: record.status,
|
|
1163
|
+
name: record.name ?? null,
|
|
1164
|
+
redirect_uris: JSON.stringify(record.redirectUris),
|
|
1165
|
+
allowed_grant_types: JSON.stringify(record.allowedGrantTypes),
|
|
1166
|
+
allowed_response_types: JSON.stringify(record.allowedResponseTypes),
|
|
1167
|
+
allowed_scopes: jsonEncode(record.allowedScopes),
|
|
1168
|
+
created_at: record.createdAt === undefined ? null : Number(record.createdAt),
|
|
1169
|
+
updated_at: record.updatedAt === undefined ? null : Number(record.updatedAt),
|
|
1170
|
+
metadata: jsonEncode(record.metadata),
|
|
1171
|
+
});
|
|
1172
|
+
const oauthConsentId = (input) => JSON.stringify([input.userId, input.clientId]);
|
|
1173
|
+
const oauthConsentValues = (record) => ({
|
|
1174
|
+
id: oauthConsentId(record),
|
|
1175
|
+
user_id: record.userId,
|
|
1176
|
+
client_id: record.clientId,
|
|
1177
|
+
scopes: JSON.stringify(record.scopes),
|
|
1178
|
+
granted_at: Number(record.grantedAt),
|
|
1179
|
+
expires_at: record.expiresAt === undefined ? null : Number(record.expiresAt),
|
|
1180
|
+
revoked_at: record.revokedAt === undefined ? null : Number(record.revokedAt),
|
|
1181
|
+
metadata: jsonEncode(record.metadata),
|
|
1182
|
+
});
|
|
1183
|
+
const oauthConsentRevoke = (input, row) => ({
|
|
1184
|
+
revoked_at: Number(row.revokedAt ?? input.revokedAt),
|
|
1185
|
+
metadata: jsonEncode(metadataWithReason(row.metadata, "revokeReason", input.reason)),
|
|
1186
|
+
});
|
|
1187
|
+
const oauthAuthorizationCodeValues = (record) => ({
|
|
1188
|
+
code_hash: record.codeHash,
|
|
1189
|
+
client_id: record.clientId,
|
|
1190
|
+
subject: record.subject,
|
|
1191
|
+
redirect_uri: record.redirectUri,
|
|
1192
|
+
scopes: JSON.stringify(record.scopes),
|
|
1193
|
+
code_challenge: record.codeChallenge ?? null,
|
|
1194
|
+
code_challenge_method: record.codeChallengeMethod ?? null,
|
|
1195
|
+
issued_at: Number(record.issuedAt),
|
|
1196
|
+
expires_at: Number(record.expiresAt),
|
|
1197
|
+
consumed_at: record.consumedAt === undefined ? null : Number(record.consumedAt),
|
|
1198
|
+
metadata: jsonEncode(record.metadata),
|
|
1199
|
+
});
|
|
1200
|
+
const oauthAuthorizationCodeMarkConsumed = (input) => ({
|
|
1201
|
+
consumed_at: Number(input.consumedAt),
|
|
1202
|
+
});
|
|
1203
|
+
const oauthClientSecretValues = (record) => ({
|
|
1204
|
+
prefix: record.prefix,
|
|
1205
|
+
client_id: record.clientId,
|
|
1206
|
+
secret_hash: record.secretHash,
|
|
1207
|
+
authentication_methods: JSON.stringify(record.authenticationMethods),
|
|
1208
|
+
created_at: Number(record.createdAt),
|
|
1209
|
+
expires_at: record.expiresAt === undefined ? null : Number(record.expiresAt),
|
|
1210
|
+
last_used_at: record.lastUsedAt === undefined ? null : Number(record.lastUsedAt),
|
|
1211
|
+
revoked_at: record.revokedAt === undefined ? null : Number(record.revokedAt),
|
|
1212
|
+
metadata: jsonEncode(record.metadata),
|
|
1213
|
+
});
|
|
1214
|
+
const oauthClientSecretMarkUsed = (input) => omitUndefined({
|
|
1215
|
+
last_used_at: Number(input.lastUsedAt),
|
|
1216
|
+
metadata: input.metadata === undefined ? undefined : jsonEncode(input.metadata),
|
|
1217
|
+
});
|
|
1218
|
+
const oauthClientSecretRevoke = (input, row) => ({
|
|
1219
|
+
revoked_at: Number(input.revokedAt),
|
|
1220
|
+
metadata: jsonEncode(metadataWithReason(row.metadata, "revokeReason", input.reason)),
|
|
1221
|
+
});
|
|
1222
|
+
const oauthProviderModeTokenValues = (record) => ({
|
|
1223
|
+
token_hash: record.tokenHash,
|
|
1224
|
+
token_type: record.tokenType,
|
|
1225
|
+
client_id: record.clientId,
|
|
1226
|
+
subject: record.subject,
|
|
1227
|
+
scopes: JSON.stringify(record.scopes),
|
|
1228
|
+
issued_at: Number(record.issuedAt),
|
|
1229
|
+
expires_at: Number(record.expiresAt),
|
|
1230
|
+
issuer: record.issuer ?? null,
|
|
1231
|
+
audience: jsonEncode(record.audience),
|
|
1232
|
+
jwt_id: record.jwtId ?? null,
|
|
1233
|
+
revoked_at: record.revokedAt === undefined ? null : Number(record.revokedAt),
|
|
1234
|
+
revocation_reason: record.revocationReason ?? null,
|
|
1235
|
+
rotated_at: record.rotatedAt === undefined ? null : Number(record.rotatedAt),
|
|
1236
|
+
replaced_by_token_hash: record.replacedByTokenHash ?? null,
|
|
1237
|
+
metadata: jsonEncode(record.metadata),
|
|
1238
|
+
});
|
|
1239
|
+
const oauthProviderModeTokenRevoke = (input, row) => ({
|
|
1240
|
+
revoked_at: Number(row.revokedAt ?? input.revokedAt),
|
|
1241
|
+
revocation_reason: row.revocationReason ?? input.reason ?? null,
|
|
1242
|
+
});
|
|
1243
|
+
const oauthProviderModeTokenRotate = (input) => ({
|
|
1244
|
+
rotated_at: Number(input.rotatedAt),
|
|
1245
|
+
replaced_by_token_hash: input.replacedByTokenHash,
|
|
1246
|
+
});
|
|
1247
|
+
const domainVerificationValues = (record) => ({
|
|
1248
|
+
id: record.id,
|
|
1249
|
+
owner_id: record.ownerId,
|
|
1250
|
+
domain: record.domain,
|
|
1251
|
+
proof_method: record.proofMethod,
|
|
1252
|
+
proof_token: record.proofToken,
|
|
1253
|
+
status: record.status,
|
|
1254
|
+
created_at: Number(record.createdAt),
|
|
1255
|
+
expires_at: Number(record.expiresAt),
|
|
1256
|
+
verified_at: record.verifiedAt === undefined ? null : Number(record.verifiedAt),
|
|
1257
|
+
revoked_at: record.revokedAt === undefined ? null : Number(record.revokedAt),
|
|
1258
|
+
last_checked_at: record.lastCheckedAt === undefined ? null : Number(record.lastCheckedAt),
|
|
1259
|
+
metadata: jsonEncode(record.metadata),
|
|
1260
|
+
});
|
|
1261
|
+
const domainVerificationMarkVerified = (input) => omitUndefined({
|
|
1262
|
+
status: "verified",
|
|
1263
|
+
verified_at: Number(input.verifiedAt),
|
|
1264
|
+
last_checked_at: Number(input.verifiedAt),
|
|
1265
|
+
metadata: input.metadata === undefined ? undefined : jsonEncode(input.metadata),
|
|
1266
|
+
});
|
|
1267
|
+
const domainVerificationRevoke = (input, row) => ({
|
|
1268
|
+
status: "revoked",
|
|
1269
|
+
revoked_at: Number(input.revokedAt),
|
|
1270
|
+
metadata: jsonEncode(metadataWithReason(row.metadata, "revokeReason", input.reason)),
|
|
1271
|
+
});
|
|
828
1272
|
const securityTimelineInsert = (event) => ({
|
|
829
1273
|
id: event.id,
|
|
830
1274
|
user_id: event.userId,
|
|
@@ -837,17 +1281,59 @@ const securityTimelineInsert = (event) => ({
|
|
|
837
1281
|
request: jsonEncode(event.request),
|
|
838
1282
|
metadata: jsonEncode(event.metadata),
|
|
839
1283
|
});
|
|
1284
|
+
const webhookOutboxInsert = (record) => ({
|
|
1285
|
+
id: record.id,
|
|
1286
|
+
endpoint_key: record.endpointKey,
|
|
1287
|
+
event: jsonEncode(record.event),
|
|
1288
|
+
status: record.status,
|
|
1289
|
+
attempts: record.attempts,
|
|
1290
|
+
next_attempt_at: Number(record.nextAttemptAt),
|
|
1291
|
+
created_at: Number(record.createdAt),
|
|
1292
|
+
updated_at: Number(record.updatedAt),
|
|
1293
|
+
delivered_at: record.deliveredAt === undefined ? null : Number(record.deliveredAt),
|
|
1294
|
+
last_error: record.lastError ?? null,
|
|
1295
|
+
});
|
|
1296
|
+
const webhookOutboxMarkDelivered = (input) => ({
|
|
1297
|
+
status: "delivered",
|
|
1298
|
+
delivered_at: Number(input.deliveredAt),
|
|
1299
|
+
updated_at: Number(input.deliveredAt),
|
|
1300
|
+
last_error: null,
|
|
1301
|
+
});
|
|
1302
|
+
const webhookOutboxMarkFailed = (input) => ({
|
|
1303
|
+
status: "failed",
|
|
1304
|
+
attempts: input.attempts,
|
|
1305
|
+
next_attempt_at: Number(input.nextAttemptAt),
|
|
1306
|
+
updated_at: Number(input.failedAt),
|
|
1307
|
+
last_error: input.error ?? null,
|
|
1308
|
+
});
|
|
1309
|
+
const webhookOutboxMarkDeadLettered = (input) => ({
|
|
1310
|
+
status: "dead_lettered",
|
|
1311
|
+
updated_at: Number(input.deadLetteredAt),
|
|
1312
|
+
last_error: input.error ?? null,
|
|
1313
|
+
});
|
|
1314
|
+
const webhookReplayInsert = (input) => ({
|
|
1315
|
+
id: input.id,
|
|
1316
|
+
expires_at: Number(input.expiresAt),
|
|
1317
|
+
created_at: Number(input.now),
|
|
1318
|
+
});
|
|
1319
|
+
const webhookReplayUpdate = (input) => ({
|
|
1320
|
+
expires_at: Number(input.expiresAt),
|
|
1321
|
+
created_at: Number(input.now),
|
|
1322
|
+
});
|
|
840
1323
|
const jwtRevocationUpdate = (record) => ({
|
|
841
1324
|
revoked_at: Number(record.revokedAt),
|
|
842
1325
|
expires_at: record.expiresAt === undefined ? null : Number(record.expiresAt),
|
|
843
1326
|
reason: record.reason ?? null,
|
|
844
1327
|
});
|
|
1328
|
+
const authSqliteTableName = (name, defaultName) => name ?? defaultName;
|
|
845
1329
|
const makeInternalAuthSqliteTables = (names = {}) => {
|
|
846
1330
|
const user = makeAuthUserTable(names.user ?? "auth_user");
|
|
847
1331
|
const credential = makeAuthCredentialTable(names.credential ?? "auth_credential");
|
|
848
1332
|
const session = makeAuthSessionTable(names.session ?? "auth_session");
|
|
849
1333
|
const verification = makeAuthVerificationTable(names.verification ?? "auth_verification");
|
|
1334
|
+
const auditLog = makeAuthAuditLogTable(authSqliteTableName(names.auditLog, "auth_audit_log"));
|
|
850
1335
|
const loginApprovalReview = makeAuthLoginApprovalReviewTable(names.loginApprovalReview ?? "auth_login_approval_review");
|
|
1336
|
+
const loginRiskHistory = makeAuthLoginRiskHistoryTable(names.loginRiskHistory ?? "auth_login_risk_history");
|
|
851
1337
|
const trustedDevice = makeAuthTrustedDeviceTable(names.trustedDevice ?? "auth_trusted_device");
|
|
852
1338
|
const passkeyCredential = makeAuthPasskeyCredentialTable(names.passkeyCredential ?? "auth_passkey_credential");
|
|
853
1339
|
const totpFactor = makeAuthTotpFactorTable(names.totpFactor ?? "auth_totp_factor");
|
|
@@ -856,8 +1342,16 @@ const makeInternalAuthSqliteTables = (names = {}) => {
|
|
|
856
1342
|
const refreshToken = makeAuthRefreshTokenTable(names.refreshToken ?? "auth_refresh_token");
|
|
857
1343
|
const jwtRevocation = makeAuthJwtRevocationTable(names.jwtRevocation ?? "auth_jwt_revocation");
|
|
858
1344
|
const oauthAccount = makeAuthOAuthAccountTable(names.oauthAccount ?? "auth_oauth_account");
|
|
1345
|
+
const oauthClient = makeAuthOAuthClientTable(authSqliteTableName(names.oauthClient, "auth_oauth_client"));
|
|
1346
|
+
const oauthConsent = makeAuthOAuthConsentTable(authSqliteTableName(names.oauthConsent, "auth_oauth_consent"));
|
|
1347
|
+
const oauthAuthorizationCode = makeAuthOAuthAuthorizationCodeTable(authSqliteTableName(names.oauthAuthorizationCode, "auth_oauth_authorization_code"));
|
|
1348
|
+
const oauthClientSecret = makeAuthOAuthClientSecretTable(authSqliteTableName(names.oauthClientSecret, "auth_oauth_client_secret"));
|
|
1349
|
+
const oauthProviderModeToken = makeAuthOAuthProviderModeTokenTable(authSqliteTableName(names.oauthProviderModeToken, "auth_oauth_provider_mode_token"));
|
|
859
1350
|
const oauthProviderTokenVault = makeAuthOAuthProviderTokenVaultTable(names.oauthProviderTokenVault ?? "auth_oauth_provider_token_vault");
|
|
1351
|
+
const domainVerification = makeAuthDomainVerificationTable(authSqliteTableName(names.domainVerification, "auth_domain_verification"));
|
|
860
1352
|
const securityTimeline = makeAuthSecurityTimelineTable(names.securityTimeline ?? "auth_security_timeline");
|
|
1353
|
+
const webhookOutbox = makeAuthWebhookOutboxTable(names.webhookOutbox ?? "auth_webhook_outbox");
|
|
1354
|
+
const webhookReplay = makeAuthWebhookReplayTable(names.webhookReplay ?? "auth_webhook_replay");
|
|
861
1355
|
return {
|
|
862
1356
|
user: {
|
|
863
1357
|
table: user,
|
|
@@ -926,6 +1420,21 @@ const makeInternalAuthSqliteTables = (names = {}) => {
|
|
|
926
1420
|
insert: verificationInsert,
|
|
927
1421
|
consume: verificationConsumeUpdate,
|
|
928
1422
|
},
|
|
1423
|
+
auditLog: {
|
|
1424
|
+
table: auditLog,
|
|
1425
|
+
select: {
|
|
1426
|
+
id: auditLog.id,
|
|
1427
|
+
type: auditLog.type,
|
|
1428
|
+
userId: auditLog.user_id,
|
|
1429
|
+
actorUserId: auditLog.actor_user_id,
|
|
1430
|
+
occurredAt: auditLog.occurred_at,
|
|
1431
|
+
requestIpHash: auditLog.request_ip_hash,
|
|
1432
|
+
requestUserAgentHash: auditLog.request_user_agent_hash,
|
|
1433
|
+
event: auditLog.event,
|
|
1434
|
+
createdAt: auditLog.created_at,
|
|
1435
|
+
},
|
|
1436
|
+
insert: auditLogInsert,
|
|
1437
|
+
},
|
|
929
1438
|
loginApprovalReview: {
|
|
930
1439
|
table: loginApprovalReview,
|
|
931
1440
|
select: {
|
|
@@ -950,6 +1459,28 @@ const makeInternalAuthSqliteTables = (names = {}) => {
|
|
|
950
1459
|
approve: loginApprovalReviewApproveUpdate,
|
|
951
1460
|
deny: loginApprovalReviewDenyUpdate,
|
|
952
1461
|
},
|
|
1462
|
+
loginRiskHistory: {
|
|
1463
|
+
table: loginRiskHistory,
|
|
1464
|
+
select: {
|
|
1465
|
+
id: loginRiskHistory.id,
|
|
1466
|
+
userId: loginRiskHistory.user_id,
|
|
1467
|
+
occurredAt: loginRiskHistory.occurred_at,
|
|
1468
|
+
outcome: loginRiskHistory.outcome,
|
|
1469
|
+
method: loginRiskHistory.method,
|
|
1470
|
+
amr: loginRiskHistory.amr,
|
|
1471
|
+
aal: loginRiskHistory.aal,
|
|
1472
|
+
deviceStatus: loginRiskHistory.device_status,
|
|
1473
|
+
deviceKey: loginRiskHistory.device_key,
|
|
1474
|
+
locationKey: loginRiskHistory.location_key,
|
|
1475
|
+
country: loginRiskHistory.country,
|
|
1476
|
+
region: loginRiskHistory.region,
|
|
1477
|
+
latitudeMicro: loginRiskHistory.latitude_micro,
|
|
1478
|
+
longitudeMicro: loginRiskHistory.longitude_micro,
|
|
1479
|
+
riskLevel: loginRiskHistory.risk_level,
|
|
1480
|
+
createdAt: loginRiskHistory.created_at,
|
|
1481
|
+
},
|
|
1482
|
+
insert: loginRiskHistoryInsert,
|
|
1483
|
+
},
|
|
953
1484
|
trustedDevice: {
|
|
954
1485
|
table: trustedDevice,
|
|
955
1486
|
select: {
|
|
@@ -1085,6 +1616,101 @@ const makeInternalAuthSqliteTables = (names = {}) => {
|
|
|
1085
1616
|
insert: oauthAccountInsert,
|
|
1086
1617
|
unlink: oauthAccountUnlink,
|
|
1087
1618
|
},
|
|
1619
|
+
oauthClient: {
|
|
1620
|
+
table: oauthClient,
|
|
1621
|
+
select: {
|
|
1622
|
+
id: oauthClient.id,
|
|
1623
|
+
type: oauthClient.type,
|
|
1624
|
+
status: oauthClient.status,
|
|
1625
|
+
name: oauthClient.name,
|
|
1626
|
+
redirectUris: oauthClient.redirect_uris,
|
|
1627
|
+
allowedGrantTypes: oauthClient.allowed_grant_types,
|
|
1628
|
+
allowedResponseTypes: oauthClient.allowed_response_types,
|
|
1629
|
+
allowedScopes: oauthClient.allowed_scopes,
|
|
1630
|
+
createdAt: oauthClient.created_at,
|
|
1631
|
+
updatedAt: oauthClient.updated_at,
|
|
1632
|
+
metadata: oauthClient.metadata,
|
|
1633
|
+
},
|
|
1634
|
+
insert: oauthClientValues,
|
|
1635
|
+
update: oauthClientValues,
|
|
1636
|
+
},
|
|
1637
|
+
oauthConsent: {
|
|
1638
|
+
table: oauthConsent,
|
|
1639
|
+
select: {
|
|
1640
|
+
id: oauthConsent.id,
|
|
1641
|
+
userId: oauthConsent.user_id,
|
|
1642
|
+
clientId: oauthConsent.client_id,
|
|
1643
|
+
scopes: oauthConsent.scopes,
|
|
1644
|
+
grantedAt: oauthConsent.granted_at,
|
|
1645
|
+
expiresAt: oauthConsent.expires_at,
|
|
1646
|
+
revokedAt: oauthConsent.revoked_at,
|
|
1647
|
+
metadata: oauthConsent.metadata,
|
|
1648
|
+
},
|
|
1649
|
+
insert: oauthConsentValues,
|
|
1650
|
+
update: oauthConsentValues,
|
|
1651
|
+
revoke: oauthConsentRevoke,
|
|
1652
|
+
},
|
|
1653
|
+
oauthAuthorizationCode: {
|
|
1654
|
+
table: oauthAuthorizationCode,
|
|
1655
|
+
select: {
|
|
1656
|
+
codeHash: oauthAuthorizationCode.code_hash,
|
|
1657
|
+
clientId: oauthAuthorizationCode.client_id,
|
|
1658
|
+
subject: oauthAuthorizationCode.subject,
|
|
1659
|
+
redirectUri: oauthAuthorizationCode.redirect_uri,
|
|
1660
|
+
scopes: oauthAuthorizationCode.scopes,
|
|
1661
|
+
codeChallenge: oauthAuthorizationCode.code_challenge,
|
|
1662
|
+
codeChallengeMethod: oauthAuthorizationCode.code_challenge_method,
|
|
1663
|
+
issuedAt: oauthAuthorizationCode.issued_at,
|
|
1664
|
+
expiresAt: oauthAuthorizationCode.expires_at,
|
|
1665
|
+
consumedAt: oauthAuthorizationCode.consumed_at,
|
|
1666
|
+
metadata: oauthAuthorizationCode.metadata,
|
|
1667
|
+
},
|
|
1668
|
+
insert: oauthAuthorizationCodeValues,
|
|
1669
|
+
update: oauthAuthorizationCodeValues,
|
|
1670
|
+
markConsumed: oauthAuthorizationCodeMarkConsumed,
|
|
1671
|
+
},
|
|
1672
|
+
oauthClientSecret: {
|
|
1673
|
+
table: oauthClientSecret,
|
|
1674
|
+
select: {
|
|
1675
|
+
prefix: oauthClientSecret.prefix,
|
|
1676
|
+
clientId: oauthClientSecret.client_id,
|
|
1677
|
+
secretHash: oauthClientSecret.secret_hash,
|
|
1678
|
+
authenticationMethods: oauthClientSecret.authentication_methods,
|
|
1679
|
+
createdAt: oauthClientSecret.created_at,
|
|
1680
|
+
expiresAt: oauthClientSecret.expires_at,
|
|
1681
|
+
lastUsedAt: oauthClientSecret.last_used_at,
|
|
1682
|
+
revokedAt: oauthClientSecret.revoked_at,
|
|
1683
|
+
metadata: oauthClientSecret.metadata,
|
|
1684
|
+
},
|
|
1685
|
+
insert: oauthClientSecretValues,
|
|
1686
|
+
update: oauthClientSecretValues,
|
|
1687
|
+
markUsed: oauthClientSecretMarkUsed,
|
|
1688
|
+
revoke: oauthClientSecretRevoke,
|
|
1689
|
+
},
|
|
1690
|
+
oauthProviderModeToken: {
|
|
1691
|
+
table: oauthProviderModeToken,
|
|
1692
|
+
select: {
|
|
1693
|
+
tokenHash: oauthProviderModeToken.token_hash,
|
|
1694
|
+
tokenType: oauthProviderModeToken.token_type,
|
|
1695
|
+
clientId: oauthProviderModeToken.client_id,
|
|
1696
|
+
subject: oauthProviderModeToken.subject,
|
|
1697
|
+
scopes: oauthProviderModeToken.scopes,
|
|
1698
|
+
issuedAt: oauthProviderModeToken.issued_at,
|
|
1699
|
+
expiresAt: oauthProviderModeToken.expires_at,
|
|
1700
|
+
issuer: oauthProviderModeToken.issuer,
|
|
1701
|
+
audience: oauthProviderModeToken.audience,
|
|
1702
|
+
jwtId: oauthProviderModeToken.jwt_id,
|
|
1703
|
+
revokedAt: oauthProviderModeToken.revoked_at,
|
|
1704
|
+
revocationReason: oauthProviderModeToken.revocation_reason,
|
|
1705
|
+
rotatedAt: oauthProviderModeToken.rotated_at,
|
|
1706
|
+
replacedByTokenHash: oauthProviderModeToken.replaced_by_token_hash,
|
|
1707
|
+
metadata: oauthProviderModeToken.metadata,
|
|
1708
|
+
},
|
|
1709
|
+
insert: oauthProviderModeTokenValues,
|
|
1710
|
+
update: oauthProviderModeTokenValues,
|
|
1711
|
+
revoke: oauthProviderModeTokenRevoke,
|
|
1712
|
+
rotate: oauthProviderModeTokenRotate,
|
|
1713
|
+
},
|
|
1088
1714
|
oauthProviderTokenVault: {
|
|
1089
1715
|
table: oauthProviderTokenVault,
|
|
1090
1716
|
select: {
|
|
@@ -1106,6 +1732,27 @@ const makeInternalAuthSqliteTables = (names = {}) => {
|
|
|
1106
1732
|
update: oauthProviderTokenVaultValues,
|
|
1107
1733
|
markRevoked: oauthProviderTokenVaultMarkRevoked,
|
|
1108
1734
|
},
|
|
1735
|
+
domainVerification: {
|
|
1736
|
+
table: domainVerification,
|
|
1737
|
+
select: {
|
|
1738
|
+
id: domainVerification.id,
|
|
1739
|
+
ownerId: domainVerification.owner_id,
|
|
1740
|
+
domain: domainVerification.domain,
|
|
1741
|
+
proofMethod: domainVerification.proof_method,
|
|
1742
|
+
proofToken: domainVerification.proof_token,
|
|
1743
|
+
status: domainVerification.status,
|
|
1744
|
+
createdAt: domainVerification.created_at,
|
|
1745
|
+
expiresAt: domainVerification.expires_at,
|
|
1746
|
+
verifiedAt: domainVerification.verified_at,
|
|
1747
|
+
revokedAt: domainVerification.revoked_at,
|
|
1748
|
+
lastCheckedAt: domainVerification.last_checked_at,
|
|
1749
|
+
metadata: domainVerification.metadata,
|
|
1750
|
+
},
|
|
1751
|
+
insert: domainVerificationValues,
|
|
1752
|
+
update: domainVerificationValues,
|
|
1753
|
+
markVerified: domainVerificationMarkVerified,
|
|
1754
|
+
revoke: domainVerificationRevoke,
|
|
1755
|
+
},
|
|
1109
1756
|
securityTimeline: {
|
|
1110
1757
|
table: securityTimeline,
|
|
1111
1758
|
select: {
|
|
@@ -1122,6 +1769,35 @@ const makeInternalAuthSqliteTables = (names = {}) => {
|
|
|
1122
1769
|
},
|
|
1123
1770
|
insert: securityTimelineInsert,
|
|
1124
1771
|
},
|
|
1772
|
+
webhookOutbox: {
|
|
1773
|
+
table: webhookOutbox,
|
|
1774
|
+
select: {
|
|
1775
|
+
id: webhookOutbox.id,
|
|
1776
|
+
endpointKey: webhookOutbox.endpoint_key,
|
|
1777
|
+
event: webhookOutbox.event,
|
|
1778
|
+
status: webhookOutbox.status,
|
|
1779
|
+
attempts: webhookOutbox.attempts,
|
|
1780
|
+
nextAttemptAt: webhookOutbox.next_attempt_at,
|
|
1781
|
+
createdAt: webhookOutbox.created_at,
|
|
1782
|
+
updatedAt: webhookOutbox.updated_at,
|
|
1783
|
+
deliveredAt: webhookOutbox.delivered_at,
|
|
1784
|
+
lastError: webhookOutbox.last_error,
|
|
1785
|
+
},
|
|
1786
|
+
insert: webhookOutboxInsert,
|
|
1787
|
+
markDelivered: webhookOutboxMarkDelivered,
|
|
1788
|
+
markFailed: webhookOutboxMarkFailed,
|
|
1789
|
+
markDeadLettered: webhookOutboxMarkDeadLettered,
|
|
1790
|
+
},
|
|
1791
|
+
webhookReplay: {
|
|
1792
|
+
table: webhookReplay,
|
|
1793
|
+
select: {
|
|
1794
|
+
id: webhookReplay.id,
|
|
1795
|
+
expiresAt: webhookReplay.expires_at,
|
|
1796
|
+
createdAt: webhookReplay.created_at,
|
|
1797
|
+
},
|
|
1798
|
+
insert: webhookReplayInsert,
|
|
1799
|
+
update: webhookReplayUpdate,
|
|
1800
|
+
},
|
|
1125
1801
|
};
|
|
1126
1802
|
};
|
|
1127
1803
|
const asAuthSqliteTables = (tables) => tables;
|
|
@@ -1132,7 +1808,9 @@ const selectUserColumns = (tables) => tables.user.select;
|
|
|
1132
1808
|
const selectCredentialColumns = (tables) => tables.credential.select;
|
|
1133
1809
|
const selectSessionColumns = (tables) => tables.session.select;
|
|
1134
1810
|
const selectVerificationColumns = (tables) => tables.verification.select;
|
|
1811
|
+
const selectAuditLogColumns = (tables) => tables.auditLog.select;
|
|
1135
1812
|
const selectLoginApprovalReviewColumns = (tables) => tables.loginApprovalReview.select;
|
|
1813
|
+
const selectLoginRiskHistoryColumns = (tables) => tables.loginRiskHistory.select;
|
|
1136
1814
|
const selectTrustedDeviceColumns = (tables) => tables.trustedDevice.select;
|
|
1137
1815
|
const selectPasskeyCredentialColumns = (tables) => tables.passkeyCredential.select;
|
|
1138
1816
|
const selectTotpFactorColumns = (tables) => tables.totpFactor.select;
|
|
@@ -1141,13 +1819,31 @@ const selectApiKeyColumns = (tables) => tables.apiKey.select;
|
|
|
1141
1819
|
const selectRefreshTokenColumns = (tables) => tables.refreshToken.select;
|
|
1142
1820
|
const selectJwtRevocationColumns = (tables) => tables.jwtRevocation.select;
|
|
1143
1821
|
const selectOAuthAccountColumns = (tables) => tables.oauthAccount.select;
|
|
1822
|
+
const selectOAuthClientColumns = (tables) => tables.oauthClient.select;
|
|
1823
|
+
const selectOAuthConsentColumns = (tables) => tables.oauthConsent.select;
|
|
1824
|
+
const selectOAuthAuthorizationCodeColumns = (tables) => tables.oauthAuthorizationCode.select;
|
|
1825
|
+
const selectOAuthClientSecretColumns = (tables) => tables.oauthClientSecret.select;
|
|
1826
|
+
const selectOAuthProviderModeTokenColumns = (tables) => tables.oauthProviderModeToken.select;
|
|
1144
1827
|
const selectOAuthProviderTokenVaultColumns = (tables) => tables.oauthProviderTokenVault.select;
|
|
1828
|
+
const selectDomainVerificationColumns = (tables) => tables.domainVerification.select;
|
|
1145
1829
|
const selectSecurityTimelineColumns = (tables) => tables.securityTimeline.select;
|
|
1830
|
+
const selectWebhookOutboxColumns = (tables) => tables.webhookOutbox.select;
|
|
1831
|
+
const selectWebhookReplayColumns = (tables) => tables.webhookReplay.select;
|
|
1146
1832
|
const storageError = (entity, operation, cause) => StorageError.fromUnknown(entity, operation, cause);
|
|
1833
|
+
const auditLogStoreError = (operation, cause) => new AuditLogStoreError({
|
|
1834
|
+
operation,
|
|
1835
|
+
message: `Audit log ${operation} failed`,
|
|
1836
|
+
cause,
|
|
1837
|
+
});
|
|
1147
1838
|
const loginApprovalReviewStoreError = (operation, cause) => new LoginApprovalReviewError({
|
|
1148
1839
|
message: `Login approval review ${operation} failed`,
|
|
1149
1840
|
cause,
|
|
1150
1841
|
});
|
|
1842
|
+
const loginRiskHistoryStoreError = (operation, cause) => new LoginRiskHistoryError({
|
|
1843
|
+
operation,
|
|
1844
|
+
message: `Login risk history ${operation} failed`,
|
|
1845
|
+
cause,
|
|
1846
|
+
});
|
|
1151
1847
|
const trustedDeviceStoreError = (operation, cause) => new TrustedDeviceError({
|
|
1152
1848
|
operation,
|
|
1153
1849
|
message: `Trusted device ${operation} failed`,
|
|
@@ -1188,16 +1884,56 @@ const oauthAccountStoreError = (operation, cause) => new OAuthAccountStoreError(
|
|
|
1188
1884
|
message: `OAuth account ${operation} failed`,
|
|
1189
1885
|
cause,
|
|
1190
1886
|
});
|
|
1887
|
+
const oauthClientStoreError = (operation, cause) => new OAuthClientStoreError({
|
|
1888
|
+
operation,
|
|
1889
|
+
message: `OAuth client ${operation} failed`,
|
|
1890
|
+
cause,
|
|
1891
|
+
});
|
|
1892
|
+
const oauthConsentStoreError = (operation, cause) => new OAuthConsentStoreError({
|
|
1893
|
+
operation,
|
|
1894
|
+
message: `OAuth consent ${operation} failed`,
|
|
1895
|
+
cause,
|
|
1896
|
+
});
|
|
1897
|
+
const oauthAuthorizationCodeStoreError = (operation, cause) => new OAuthAuthorizationCodeStoreError({
|
|
1898
|
+
operation,
|
|
1899
|
+
message: `OAuth authorization code ${operation} failed`,
|
|
1900
|
+
cause,
|
|
1901
|
+
});
|
|
1902
|
+
const oauthClientSecretStoreError = (operation, cause) => new OAuthClientSecretStoreError({
|
|
1903
|
+
operation,
|
|
1904
|
+
message: `OAuth client secret ${operation} failed`,
|
|
1905
|
+
cause,
|
|
1906
|
+
});
|
|
1907
|
+
const oauthProviderModeTokenStoreError = (operation, cause) => new OAuthProviderModeTokenStoreError({
|
|
1908
|
+
operation,
|
|
1909
|
+
message: `OAuth provider-mode token ${operation} failed`,
|
|
1910
|
+
cause,
|
|
1911
|
+
});
|
|
1191
1912
|
const oauthProviderTokenVaultError = (operation, cause) => new OAuthProviderTokenVaultError({
|
|
1192
1913
|
operation,
|
|
1193
1914
|
message: `OAuth provider token vault ${operation} failed`,
|
|
1194
1915
|
cause,
|
|
1195
1916
|
});
|
|
1917
|
+
const domainVerificationStoreError = (operation, cause) => new DomainVerificationStoreError({
|
|
1918
|
+
operation,
|
|
1919
|
+
message: `Domain verification ${operation} failed`,
|
|
1920
|
+
cause,
|
|
1921
|
+
});
|
|
1196
1922
|
const securityTimelineStoreError = (operation, cause) => new SecurityTimelineStoreError({
|
|
1197
1923
|
operation,
|
|
1198
1924
|
message: `Security timeline ${operation} failed`,
|
|
1199
1925
|
cause,
|
|
1200
1926
|
});
|
|
1927
|
+
const webhookOutboxStoreError = (operation, cause) => new WebhookOutboxStoreError({
|
|
1928
|
+
operation,
|
|
1929
|
+
message: `Webhook outbox ${operation} failed`,
|
|
1930
|
+
cause,
|
|
1931
|
+
});
|
|
1932
|
+
const webhookReplayStoreError = (operation, cause) => new WebhookReplayStoreError({
|
|
1933
|
+
operation,
|
|
1934
|
+
message: `Webhook replay ${operation} failed`,
|
|
1935
|
+
cause,
|
|
1936
|
+
});
|
|
1201
1937
|
const findUserById = (executor, tables, id, operation = "find") => executePlan(executor, Query.select(selectUserColumns(tables)).pipe(Query.from(tables.user.table), Query.where(queryEq(tables.user.select.id, id)))).pipe(Effect.mapError((cause) => storageError("user", operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
1202
1938
|
? Option.none()
|
|
1203
1939
|
: Option.some(decodeUserRow(tables, rows[0]))));
|
|
@@ -1260,6 +1996,44 @@ const findOAuthAccountByProviderAccount = (executor, tables, input, operation =
|
|
|
1260
1996
|
? Option.none()
|
|
1261
1997
|
: Option.some(decodeOAuthAccountRow(tables, rows[0]))));
|
|
1262
1998
|
};
|
|
1999
|
+
const findOAuthClientById = (executor, tables, input, operation = "find") => executePlan(executor, Query.select(selectOAuthClientColumns(tables)).pipe(Query.from(tables.oauthClient.table), Query.where(queryEq(tables.oauthClient.select.id, input.clientId)))).pipe(Effect.mapError((cause) => oauthClientStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2000
|
+
? Option.none()
|
|
2001
|
+
: Option.some(decodeOAuthClientRow(tables, rows[0]))));
|
|
2002
|
+
const findOAuthConsentByUserAndClient = (executor, tables, input, operation = "find-active") => executePlan(executor, Query.select(selectOAuthConsentColumns(tables)).pipe(Query.from(tables.oauthConsent.table), Query.where(queryEq(tables.oauthConsent.select.userId, input.userId)), Query.where(queryEq(tables.oauthConsent.select.clientId, input.clientId)))).pipe(Effect.mapError((cause) => oauthConsentStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2003
|
+
? Option.none()
|
|
2004
|
+
: Option.some(decodeOAuthConsentRow(tables, rows[0]))));
|
|
2005
|
+
const deleteOAuthConsentRowsBefore = (executor, tables, column, before) => executePlan(executor, Query.delete(tables.oauthConsent.table).pipe(Query.where(queryLt(column, Number(before))), Query.returning({ id: tables.oauthConsent.select.id }))).pipe(Effect.map((rows) => rows.length));
|
|
2006
|
+
const deleteOAuthInactiveConsents = (executor, tables, input) => Effect.gen(function* () {
|
|
2007
|
+
const expiredDeleted = input.beforeExpiresAt === undefined
|
|
2008
|
+
? 0
|
|
2009
|
+
: yield* deleteOAuthConsentRowsBefore(executor, tables, tables.oauthConsent.select.expiresAt, input.beforeExpiresAt);
|
|
2010
|
+
const revokedDeleted = input.beforeRevokedAt === undefined
|
|
2011
|
+
? 0
|
|
2012
|
+
: yield* deleteOAuthConsentRowsBefore(executor, tables, tables.oauthConsent.select.revokedAt, input.beforeRevokedAt);
|
|
2013
|
+
return expiredDeleted + revokedDeleted;
|
|
2014
|
+
}).pipe(Effect.mapError((cause) => oauthConsentStoreError("deleteInactive", cause)));
|
|
2015
|
+
const findOAuthAuthorizationCodeByHash = (executor, tables, input, operation = "find") => executePlan(executor, Query.select(selectOAuthAuthorizationCodeColumns(tables)).pipe(Query.from(tables.oauthAuthorizationCode.table), Query.where(queryEq(tables.oauthAuthorizationCode.select.codeHash, input.codeHash)))).pipe(Effect.mapError((cause) => oauthAuthorizationCodeStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2016
|
+
? Option.none()
|
|
2017
|
+
: Option.some(decodeOAuthAuthorizationCodeRow(tables, rows[0]))));
|
|
2018
|
+
const findOAuthClientSecretByClientIdAndPrefix = (executor, tables, input, operation = "find") => executePlan(executor, Query.select(selectOAuthClientSecretColumns(tables)).pipe(Query.from(tables.oauthClientSecret.table), Query.where(queryEq(tables.oauthClientSecret.select.clientId, input.clientId)), Query.where(queryEq(tables.oauthClientSecret.select.prefix, input.prefix)))).pipe(Effect.mapError((cause) => oauthClientSecretStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2019
|
+
? Option.none()
|
|
2020
|
+
: Option.some(decodeOAuthClientSecretRow(tables, rows[0]))));
|
|
2021
|
+
const findOAuthProviderModeTokenByHash = (executor, tables, input, operation = "find") => executePlan(executor, Query.select(selectOAuthProviderModeTokenColumns(tables)).pipe(Query.from(tables.oauthProviderModeToken.table), Query.where(queryEq(tables.oauthProviderModeToken.select.tokenHash, input.tokenHash)))).pipe(Effect.mapError((cause) => oauthProviderModeTokenStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2022
|
+
? Option.none()
|
|
2023
|
+
: Option.some(decodeOAuthProviderModeTokenRow(tables, rows[0]))));
|
|
2024
|
+
const deleteOAuthProviderModeTokenRowsBefore = (executor, tables, column, before) => executePlan(executor, Query.delete(tables.oauthProviderModeToken.table).pipe(Query.where(queryLt(column, Number(before))), Query.returning({ tokenHash: tables.oauthProviderModeToken.select.tokenHash }))).pipe(Effect.map((rows) => rows.length));
|
|
2025
|
+
const deleteOAuthProviderModeRetiredTokens = (executor, tables, input) => Effect.gen(function* () {
|
|
2026
|
+
const expiredDeleted = input.beforeExpiresAt === undefined
|
|
2027
|
+
? 0
|
|
2028
|
+
: yield* deleteOAuthProviderModeTokenRowsBefore(executor, tables, tables.oauthProviderModeToken.select.expiresAt, input.beforeExpiresAt);
|
|
2029
|
+
const revokedDeleted = input.beforeRevokedAt === undefined
|
|
2030
|
+
? 0
|
|
2031
|
+
: yield* deleteOAuthProviderModeTokenRowsBefore(executor, tables, tables.oauthProviderModeToken.select.revokedAt, input.beforeRevokedAt);
|
|
2032
|
+
const rotatedDeleted = input.beforeRotatedAt === undefined
|
|
2033
|
+
? 0
|
|
2034
|
+
: yield* deleteOAuthProviderModeTokenRowsBefore(executor, tables, tables.oauthProviderModeToken.select.rotatedAt, input.beforeRotatedAt);
|
|
2035
|
+
return expiredDeleted + revokedDeleted + rotatedDeleted;
|
|
2036
|
+
}).pipe(Effect.mapError((cause) => oauthProviderModeTokenStoreError("deleteRetired", cause)));
|
|
1263
2037
|
const findOAuthProviderTokenVaultRecordByAccountId = (executor, tables, input, operation, includeRevoked = false) => {
|
|
1264
2038
|
const base = Query.select(selectOAuthProviderTokenVaultColumns(tables)).pipe(Query.from(tables.oauthProviderTokenVault.table), Query.where(queryEq(tables.oauthProviderTokenVault.select.accountId, input.accountId)));
|
|
1265
2039
|
const query = includeRevoked
|
|
@@ -1269,7 +2043,175 @@ const findOAuthProviderTokenVaultRecordByAccountId = (executor, tables, input, o
|
|
|
1269
2043
|
? Option.none()
|
|
1270
2044
|
: Option.some(decodeOAuthProviderTokenVaultRow(tables, rows[0]))));
|
|
1271
2045
|
};
|
|
2046
|
+
const findDomainVerificationById = (executor, tables, id, operation = "find") => executePlan(executor, Query.select(selectDomainVerificationColumns(tables)).pipe(Query.from(tables.domainVerification.table), Query.where(queryEq(tables.domainVerification.select.id, id)))).pipe(Effect.mapError((cause) => domainVerificationStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2047
|
+
? Option.none()
|
|
2048
|
+
: Option.some(decodeDomainVerificationRecord(tables, rows[0]))));
|
|
2049
|
+
const findDomainVerificationByOwnerAndDomain = (executor, tables, input, operation = "find") => executePlan(executor, Query.select(selectDomainVerificationColumns(tables)).pipe(Query.from(tables.domainVerification.table), Query.where(queryEq(tables.domainVerification.select.ownerId, input.ownerId)), Query.where(queryEq(tables.domainVerification.select.domain, input.domain)))).pipe(Effect.mapError((cause) => domainVerificationStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2050
|
+
? Option.none()
|
|
2051
|
+
: Option.some(decodeDomainVerificationRecord(tables, rows[0]))));
|
|
1272
2052
|
const listSecurityTimelineByUser = (executor, tables, input, operation = "list") => executePlan(executor, Query.select(selectSecurityTimelineColumns(tables)).pipe(Query.from(tables.securityTimeline.table), Query.where(queryEq(tables.securityTimeline.select.userId, input.userId)))).pipe(Effect.mapError((cause) => securityTimelineStoreError(operation, cause)), Effect.map((rows) => filterSecurityTimelineEvents(rows.map((row) => decodeSecurityTimelineEvent(tables, row)), input)));
|
|
2053
|
+
const deleteSecurityTimelineBefore = (executor, tables, input) => {
|
|
2054
|
+
const base = Query.delete(tables.securityTimeline.table).pipe(Query.where(queryLt(tables.securityTimeline.select.occurredAt, Number(input.beforeOccurredAt))));
|
|
2055
|
+
const query = input.userId === undefined
|
|
2056
|
+
? base
|
|
2057
|
+
: base.pipe(Query.where(queryEq(tables.securityTimeline.select.userId, input.userId)));
|
|
2058
|
+
return executePlan(executor, query.pipe(Query.returning({ id: tables.securityTimeline.select.id }))).pipe(Effect.mapError((cause) => securityTimelineStoreError("deleteBefore", cause)), Effect.map((rows) => rows.length));
|
|
2059
|
+
};
|
|
2060
|
+
const findWebhookOutboxRecordById = (executor, tables, id, operation) => executePlan(executor, Query.select(selectWebhookOutboxColumns(tables)).pipe(Query.from(tables.webhookOutbox.table), Query.where(queryEq(tables.webhookOutbox.select.id, id)))).pipe(Effect.mapError((cause) => webhookOutboxStoreError(operation, cause)), Effect.map((rows) => rows[0] === undefined
|
|
2061
|
+
? Option.none()
|
|
2062
|
+
: Option.some(decodeWebhookOutboxRecord(tables, rows[0]))));
|
|
2063
|
+
const claimDueWebhookOutboxRecords = (executor, tables, input) => Effect.gen(function* () {
|
|
2064
|
+
const now = input.now ?? (yield* currentUnixMillis);
|
|
2065
|
+
const base = Query.select(selectWebhookOutboxColumns(tables)).pipe(Query.from(tables.webhookOutbox.table), Query.where(queryLte(tables.webhookOutbox.select.nextAttemptAt, Number(now))));
|
|
2066
|
+
const query = input.endpointKey === undefined
|
|
2067
|
+
? base
|
|
2068
|
+
: base.pipe(Query.where(queryEq(tables.webhookOutbox.select.endpointKey, input.endpointKey)));
|
|
2069
|
+
const rows = yield* executePlan(executor, query).pipe(Effect.mapError((cause) => webhookOutboxStoreError("claimDue", cause)));
|
|
2070
|
+
return filterDueWebhookOutboxRecords(rows.map((row) => decodeWebhookOutboxRecord(tables, row)), { ...input, now });
|
|
2071
|
+
});
|
|
2072
|
+
const deleteWebhookOutboxRecordsBefore = (executor, tables, input) => {
|
|
2073
|
+
const [firstStatus, ...remainingStatuses] = input.statuses;
|
|
2074
|
+
const base = Query.delete(tables.webhookOutbox.table).pipe(Query.where(queryLt(tables.webhookOutbox.select.updatedAt, Number(input.beforeUpdatedAt))), Query.where(queryIn(tables.webhookOutbox.select.status, firstStatus, ...remainingStatuses)));
|
|
2075
|
+
const query = input.endpointKey === undefined
|
|
2076
|
+
? base
|
|
2077
|
+
: base.pipe(Query.where(queryEq(tables.webhookOutbox.select.endpointKey, input.endpointKey)));
|
|
2078
|
+
return executePlan(executor, query.pipe(Query.returning({ id: tables.webhookOutbox.select.id }))).pipe(Effect.mapError((cause) => webhookOutboxStoreError("deleteBefore", cause)), Effect.map((rows) => rows.length));
|
|
2079
|
+
};
|
|
2080
|
+
const deleteExpiredWebhookReplayRecords = (executor, tables, input) => Effect.gen(function* () {
|
|
2081
|
+
const now = input.now ?? (yield* currentUnixMillis);
|
|
2082
|
+
return yield* executePlan(executor, Query.delete(tables.webhookReplay.table).pipe(Query.where(queryLt(tables.webhookReplay.select.expiresAt, Number(now))), Query.returning({ id: tables.webhookReplay.select.id }))).pipe(Effect.mapError((cause) => webhookReplayStoreError("deleteExpired", cause)), Effect.map((rows) => rows.length));
|
|
2083
|
+
});
|
|
2084
|
+
const listAuditLogRecords = (executor, tables, input = {}) => {
|
|
2085
|
+
if (input.types !== undefined && input.types.length === 0) {
|
|
2086
|
+
return Effect.succeed([]);
|
|
2087
|
+
}
|
|
2088
|
+
const base = Query.select(selectAuditLogColumns(tables)).pipe(Query.from(tables.auditLog.table));
|
|
2089
|
+
const byUser = input.userId === undefined
|
|
2090
|
+
? base
|
|
2091
|
+
: base.pipe(Query.where(queryEq(tables.auditLog.select.userId, input.userId)));
|
|
2092
|
+
const byOccurredAt = input.beforeOccurredAt === undefined
|
|
2093
|
+
? byUser
|
|
2094
|
+
: byUser.pipe(Query.where(queryLt(tables.auditLog.select.occurredAt, Number(input.beforeOccurredAt))));
|
|
2095
|
+
const query = input.types === undefined
|
|
2096
|
+
? byOccurredAt
|
|
2097
|
+
: byOccurredAt.pipe(Query.where(queryIn(tables.auditLog.select.type, input.types[0], ...input.types.slice(1))));
|
|
2098
|
+
return executePlan(executor, query).pipe(Effect.mapError((cause) => auditLogStoreError("list", cause)), Effect.map((rows) => filterAuditLogEvents(rows.map((row) => decodeAuditLogEvent(tables, row)), input)));
|
|
2099
|
+
};
|
|
2100
|
+
const deleteAuditLogRecordsBefore = (executor, tables, input) => {
|
|
2101
|
+
const base = Query.delete(tables.auditLog.table).pipe(Query.where(queryLt(tables.auditLog.select.occurredAt, Number(input.beforeOccurredAt))));
|
|
2102
|
+
const query = input.userId === undefined
|
|
2103
|
+
? base
|
|
2104
|
+
: base.pipe(Query.where(queryEq(tables.auditLog.select.userId, input.userId)));
|
|
2105
|
+
return executePlan(executor, query.pipe(Query.returning({ occurredAt: tables.auditLog.select.occurredAt }))).pipe(Effect.mapError((cause) => auditLogStoreError("deleteBefore", cause)), Effect.map((rows) => rows.length));
|
|
2106
|
+
};
|
|
2107
|
+
const defaultLoginRiskHistoryRecentWindowMillis = 15 * 60 * 1000;
|
|
2108
|
+
const defaultLoginRiskHistoryWindowMillis = 90 * 24 * 60 * 60 * 1000;
|
|
2109
|
+
const defaultLoginRiskImpossibleTravelWindowMillis = 24 * 60 * 60 * 1000;
|
|
2110
|
+
const defaultLoginRiskImpossibleTravelKmh = 900;
|
|
2111
|
+
const positiveWindowMillis = (value, defaultValue) => value === undefined || !Number.isFinite(value)
|
|
2112
|
+
? defaultValue
|
|
2113
|
+
: Math.max(0, value);
|
|
2114
|
+
const loginRiskHistoryOptions = (options) => ({
|
|
2115
|
+
recentWindowMillis: positiveWindowMillis(options?.recentWindowMillis, defaultLoginRiskHistoryRecentWindowMillis),
|
|
2116
|
+
historyWindowMillis: positiveWindowMillis(options?.historyWindowMillis, defaultLoginRiskHistoryWindowMillis),
|
|
2117
|
+
impossibleTravelWindowMillis: positiveWindowMillis(options?.impossibleTravelWindowMillis, defaultLoginRiskImpossibleTravelWindowMillis),
|
|
2118
|
+
impossibleTravelKmh: options?.impossibleTravelKmh === undefined ||
|
|
2119
|
+
!Number.isFinite(options.impossibleTravelKmh)
|
|
2120
|
+
? defaultLoginRiskImpossibleTravelKmh
|
|
2121
|
+
: Math.max(0, options.impossibleTravelKmh),
|
|
2122
|
+
});
|
|
2123
|
+
const toRadians = (degrees) => (degrees * Math.PI) / 180;
|
|
2124
|
+
const distanceKm = (first, second) => {
|
|
2125
|
+
const earthRadiusKm = 6371;
|
|
2126
|
+
const latitudeDelta = toRadians(second.latitude - first.latitude);
|
|
2127
|
+
const longitudeDelta = toRadians(second.longitude - first.longitude);
|
|
2128
|
+
const firstLatitude = toRadians(first.latitude);
|
|
2129
|
+
const secondLatitude = toRadians(second.latitude);
|
|
2130
|
+
const haversine = Math.sin(latitudeDelta / 2) ** 2 +
|
|
2131
|
+
Math.cos(firstLatitude) *
|
|
2132
|
+
Math.cos(secondLatitude) *
|
|
2133
|
+
Math.sin(longitudeDelta / 2) ** 2;
|
|
2134
|
+
return (2 * earthRadiusKm * Math.atan2(Math.sqrt(haversine), Math.sqrt(1 - haversine)));
|
|
2135
|
+
};
|
|
2136
|
+
const hasCoordinates = (value) => value.latitude !== undefined &&
|
|
2137
|
+
Number.isFinite(value.latitude) &&
|
|
2138
|
+
value.longitude !== undefined &&
|
|
2139
|
+
Number.isFinite(value.longitude);
|
|
2140
|
+
const loginRiskHistoryLookupResult = (input, rows, options) => {
|
|
2141
|
+
const normalized = loginRiskHistoryOptions(options);
|
|
2142
|
+
const occurredAt = Number(input.occurredAt);
|
|
2143
|
+
const recentStart = occurredAt - normalized.recentWindowMillis;
|
|
2144
|
+
const historyStart = occurredAt - normalized.historyWindowMillis;
|
|
2145
|
+
const impossibleTravelStart = occurredAt - normalized.impossibleTravelWindowMillis;
|
|
2146
|
+
const previousRows = rows.filter((row) => Number(row.occurredAt) < occurredAt);
|
|
2147
|
+
const recentRows = previousRows.filter((row) => Number(row.occurredAt) >= recentStart);
|
|
2148
|
+
const historyRows = previousRows.filter((row) => Number(row.occurredAt) >= historyStart);
|
|
2149
|
+
const recentFailedLoginCount = recentRows.filter((row) => row.outcome === "failure").length;
|
|
2150
|
+
const recentSuccessfulLoginCount = recentRows.filter((row) => row.outcome === "success").length;
|
|
2151
|
+
const knownDevice = input.deviceKey === undefined
|
|
2152
|
+
? undefined
|
|
2153
|
+
: historyRows.some((row) => row.deviceKey === input.deviceKey);
|
|
2154
|
+
const knownLocation = input.locationKey === undefined
|
|
2155
|
+
? undefined
|
|
2156
|
+
: historyRows.some((row) => row.locationKey === input.locationKey);
|
|
2157
|
+
const currentLocation = {
|
|
2158
|
+
latitude: input.request?.latitude,
|
|
2159
|
+
longitude: input.request?.longitude,
|
|
2160
|
+
};
|
|
2161
|
+
const impossibleTravel = hasCoordinates(currentLocation)
|
|
2162
|
+
? previousRows
|
|
2163
|
+
.filter((row) => row.outcome === "success" &&
|
|
2164
|
+
Number(row.occurredAt) >= impossibleTravelStart)
|
|
2165
|
+
.some((row) => {
|
|
2166
|
+
const previousLocation = {
|
|
2167
|
+
latitude: row.latitude,
|
|
2168
|
+
longitude: row.longitude,
|
|
2169
|
+
};
|
|
2170
|
+
if (!hasCoordinates(previousLocation)) {
|
|
2171
|
+
return false;
|
|
2172
|
+
}
|
|
2173
|
+
const elapsedHours = (occurredAt - Number(row.occurredAt)) / 3_600_000;
|
|
2174
|
+
return (elapsedHours > 0 &&
|
|
2175
|
+
distanceKm(previousLocation, currentLocation) / elapsedHours >
|
|
2176
|
+
normalized.impossibleTravelKmh);
|
|
2177
|
+
})
|
|
2178
|
+
: undefined;
|
|
2179
|
+
const recentRiskLevels = recentRows.flatMap((row) => row.riskLevel === undefined ? [] : [row.riskLevel]);
|
|
2180
|
+
const riskLevel = recentRiskLevels.length === 0
|
|
2181
|
+
? undefined
|
|
2182
|
+
: maxLoginRiskLevel(recentRiskLevels, "unknown");
|
|
2183
|
+
const reasons = [
|
|
2184
|
+
...(recentFailedLoginCount > 0 ? ["recent-failed-login"] : []),
|
|
2185
|
+
...(knownDevice === false ? ["new-device"] : []),
|
|
2186
|
+
...(knownLocation === false ? ["new-location"] : []),
|
|
2187
|
+
...(impossibleTravel === true ? ["impossible-travel"] : []),
|
|
2188
|
+
];
|
|
2189
|
+
return omitUndefined({
|
|
2190
|
+
recentLoginCount: recentRows.length,
|
|
2191
|
+
recentFailedLoginCount,
|
|
2192
|
+
recentSuccessfulLoginCount,
|
|
2193
|
+
knownDevice,
|
|
2194
|
+
newDevice: knownDevice === undefined ? undefined : !knownDevice,
|
|
2195
|
+
knownLocation,
|
|
2196
|
+
newLocation: knownLocation === undefined ? undefined : !knownLocation,
|
|
2197
|
+
impossibleTravel,
|
|
2198
|
+
riskLevel,
|
|
2199
|
+
reasons: reasons.length === 0 ? undefined : reasons,
|
|
2200
|
+
});
|
|
2201
|
+
};
|
|
2202
|
+
const lookupLoginRiskHistory = (executor, tables, input, options) => {
|
|
2203
|
+
const normalized = loginRiskHistoryOptions(options);
|
|
2204
|
+
const occurredAt = Number(input.occurredAt);
|
|
2205
|
+
const earliestOccurredAt = Math.min(occurredAt - normalized.recentWindowMillis, occurredAt - normalized.historyWindowMillis, occurredAt - normalized.impossibleTravelWindowMillis);
|
|
2206
|
+
return executePlan(executor, Query.select(selectLoginRiskHistoryColumns(tables)).pipe(Query.from(tables.loginRiskHistory.table), Query.where(queryEq(tables.loginRiskHistory.select.userId, input.userId)), Query.where(queryLt(tables.loginRiskHistory.select.occurredAt, occurredAt)), Query.where(queryGt(tables.loginRiskHistory.select.occurredAt, earliestOccurredAt - 1)))).pipe(Effect.mapError((cause) => loginRiskHistoryStoreError("lookup", cause)), Effect.map((rows) => loginRiskHistoryLookupResult(input, rows.map((row) => decodeLoginRiskHistoryRecord(tables, row)), options)));
|
|
2207
|
+
};
|
|
2208
|
+
const deleteLoginRiskHistoryRecordsBefore = (executor, tables, input) => {
|
|
2209
|
+
const base = Query.delete(tables.loginRiskHistory.table).pipe(Query.where(queryLt(tables.loginRiskHistory.select.occurredAt, Number(input.beforeOccurredAt))));
|
|
2210
|
+
const query = input.userId === undefined
|
|
2211
|
+
? base
|
|
2212
|
+
: base.pipe(Query.where(queryEq(tables.loginRiskHistory.select.userId, input.userId)));
|
|
2213
|
+
return executePlan(executor, query.pipe(Query.returning({ id: tables.loginRiskHistory.select.id }))).pipe(Effect.mapError((cause) => loginRiskHistoryStoreError("deleteBefore", cause)), Effect.map((rows) => rows.length));
|
|
2214
|
+
};
|
|
1273
2215
|
export const makeEffectQbSqliteUserStore = (executor, options = {}) => {
|
|
1274
2216
|
const tables = options.tables ?? authSqliteTables;
|
|
1275
2217
|
return UserStore.make({
|
|
@@ -1349,6 +2291,17 @@ export const makeEffectQbSqliteVerificationStore = (executor, options = {}) => {
|
|
|
1349
2291
|
},
|
|
1350
2292
|
});
|
|
1351
2293
|
};
|
|
2294
|
+
export const makeEffectQbSqliteAuditLogStore = (executor, options = {}) => {
|
|
2295
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2296
|
+
return AuditLogStore.make({
|
|
2297
|
+
insert: (event) => Effect.gen(function* () {
|
|
2298
|
+
const createdAt = yield* currentUnixMillis;
|
|
2299
|
+
yield* executePlan(executor, queryInsert(tables.auditLog.table, mutationValues(tables.auditLog.insert(event, createdAt)))).pipe(Effect.mapError((cause) => auditLogStoreError("insert", cause)), Effect.asVoid);
|
|
2300
|
+
}),
|
|
2301
|
+
list: (input = {}) => listAuditLogRecords(executor, tables, input),
|
|
2302
|
+
deleteBefore: (input) => deleteAuditLogRecordsBefore(executor, tables, input),
|
|
2303
|
+
});
|
|
2304
|
+
};
|
|
1352
2305
|
export const makeEffectQbSqliteLoginApprovalReviewStore = (executor, options = {}) => {
|
|
1353
2306
|
const tables = options.tables ?? authSqliteTables;
|
|
1354
2307
|
return LoginApprovalReviewStore.make({
|
|
@@ -1362,6 +2315,17 @@ export const makeEffectQbSqliteLoginApprovalReviewStore = (executor, options = {
|
|
|
1362
2315
|
: Option.some(decodeLoginApprovalReviewRow(tables, rows[0])))),
|
|
1363
2316
|
});
|
|
1364
2317
|
};
|
|
2318
|
+
export const makeEffectQbSqliteLoginRiskHistoryStore = (executor, options = {}) => {
|
|
2319
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2320
|
+
return LoginRiskHistory.make({
|
|
2321
|
+
lookup: (input) => lookupLoginRiskHistory(executor, tables, input, options.loginRiskHistory),
|
|
2322
|
+
record: (input) => Effect.gen(function* () {
|
|
2323
|
+
const createdAt = input.createdAt ?? (yield* currentUnixMillis);
|
|
2324
|
+
yield* executePlan(executor, queryInsert(tables.loginRiskHistory.table, mutationValues(tables.loginRiskHistory.insert({ ...input, createdAt })))).pipe(Effect.mapError((cause) => loginRiskHistoryStoreError("record", cause)), Effect.asVoid);
|
|
2325
|
+
}),
|
|
2326
|
+
deleteBefore: (input) => deleteLoginRiskHistoryRecordsBefore(executor, tables, input),
|
|
2327
|
+
});
|
|
2328
|
+
};
|
|
1365
2329
|
export const makeEffectQbSqliteTrustedDeviceStore = (executor, options = {}) => {
|
|
1366
2330
|
const tables = options.tables ?? authSqliteTables;
|
|
1367
2331
|
return TrustedDeviceStore.make({
|
|
@@ -1567,6 +2531,118 @@ export const makeEffectQbSqliteOAuthAccountStore = (executor, options = {}) => {
|
|
|
1567
2531
|
})),
|
|
1568
2532
|
});
|
|
1569
2533
|
};
|
|
2534
|
+
export const makeEffectQbSqliteOAuthClientStore = (executor, options = {}) => {
|
|
2535
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2536
|
+
return OAuthClientStore.make({
|
|
2537
|
+
upsert: (record) => executePlan(executor, queryInsert(tables.oauthClient.table, mutationValues(tables.oauthClient.insert(record))).pipe(Query.onConflict("id", {
|
|
2538
|
+
update: mutationValues(tables.oauthClient.update(record)),
|
|
2539
|
+
}))).pipe(Effect.mapError((cause) => oauthClientStoreError("upsert", cause)), Effect.asVoid),
|
|
2540
|
+
find: (input) => findOAuthClientById(executor, tables, input),
|
|
2541
|
+
list: (input = {}) => {
|
|
2542
|
+
const base = Query.select(selectOAuthClientColumns(tables)).pipe(Query.from(tables.oauthClient.table));
|
|
2543
|
+
const query = input.includeDisabled === true
|
|
2544
|
+
? base
|
|
2545
|
+
: base.pipe(Query.where(queryEq(tables.oauthClient.select.status, "active")));
|
|
2546
|
+
return executePlan(executor, query).pipe(Effect.mapError((cause) => oauthClientStoreError("list", cause)), Effect.map((rows) => rows.map((row) => decodeOAuthClientRow(tables, row))));
|
|
2547
|
+
},
|
|
2548
|
+
validateRedirectUri: (input) => findOAuthClientById(executor, tables, input, "validate-redirect-uri").pipe(Effect.map((client) => oauthClientRedirectUriValidationResult(Option.isNone(client) ? undefined : client.value, input))),
|
|
2549
|
+
});
|
|
2550
|
+
};
|
|
2551
|
+
export const makeEffectQbSqliteOAuthConsentStore = (executor, options = {}) => {
|
|
2552
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2553
|
+
return OAuthConsentStore.make({
|
|
2554
|
+
upsert: (record) => executePlan(executor, queryInsert(tables.oauthConsent.table, mutationValues(tables.oauthConsent.insert(record))).pipe(Query.onConflict("id", {
|
|
2555
|
+
update: mutationValues(tables.oauthConsent.update(record)),
|
|
2556
|
+
}))).pipe(Effect.mapError((cause) => oauthConsentStoreError("upsert", cause)), Effect.asVoid),
|
|
2557
|
+
findActive: (input) => findOAuthConsentByUserAndClient(executor, tables, input).pipe(Effect.map((record) => Option.isNone(record) || !isOAuthConsentActive(record.value, input)
|
|
2558
|
+
? Option.none()
|
|
2559
|
+
: Option.some(record.value))),
|
|
2560
|
+
listForUser: (input) => executePlan(executor, Query.select(selectOAuthConsentColumns(tables)).pipe(Query.from(tables.oauthConsent.table), Query.where(queryEq(tables.oauthConsent.select.userId, input.userId)))).pipe(Effect.mapError((cause) => oauthConsentStoreError("list-for-user", cause)), Effect.map((rows) => rows
|
|
2561
|
+
.map((row) => decodeOAuthConsentRow(tables, row))
|
|
2562
|
+
.filter((record) => input.includeInactive === true ||
|
|
2563
|
+
isOAuthConsentActive(record, { now: input.now })))),
|
|
2564
|
+
revoke: (input) => findOAuthConsentByUserAndClient(executor, tables, input, "revoke").pipe(Effect.flatMap((row) => {
|
|
2565
|
+
if (Option.isNone(row)) {
|
|
2566
|
+
return Effect.succeed(Option.none());
|
|
2567
|
+
}
|
|
2568
|
+
return executePlan(executor, queryUpdate(tables.oauthConsent.table, mutationValues(tables.oauthConsent.revoke(input, row.value))).pipe(Query.where(queryEq(tables.oauthConsent.select.userId, input.userId)), Query.where(queryEq(tables.oauthConsent.select.clientId, input.clientId)), Query.returning(selectOAuthConsentColumns(tables)))).pipe(Effect.mapError((cause) => oauthConsentStoreError("revoke", cause)), Effect.map((rows) => rows[0] === undefined
|
|
2569
|
+
? Option.none()
|
|
2570
|
+
: Option.some(decodeOAuthConsentRow(tables, rows[0]))));
|
|
2571
|
+
})),
|
|
2572
|
+
deleteInactive: (input) => deleteOAuthInactiveConsents(executor, tables, input),
|
|
2573
|
+
});
|
|
2574
|
+
};
|
|
2575
|
+
export const makeEffectQbSqliteOAuthAuthorizationCodeStore = (executor, options = {}) => {
|
|
2576
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2577
|
+
return OAuthAuthorizationCodeStore.make({
|
|
2578
|
+
upsert: (record) => executePlan(executor, queryInsert(tables.oauthAuthorizationCode.table, mutationValues(tables.oauthAuthorizationCode.insert(record))).pipe(Query.onConflict("code_hash", {
|
|
2579
|
+
update: mutationValues(tables.oauthAuthorizationCode.update(record)),
|
|
2580
|
+
}))).pipe(Effect.mapError((cause) => oauthAuthorizationCodeStoreError("upsert", cause)), Effect.asVoid),
|
|
2581
|
+
findByHash: (input) => findOAuthAuthorizationCodeByHash(executor, tables, input),
|
|
2582
|
+
markConsumed: (input) => executePlan(executor, queryUpdate(tables.oauthAuthorizationCode.table, mutationValues(tables.oauthAuthorizationCode.markConsumed(input))).pipe(Query.where(queryEq(tables.oauthAuthorizationCode.select.codeHash, input.codeHash)), Query.where(queryIsNull(tables.oauthAuthorizationCode.select.consumedAt)), Query.returning({ codeHash: tables.oauthAuthorizationCode.select.codeHash }))).pipe(Effect.mapError((cause) => oauthAuthorizationCodeStoreError("mark-consumed", cause)), Effect.flatMap((rows) => {
|
|
2583
|
+
const [consumed] = rows;
|
|
2584
|
+
if (consumed !== undefined) {
|
|
2585
|
+
return findOAuthAuthorizationCodeByHash(executor, tables, { codeHash: consumed.codeHash }, "mark-consumed").pipe(Effect.map((record) => Option.isNone(record)
|
|
2586
|
+
? { status: "missing" }
|
|
2587
|
+
: {
|
|
2588
|
+
status: "consumed",
|
|
2589
|
+
record: record.value,
|
|
2590
|
+
}));
|
|
2591
|
+
}
|
|
2592
|
+
return findOAuthAuthorizationCodeByHash(executor, tables, { codeHash: input.codeHash }, "mark-consumed").pipe(Effect.map((record) => Option.isNone(record)
|
|
2593
|
+
? { status: "missing" }
|
|
2594
|
+
: {
|
|
2595
|
+
status: "already_consumed",
|
|
2596
|
+
record: record.value,
|
|
2597
|
+
}));
|
|
2598
|
+
})),
|
|
2599
|
+
});
|
|
2600
|
+
};
|
|
2601
|
+
export const makeEffectQbSqliteOAuthClientSecretStore = (executor, options = {}) => {
|
|
2602
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2603
|
+
return OAuthClientSecretStore.make({
|
|
2604
|
+
upsert: (record) => executePlan(executor, queryInsert(tables.oauthClientSecret.table, mutationValues(tables.oauthClientSecret.insert(record))).pipe(Query.onConflict("prefix", {
|
|
2605
|
+
update: mutationValues(tables.oauthClientSecret.update(record)),
|
|
2606
|
+
}))).pipe(Effect.mapError((cause) => oauthClientSecretStoreError("upsert", cause)), Effect.asVoid),
|
|
2607
|
+
findByClientIdAndPrefix: (input) => findOAuthClientSecretByClientIdAndPrefix(executor, tables, input),
|
|
2608
|
+
markUsed: (input) => executePlan(executor, queryUpdate(tables.oauthClientSecret.table, mutationValues(tables.oauthClientSecret.markUsed(input))).pipe(Query.where(queryEq(tables.oauthClientSecret.select.clientId, input.clientId)), Query.where(queryEq(tables.oauthClientSecret.select.prefix, input.prefix)), Query.where(queryIsNull(tables.oauthClientSecret.select.revokedAt)), Query.returning(selectOAuthClientSecretColumns(tables)))).pipe(Effect.mapError((cause) => oauthClientSecretStoreError("mark-used", cause)), Effect.map((rows) => rows[0] === undefined
|
|
2609
|
+
? Option.none()
|
|
2610
|
+
: Option.some(decodeOAuthClientSecretRow(tables, rows[0])))),
|
|
2611
|
+
revoke: (input) => findOAuthClientSecretByClientIdAndPrefix(executor, tables, input, "revoke").pipe(Effect.flatMap((row) => {
|
|
2612
|
+
if (Option.isNone(row)) {
|
|
2613
|
+
return Effect.succeed(Option.none());
|
|
2614
|
+
}
|
|
2615
|
+
return executePlan(executor, queryUpdate(tables.oauthClientSecret.table, mutationValues(tables.oauthClientSecret.revoke(input, row.value))).pipe(Query.where(queryEq(tables.oauthClientSecret.select.clientId, input.clientId)), Query.where(queryEq(tables.oauthClientSecret.select.prefix, input.prefix)), Query.returning(selectOAuthClientSecretColumns(tables)))).pipe(Effect.mapError((cause) => oauthClientSecretStoreError("revoke", cause)), Effect.map((rows) => rows[0] === undefined
|
|
2616
|
+
? Option.none()
|
|
2617
|
+
: Option.some(decodeOAuthClientSecretRow(tables, rows[0]))));
|
|
2618
|
+
})),
|
|
2619
|
+
});
|
|
2620
|
+
};
|
|
2621
|
+
export const makeEffectQbSqliteOAuthProviderModeTokenStore = (executor, options = {}) => {
|
|
2622
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2623
|
+
return OAuthProviderModeTokenStore.make({
|
|
2624
|
+
upsert: (record) => executePlan(executor, queryInsert(tables.oauthProviderModeToken.table, mutationValues(tables.oauthProviderModeToken.insert(record))).pipe(Query.onConflict("token_hash", {
|
|
2625
|
+
update: mutationValues(tables.oauthProviderModeToken.update(record)),
|
|
2626
|
+
}))).pipe(Effect.mapError((cause) => oauthProviderModeTokenStoreError("upsert", cause)), Effect.asVoid),
|
|
2627
|
+
findByHash: (input) => findOAuthProviderModeTokenByHash(executor, tables, input),
|
|
2628
|
+
revokeByHash: (input) => findOAuthProviderModeTokenByHash(executor, tables, input, "revoke").pipe(Effect.flatMap((row) => {
|
|
2629
|
+
if (Option.isNone(row) ||
|
|
2630
|
+
(input.tokenTypeHint !== undefined &&
|
|
2631
|
+
row.value.tokenType !== input.tokenTypeHint)) {
|
|
2632
|
+
return Effect.succeed(Option.none());
|
|
2633
|
+
}
|
|
2634
|
+
return executePlan(executor, queryUpdate(tables.oauthProviderModeToken.table, mutationValues(tables.oauthProviderModeToken.revoke(input, row.value))).pipe(Query.where(queryEq(tables.oauthProviderModeToken.select.tokenHash, input.tokenHash)), Query.returning(selectOAuthProviderModeTokenColumns(tables)))).pipe(Effect.mapError((cause) => oauthProviderModeTokenStoreError("revoke", cause)), Effect.map((rows) => rows[0] === undefined
|
|
2635
|
+
? Option.none()
|
|
2636
|
+
: Option.some(decodeOAuthProviderModeTokenRow(tables, rows[0]))));
|
|
2637
|
+
})),
|
|
2638
|
+
rotateRefreshToken: (input) => executePlan(executor, queryUpdate(tables.oauthProviderModeToken.table, mutationValues(tables.oauthProviderModeToken.rotate(input))).pipe(Query.where(queryEq(tables.oauthProviderModeToken.select.tokenHash, input.tokenHash)), Query.where(queryEq(tables.oauthProviderModeToken.select.tokenType, "refresh_token")), Query.where(queryIsNull(tables.oauthProviderModeToken.select.revokedAt)), Query.where(queryIsNull(tables.oauthProviderModeToken.select.rotatedAt)), Query.returning({
|
|
2639
|
+
tokenHash: tables.oauthProviderModeToken.select.tokenHash,
|
|
2640
|
+
}))).pipe(Effect.mapError((cause) => oauthProviderModeTokenStoreError("rotate", cause)), Effect.flatMap((rows) => rows[0] === undefined
|
|
2641
|
+
? Effect.succeed(Option.none())
|
|
2642
|
+
: findOAuthProviderModeTokenByHash(executor, tables, { tokenHash: rows[0].tokenHash }, "rotate"))),
|
|
2643
|
+
deleteRetired: (input) => deleteOAuthProviderModeRetiredTokens(executor, tables, input),
|
|
2644
|
+
});
|
|
2645
|
+
};
|
|
1570
2646
|
export const makeEffectQbSqliteOAuthProviderTokenVault = (executor, options = {}) => {
|
|
1571
2647
|
const tables = options.tables ?? authSqliteTables;
|
|
1572
2648
|
return OAuthProviderTokenVault.make({
|
|
@@ -1592,11 +2668,112 @@ export const makeEffectQbSqliteOAuthProviderTokenVault = (executor, options = {}
|
|
|
1592
2668
|
})),
|
|
1593
2669
|
});
|
|
1594
2670
|
};
|
|
2671
|
+
export const makeEffectQbSqliteDomainVerificationStore = (executor, options = {}) => {
|
|
2672
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2673
|
+
return DomainVerificationStore.make({
|
|
2674
|
+
upsert: (record) => findDomainVerificationByOwnerAndDomain(executor, tables, { ownerId: record.ownerId, domain: record.domain }, "upsert").pipe(Effect.flatMap((existing) => Option.isNone(existing)
|
|
2675
|
+
? executePlan(executor, queryInsert(tables.domainVerification.table, mutationValues(tables.domainVerification.insert(record))))
|
|
2676
|
+
: executePlan(executor, queryUpdate(tables.domainVerification.table, mutationValues(tables.domainVerification.update(record))).pipe(Query.where(queryEq(tables.domainVerification.select.ownerId, record.ownerId)), Query.where(queryEq(tables.domainVerification.select.domain, record.domain))))), Effect.mapError((cause) => cause instanceof DomainVerificationStoreError
|
|
2677
|
+
? cause
|
|
2678
|
+
: domainVerificationStoreError("upsert", cause)), Effect.asVoid),
|
|
2679
|
+
findById: (id) => findDomainVerificationById(executor, tables, id),
|
|
2680
|
+
findByOwnerAndDomain: (input) => findDomainVerificationByOwnerAndDomain(executor, tables, input),
|
|
2681
|
+
listByOwner: (input) => {
|
|
2682
|
+
const base = Query.select(selectDomainVerificationColumns(tables)).pipe(Query.from(tables.domainVerification.table), Query.where(queryEq(tables.domainVerification.select.ownerId, input.ownerId)));
|
|
2683
|
+
const query = input.includeRevoked === true
|
|
2684
|
+
? base
|
|
2685
|
+
: base.pipe(Query.where(queryIsNull(tables.domainVerification.select.revokedAt)));
|
|
2686
|
+
return executePlan(executor, query).pipe(Effect.mapError((cause) => domainVerificationStoreError("list", cause)), Effect.map((rows) => rows.map((row) => decodeDomainVerificationRecord(tables, row))));
|
|
2687
|
+
},
|
|
2688
|
+
markVerified: (input) => executePlan(executor, queryUpdate(tables.domainVerification.table, mutationValues(tables.domainVerification.markVerified(input))).pipe(Query.where(queryEq(tables.domainVerification.select.id, input.id)), Query.where(queryEq(tables.domainVerification.select.status, "pending")), Query.returning(selectDomainVerificationColumns(tables)))).pipe(Effect.mapError((cause) => domainVerificationStoreError("mark-verified", cause)), Effect.map((rows) => rows[0] === undefined
|
|
2689
|
+
? Option.none()
|
|
2690
|
+
: Option.some(decodeDomainVerificationRecord(tables, rows[0])))),
|
|
2691
|
+
revoke: (input) => findDomainVerificationById(executor, tables, input.id, "revoke").pipe(Effect.flatMap((record) => {
|
|
2692
|
+
if (Option.isNone(record)) {
|
|
2693
|
+
return Effect.void;
|
|
2694
|
+
}
|
|
2695
|
+
return executePlan(executor, queryUpdate(tables.domainVerification.table, mutationValues(tables.domainVerification.revoke(input, record.value))).pipe(Query.where(queryEq(tables.domainVerification.select.id, input.id)))).pipe(Effect.mapError((cause) => domainVerificationStoreError("revoke", cause)), Effect.asVoid);
|
|
2696
|
+
})),
|
|
2697
|
+
});
|
|
2698
|
+
};
|
|
1595
2699
|
export const makeEffectQbSqliteSecurityTimelineStore = (executor, options = {}) => {
|
|
1596
2700
|
const tables = options.tables ?? authSqliteTables;
|
|
1597
2701
|
return SecurityTimelineStore.make({
|
|
1598
2702
|
insert: (event) => executePlan(executor, queryInsert(tables.securityTimeline.table, mutationValues(tables.securityTimeline.insert(event)))).pipe(Effect.mapError((cause) => securityTimelineStoreError("insert", cause)), Effect.asVoid),
|
|
1599
2703
|
listByUser: (input) => listSecurityTimelineByUser(executor, tables, input),
|
|
2704
|
+
deleteBefore: (input) => deleteSecurityTimelineBefore(executor, tables, input),
|
|
2705
|
+
});
|
|
2706
|
+
};
|
|
2707
|
+
export const makeEffectQbSqliteWebhookOutboxStore = (executor, options = {}) => {
|
|
2708
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2709
|
+
return WebhookOutboxStore.make({
|
|
2710
|
+
enqueue: (input) => Effect.gen(function* () {
|
|
2711
|
+
const now = input.now ?? (yield* currentUnixMillis);
|
|
2712
|
+
const record = {
|
|
2713
|
+
id: input.id,
|
|
2714
|
+
endpointKey: input.endpointKey,
|
|
2715
|
+
event: input.event,
|
|
2716
|
+
status: "pending",
|
|
2717
|
+
attempts: 0,
|
|
2718
|
+
nextAttemptAt: input.nextAttemptAt ?? now,
|
|
2719
|
+
createdAt: now,
|
|
2720
|
+
updatedAt: now,
|
|
2721
|
+
};
|
|
2722
|
+
yield* executePlan(executor, queryInsert(tables.webhookOutbox.table, mutationValues(tables.webhookOutbox.insert(record)))).pipe(Effect.mapError((cause) => webhookOutboxStoreError("enqueue", cause)), Effect.asVoid);
|
|
2723
|
+
return record;
|
|
2724
|
+
}),
|
|
2725
|
+
claimDue: (input) => claimDueWebhookOutboxRecords(executor, tables, input),
|
|
2726
|
+
markDelivered: (input) => Effect.gen(function* () {
|
|
2727
|
+
const existing = yield* findWebhookOutboxRecordById(executor, tables, input.id, "markDelivered");
|
|
2728
|
+
if (Option.isNone(existing) || existing.value.status === "dead_lettered") {
|
|
2729
|
+
return;
|
|
2730
|
+
}
|
|
2731
|
+
const deliveredAt = input.deliveredAt ?? (yield* currentUnixMillis);
|
|
2732
|
+
yield* executePlan(executor, queryUpdate(tables.webhookOutbox.table, mutationValues(tables.webhookOutbox.markDelivered({ ...input, deliveredAt }))).pipe(Query.where(queryEq(tables.webhookOutbox.select.id, input.id)))).pipe(Effect.mapError((cause) => webhookOutboxStoreError("markDelivered", cause)), Effect.asVoid);
|
|
2733
|
+
}),
|
|
2734
|
+
markFailed: (input) => Effect.gen(function* () {
|
|
2735
|
+
const existing = yield* findWebhookOutboxRecordById(executor, tables, input.id, "markFailed");
|
|
2736
|
+
if (Option.isNone(existing) ||
|
|
2737
|
+
existing.value.status === "delivered" ||
|
|
2738
|
+
existing.value.status === "dead_lettered") {
|
|
2739
|
+
return;
|
|
2740
|
+
}
|
|
2741
|
+
const failedAt = input.failedAt ?? (yield* currentUnixMillis);
|
|
2742
|
+
yield* executePlan(executor, queryUpdate(tables.webhookOutbox.table, mutationValues(tables.webhookOutbox.markFailed({
|
|
2743
|
+
...input,
|
|
2744
|
+
failedAt,
|
|
2745
|
+
attempts: existing.value.attempts + 1,
|
|
2746
|
+
}))).pipe(Query.where(queryEq(tables.webhookOutbox.select.id, input.id)))).pipe(Effect.mapError((cause) => webhookOutboxStoreError("markFailed", cause)), Effect.asVoid);
|
|
2747
|
+
}),
|
|
2748
|
+
markDeadLettered: (input) => Effect.gen(function* () {
|
|
2749
|
+
const existing = yield* findWebhookOutboxRecordById(executor, tables, input.id, "markDeadLettered");
|
|
2750
|
+
if (Option.isNone(existing) ||
|
|
2751
|
+
existing.value.status === "delivered" ||
|
|
2752
|
+
existing.value.status === "dead_lettered") {
|
|
2753
|
+
return;
|
|
2754
|
+
}
|
|
2755
|
+
const deadLetteredAt = input.deadLetteredAt ?? (yield* currentUnixMillis);
|
|
2756
|
+
yield* executePlan(executor, queryUpdate(tables.webhookOutbox.table, mutationValues(tables.webhookOutbox.markDeadLettered({
|
|
2757
|
+
...input,
|
|
2758
|
+
deadLetteredAt,
|
|
2759
|
+
}))).pipe(Query.where(queryEq(tables.webhookOutbox.select.id, input.id)))).pipe(Effect.mapError((cause) => webhookOutboxStoreError("markDeadLettered", cause)), Effect.asVoid);
|
|
2760
|
+
}),
|
|
2761
|
+
deleteBefore: (input) => deleteWebhookOutboxRecordsBefore(executor, tables, input),
|
|
2762
|
+
});
|
|
2763
|
+
};
|
|
2764
|
+
export const makeEffectQbSqliteWebhookReplayStore = (executor, options = {}) => {
|
|
2765
|
+
const tables = options.tables ?? authSqliteTables;
|
|
2766
|
+
return WebhookReplayStore.make({
|
|
2767
|
+
claim: (input) => Effect.gen(function* () {
|
|
2768
|
+
const now = input.now ?? (yield* currentUnixMillis);
|
|
2769
|
+
const claim = { ...input, now };
|
|
2770
|
+
const rows = yield* executePlan(executor, queryInsert(tables.webhookReplay.table, mutationValues(tables.webhookReplay.insert(claim))).pipe(Query.onConflict("id", {
|
|
2771
|
+
update: mutationValues(tables.webhookReplay.update(claim)),
|
|
2772
|
+
where: queryLt(tables.webhookReplay.select.expiresAt, Number(now)),
|
|
2773
|
+
}), Query.returning(selectWebhookReplayColumns(tables)))).pipe(Effect.mapError((cause) => webhookReplayStoreError("claim", cause)));
|
|
2774
|
+
return rows.length > 0;
|
|
2775
|
+
}),
|
|
2776
|
+
deleteExpired: (input = {}) => deleteExpiredWebhookReplayRecords(executor, tables, input),
|
|
1600
2777
|
});
|
|
1601
2778
|
};
|
|
1602
2779
|
export const makeEffectQbSqliteStorage = (executor, options = {}) => ({
|
|
@@ -1604,7 +2781,9 @@ export const makeEffectQbSqliteStorage = (executor, options = {}) => ({
|
|
|
1604
2781
|
credentialStore: makeEffectQbSqliteCredentialStore(executor, options),
|
|
1605
2782
|
sessionStore: makeEffectQbSqliteSessionStore(executor, options),
|
|
1606
2783
|
verificationStore: makeEffectQbSqliteVerificationStore(executor, options),
|
|
2784
|
+
auditLogStore: makeEffectQbSqliteAuditLogStore(executor, options),
|
|
1607
2785
|
loginApprovalReviewStore: makeEffectQbSqliteLoginApprovalReviewStore(executor, options),
|
|
2786
|
+
loginRiskHistoryStore: makeEffectQbSqliteLoginRiskHistoryStore(executor, options),
|
|
1608
2787
|
trustedDeviceStore: makeEffectQbSqliteTrustedDeviceStore(executor, options),
|
|
1609
2788
|
passkeyCredentialStore: makeEffectQbSqlitePasskeyCredentialStore(executor, options),
|
|
1610
2789
|
totpFactorStore: makeEffectQbSqliteTotpFactorStore(executor, options),
|
|
@@ -1613,10 +2792,18 @@ export const makeEffectQbSqliteStorage = (executor, options = {}) => ({
|
|
|
1613
2792
|
refreshTokenStore: makeEffectQbSqliteRefreshTokenStore(executor, options),
|
|
1614
2793
|
jwtRevocationStore: makeEffectQbSqliteJwtRevocationStore(executor, options),
|
|
1615
2794
|
oauthAccountStore: makeEffectQbSqliteOAuthAccountStore(executor, options),
|
|
2795
|
+
oauthClientStore: makeEffectQbSqliteOAuthClientStore(executor, options),
|
|
2796
|
+
oauthConsentStore: makeEffectQbSqliteOAuthConsentStore(executor, options),
|
|
2797
|
+
oauthAuthorizationCodeStore: makeEffectQbSqliteOAuthAuthorizationCodeStore(executor, options),
|
|
2798
|
+
oauthClientSecretStore: makeEffectQbSqliteOAuthClientSecretStore(executor, options),
|
|
2799
|
+
oauthProviderModeTokenStore: makeEffectQbSqliteOAuthProviderModeTokenStore(executor, options),
|
|
1616
2800
|
oauthProviderTokenVault: makeEffectQbSqliteOAuthProviderTokenVault(executor, options),
|
|
2801
|
+
domainVerificationStore: makeEffectQbSqliteDomainVerificationStore(executor, options),
|
|
1617
2802
|
securityTimelineStore: makeEffectQbSqliteSecurityTimelineStore(executor, options),
|
|
2803
|
+
webhookOutboxStore: makeEffectQbSqliteWebhookOutboxStore(executor, options),
|
|
2804
|
+
webhookReplayStore: makeEffectQbSqliteWebhookReplayStore(executor, options),
|
|
1618
2805
|
});
|
|
1619
|
-
export const EffectQbSqliteAuthStorageLive = (executor, options = {}) => Layer.mergeAll(Layer.succeed(UserStore)(makeEffectQbSqliteUserStore(executor, options)), Layer.succeed(CredentialStore)(makeEffectQbSqliteCredentialStore(executor, options)), Layer.succeed(SessionStore)(makeEffectQbSqliteSessionStore(executor, options)), Layer.succeed(VerificationStore)(makeEffectQbSqliteVerificationStore(executor, options)), Layer.succeed(LoginApprovalReviewStore)(makeEffectQbSqliteLoginApprovalReviewStore(executor, options)), Layer.succeed(TrustedDeviceStore)(makeEffectQbSqliteTrustedDeviceStore(executor, options)), Layer.succeed(PasskeyCredentialStore)(makeEffectQbSqlitePasskeyCredentialStore(executor, options)), Layer.succeed(TotpFactorStore)(makeEffectQbSqliteTotpFactorStore(executor, options)), Layer.succeed(RecoveryCodeStore)(makeEffectQbSqliteRecoveryCodeStore(executor, options)), Layer.succeed(ApiKeyStore)(makeEffectQbSqliteApiKeyStore(executor, options)), Layer.succeed(RefreshTokenStore)(makeEffectQbSqliteRefreshTokenStore(executor, options)), Layer.succeed(JwtRevocationStore)(makeEffectQbSqliteJwtRevocationStore(executor, options)), Layer.succeed(OAuthAccountStore)(makeEffectQbSqliteOAuthAccountStore(executor, options)), Layer.succeed(OAuthProviderTokenVault)(makeEffectQbSqliteOAuthProviderTokenVault(executor, options)), Layer.succeed(SecurityTimelineStore)(makeEffectQbSqliteSecurityTimelineStore(executor, options)));
|
|
2806
|
+
export const EffectQbSqliteAuthStorageLive = (executor, options = {}) => Layer.mergeAll(Layer.succeed(UserStore)(makeEffectQbSqliteUserStore(executor, 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(RecoveryCodeStore)(makeEffectQbSqliteRecoveryCodeStore(executor, options)), Layer.succeed(ApiKeyStore)(makeEffectQbSqliteApiKeyStore(executor, options)), Layer.succeed(RefreshTokenStore)(makeEffectQbSqliteRefreshTokenStore(executor, options)), Layer.succeed(JwtRevocationStore)(makeEffectQbSqliteJwtRevocationStore(executor, options)), Layer.succeed(OAuthAccountStore)(makeEffectQbSqliteOAuthAccountStore(executor, 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)));
|
|
1620
2807
|
export const makeD1EffectQbSqliteExecutor = (database) => Executor.make({
|
|
1621
2808
|
driver: Executor.driver((query) => Effect.tryPromise({
|
|
1622
2809
|
try: () => database
|