@oimlsmart/platform-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -0
- package/migrations/0001_init.sql +69 -0
- package/migrations/0002_identity.sql +24 -0
- package/migrations/0003_federation_peers.sql +21 -0
- package/migrations/0003_users_rbac.sql +8 -0
- package/migrations/0004_oidc_op.sql +61 -0
- package/migrations/0005_upstream_providers.sql +34 -0
- package/migrations/0006_op_accounts.sql +28 -0
- package/migrations/0007_org_join_requests.sql +26 -0
- package/migrations/0008_op_client_roles.sql +19 -0
- package/migrations/0009_account_console.sql +32 -0
- package/migrations/0009_sso_states.sql +13 -0
- package/migrations/0010_notify_events.sql +23 -0
- package/migrations/0011_op_launch.sql +18 -0
- package/migrations/0011_org_memberships.sql +62 -0
- package/migrations/0012_notify_subscriptions.sql +57 -0
- package/migrations/0012_strong_auth.sql +109 -0
- package/migrations/0013_org_registry.sql +53 -0
- package/migrations/0014_notify_inbox.sql +34 -0
- package/migrations/0015_certificate_holder_attribution.sql +63 -0
- package/migrations/0016_instrument_registrations.sql +78 -0
- package/package.json +52 -0
- package/src/client-info.ts +25 -0
- package/src/context.ts +31 -0
- package/src/github.ts +284 -0
- package/src/mailer.ts +309 -0
- package/src/oidc.ts +369 -0
- package/src/profile/node.ts +83 -0
- package/src/profile.ts +582 -0
- package/src/rbac/node.ts +42 -0
- package/src/rbac.ts +53 -0
- package/src/session.ts +45 -0
- package/src/store/d1.ts +2850 -0
- package/src/store/sqlite/entities.ts +71 -0
- package/src/store/sqlite/events.ts +82 -0
- package/src/store/sqlite/factors-store.ts +348 -0
- package/src/store/sqlite/notify.ts +247 -0
- package/src/store/sqlite/op-accounts-store.ts +470 -0
- package/src/store/sqlite/op-store.ts +280 -0
- package/src/store/sqlite/schema.sql +745 -0
- package/src/store/sqlite/store.ts +1390 -0
- package/src/store/sqlite/upstream-store.ts +148 -0
- package/src/store/sqlite.ts +1027 -0
- package/src/store.ts +1826 -0
- package/src/vocab/index.ts +12 -0
- package/src/vocab/permissions.ts +398 -0
- package/src/vocab/rbac.ts +281 -0
- package/src/vocab/roles.ts +162 -0
|
@@ -0,0 +1,1027 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
2
|
+
// The SQLite ServerStore (TODO.cs-e2e/14): the node/self-hosted half
|
|
3
|
+
// of the backend seam — the SAME sync modules the server always used
|
|
4
|
+
// (store.ts + entities.ts, better-sqlite3) exposed through the async
|
|
5
|
+
// ServerStore contract the routes consume. Zero behavior change: every
|
|
6
|
+
// method delegates one-for-one.
|
|
7
|
+
//
|
|
8
|
+
// NODE-ONLY: this module imports better-sqlite3 through store.ts. The
|
|
9
|
+
// Worker bundle never sees it (the worker entry installs the D1 store
|
|
10
|
+
// instead) — the audit the wrangler config documents.
|
|
11
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
12
|
+
|
|
13
|
+
import { fileURLToPath } from 'url'
|
|
14
|
+
import {
|
|
15
|
+
attributeCertificateHolderOrg,
|
|
16
|
+
authenticateDemo,
|
|
17
|
+
cleanExpiredSessions,
|
|
18
|
+
consumeSsoState,
|
|
19
|
+
createCertificateHolderClaim,
|
|
20
|
+
createLocalUser,
|
|
21
|
+
createOrgJoinRequest,
|
|
22
|
+
createOrgMembership,
|
|
23
|
+
createOrgRegistryOrg,
|
|
24
|
+
createInstrumentRegistration,
|
|
25
|
+
createSession,
|
|
26
|
+
decideCertificateHolderClaim,
|
|
27
|
+
decideIdentityApproval,
|
|
28
|
+
decideOrgJoinRequest,
|
|
29
|
+
deleteOrgMembership,
|
|
30
|
+
deleteOrgRegistryOrg,
|
|
31
|
+
deleteSession,
|
|
32
|
+
findOrCreateOAuthUser,
|
|
33
|
+
findPendingCertificateHolderClaim,
|
|
34
|
+
findPendingOrgJoinRequestByEmail,
|
|
35
|
+
findUserByEmail,
|
|
36
|
+
findUserByProvider,
|
|
37
|
+
getCertificateHolderClaim,
|
|
38
|
+
getCertificateHolderOrg,
|
|
39
|
+
getDb,
|
|
40
|
+
getFederationPeer,
|
|
41
|
+
getIdentityApproval,
|
|
42
|
+
getInstrumentRegistration,
|
|
43
|
+
getOrgJoinRequest,
|
|
44
|
+
getOrgMembership,
|
|
45
|
+
getOrgRegistryOrg,
|
|
46
|
+
getSessionActiveOrg,
|
|
47
|
+
getSessionIdTokenHint,
|
|
48
|
+
getSessionUser,
|
|
49
|
+
getUserById,
|
|
50
|
+
linkProviderIdentity,
|
|
51
|
+
listCertificateHolderClaims,
|
|
52
|
+
listCertificateHolderOrgs,
|
|
53
|
+
listFederationPeers,
|
|
54
|
+
listIdentityApprovals,
|
|
55
|
+
listInstrumentRegistrations,
|
|
56
|
+
listInstrumentRegistrationsForCertificate,
|
|
57
|
+
listInstrumentRegistrationsForHolder,
|
|
58
|
+
listOrgJoinRequests,
|
|
59
|
+
listOrgMembers,
|
|
60
|
+
listOrgMemberships,
|
|
61
|
+
listOrgRegistryOrgs,
|
|
62
|
+
listUsers,
|
|
63
|
+
provisionSsoUser,
|
|
64
|
+
putSsoState,
|
|
65
|
+
revokeFederationPeer,
|
|
66
|
+
seedDemoAccounts,
|
|
67
|
+
setInstrumentRegistrationLifecycle,
|
|
68
|
+
setOrgMembershipRoles,
|
|
69
|
+
setOrgMembershipState,
|
|
70
|
+
setOrgRegistryOrgState,
|
|
71
|
+
setSessionActiveOrg,
|
|
72
|
+
setUserActive,
|
|
73
|
+
setUserRoles,
|
|
74
|
+
touchLastLogin,
|
|
75
|
+
updateOrgRegistryOrg,
|
|
76
|
+
updateUserRoleOrg,
|
|
77
|
+
upsertFederationPeer,
|
|
78
|
+
upsertIdentityApproval,
|
|
79
|
+
} from './sqlite/store'
|
|
80
|
+
import {
|
|
81
|
+
changesAfter,
|
|
82
|
+
deleteEntity,
|
|
83
|
+
getEntity,
|
|
84
|
+
latestChangeSeq,
|
|
85
|
+
listEntities,
|
|
86
|
+
putEntity,
|
|
87
|
+
} from './sqlite/entities'
|
|
88
|
+
import {
|
|
89
|
+
appendEvent,
|
|
90
|
+
eventsAfter,
|
|
91
|
+
eventsMatching,
|
|
92
|
+
getEvent,
|
|
93
|
+
latestEventSeq,
|
|
94
|
+
} from './sqlite/events'
|
|
95
|
+
import {
|
|
96
|
+
deleteNotifyEntityMute,
|
|
97
|
+
deleteNotifyRule,
|
|
98
|
+
getNotifyPreferences,
|
|
99
|
+
listNotifyEntityMutes,
|
|
100
|
+
listNotifyInboxStates,
|
|
101
|
+
listNotifyRules,
|
|
102
|
+
notifyEntityMutesForEvent,
|
|
103
|
+
notifyRulesForEvent,
|
|
104
|
+
putNotifyEntityMute,
|
|
105
|
+
putNotifyInboxState,
|
|
106
|
+
putNotifyPreferences,
|
|
107
|
+
putNotifyRule,
|
|
108
|
+
} from './sqlite/notify'
|
|
109
|
+
import {
|
|
110
|
+
consumeOidcCode,
|
|
111
|
+
createOidcAccessToken,
|
|
112
|
+
createOidcAuthorization,
|
|
113
|
+
createOidcCode,
|
|
114
|
+
decideOidcAuthorization,
|
|
115
|
+
getOidcAccessToken,
|
|
116
|
+
getOidcAuthorization,
|
|
117
|
+
getOidcClient,
|
|
118
|
+
listOidcClients,
|
|
119
|
+
listOidcKeys,
|
|
120
|
+
retireOidcKey,
|
|
121
|
+
setOidcClientStatus,
|
|
122
|
+
setOidcClientLaunch,
|
|
123
|
+
upsertOidcClient,
|
|
124
|
+
upsertOidcKey,
|
|
125
|
+
} from './sqlite/op-store'
|
|
126
|
+
import {
|
|
127
|
+
createIdentityLink,
|
|
128
|
+
deleteIdentityLink,
|
|
129
|
+
deleteIdentityProvider,
|
|
130
|
+
findIdentityLink,
|
|
131
|
+
getIdentityProvider,
|
|
132
|
+
listIdentityLinks,
|
|
133
|
+
listIdentityProviders,
|
|
134
|
+
setIdentityProviderEnabled,
|
|
135
|
+
upsertIdentityProvider,
|
|
136
|
+
} from './sqlite/upstream-store'
|
|
137
|
+
import {
|
|
138
|
+
completeEmailChange,
|
|
139
|
+
completeEnrollment,
|
|
140
|
+
countSignInMethods,
|
|
141
|
+
createEmailChangeToken,
|
|
142
|
+
createEnrollmentToken,
|
|
143
|
+
createOpAccount,
|
|
144
|
+
deleteAllUserSessions,
|
|
145
|
+
deleteOpClientRoles,
|
|
146
|
+
deleteOtherSessions,
|
|
147
|
+
deletePasswordHash,
|
|
148
|
+
deleteSessionById,
|
|
149
|
+
eraseOpAccount,
|
|
150
|
+
getEmailChangeToken,
|
|
151
|
+
getEnrollmentToken,
|
|
152
|
+
getOpClientRoles,
|
|
153
|
+
getPasswordLogin,
|
|
154
|
+
getPendingEmailChange,
|
|
155
|
+
lastAccountSignIns,
|
|
156
|
+
listAllOpClientRoles,
|
|
157
|
+
listOpClientRoles,
|
|
158
|
+
listOpLiveSessions,
|
|
159
|
+
listUserSessions,
|
|
160
|
+
revokeOpUserCredentials,
|
|
161
|
+
setOpClientRoles,
|
|
162
|
+
setPasswordHash,
|
|
163
|
+
setUserAvatar,
|
|
164
|
+
updateOpAccount,
|
|
165
|
+
updateUserName,
|
|
166
|
+
} from './sqlite/op-accounts-store'
|
|
167
|
+
import { installStore, type AuthUserPayload, type CertificateHolderClaim, type CertificateHolderOrg, type CompleteEmailChangeResult, type CompleteEnrollmentResult, type EmailChangeToken, type EnrollmentToken, type EntityChange, type EntityRow, type EventKeyFilter, type FederationPeer, type IdentityApproval, type IdentityLink, type IdentityProvider, type InstrumentRegistration, type InstrumentRegistrationLifecycle, type InstrumentRegistrationScopeStatus, type NotifyEntityMute, type NotifyInboxState, type NotifyPreferences, type NotifyRule, type OAuthInitialAssignment, type OidcAccessToken, type OidcAuthorization, type OidcClient, type OidcClientLaunch, type OidcCode, type OidcKeyRow, type OpAccountErasure, type OpClientRoleAssignment, type OpLiveSession, type OrgJoinRequest, type OrgMembership, type OrgMembershipState, type OrgRegistryContact, type OrgRegistryOrg, type OrgRegistryState, type PlatformEvent, type ServerStore, type SessionView, type SsoSignInState, type UserAdminRow, type AdvanceCounterResult, type MfaPending, type RecoveryCodeState, type TotpSecret, type WebauthnChallenge, type WebauthnCredential } from '../store'
|
|
168
|
+
import {
|
|
169
|
+
advanceWebauthnCounter,
|
|
170
|
+
consumeMfaPending,
|
|
171
|
+
consumeRecoveryCode,
|
|
172
|
+
consumeWebauthnChallenge,
|
|
173
|
+
createMfaPending,
|
|
174
|
+
createTotpSecret,
|
|
175
|
+
createWebauthnChallenge,
|
|
176
|
+
createWebauthnCredential,
|
|
177
|
+
deleteTotpSecret,
|
|
178
|
+
deleteWebauthnCredential,
|
|
179
|
+
getMfaPending,
|
|
180
|
+
getTotpSecret,
|
|
181
|
+
getWebauthnCredential,
|
|
182
|
+
listTotpSecrets,
|
|
183
|
+
listWebauthnCredentials,
|
|
184
|
+
markTotpSecretUsed,
|
|
185
|
+
markTotpSecretVerified,
|
|
186
|
+
recordMfaPendingFailure,
|
|
187
|
+
recordTotpEnrollFailure,
|
|
188
|
+
replaceRecoveryCodes,
|
|
189
|
+
recoveryCodeState,
|
|
190
|
+
} from './sqlite/factors-store'
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
/** The workflow tables the reset wipe covers (the D1 store's
|
|
194
|
+
* WIPE_TABLES twin — one rule, two backends): ordinary rowid tables
|
|
195
|
+
* all, so ranged rounds address rows by a stable rowid window. The
|
|
196
|
+
* TODO.notify/01 event store wipes with them — its rows reference the
|
|
197
|
+
* workflow entities a reset removes (the feed's read-time visibility
|
|
198
|
+
* gate would drop the orphans anyway; wiping keeps the demo honest).
|
|
199
|
+
* TODO.register/03: the instrument register wipes too — the e2e
|
|
200
|
+
* isolation contract resets it with the rest of the mutable workflow
|
|
201
|
+
* state. */
|
|
202
|
+
const WIPE_TABLES = ['entity_changes', 'evidence_records', 'entities', 'events', 'instrument_registrations'] as const
|
|
203
|
+
|
|
204
|
+
export function createSqliteServerStore(): ServerStore {
|
|
205
|
+
return {
|
|
206
|
+
// ── users / sessions ──
|
|
207
|
+
async seedDemoAccounts(): Promise<void> {
|
|
208
|
+
seedDemoAccounts()
|
|
209
|
+
},
|
|
210
|
+
async authenticateDemo(email: string, password: string): Promise<AuthUserPayload | null> {
|
|
211
|
+
return authenticateDemo(email, password)
|
|
212
|
+
},
|
|
213
|
+
async findOrCreateOAuthUser(
|
|
214
|
+
provider: string,
|
|
215
|
+
providerAccountId: string,
|
|
216
|
+
email: string,
|
|
217
|
+
name: string,
|
|
218
|
+
avatarUrl?: string,
|
|
219
|
+
initial?: OAuthInitialAssignment,
|
|
220
|
+
): Promise<AuthUserPayload> {
|
|
221
|
+
return findOrCreateOAuthUser(provider, providerAccountId, email, name, avatarUrl, initial)
|
|
222
|
+
},
|
|
223
|
+
async createSession(
|
|
224
|
+
userId: string,
|
|
225
|
+
opts?: { idTokenHint?: string | null; userAgent?: string | null; ip?: string | null; amr?: string[] | null },
|
|
226
|
+
): Promise<string> {
|
|
227
|
+
return createSession(userId, opts)
|
|
228
|
+
},
|
|
229
|
+
async touchLastLogin(userId: string): Promise<void> {
|
|
230
|
+
touchLastLogin(userId)
|
|
231
|
+
},
|
|
232
|
+
async getSessionUser(token: string): Promise<AuthUserPayload | null> {
|
|
233
|
+
return getSessionUser(token)
|
|
234
|
+
},
|
|
235
|
+
async getSessionIdTokenHint(token: string): Promise<string | null> {
|
|
236
|
+
return getSessionIdTokenHint(token)
|
|
237
|
+
},
|
|
238
|
+
async deleteSession(token: string): Promise<void> {
|
|
239
|
+
deleteSession(token)
|
|
240
|
+
},
|
|
241
|
+
async cleanExpiredSessions(): Promise<void> {
|
|
242
|
+
cleanExpiredSessions()
|
|
243
|
+
},
|
|
244
|
+
async listDemoAccounts(): Promise<Array<{ email: string; name: string; role: string }>> {
|
|
245
|
+
return getDb()
|
|
246
|
+
.prepare("SELECT email, name, role FROM users WHERE provider = 'demo' ORDER BY role, name")
|
|
247
|
+
.all() as Array<{ email: string; name: string; role: string }>
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
// ── identity federation (TODO.federation/10) ──
|
|
251
|
+
async findUserByEmail(email: string): Promise<AuthUserPayload | null> {
|
|
252
|
+
return findUserByEmail(email)
|
|
253
|
+
},
|
|
254
|
+
async getUserById(id: string): Promise<AuthUserPayload | null> {
|
|
255
|
+
return getUserById(id)
|
|
256
|
+
},
|
|
257
|
+
async findUserByProvider(provider: string, providerAccountId: string): Promise<AuthUserPayload | null> {
|
|
258
|
+
return findUserByProvider(provider, providerAccountId)
|
|
259
|
+
},
|
|
260
|
+
async provisionSsoUser(input: {
|
|
261
|
+
email: string
|
|
262
|
+
name: string
|
|
263
|
+
provider: string
|
|
264
|
+
providerAccountId: string
|
|
265
|
+
role: string
|
|
266
|
+
orgId: string | null
|
|
267
|
+
}): Promise<AuthUserPayload> {
|
|
268
|
+
return provisionSsoUser(input)
|
|
269
|
+
},
|
|
270
|
+
async linkProviderIdentity(userId: string, provider: string, providerAccountId: string): Promise<void> {
|
|
271
|
+
linkProviderIdentity(userId, provider, providerAccountId)
|
|
272
|
+
},
|
|
273
|
+
async updateUserRoleOrg(userId: string, role: string, orgId: string | null): Promise<void> {
|
|
274
|
+
updateUserRoleOrg(userId, role, orgId)
|
|
275
|
+
},
|
|
276
|
+
async upsertIdentityApproval(input: {
|
|
277
|
+
email: string
|
|
278
|
+
name: string
|
|
279
|
+
issuer: string
|
|
280
|
+
sub: string
|
|
281
|
+
claimsJson: string | null
|
|
282
|
+
}): Promise<IdentityApproval> {
|
|
283
|
+
return upsertIdentityApproval(input)
|
|
284
|
+
},
|
|
285
|
+
async getIdentityApproval(issuer: string, sub: string): Promise<IdentityApproval | null> {
|
|
286
|
+
return getIdentityApproval(issuer, sub)
|
|
287
|
+
},
|
|
288
|
+
async listIdentityApprovals(status?: IdentityApproval['status']): Promise<IdentityApproval[]> {
|
|
289
|
+
return listIdentityApprovals(status)
|
|
290
|
+
},
|
|
291
|
+
async decideIdentityApproval(
|
|
292
|
+
id: string,
|
|
293
|
+
decision: { status: 'approved' | 'rejected'; role?: string; orgId?: string | null; decidedBy: string },
|
|
294
|
+
): Promise<IdentityApproval | null> {
|
|
295
|
+
return decideIdentityApproval(id, decision)
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
// ── the SSO sign-in state jar (TODO.identity/04) ──
|
|
299
|
+
async putSsoState(input: { state: string; nonce: string; verifier: string; ttlMs: number }): Promise<void> {
|
|
300
|
+
putSsoState(input)
|
|
301
|
+
},
|
|
302
|
+
async consumeSsoState(state: string): Promise<SsoSignInState | null> {
|
|
303
|
+
return consumeSsoState(state)
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
// ── federation peers (TODO.federation/04) ──
|
|
307
|
+
async listFederationPeers(status?: FederationPeer['status']): Promise<FederationPeer[]> {
|
|
308
|
+
return listFederationPeers(status)
|
|
309
|
+
},
|
|
310
|
+
async getFederationPeer(id: string): Promise<FederationPeer | null> {
|
|
311
|
+
return getFederationPeer(id)
|
|
312
|
+
},
|
|
313
|
+
async upsertFederationPeer(input: {
|
|
314
|
+
id: string
|
|
315
|
+
name: string
|
|
316
|
+
roles: string
|
|
317
|
+
descriptorUrl: string | null
|
|
318
|
+
descriptorJson: string
|
|
319
|
+
pinnedVia: FederationPeer['pinnedVia']
|
|
320
|
+
connectivity: FederationPeer['connectivity']
|
|
321
|
+
addedBy: string | null
|
|
322
|
+
}): Promise<FederationPeer> {
|
|
323
|
+
return upsertFederationPeer(input)
|
|
324
|
+
},
|
|
325
|
+
async revokeFederationPeer(id: string, revokedBy: string): Promise<FederationPeer | null> {
|
|
326
|
+
return revokeFederationPeer(id, revokedBy)
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
// ── user administration (TODO.federation/12) ──
|
|
330
|
+
async listUsers(): Promise<UserAdminRow[]> {
|
|
331
|
+
return listUsers()
|
|
332
|
+
},
|
|
333
|
+
async createLocalUser(input: {
|
|
334
|
+
email: string
|
|
335
|
+
name: string
|
|
336
|
+
role: string
|
|
337
|
+
roles?: string[]
|
|
338
|
+
orgId?: string | null
|
|
339
|
+
}): Promise<UserAdminRow> {
|
|
340
|
+
return createLocalUser(input)
|
|
341
|
+
},
|
|
342
|
+
async setUserRoles(id: string, role: string, roles: string[]): Promise<boolean> {
|
|
343
|
+
return setUserRoles(id, role, roles)
|
|
344
|
+
},
|
|
345
|
+
async setUserActive(id: string, active: boolean): Promise<boolean> {
|
|
346
|
+
return setUserActive(id, active)
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
// ── organization administration (TODO.identity/10) ──
|
|
350
|
+
async createOrgJoinRequest(input: {
|
|
351
|
+
name: string
|
|
352
|
+
email: string
|
|
353
|
+
orgId: string | null
|
|
354
|
+
orgNameText: string | null
|
|
355
|
+
requestedRole: string
|
|
356
|
+
note?: string | null
|
|
357
|
+
}): Promise<OrgJoinRequest> {
|
|
358
|
+
return createOrgJoinRequest(input)
|
|
359
|
+
},
|
|
360
|
+
async getOrgJoinRequest(id: string): Promise<OrgJoinRequest | null> {
|
|
361
|
+
return getOrgJoinRequest(id)
|
|
362
|
+
},
|
|
363
|
+
async listOrgJoinRequests(filter?: {
|
|
364
|
+
scope?: 'org' | 'unregistered' | 'all'
|
|
365
|
+
orgId?: string
|
|
366
|
+
status?: OrgJoinRequest['status']
|
|
367
|
+
}): Promise<OrgJoinRequest[]> {
|
|
368
|
+
return listOrgJoinRequests(filter)
|
|
369
|
+
},
|
|
370
|
+
async decideOrgJoinRequest(
|
|
371
|
+
id: string,
|
|
372
|
+
decision: {
|
|
373
|
+
status: 'approved' | 'refused'
|
|
374
|
+
decidedBy: string
|
|
375
|
+
refusalReason?: string | null
|
|
376
|
+
invitedUserId?: string | null
|
|
377
|
+
},
|
|
378
|
+
): Promise<OrgJoinRequest | null> {
|
|
379
|
+
return decideOrgJoinRequest(id, decision)
|
|
380
|
+
},
|
|
381
|
+
async findPendingOrgJoinRequestByEmail(email: string): Promise<OrgJoinRequest | null> {
|
|
382
|
+
return findPendingOrgJoinRequestByEmail(email)
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
// ── organization memberships (TODO.identity/11) ──
|
|
386
|
+
async listOrgMemberships(userId: string): Promise<OrgMembership[]> {
|
|
387
|
+
return listOrgMemberships(userId)
|
|
388
|
+
},
|
|
389
|
+
async listOrgMembers(orgId: string): Promise<OrgMembership[]> {
|
|
390
|
+
return listOrgMembers(orgId)
|
|
391
|
+
},
|
|
392
|
+
async getOrgMembership(userId: string, orgId: string): Promise<OrgMembership | null> {
|
|
393
|
+
return getOrgMembership(userId, orgId)
|
|
394
|
+
},
|
|
395
|
+
async createOrgMembership(input: {
|
|
396
|
+
userId: string
|
|
397
|
+
orgId: string
|
|
398
|
+
roles: string[]
|
|
399
|
+
state: OrgMembershipState
|
|
400
|
+
invitedBy?: string | null
|
|
401
|
+
}): Promise<OrgMembership | null> {
|
|
402
|
+
return createOrgMembership(input)
|
|
403
|
+
},
|
|
404
|
+
async setOrgMembershipRoles(userId: string, orgId: string, roles: string[]): Promise<boolean> {
|
|
405
|
+
return setOrgMembershipRoles(userId, orgId, roles)
|
|
406
|
+
},
|
|
407
|
+
async setOrgMembershipState(
|
|
408
|
+
userId: string,
|
|
409
|
+
orgId: string,
|
|
410
|
+
state: OrgMembershipState,
|
|
411
|
+
actor?: string | null,
|
|
412
|
+
): Promise<OrgMembership | null> {
|
|
413
|
+
return setOrgMembershipState(userId, orgId, state, actor)
|
|
414
|
+
},
|
|
415
|
+
async deleteOrgMembership(userId: string, orgId: string): Promise<boolean> {
|
|
416
|
+
return deleteOrgMembership(userId, orgId)
|
|
417
|
+
},
|
|
418
|
+
async getSessionActiveOrg(token: string): Promise<string | null> {
|
|
419
|
+
return getSessionActiveOrg(token)
|
|
420
|
+
},
|
|
421
|
+
async setSessionActiveOrg(token: string, orgId: string | null): Promise<boolean> {
|
|
422
|
+
return setSessionActiveOrg(token, orgId)
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
// ── the organization registry (TODO.identity-features/05) ──
|
|
426
|
+
async listOrgRegistryOrgs(): Promise<OrgRegistryOrg[]> {
|
|
427
|
+
return listOrgRegistryOrgs()
|
|
428
|
+
},
|
|
429
|
+
async getOrgRegistryOrg(id: string): Promise<OrgRegistryOrg | null> {
|
|
430
|
+
return getOrgRegistryOrg(id)
|
|
431
|
+
},
|
|
432
|
+
async createOrgRegistryOrg(input: {
|
|
433
|
+
id: string
|
|
434
|
+
name: string
|
|
435
|
+
shortName?: string | null
|
|
436
|
+
kind?: string | null
|
|
437
|
+
country?: string | null
|
|
438
|
+
contacts?: OrgRegistryContact[]
|
|
439
|
+
participantRef?: string | null
|
|
440
|
+
createdBy?: string | null
|
|
441
|
+
}): Promise<OrgRegistryOrg | null> {
|
|
442
|
+
return createOrgRegistryOrg(input)
|
|
443
|
+
},
|
|
444
|
+
async updateOrgRegistryOrg(
|
|
445
|
+
id: string,
|
|
446
|
+
patch: {
|
|
447
|
+
name?: string
|
|
448
|
+
shortName?: string | null
|
|
449
|
+
kind?: string | null
|
|
450
|
+
country?: string | null
|
|
451
|
+
contacts?: OrgRegistryContact[]
|
|
452
|
+
participantRef?: string | null
|
|
453
|
+
},
|
|
454
|
+
actor?: string | null,
|
|
455
|
+
): Promise<OrgRegistryOrg | null> {
|
|
456
|
+
return updateOrgRegistryOrg(id, patch, actor)
|
|
457
|
+
},
|
|
458
|
+
async setOrgRegistryOrgState(id: string, state: OrgRegistryState, actor?: string | null): Promise<OrgRegistryOrg | null> {
|
|
459
|
+
return setOrgRegistryOrgState(id, state, actor)
|
|
460
|
+
},
|
|
461
|
+
async deleteOrgRegistryOrg(id: string): Promise<boolean> {
|
|
462
|
+
return deleteOrgRegistryOrg(id)
|
|
463
|
+
},
|
|
464
|
+
|
|
465
|
+
// ── the register's holder-org attribution (TODO.register/02) ──
|
|
466
|
+
async attributeCertificateHolderOrg(input: {
|
|
467
|
+
certificateId: string
|
|
468
|
+
orgId: string
|
|
469
|
+
orgName: string
|
|
470
|
+
source: CertificateHolderOrg['source']
|
|
471
|
+
attributedAt: string
|
|
472
|
+
attributedBy?: string | null
|
|
473
|
+
claimId?: string | null
|
|
474
|
+
}): Promise<CertificateHolderOrg | null> {
|
|
475
|
+
return attributeCertificateHolderOrg(input)
|
|
476
|
+
},
|
|
477
|
+
async getCertificateHolderOrg(certificateId: string): Promise<CertificateHolderOrg | null> {
|
|
478
|
+
return getCertificateHolderOrg(certificateId)
|
|
479
|
+
},
|
|
480
|
+
async listCertificateHolderOrgs(filter?: { orgId?: string }): Promise<CertificateHolderOrg[]> {
|
|
481
|
+
return listCertificateHolderOrgs(filter)
|
|
482
|
+
},
|
|
483
|
+
async createCertificateHolderClaim(input: {
|
|
484
|
+
certificateId: string
|
|
485
|
+
claimantOrgId: string
|
|
486
|
+
claimantOrgName: string
|
|
487
|
+
matchedHolderName: string
|
|
488
|
+
claimedBy: string
|
|
489
|
+
}): Promise<CertificateHolderClaim> {
|
|
490
|
+
return createCertificateHolderClaim(input)
|
|
491
|
+
},
|
|
492
|
+
async getCertificateHolderClaim(id: string): Promise<CertificateHolderClaim | null> {
|
|
493
|
+
return getCertificateHolderClaim(id)
|
|
494
|
+
},
|
|
495
|
+
async listCertificateHolderClaims(filter?: {
|
|
496
|
+
state?: CertificateHolderClaim['state']
|
|
497
|
+
claimantOrgId?: string
|
|
498
|
+
certificateId?: string
|
|
499
|
+
}): Promise<CertificateHolderClaim[]> {
|
|
500
|
+
return listCertificateHolderClaims(filter)
|
|
501
|
+
},
|
|
502
|
+
async decideCertificateHolderClaim(
|
|
503
|
+
id: string,
|
|
504
|
+
decision: { status: 'confirmed' | 'refused'; decidedBy: string; refusalReason?: string | null },
|
|
505
|
+
): Promise<CertificateHolderClaim | null> {
|
|
506
|
+
return decideCertificateHolderClaim(id, decision)
|
|
507
|
+
},
|
|
508
|
+
async findPendingCertificateHolderClaim(certificateId: string): Promise<CertificateHolderClaim | null> {
|
|
509
|
+
return findPendingCertificateHolderClaim(certificateId)
|
|
510
|
+
},
|
|
511
|
+
|
|
512
|
+
// ── the instrument register (TODO.register/03) ──
|
|
513
|
+
async listInstrumentRegistrations(): Promise<InstrumentRegistration[]> {
|
|
514
|
+
return listInstrumentRegistrations()
|
|
515
|
+
},
|
|
516
|
+
async listInstrumentRegistrationsForCertificate(certificateId: string): Promise<InstrumentRegistration[]> {
|
|
517
|
+
return listInstrumentRegistrationsForCertificate(certificateId)
|
|
518
|
+
},
|
|
519
|
+
async listInstrumentRegistrationsForHolder(holderOrgId: string): Promise<InstrumentRegistration[]> {
|
|
520
|
+
return listInstrumentRegistrationsForHolder(holderOrgId)
|
|
521
|
+
},
|
|
522
|
+
async getInstrumentRegistration(id: string): Promise<InstrumentRegistration | null> {
|
|
523
|
+
return getInstrumentRegistration(id)
|
|
524
|
+
},
|
|
525
|
+
async createInstrumentRegistration(input: {
|
|
526
|
+
id: string
|
|
527
|
+
certificateId: string
|
|
528
|
+
holderOrgId: string
|
|
529
|
+
standardId: string
|
|
530
|
+
serialNumber: string
|
|
531
|
+
manufactureDate?: string | null
|
|
532
|
+
designations?: Record<string, unknown>
|
|
533
|
+
scopeStatus: InstrumentRegistrationScopeStatus
|
|
534
|
+
scopeDetail?: string | null
|
|
535
|
+
registeredBy?: string | null
|
|
536
|
+
}): Promise<InstrumentRegistration | null> {
|
|
537
|
+
return createInstrumentRegistration(input)
|
|
538
|
+
},
|
|
539
|
+
async setInstrumentRegistrationLifecycle(
|
|
540
|
+
id: string,
|
|
541
|
+
lifecycle: InstrumentRegistrationLifecycle,
|
|
542
|
+
actor?: string | null,
|
|
543
|
+
): Promise<InstrumentRegistration | null> {
|
|
544
|
+
return setInstrumentRegistrationLifecycle(id, lifecycle, actor)
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
// ── the OIDC Provider (TODO.identity/01) ──
|
|
548
|
+
async getOidcClient(clientId: string): Promise<OidcClient | null> {
|
|
549
|
+
return getOidcClient(clientId)
|
|
550
|
+
},
|
|
551
|
+
async listOidcClients(): Promise<OidcClient[]> {
|
|
552
|
+
return listOidcClients()
|
|
553
|
+
},
|
|
554
|
+
async upsertOidcClient(input: {
|
|
555
|
+
clientId: string
|
|
556
|
+
name: string
|
|
557
|
+
secretHash: string | null
|
|
558
|
+
redirectUris: string[]
|
|
559
|
+
claimsPolicy: { claims: string[] } | null
|
|
560
|
+
createdBy?: string | null
|
|
561
|
+
}): Promise<OidcClient> {
|
|
562
|
+
return upsertOidcClient(input)
|
|
563
|
+
},
|
|
564
|
+
async setOidcClientStatus(clientId: string, status: OidcClient['status']): Promise<OidcClient | null> {
|
|
565
|
+
return setOidcClientStatus(clientId, status)
|
|
566
|
+
},
|
|
567
|
+
async setOidcClientLaunch(clientId: string, launch: OidcClientLaunch | null): Promise<OidcClient | null> {
|
|
568
|
+
return setOidcClientLaunch(clientId, launch)
|
|
569
|
+
},
|
|
570
|
+
async createOidcAuthorization(input: {
|
|
571
|
+
id: string
|
|
572
|
+
clientId: string
|
|
573
|
+
redirectUri: string
|
|
574
|
+
scope: string
|
|
575
|
+
state: string
|
|
576
|
+
nonce: string | null
|
|
577
|
+
codeChallenge: string
|
|
578
|
+
userId: string | null
|
|
579
|
+
ttlMs: number
|
|
580
|
+
}): Promise<OidcAuthorization> {
|
|
581
|
+
return createOidcAuthorization(input)
|
|
582
|
+
},
|
|
583
|
+
async getOidcAuthorization(id: string): Promise<OidcAuthorization | null> {
|
|
584
|
+
return getOidcAuthorization(id)
|
|
585
|
+
},
|
|
586
|
+
async decideOidcAuthorization(
|
|
587
|
+
id: string,
|
|
588
|
+
decision: { userId: string; decision: 'allow' | 'deny' },
|
|
589
|
+
): Promise<OidcAuthorization | null> {
|
|
590
|
+
return decideOidcAuthorization(id, decision)
|
|
591
|
+
},
|
|
592
|
+
async createOidcCode(input: {
|
|
593
|
+
code: string
|
|
594
|
+
clientId: string
|
|
595
|
+
redirectUri: string
|
|
596
|
+
scope: string
|
|
597
|
+
nonce: string | null
|
|
598
|
+
codeChallenge: string
|
|
599
|
+
userId: string
|
|
600
|
+
contextOrg?: string | null
|
|
601
|
+
amr?: string[] | null
|
|
602
|
+
ttlMs: number
|
|
603
|
+
}): Promise<void> {
|
|
604
|
+
createOidcCode(input)
|
|
605
|
+
},
|
|
606
|
+
async consumeOidcCode(code: string): Promise<OidcCode | null> {
|
|
607
|
+
return consumeOidcCode(code)
|
|
608
|
+
},
|
|
609
|
+
async createOidcAccessToken(input: {
|
|
610
|
+
token: string
|
|
611
|
+
userId: string
|
|
612
|
+
clientId: string
|
|
613
|
+
scope: string
|
|
614
|
+
contextOrg?: string | null
|
|
615
|
+
amr?: string[] | null
|
|
616
|
+
ttlMs: number
|
|
617
|
+
}): Promise<void> {
|
|
618
|
+
createOidcAccessToken(input)
|
|
619
|
+
},
|
|
620
|
+
async getOidcAccessToken(token: string): Promise<OidcAccessToken | null> {
|
|
621
|
+
return getOidcAccessToken(token)
|
|
622
|
+
},
|
|
623
|
+
async listOidcKeys(): Promise<OidcKeyRow[]> {
|
|
624
|
+
return listOidcKeys()
|
|
625
|
+
},
|
|
626
|
+
async upsertOidcKey(input: { kid: string; publicJwk: string }): Promise<void> {
|
|
627
|
+
upsertOidcKey(input)
|
|
628
|
+
},
|
|
629
|
+
async retireOidcKey(kid: string): Promise<void> {
|
|
630
|
+
retireOidcKey(kid)
|
|
631
|
+
},
|
|
632
|
+
|
|
633
|
+
// ── the upstream providers (TODO.identity/08) ──
|
|
634
|
+
async listIdentityProviders(): Promise<IdentityProvider[]> {
|
|
635
|
+
return listIdentityProviders()
|
|
636
|
+
},
|
|
637
|
+
async getIdentityProvider(id: string): Promise<IdentityProvider | null> {
|
|
638
|
+
return getIdentityProvider(id)
|
|
639
|
+
},
|
|
640
|
+
async upsertIdentityProvider(input: {
|
|
641
|
+
id: string
|
|
642
|
+
kind: IdentityProvider['kind']
|
|
643
|
+
displayName: string
|
|
644
|
+
brandMark?: string | null
|
|
645
|
+
issuer?: string | null
|
|
646
|
+
clientId: string
|
|
647
|
+
clientSecretRef?: string | null
|
|
648
|
+
scopes?: string | null
|
|
649
|
+
enabled?: boolean
|
|
650
|
+
createdBy?: string | null
|
|
651
|
+
}): Promise<IdentityProvider> {
|
|
652
|
+
return upsertIdentityProvider(input)
|
|
653
|
+
},
|
|
654
|
+
async setIdentityProviderEnabled(id: string, enabled: boolean): Promise<IdentityProvider | null> {
|
|
655
|
+
return setIdentityProviderEnabled(id, enabled)
|
|
656
|
+
},
|
|
657
|
+
async deleteIdentityProvider(id: string): Promise<boolean> {
|
|
658
|
+
return deleteIdentityProvider(id)
|
|
659
|
+
},
|
|
660
|
+
|
|
661
|
+
// ── the linked identities (TODO.identity/02's shape, 08's flows) ──
|
|
662
|
+
async listIdentityLinks(userId: string): Promise<IdentityLink[]> {
|
|
663
|
+
return listIdentityLinks(userId)
|
|
664
|
+
},
|
|
665
|
+
async findIdentityLink(provider: string, providerAccountId: string): Promise<IdentityLink | null> {
|
|
666
|
+
return findIdentityLink(provider, providerAccountId)
|
|
667
|
+
},
|
|
668
|
+
async createIdentityLink(input: {
|
|
669
|
+
userId: string
|
|
670
|
+
provider: string
|
|
671
|
+
providerAccountId: string
|
|
672
|
+
linkedBy?: string | null
|
|
673
|
+
}): Promise<IdentityLink | null> {
|
|
674
|
+
return createIdentityLink(input)
|
|
675
|
+
},
|
|
676
|
+
async deleteIdentityLink(userId: string, provider: string): Promise<boolean> {
|
|
677
|
+
return deleteIdentityLink(userId, provider)
|
|
678
|
+
},
|
|
679
|
+
|
|
680
|
+
// ── the OP's account model (TODO.identity/02) ──
|
|
681
|
+
async createOpAccount(input: {
|
|
682
|
+
email: string
|
|
683
|
+
name: string
|
|
684
|
+
role: string
|
|
685
|
+
createdBy?: string | null
|
|
686
|
+
}): Promise<UserAdminRow | null> {
|
|
687
|
+
return createOpAccount(input)
|
|
688
|
+
},
|
|
689
|
+
async getPasswordLogin(email: string): Promise<{ userId: string; hash: string; active: boolean } | null> {
|
|
690
|
+
return getPasswordLogin(email)
|
|
691
|
+
},
|
|
692
|
+
async setPasswordHash(userId: string, hash: string, setBy?: string | null): Promise<void> {
|
|
693
|
+
setPasswordHash(userId, hash, setBy)
|
|
694
|
+
},
|
|
695
|
+
async countSignInMethods(userId: string): Promise<{ password: boolean; links: number; passkeys: number }> {
|
|
696
|
+
return countSignInMethods(userId)
|
|
697
|
+
},
|
|
698
|
+
async createEnrollmentToken(input: {
|
|
699
|
+
token: string
|
|
700
|
+
userId: string
|
|
701
|
+
createdBy?: string | null
|
|
702
|
+
ttlMs: number
|
|
703
|
+
}): Promise<EnrollmentToken> {
|
|
704
|
+
return createEnrollmentToken(input)
|
|
705
|
+
},
|
|
706
|
+
async getEnrollmentToken(token: string): Promise<EnrollmentToken | null> {
|
|
707
|
+
return getEnrollmentToken(token)
|
|
708
|
+
},
|
|
709
|
+
async completeEnrollment(token: string, passwordHash: string, setBy?: string | null): Promise<CompleteEnrollmentResult> {
|
|
710
|
+
return completeEnrollment(token, passwordHash, setBy)
|
|
711
|
+
},
|
|
712
|
+
async listUserSessions(userId: string, currentToken?: string): Promise<SessionView[]> {
|
|
713
|
+
return listUserSessions(userId, currentToken)
|
|
714
|
+
},
|
|
715
|
+
async deleteSessionById(userId: string, sessionId: string): Promise<boolean> {
|
|
716
|
+
return deleteSessionById(userId, sessionId)
|
|
717
|
+
},
|
|
718
|
+
async listOpLiveSessions(currentToken?: string): Promise<OpLiveSession[]> {
|
|
719
|
+
return listOpLiveSessions(currentToken)
|
|
720
|
+
},
|
|
721
|
+
async deleteAllUserSessions(userId: string): Promise<number> {
|
|
722
|
+
return deleteAllUserSessions(userId)
|
|
723
|
+
},
|
|
724
|
+
// ── the account console (TODO.identity/06) ──
|
|
725
|
+
async updateUserName(userId: string, name: string): Promise<boolean> {
|
|
726
|
+
return updateUserName(userId, name)
|
|
727
|
+
},
|
|
728
|
+
async setUserAvatar(userId: string, avatarUrl: string | null): Promise<boolean> {
|
|
729
|
+
return setUserAvatar(userId, avatarUrl)
|
|
730
|
+
},
|
|
731
|
+
async deletePasswordHash(userId: string): Promise<boolean> {
|
|
732
|
+
return deletePasswordHash(userId)
|
|
733
|
+
},
|
|
734
|
+
async deleteOtherSessions(userId: string, keepToken: string): Promise<number> {
|
|
735
|
+
return deleteOtherSessions(userId, keepToken)
|
|
736
|
+
},
|
|
737
|
+
async createEmailChangeToken(input: {
|
|
738
|
+
token: string
|
|
739
|
+
userId: string
|
|
740
|
+
newEmail: string
|
|
741
|
+
deliveredBy: 'mailer' | 'shown'
|
|
742
|
+
ttlMs: number
|
|
743
|
+
}): Promise<EmailChangeToken> {
|
|
744
|
+
return createEmailChangeToken(input)
|
|
745
|
+
},
|
|
746
|
+
async getEmailChangeToken(token: string): Promise<EmailChangeToken | null> {
|
|
747
|
+
return getEmailChangeToken(token)
|
|
748
|
+
},
|
|
749
|
+
async getPendingEmailChange(userId: string): Promise<EmailChangeToken | null> {
|
|
750
|
+
return getPendingEmailChange(userId)
|
|
751
|
+
},
|
|
752
|
+
async completeEmailChange(token: string): Promise<CompleteEmailChangeResult> {
|
|
753
|
+
return completeEmailChange(token)
|
|
754
|
+
},
|
|
755
|
+
|
|
756
|
+
// ── strong authentication: the factor registry (TODO.identity-sso/02 + /03) ──
|
|
757
|
+
async createWebauthnChallenge(input: {
|
|
758
|
+
challenge: string
|
|
759
|
+
userId: string | null
|
|
760
|
+
kind: WebauthnChallenge['kind']
|
|
761
|
+
ttlMs: number
|
|
762
|
+
}): Promise<void> {
|
|
763
|
+
createWebauthnChallenge(input)
|
|
764
|
+
},
|
|
765
|
+
async consumeWebauthnChallenge(challenge: string): Promise<WebauthnChallenge | null> {
|
|
766
|
+
return consumeWebauthnChallenge(challenge)
|
|
767
|
+
},
|
|
768
|
+
async createWebauthnCredential(input: {
|
|
769
|
+
credentialId: string
|
|
770
|
+
userId: string
|
|
771
|
+
name: string
|
|
772
|
+
publicKeyCose: string
|
|
773
|
+
signCount: number
|
|
774
|
+
aaguid: string | null
|
|
775
|
+
transports: string[]
|
|
776
|
+
ip?: string | null
|
|
777
|
+
}): Promise<WebauthnCredential | null> {
|
|
778
|
+
return createWebauthnCredential(input)
|
|
779
|
+
},
|
|
780
|
+
async listWebauthnCredentials(userId: string): Promise<WebauthnCredential[]> {
|
|
781
|
+
return listWebauthnCredentials(userId)
|
|
782
|
+
},
|
|
783
|
+
async getWebauthnCredential(credentialId: string): Promise<WebauthnCredential | null> {
|
|
784
|
+
return getWebauthnCredential(credentialId)
|
|
785
|
+
},
|
|
786
|
+
async deleteWebauthnCredential(userId: string, credentialId: string): Promise<boolean> {
|
|
787
|
+
return deleteWebauthnCredential(userId, credentialId)
|
|
788
|
+
},
|
|
789
|
+
async advanceWebauthnCounter(credentialId: string, newCount: number, opts?: { ip?: string | null }): Promise<AdvanceCounterResult> {
|
|
790
|
+
return advanceWebauthnCounter(credentialId, newCount, opts)
|
|
791
|
+
},
|
|
792
|
+
async createTotpSecret(input: { id: string; userId: string; name: string; secret: string }): Promise<TotpSecret> {
|
|
793
|
+
return createTotpSecret(input)
|
|
794
|
+
},
|
|
795
|
+
async listTotpSecrets(userId: string): Promise<TotpSecret[]> {
|
|
796
|
+
return listTotpSecrets(userId)
|
|
797
|
+
},
|
|
798
|
+
async getTotpSecret(id: string): Promise<TotpSecret | null> {
|
|
799
|
+
return getTotpSecret(id)
|
|
800
|
+
},
|
|
801
|
+
async markTotpSecretVerified(id: string, userId: string, name: string): Promise<boolean> {
|
|
802
|
+
return markTotpSecretVerified(id, userId, name)
|
|
803
|
+
},
|
|
804
|
+
async recordTotpEnrollFailure(id: string, userId: string): Promise<number> {
|
|
805
|
+
return recordTotpEnrollFailure(id, userId)
|
|
806
|
+
},
|
|
807
|
+
async markTotpSecretUsed(id: string, opts?: { ip?: string | null }): Promise<void> {
|
|
808
|
+
markTotpSecretUsed(id, opts)
|
|
809
|
+
},
|
|
810
|
+
async deleteTotpSecret(userId: string, id: string): Promise<boolean> {
|
|
811
|
+
return deleteTotpSecret(userId, id)
|
|
812
|
+
},
|
|
813
|
+
async replaceRecoveryCodes(userId: string, batch: string, codeHashes: string[]): Promise<void> {
|
|
814
|
+
replaceRecoveryCodes(userId, batch, codeHashes)
|
|
815
|
+
},
|
|
816
|
+
async recoveryCodeState(userId: string): Promise<RecoveryCodeState> {
|
|
817
|
+
return recoveryCodeState(userId)
|
|
818
|
+
},
|
|
819
|
+
async consumeRecoveryCode(userId: string, codeHash: string): Promise<boolean> {
|
|
820
|
+
return consumeRecoveryCode(userId, codeHash)
|
|
821
|
+
},
|
|
822
|
+
async createMfaPending(input: { token: string; userId: string; amr: string[]; ttlMs: number }): Promise<void> {
|
|
823
|
+
createMfaPending(input)
|
|
824
|
+
},
|
|
825
|
+
async getMfaPending(token: string): Promise<MfaPending | null> {
|
|
826
|
+
return getMfaPending(token)
|
|
827
|
+
},
|
|
828
|
+
async consumeMfaPending(token: string): Promise<MfaPending | null> {
|
|
829
|
+
return consumeMfaPending(token)
|
|
830
|
+
},
|
|
831
|
+
async recordMfaPendingFailure(token: string): Promise<MfaPending | null> {
|
|
832
|
+
return recordMfaPendingFailure(token)
|
|
833
|
+
},
|
|
834
|
+
|
|
835
|
+
// ── the central user registry (TODO.identity/03) ──
|
|
836
|
+
async listOpClientRoles(userId: string): Promise<OpClientRoleAssignment[]> {
|
|
837
|
+
return listOpClientRoles(userId)
|
|
838
|
+
},
|
|
839
|
+
async listAllOpClientRoles(): Promise<OpClientRoleAssignment[]> {
|
|
840
|
+
return listAllOpClientRoles()
|
|
841
|
+
},
|
|
842
|
+
async getOpClientRoles(userId: string, clientId: string): Promise<string[] | null> {
|
|
843
|
+
return getOpClientRoles(userId, clientId)
|
|
844
|
+
},
|
|
845
|
+
async setOpClientRoles(userId: string, clientId: string, roles: string[], assignedBy: string | null): Promise<void> {
|
|
846
|
+
setOpClientRoles(userId, clientId, roles, assignedBy)
|
|
847
|
+
},
|
|
848
|
+
async deleteOpClientRoles(userId: string, clientId: string): Promise<boolean> {
|
|
849
|
+
return deleteOpClientRoles(userId, clientId)
|
|
850
|
+
},
|
|
851
|
+
async revokeOpUserCredentials(userId: string): Promise<{ sessions: number; accessTokens: number; codes: number; authorizations: number }> {
|
|
852
|
+
return revokeOpUserCredentials(userId)
|
|
853
|
+
},
|
|
854
|
+
async eraseOpAccount(userId: string): Promise<OpAccountErasure | null> {
|
|
855
|
+
return eraseOpAccount(userId)
|
|
856
|
+
},
|
|
857
|
+
async updateOpAccount(id: string, input: { name?: string; email?: string }): Promise<boolean> {
|
|
858
|
+
return updateOpAccount(id, input)
|
|
859
|
+
},
|
|
860
|
+
async lastAccountSignIns(): Promise<Record<string, string>> {
|
|
861
|
+
return lastAccountSignIns()
|
|
862
|
+
},
|
|
863
|
+
|
|
864
|
+
// ── the workflow entity store + change journal ──
|
|
865
|
+
async listEntities(store: string): Promise<EntityRow[]> {
|
|
866
|
+
return listEntities(store)
|
|
867
|
+
},
|
|
868
|
+
async getEntity(store: string, id: string): Promise<EntityRow | undefined> {
|
|
869
|
+
return getEntity(store, id)
|
|
870
|
+
},
|
|
871
|
+
async putEntity(store: string, id: string, orgId: string | null, data: string): Promise<void> {
|
|
872
|
+
putEntity(store, id, orgId, data)
|
|
873
|
+
},
|
|
874
|
+
async deleteEntity(store: string, id: string): Promise<boolean> {
|
|
875
|
+
return deleteEntity(store, id)
|
|
876
|
+
},
|
|
877
|
+
async changesAfter(seq: number, limit = 500): Promise<EntityChange[]> {
|
|
878
|
+
return changesAfter(seq, limit)
|
|
879
|
+
},
|
|
880
|
+
async latestChangeSeq(): Promise<number> {
|
|
881
|
+
return latestChangeSeq()
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
// ── the platform event store (TODO.notify/01) ──
|
|
885
|
+
async appendEvent(input: {
|
|
886
|
+
id: string
|
|
887
|
+
domain: string
|
|
888
|
+
entityId: string
|
|
889
|
+
action: string
|
|
890
|
+
payload: string
|
|
891
|
+
}): Promise<PlatformEvent> {
|
|
892
|
+
return appendEvent(input)
|
|
893
|
+
},
|
|
894
|
+
async eventsAfter(seq: number, limit = 500): Promise<PlatformEvent[]> {
|
|
895
|
+
return eventsAfter(seq, limit)
|
|
896
|
+
},
|
|
897
|
+
async latestEventSeq(): Promise<number> {
|
|
898
|
+
return latestEventSeq()
|
|
899
|
+
},
|
|
900
|
+
async getEvent(id: string): Promise<PlatformEvent | null> {
|
|
901
|
+
return getEvent(id)
|
|
902
|
+
},
|
|
903
|
+
async eventsMatching(filter: EventKeyFilter, limit = 500): Promise<PlatformEvent[]> {
|
|
904
|
+
return eventsMatching(filter, limit)
|
|
905
|
+
},
|
|
906
|
+
|
|
907
|
+
// ── the notification subscriptions store (TODO.notify/02) ──
|
|
908
|
+
async listNotifyRules(userId: string): Promise<NotifyRule[]> {
|
|
909
|
+
return listNotifyRules(userId)
|
|
910
|
+
},
|
|
911
|
+
async putNotifyRule(input: {
|
|
912
|
+
id: string
|
|
913
|
+
userId: string
|
|
914
|
+
pattern: string
|
|
915
|
+
domain: string
|
|
916
|
+
entityId: string | null
|
|
917
|
+
action: string | null
|
|
918
|
+
mode: NotifyRule['mode']
|
|
919
|
+
channelOverrides: string | null
|
|
920
|
+
}): Promise<NotifyRule> {
|
|
921
|
+
return putNotifyRule(input)
|
|
922
|
+
},
|
|
923
|
+
async deleteNotifyRule(userId: string, pattern: string): Promise<boolean> {
|
|
924
|
+
return deleteNotifyRule(userId, pattern)
|
|
925
|
+
},
|
|
926
|
+
async notifyRulesForEvent(filter: { domain: string; entityId: string; action: string }): Promise<NotifyRule[]> {
|
|
927
|
+
return notifyRulesForEvent(filter)
|
|
928
|
+
},
|
|
929
|
+
async listNotifyEntityMutes(userId: string): Promise<NotifyEntityMute[]> {
|
|
930
|
+
return listNotifyEntityMutes(userId)
|
|
931
|
+
},
|
|
932
|
+
async putNotifyEntityMute(input: { id: string; userId: string; domain: string; entityId: string }): Promise<NotifyEntityMute> {
|
|
933
|
+
return putNotifyEntityMute(input)
|
|
934
|
+
},
|
|
935
|
+
async deleteNotifyEntityMute(userId: string, domain: string, entityId: string): Promise<boolean> {
|
|
936
|
+
return deleteNotifyEntityMute(userId, domain, entityId)
|
|
937
|
+
},
|
|
938
|
+
async notifyEntityMutesForEvent(domain: string, entityId: string): Promise<NotifyEntityMute[]> {
|
|
939
|
+
return notifyEntityMutesForEvent(domain, entityId)
|
|
940
|
+
},
|
|
941
|
+
async getNotifyPreferences(userId: string): Promise<NotifyPreferences | null> {
|
|
942
|
+
return getNotifyPreferences(userId)
|
|
943
|
+
},
|
|
944
|
+
async putNotifyPreferences(userId: string, channels: string): Promise<NotifyPreferences> {
|
|
945
|
+
return putNotifyPreferences(userId, channels)
|
|
946
|
+
},
|
|
947
|
+
|
|
948
|
+
// ── the inbox state (TODO.notify/03) ──
|
|
949
|
+
async listNotifyInboxStates(userId: string): Promise<NotifyInboxState[]> {
|
|
950
|
+
return listNotifyInboxStates(userId)
|
|
951
|
+
},
|
|
952
|
+
async putNotifyInboxState(input: {
|
|
953
|
+
userId: string
|
|
954
|
+
eventId: string
|
|
955
|
+
read?: boolean
|
|
956
|
+
done?: boolean
|
|
957
|
+
}): Promise<NotifyInboxState> {
|
|
958
|
+
return putNotifyInboxState(input)
|
|
959
|
+
},
|
|
960
|
+
|
|
961
|
+
// ── provisioning / dev support ──
|
|
962
|
+
async wipeWorkflowStores(range?: { after: number; through: number }): Promise<number> {
|
|
963
|
+
const db = getDb()
|
|
964
|
+
let rows = 0
|
|
965
|
+
// One transaction, the same atomicity the D1 batch gives.
|
|
966
|
+
db.transaction(() => {
|
|
967
|
+
for (const table of WIPE_TABLES) {
|
|
968
|
+
rows += range
|
|
969
|
+
? db.prepare(`DELETE FROM ${table} WHERE rowid > ? AND rowid <= ?`).run(range.after, range.through).changes
|
|
970
|
+
: db.prepare(`DELETE FROM ${table}`).run().changes
|
|
971
|
+
}
|
|
972
|
+
})()
|
|
973
|
+
return rows
|
|
974
|
+
},
|
|
975
|
+
async workflowStoreRowCeiling(): Promise<number> {
|
|
976
|
+
const row = getDb().prepare(
|
|
977
|
+
`SELECT MAX(ceiling) AS ceiling FROM (
|
|
978
|
+
SELECT MAX(rowid) AS ceiling FROM entity_changes
|
|
979
|
+
UNION ALL SELECT MAX(rowid) FROM evidence_records
|
|
980
|
+
UNION ALL SELECT MAX(rowid) FROM entities
|
|
981
|
+
UNION ALL SELECT MAX(rowid) FROM events
|
|
982
|
+
UNION ALL SELECT MAX(rowid) FROM instrument_registrations)`,
|
|
983
|
+
).get() as { ceiling: number | null }
|
|
984
|
+
return row.ceiling ?? 0
|
|
985
|
+
},
|
|
986
|
+
async countEntities(): Promise<number> {
|
|
987
|
+
return (getDb().prepare('SELECT COUNT(*) AS n FROM entities').get() as { n: number }).n
|
|
988
|
+
},
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/** The node composition root's one-liner: the SQLite store becomes THE
|
|
993
|
+
* store (server/index.ts, the node scripts, the route-level tests). */
|
|
994
|
+
export function installSqliteStore(): ServerStore {
|
|
995
|
+
const store = createSqliteServerStore()
|
|
996
|
+
installStore(store)
|
|
997
|
+
return store
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// ── The extraction surface (TODO.identity-extract/01) ───────────────
|
|
1001
|
+
// This subpath IS the SQLite cone (the map, PROGRESS/41 §2.1): the six
|
|
1002
|
+
// pre-extraction modules (the composer above + store/entities/
|
|
1003
|
+
// op-store/op-accounts-store/upstream-store under ./sqlite/) behind one
|
|
1004
|
+
// specifier, so the cone's direct consumers (the dev-reset seam's
|
|
1005
|
+
// getDb, the evidence adapter, the SQLite repository, the route-level
|
|
1006
|
+
// tests) import unchanged names from the package.
|
|
1007
|
+
export * from './sqlite/store'
|
|
1008
|
+
export * from './sqlite/entities'
|
|
1009
|
+
export * from './sqlite/events'
|
|
1010
|
+
export * from './sqlite/op-store'
|
|
1011
|
+
export * from './sqlite/op-accounts-store'
|
|
1012
|
+
export * from './sqlite/factors-store'
|
|
1013
|
+
export * from './sqlite/upstream-store'
|
|
1014
|
+
|
|
1015
|
+
/** The SQLite store's own DDL, shipped with the package. Consumers that
|
|
1016
|
+
* replay the schema (reset-db, the tripwires) read it from this path
|
|
1017
|
+
* instead of guessing the package's installed location. */
|
|
1018
|
+
export const SQLITE_SCHEMA_PATH = fileURLToPath(new URL('./sqlite/schema.sql', import.meta.url))
|
|
1019
|
+
|
|
1020
|
+
/** The canonical D1 migration set, shipped with the package
|
|
1021
|
+
* (migrations/): the ONE set both deployments apply. Wrangler's
|
|
1022
|
+
* migrations_dir points at this directory in the consumer's
|
|
1023
|
+
* node_modules, and the deploys' D1 journals key the bookkeeping on
|
|
1024
|
+
* the FILENAMES. Expand-only, never renumber (AGENTS.md, the
|
|
1025
|
+
* migration contract). The migrations test pins this set's end state
|
|
1026
|
+
* to schema.sql in lockstep. */
|
|
1027
|
+
export const MIGRATIONS_DIR = fileURLToPath(new URL('../../migrations', import.meta.url))
|