@learncard/lca-api-service 1.6.3 → 1.7.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/.env.example +2 -0
- package/CHANGELOG.md +114 -0
- package/config/config.dev.json +1 -0
- package/config/config.example.json +1 -0
- package/config/config.production.json +1 -0
- package/config/config.scouts.dev.json +1 -0
- package/config/config.scouts.production.json +1 -0
- package/dist/accesslayer/notifications/create.d.ts +2 -1
- package/dist/app.d.ts +70 -8
- package/dist/config/environment.d.ts +6 -0
- package/dist/config/stageConfig.d.ts +4 -0
- package/dist/helpers/analyticsEligibility.d.ts +6 -0
- package/dist/helpers/brainUrl.d.ts +1 -0
- package/dist/helpers/brainUrl.test.d.ts +1 -0
- package/dist/helpers/currentProfile.d.ts +6 -0
- package/dist/helpers/currentProfile.test.d.ts +1 -0
- package/dist/helpers/retryingOnce.d.ts +1 -0
- package/dist/helpers/retryingOnce.test.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/models/EscrowHold.d.ts +1 -0
- package/dist/models/EscrowHold.indexes.test.d.ts +1 -0
- package/dist/models/Notification.d.ts +114 -2
- package/dist/models/SigningAuthority.d.ts +1 -1
- package/dist/models/UserKey.d.ts +23 -0
- package/dist/publish-metafile.json +1 -1
- package/dist/routes/credentials.d.ts +1 -1
- package/dist/routes/index.d.ts +5 -0
- package/dist/routes/keys.d.ts +1 -0
- package/dist/routes/notifications.d.ts +65 -4
- package/dist/routes/preferences.test.d.ts +1 -0
- package/dist/routes/signing-authority.d.ts +3 -3
- package/dist/services/escrow-enclave/index.d.ts +2 -0
- package/dist/services/escrow-enclave/logFailure.d.ts +1 -0
- package/dist/types/credentials.d.ts +1 -1
- package/dist/types/notifications.d.ts +118 -2
- package/docs/bedrock-generation.md +7 -6
- package/lambdaApp.test.ts +114 -0
- package/lambdaApp.ts +23 -11
- package/package.json +11 -11
- package/scripts/escrow-lambda-http.ts +74 -0
- package/scripts/verify-escrow-startup.mjs +463 -0
- package/serverless-local.yml +1 -1
- package/serverless.yml +1 -1
- package/src/accesslayer/notifications/create.test.ts +80 -0
- package/src/accesslayer/notifications/create.ts +97 -2
- package/src/config/environment.test.ts +27 -1
- package/src/config/environment.ts +16 -0
- package/src/config/escrowDeployment.test.ts +1 -0
- package/src/docker-entry.ts +1 -2
- package/src/helpers/analyticsEligibility.ts +15 -0
- package/src/helpers/brainUrl.test.ts +13 -0
- package/src/helpers/brainUrl.ts +3 -0
- package/src/helpers/currentProfile.test.ts +55 -0
- package/src/helpers/currentProfile.ts +58 -0
- package/src/helpers/locale.helpers.test.ts +4 -1
- package/src/helpers/locale.helpers.ts +4 -2
- package/src/helpers/retryingOnce.test.ts +33 -0
- package/src/helpers/retryingOnce.ts +18 -0
- package/src/models/EscrowHold.indexes.test.ts +208 -0
- package/src/models/EscrowHold.ts +106 -51
- package/src/models/UserKey.ts +69 -1
- package/src/routes/escrow.ts +18 -11
- package/src/routes/index.ts +5 -8
- package/src/routes/keys.ts +8 -0
- package/src/routes/notifications.ts +34 -1
- package/src/routes/preferences.test.ts +216 -0
- package/src/routes/preferences.ts +54 -4
- package/src/services/escrow-enclave/index.ts +38 -1
- package/src/services/escrow-enclave/logFailure.ts +5 -1
- package/src/services/escrow-enclave/production.test.ts +64 -0
- package/src/services/escrow-enclave/softwareEnclave.test.ts +14 -2
- package/test/jobs/escrowHoldReminders.spec.ts +21 -4
- package/test/keys-escrow.spec.ts +131 -3
- package/test/keys-lifecycle-invariants.spec.ts +235 -0
- package/test/notifications.spec.ts +102 -0
- package/tsconfig.entrypoints.json +1 -1
- package/vitest.config.ts +1 -0
- package/scripts/node24-runtime.cjs +0 -9
- package/scripts/verify-node24-layer.cjs +0 -49
package/dist/routes/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export type Context = {
|
|
|
25
25
|
debug?: boolean;
|
|
26
26
|
clientIp?: string;
|
|
27
27
|
providerToken?: string;
|
|
28
|
+
authorizationHeader?: string;
|
|
28
29
|
};
|
|
29
30
|
export declare const t: import("@trpc/server").TRPCRootObject<Context, OpenApiMeta, import("@trpc/server").TRPCRuntimeConfigOptions<Context, OpenApiMeta>, {
|
|
30
31
|
ctx: Context;
|
|
@@ -45,6 +46,7 @@ export declare const openRoute: import("@trpc/server").TRPCProcedureBuilder<Cont
|
|
|
45
46
|
domain: string;
|
|
46
47
|
clientIp: string | undefined;
|
|
47
48
|
providerToken: string | undefined;
|
|
49
|
+
authorizationHeader: string | undefined;
|
|
48
50
|
}, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
|
|
49
51
|
export declare const didRoute: import("@trpc/server").TRPCProcedureBuilder<Context, OpenApiMeta, {
|
|
50
52
|
tenant: ResolvedTenant;
|
|
@@ -57,6 +59,7 @@ export declare const didRoute: import("@trpc/server").TRPCProcedureBuilder<Conte
|
|
|
57
59
|
domain: string;
|
|
58
60
|
clientIp: string | undefined;
|
|
59
61
|
providerToken: string | undefined;
|
|
62
|
+
authorizationHeader: string | undefined;
|
|
60
63
|
}, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
|
|
61
64
|
export declare const authorizedDidRoute: import("@trpc/server").TRPCProcedureBuilder<Context, OpenApiMeta, {
|
|
62
65
|
tenant: ResolvedTenant;
|
|
@@ -69,6 +72,7 @@ export declare const authorizedDidRoute: import("@trpc/server").TRPCProcedureBui
|
|
|
69
72
|
domain: string;
|
|
70
73
|
clientIp: string | undefined;
|
|
71
74
|
providerToken: string | undefined;
|
|
75
|
+
authorizationHeader: string | undefined;
|
|
72
76
|
}, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
|
|
73
77
|
export declare const didAndChallengeRoute: import("@trpc/server").TRPCProcedureBuilder<Context, OpenApiMeta, {
|
|
74
78
|
tenant: ResolvedTenant;
|
|
@@ -81,4 +85,5 @@ export declare const didAndChallengeRoute: import("@trpc/server").TRPCProcedureB
|
|
|
81
85
|
domain: string;
|
|
82
86
|
clientIp: string | undefined;
|
|
83
87
|
providerToken: string | undefined;
|
|
88
|
+
authorizationHeader: string | undefined;
|
|
84
89
|
}, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
|
package/dist/routes/keys.d.ts
CHANGED
|
@@ -199,6 +199,7 @@ export declare const keysRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
199
199
|
};
|
|
200
200
|
priorEscrowEnrollment: boolean;
|
|
201
201
|
sssActivationState: "active" | "provisional";
|
|
202
|
+
isWeb3AuthLogin: boolean;
|
|
202
203
|
escrowStale?: "mode-mismatch" | "key-rotated" | undefined;
|
|
203
204
|
escrowBlobIdentity?: string | undefined;
|
|
204
205
|
escrowUpdating?: boolean | undefined;
|
|
@@ -16,7 +16,7 @@ export declare const notificationsRouter: import("@trpc/server").TRPCBuiltRouter
|
|
|
16
16
|
archived?: boolean | undefined;
|
|
17
17
|
read?: boolean | undefined;
|
|
18
18
|
actionStatus?: "PENDING" | "COMPLETED" | "REJECTED" | undefined;
|
|
19
|
-
type?: "GUARDIAN_APPROVED" | "GUARDIAN_REJECTED" | "CONNECTION_REQUEST" | "CONNECTION_REQUEST_EXPIRED_INVITE" | "CONNECTION_ACCEPTED" | "CREDENTIAL_RECEIVED" | "CREDENTIAL_ACCEPTED" | "BOOST_RECEIVED" | "BOOST_ACCEPTED" | "PRESENTATION_REQUEST" | "PRESENTATION_RECEIVED" | "CONSENT_FLOW_TRANSACTION" | "ISSUANCE_CLAIMED" | "ISSUANCE_DELIVERED" | "ISSUANCE_ERROR" | "PROFILE_PARENT_APPROVED" | "APP_LISTING_SUBMITTED" | "APP_LISTING_APPROVED" | "APP_LISTING_REJECTED" | "APP_LISTING_WITHDRAWN" | "DEVICE_LINK_REQUEST" | "GUARDIAN_APPROVAL_PENDING" | "APP_NOTIFICATION" | "CREDENTIAL_REVOKED" | "CREDENTIAL_SUSPENDED" | "CREDENTIAL_UNSUSPENDED" | "CREDENTIAL_REFRESHED" | undefined;
|
|
19
|
+
type?: "GUARDIAN_APPROVED" | "GUARDIAN_REJECTED" | "CONNECTION_REQUEST" | "CONNECTION_REQUEST_EXPIRED_INVITE" | "CONNECTION_ACCEPTED" | "CREDENTIAL_RECEIVED" | "CREDENTIAL_ACCEPTED" | "BOOST_RECEIVED" | "BOOST_ACCEPTED" | "PRESENTATION_REQUEST" | "PRESENTATION_RECEIVED" | "CONSENT_FLOW_TRANSACTION" | "ISSUANCE_CLAIMED" | "ISSUANCE_DELIVERED" | "ISSUANCE_ERROR" | "PROFILE_PARENT_APPROVED" | "APP_LISTING_SUBMITTED" | "APP_LISTING_APPROVED" | "APP_LISTING_REJECTED" | "APP_LISTING_WITHDRAWN" | "DEVICE_LINK_REQUEST" | "GUARDIAN_APPROVAL_PENDING" | "APP_NOTIFICATION" | "ANNOUNCEMENT" | "CREDENTIAL_REVOKED" | "CREDENTIAL_SUSPENDED" | "CREDENTIAL_UNSUSPENDED" | "CREDENTIAL_REFRESHED" | "CONSENT_FLOW_CONTRACT_UPDATED" | undefined;
|
|
20
20
|
} | undefined;
|
|
21
21
|
};
|
|
22
22
|
output: {
|
|
@@ -29,7 +29,7 @@ export declare const notificationsRouter: import("@trpc/server").TRPCBuiltRouter
|
|
|
29
29
|
queryNotifications: import("@trpc/server").TRPCQueryProcedure<{
|
|
30
30
|
input: {
|
|
31
31
|
query: {
|
|
32
|
-
type?: "GUARDIAN_APPROVED" | "GUARDIAN_REJECTED" | "CONNECTION_REQUEST" | "CONNECTION_REQUEST_EXPIRED_INVITE" | "CONNECTION_ACCEPTED" | "CREDENTIAL_RECEIVED" | "CREDENTIAL_ACCEPTED" | "BOOST_RECEIVED" | "BOOST_ACCEPTED" | "PRESENTATION_REQUEST" | "PRESENTATION_RECEIVED" | "CONSENT_FLOW_TRANSACTION" | "ISSUANCE_CLAIMED" | "ISSUANCE_DELIVERED" | "ISSUANCE_ERROR" | "PROFILE_PARENT_APPROVED" | "APP_LISTING_SUBMITTED" | "APP_LISTING_APPROVED" | "APP_LISTING_REJECTED" | "APP_LISTING_WITHDRAWN" | "DEVICE_LINK_REQUEST" | "GUARDIAN_APPROVAL_PENDING" | "APP_NOTIFICATION" | "CREDENTIAL_REVOKED" | "CREDENTIAL_SUSPENDED" | "CREDENTIAL_UNSUSPENDED" | "CREDENTIAL_REFRESHED" | undefined;
|
|
32
|
+
type?: "GUARDIAN_APPROVED" | "GUARDIAN_REJECTED" | "CONNECTION_REQUEST" | "CONNECTION_REQUEST_EXPIRED_INVITE" | "CONNECTION_ACCEPTED" | "CREDENTIAL_RECEIVED" | "CREDENTIAL_ACCEPTED" | "BOOST_RECEIVED" | "BOOST_ACCEPTED" | "PRESENTATION_REQUEST" | "PRESENTATION_RECEIVED" | "CONSENT_FLOW_TRANSACTION" | "ISSUANCE_CLAIMED" | "ISSUANCE_DELIVERED" | "ISSUANCE_ERROR" | "PROFILE_PARENT_APPROVED" | "APP_LISTING_SUBMITTED" | "APP_LISTING_APPROVED" | "APP_LISTING_REJECTED" | "APP_LISTING_WITHDRAWN" | "DEVICE_LINK_REQUEST" | "GUARDIAN_APPROVAL_PENDING" | "APP_NOTIFICATION" | "ANNOUNCEMENT" | "CREDENTIAL_REVOKED" | "CREDENTIAL_SUSPENDED" | "CREDENTIAL_UNSUSPENDED" | "CREDENTIAL_REFRESHED" | "CONSENT_FLOW_CONTRACT_UPDATED" | undefined;
|
|
33
33
|
'from.did'?: string | undefined;
|
|
34
34
|
'from.profileId'?: string | undefined;
|
|
35
35
|
'data.vcUris'?: string | string[] | undefined;
|
|
@@ -85,7 +85,7 @@ export declare const notificationsRouter: import("@trpc/server").TRPCBuiltRouter
|
|
|
85
85
|
}>;
|
|
86
86
|
sendNotification: import("@trpc/server").TRPCMutationProcedure<{
|
|
87
87
|
input: {
|
|
88
|
-
type: "GUARDIAN_APPROVED" | "GUARDIAN_REJECTED" | "CONNECTION_REQUEST" | "CONNECTION_REQUEST_EXPIRED_INVITE" | "CONNECTION_ACCEPTED" | "CREDENTIAL_RECEIVED" | "CREDENTIAL_ACCEPTED" | "BOOST_RECEIVED" | "BOOST_ACCEPTED" | "PRESENTATION_REQUEST" | "PRESENTATION_RECEIVED" | "CONSENT_FLOW_TRANSACTION" | "ISSUANCE_CLAIMED" | "ISSUANCE_DELIVERED" | "ISSUANCE_ERROR" | "PROFILE_PARENT_APPROVED" | "APP_LISTING_SUBMITTED" | "APP_LISTING_APPROVED" | "APP_LISTING_REJECTED" | "APP_LISTING_WITHDRAWN" | "DEVICE_LINK_REQUEST" | "GUARDIAN_APPROVAL_PENDING" | "APP_NOTIFICATION" | "CREDENTIAL_REVOKED" | "CREDENTIAL_SUSPENDED" | "CREDENTIAL_UNSUSPENDED" | "CREDENTIAL_REFRESHED";
|
|
88
|
+
type: "GUARDIAN_APPROVED" | "GUARDIAN_REJECTED" | "CONNECTION_REQUEST" | "CONNECTION_REQUEST_EXPIRED_INVITE" | "CONNECTION_ACCEPTED" | "CREDENTIAL_RECEIVED" | "CREDENTIAL_ACCEPTED" | "BOOST_RECEIVED" | "BOOST_ACCEPTED" | "PRESENTATION_REQUEST" | "PRESENTATION_RECEIVED" | "CONSENT_FLOW_TRANSACTION" | "ISSUANCE_CLAIMED" | "ISSUANCE_DELIVERED" | "ISSUANCE_ERROR" | "PROFILE_PARENT_APPROVED" | "APP_LISTING_SUBMITTED" | "APP_LISTING_APPROVED" | "APP_LISTING_REJECTED" | "APP_LISTING_WITHDRAWN" | "DEVICE_LINK_REQUEST" | "GUARDIAN_APPROVAL_PENDING" | "APP_NOTIFICATION" | "ANNOUNCEMENT" | "CREDENTIAL_REVOKED" | "CREDENTIAL_SUSPENDED" | "CREDENTIAL_UNSUSPENDED" | "CREDENTIAL_REFRESHED" | "CONSENT_FLOW_CONTRACT_UPDATED";
|
|
89
89
|
to: {
|
|
90
90
|
profileId?: string | undefined;
|
|
91
91
|
displayName?: string | undefined;
|
|
@@ -176,7 +176,7 @@ export declare const notificationsRouter: import("@trpc/server").TRPCBuiltRouter
|
|
|
176
176
|
vpUris?: string[] | undefined;
|
|
177
177
|
transaction?: {
|
|
178
178
|
id: string;
|
|
179
|
-
action: "write" | "
|
|
179
|
+
action: "write" | "consent" | "update" | "sync" | "withdraw" | "reconsent";
|
|
180
180
|
date: string;
|
|
181
181
|
expiresAt?: string | undefined;
|
|
182
182
|
oneTime?: boolean | undefined;
|
|
@@ -214,7 +214,64 @@ export declare const notificationsRouter: import("@trpc/server").TRPCBuiltRouter
|
|
|
214
214
|
requestedBy: string;
|
|
215
215
|
externalReferenceId?: string | undefined;
|
|
216
216
|
} | undefined;
|
|
217
|
+
kind?: "relaxed" | "expanded_optional" | "requires_consent" | undefined;
|
|
217
218
|
uris?: string[] | undefined;
|
|
219
|
+
consentedVersion?: number | undefined;
|
|
220
|
+
reconsentDeadline?: string | undefined;
|
|
221
|
+
newOptionsUntil?: string | undefined;
|
|
222
|
+
} | undefined;
|
|
223
|
+
contractUri?: string | undefined;
|
|
224
|
+
contractName?: string | undefined;
|
|
225
|
+
fromVersion?: number | undefined;
|
|
226
|
+
toVersion?: number | undefined;
|
|
227
|
+
kind?: "relaxed" | "expanded_optional" | "requires_consent" | undefined;
|
|
228
|
+
reason?: string | undefined;
|
|
229
|
+
diff?: {
|
|
230
|
+
added: {
|
|
231
|
+
area: "read" | "write";
|
|
232
|
+
type: "personal" | "credential";
|
|
233
|
+
key: string;
|
|
234
|
+
required: boolean;
|
|
235
|
+
reason?: string | undefined;
|
|
236
|
+
}[];
|
|
237
|
+
removed: {
|
|
238
|
+
area: "read" | "write";
|
|
239
|
+
type: "personal" | "credential";
|
|
240
|
+
key: string;
|
|
241
|
+
required: boolean;
|
|
242
|
+
reason?: string | undefined;
|
|
243
|
+
}[];
|
|
244
|
+
changed: {
|
|
245
|
+
area: "read" | "write";
|
|
246
|
+
type: "personal" | "credential";
|
|
247
|
+
key: string;
|
|
248
|
+
required: boolean;
|
|
249
|
+
reason?: string | undefined;
|
|
250
|
+
}[];
|
|
251
|
+
details?: {
|
|
252
|
+
field: "expiresAt" | "name" | "description" | "image" | "subtitle" | "reasonForAccessing" | "needsGuardianConsent" | "redirectUrl" | "frontDoorBoostUri" | "writers" | "autoboosts";
|
|
253
|
+
before?: string | boolean | string[] | undefined;
|
|
254
|
+
after?: string | boolean | string[] | undefined;
|
|
255
|
+
}[] | undefined;
|
|
256
|
+
} | undefined;
|
|
257
|
+
reconsentDeadline?: string | undefined;
|
|
258
|
+
reviewUrl?: string | undefined;
|
|
259
|
+
preview?: {
|
|
260
|
+
headline: string;
|
|
261
|
+
subhead: string;
|
|
262
|
+
rows: {
|
|
263
|
+
scope: {
|
|
264
|
+
area: "read" | "write";
|
|
265
|
+
type: "personal" | "credential";
|
|
266
|
+
key: string;
|
|
267
|
+
required: boolean;
|
|
268
|
+
reason?: string | undefined;
|
|
269
|
+
};
|
|
270
|
+
change: "added" | "removed" | "changed";
|
|
271
|
+
label: string;
|
|
272
|
+
subtitle: string;
|
|
273
|
+
}[];
|
|
274
|
+
primaryLabel: string;
|
|
218
275
|
} | undefined;
|
|
219
276
|
inbox?: {
|
|
220
277
|
issuanceId: string;
|
|
@@ -234,6 +291,10 @@ export declare const notificationsRouter: import("@trpc/server").TRPCBuiltRouter
|
|
|
234
291
|
promptId: string;
|
|
235
292
|
counterpartProfileId: string;
|
|
236
293
|
} | undefined;
|
|
294
|
+
campaignId?: string | undefined;
|
|
295
|
+
campaignCreatedAt?: string | undefined;
|
|
296
|
+
campaignHasInApp?: boolean | undefined;
|
|
297
|
+
campaignTestId?: string | undefined;
|
|
237
298
|
} | undefined;
|
|
238
299
|
} | undefined;
|
|
239
300
|
sent?: string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -10,8 +10,8 @@ export declare const signingAuthorityRouter: import("@trpc/server").TRPCBuiltRou
|
|
|
10
10
|
ownerDid?: string | undefined;
|
|
11
11
|
};
|
|
12
12
|
output: {
|
|
13
|
-
ownerDid: string;
|
|
14
13
|
name: string;
|
|
14
|
+
ownerDid: string;
|
|
15
15
|
did: string;
|
|
16
16
|
endpoint: string;
|
|
17
17
|
_id?: string | undefined;
|
|
@@ -24,8 +24,8 @@ export declare const signingAuthorityRouter: import("@trpc/server").TRPCBuiltRou
|
|
|
24
24
|
ownerDid: string;
|
|
25
25
|
};
|
|
26
26
|
output: {
|
|
27
|
-
ownerDid: string;
|
|
28
27
|
name: string;
|
|
28
|
+
ownerDid: string;
|
|
29
29
|
did: string;
|
|
30
30
|
endpoint: string;
|
|
31
31
|
_id?: string | undefined;
|
|
@@ -35,8 +35,8 @@ export declare const signingAuthorityRouter: import("@trpc/server").TRPCBuiltRou
|
|
|
35
35
|
signingAuthorities: import("@trpc/server").TRPCQueryProcedure<{
|
|
36
36
|
input: void;
|
|
37
37
|
output: {
|
|
38
|
-
ownerDid: string;
|
|
39
38
|
name: string;
|
|
39
|
+
ownerDid: string;
|
|
40
40
|
did: string;
|
|
41
41
|
endpoint: string;
|
|
42
42
|
_id?: string | undefined;
|
|
@@ -5,8 +5,10 @@ export * from './softwareEnclave';
|
|
|
5
5
|
export * from './remoteEnclave';
|
|
6
6
|
export * from './notifications';
|
|
7
7
|
export declare const isEscrowEnabled: () => boolean;
|
|
8
|
+
export declare const checkEscrowRemoteConfig: () => void;
|
|
8
9
|
export declare const isEscrowRemoteMode: () => boolean;
|
|
9
10
|
export declare const activeEscrowClientMode: () => "software" | "nitro";
|
|
11
|
+
export declare const getEscrowAuthorityTenant: () => string;
|
|
10
12
|
export declare const getEscrowHoldDurationMs: () => number;
|
|
11
13
|
export declare const getEscrowHoldRestartMinAgeMs: () => number;
|
|
12
14
|
export declare const getEscrowEnclave: () => EscrowEnclave;
|
|
@@ -159,8 +159,8 @@ export declare const IssueEndpointValidator: z.ZodObject<{
|
|
|
159
159
|
}, z.core.$strip>>;
|
|
160
160
|
signingAuthority: z.ZodObject<{
|
|
161
161
|
did: z.ZodString;
|
|
162
|
-
ownerDid: z.ZodString;
|
|
163
162
|
name: z.ZodString;
|
|
163
|
+
ownerDid: z.ZodString;
|
|
164
164
|
}, z.core.$strip>;
|
|
165
165
|
encryption: z.ZodOptional<z.ZodObject<{
|
|
166
166
|
recipients: z.ZodArray<z.ZodString>;
|
|
@@ -52,10 +52,12 @@ export declare const NotificationQueryFiltersValidator: z.ZodObject<{
|
|
|
52
52
|
DEVICE_LINK_REQUEST: "DEVICE_LINK_REQUEST";
|
|
53
53
|
GUARDIAN_APPROVAL_PENDING: "GUARDIAN_APPROVAL_PENDING";
|
|
54
54
|
APP_NOTIFICATION: "APP_NOTIFICATION";
|
|
55
|
+
ANNOUNCEMENT: "ANNOUNCEMENT";
|
|
55
56
|
CREDENTIAL_REVOKED: "CREDENTIAL_REVOKED";
|
|
56
57
|
CREDENTIAL_SUSPENDED: "CREDENTIAL_SUSPENDED";
|
|
57
58
|
CREDENTIAL_UNSUSPENDED: "CREDENTIAL_UNSUSPENDED";
|
|
58
59
|
CREDENTIAL_REFRESHED: "CREDENTIAL_REFRESHED";
|
|
60
|
+
CONSENT_FLOW_CONTRACT_UPDATED: "CONSENT_FLOW_CONTRACT_UPDATED";
|
|
59
61
|
}>>;
|
|
60
62
|
}, z.core.$strip>;
|
|
61
63
|
export type NotificationQueryFiltersType = z.infer<typeof NotificationQueryFiltersValidator>;
|
|
@@ -101,10 +103,12 @@ export declare const PaginatedNotificationsValidator: z.ZodObject<{
|
|
|
101
103
|
DEVICE_LINK_REQUEST: "DEVICE_LINK_REQUEST";
|
|
102
104
|
GUARDIAN_APPROVAL_PENDING: "GUARDIAN_APPROVAL_PENDING";
|
|
103
105
|
APP_NOTIFICATION: "APP_NOTIFICATION";
|
|
106
|
+
ANNOUNCEMENT: "ANNOUNCEMENT";
|
|
104
107
|
CREDENTIAL_REVOKED: "CREDENTIAL_REVOKED";
|
|
105
108
|
CREDENTIAL_SUSPENDED: "CREDENTIAL_SUSPENDED";
|
|
106
109
|
CREDENTIAL_UNSUSPENDED: "CREDENTIAL_UNSUSPENDED";
|
|
107
110
|
CREDENTIAL_REFRESHED: "CREDENTIAL_REFRESHED";
|
|
111
|
+
CONSENT_FLOW_CONTRACT_UPDATED: "CONSENT_FLOW_CONTRACT_UPDATED";
|
|
108
112
|
}>;
|
|
109
113
|
to: z.ZodIntersection<z.ZodObject<{
|
|
110
114
|
profileId: z.ZodOptional<z.ZodString>;
|
|
@@ -246,14 +250,120 @@ export declare const PaginatedNotificationsValidator: z.ZodObject<{
|
|
|
246
250
|
}, z.core.$strip>>;
|
|
247
251
|
id: z.ZodString;
|
|
248
252
|
action: z.ZodEnum<{
|
|
249
|
-
update: "update";
|
|
250
|
-
write: "write";
|
|
251
253
|
consent: "consent";
|
|
254
|
+
write: "write";
|
|
255
|
+
update: "update";
|
|
252
256
|
sync: "sync";
|
|
253
257
|
withdraw: "withdraw";
|
|
258
|
+
reconsent: "reconsent";
|
|
254
259
|
}>;
|
|
260
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
261
|
+
relaxed: "relaxed";
|
|
262
|
+
expanded_optional: "expanded_optional";
|
|
263
|
+
requires_consent: "requires_consent";
|
|
264
|
+
}>>;
|
|
255
265
|
date: z.ZodString;
|
|
256
266
|
uris: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
267
|
+
consentedVersion: z.ZodOptional<z.ZodNumber>;
|
|
268
|
+
reconsentDeadline: z.ZodOptional<z.ZodString>;
|
|
269
|
+
newOptionsUntil: z.ZodOptional<z.ZodString>;
|
|
270
|
+
}, z.core.$strip>>;
|
|
271
|
+
contractUri: z.ZodOptional<z.ZodString>;
|
|
272
|
+
contractName: z.ZodOptional<z.ZodString>;
|
|
273
|
+
fromVersion: z.ZodOptional<z.ZodNumber>;
|
|
274
|
+
toVersion: z.ZodOptional<z.ZodNumber>;
|
|
275
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
276
|
+
relaxed: "relaxed";
|
|
277
|
+
expanded_optional: "expanded_optional";
|
|
278
|
+
requires_consent: "requires_consent";
|
|
279
|
+
}>>;
|
|
280
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
281
|
+
diff: z.ZodOptional<z.ZodObject<{
|
|
282
|
+
added: z.ZodArray<z.ZodObject<{
|
|
283
|
+
area: z.ZodEnum<{
|
|
284
|
+
read: "read";
|
|
285
|
+
write: "write";
|
|
286
|
+
}>;
|
|
287
|
+
type: z.ZodEnum<{
|
|
288
|
+
credential: "credential";
|
|
289
|
+
personal: "personal";
|
|
290
|
+
}>;
|
|
291
|
+
key: z.ZodString;
|
|
292
|
+
required: z.ZodBoolean;
|
|
293
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
294
|
+
}, z.core.$strip>>;
|
|
295
|
+
removed: z.ZodArray<z.ZodObject<{
|
|
296
|
+
area: z.ZodEnum<{
|
|
297
|
+
read: "read";
|
|
298
|
+
write: "write";
|
|
299
|
+
}>;
|
|
300
|
+
type: z.ZodEnum<{
|
|
301
|
+
credential: "credential";
|
|
302
|
+
personal: "personal";
|
|
303
|
+
}>;
|
|
304
|
+
key: z.ZodString;
|
|
305
|
+
required: z.ZodBoolean;
|
|
306
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
307
|
+
}, z.core.$strip>>;
|
|
308
|
+
changed: z.ZodArray<z.ZodObject<{
|
|
309
|
+
area: z.ZodEnum<{
|
|
310
|
+
read: "read";
|
|
311
|
+
write: "write";
|
|
312
|
+
}>;
|
|
313
|
+
type: z.ZodEnum<{
|
|
314
|
+
credential: "credential";
|
|
315
|
+
personal: "personal";
|
|
316
|
+
}>;
|
|
317
|
+
key: z.ZodString;
|
|
318
|
+
required: z.ZodBoolean;
|
|
319
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
320
|
+
}, z.core.$strip>>;
|
|
321
|
+
details: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
322
|
+
field: z.ZodEnum<{
|
|
323
|
+
name: "name";
|
|
324
|
+
description: "description";
|
|
325
|
+
image: "image";
|
|
326
|
+
expiresAt: "expiresAt";
|
|
327
|
+
subtitle: "subtitle";
|
|
328
|
+
reasonForAccessing: "reasonForAccessing";
|
|
329
|
+
needsGuardianConsent: "needsGuardianConsent";
|
|
330
|
+
redirectUrl: "redirectUrl";
|
|
331
|
+
frontDoorBoostUri: "frontDoorBoostUri";
|
|
332
|
+
writers: "writers";
|
|
333
|
+
autoboosts: "autoboosts";
|
|
334
|
+
}>;
|
|
335
|
+
before: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodArray<z.ZodString>]>>;
|
|
336
|
+
after: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodArray<z.ZodString>]>>;
|
|
337
|
+
}, z.core.$strip>>>;
|
|
338
|
+
}, z.core.$strip>>;
|
|
339
|
+
reconsentDeadline: z.ZodOptional<z.ZodString>;
|
|
340
|
+
reviewUrl: z.ZodOptional<z.ZodString>;
|
|
341
|
+
preview: z.ZodOptional<z.ZodObject<{
|
|
342
|
+
headline: z.ZodString;
|
|
343
|
+
subhead: z.ZodString;
|
|
344
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
345
|
+
scope: z.ZodObject<{
|
|
346
|
+
area: z.ZodEnum<{
|
|
347
|
+
read: "read";
|
|
348
|
+
write: "write";
|
|
349
|
+
}>;
|
|
350
|
+
type: z.ZodEnum<{
|
|
351
|
+
credential: "credential";
|
|
352
|
+
personal: "personal";
|
|
353
|
+
}>;
|
|
354
|
+
key: z.ZodString;
|
|
355
|
+
required: z.ZodBoolean;
|
|
356
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
357
|
+
}, z.core.$strip>;
|
|
358
|
+
change: z.ZodEnum<{
|
|
359
|
+
added: "added";
|
|
360
|
+
removed: "removed";
|
|
361
|
+
changed: "changed";
|
|
362
|
+
}>;
|
|
363
|
+
label: z.ZodString;
|
|
364
|
+
subtitle: z.ZodString;
|
|
365
|
+
}, z.core.$strip>>;
|
|
366
|
+
primaryLabel: z.ZodString;
|
|
257
367
|
}, z.core.$strip>>;
|
|
258
368
|
inbox: z.ZodOptional<z.ZodObject<{
|
|
259
369
|
issuanceId: z.ZodString;
|
|
@@ -278,6 +388,10 @@ export declare const PaginatedNotificationsValidator: z.ZodObject<{
|
|
|
278
388
|
promptId: z.ZodString;
|
|
279
389
|
counterpartProfileId: z.ZodString;
|
|
280
390
|
}, z.core.$strip>>;
|
|
391
|
+
campaignId: z.ZodOptional<z.ZodString>;
|
|
392
|
+
campaignCreatedAt: z.ZodOptional<z.ZodISODateTime>;
|
|
393
|
+
campaignHasInApp: z.ZodOptional<z.ZodBoolean>;
|
|
394
|
+
campaignTestId: z.ZodOptional<z.ZodUUID>;
|
|
281
395
|
}, z.core.$catchall<z.ZodUnknown>>>;
|
|
282
396
|
}, z.core.$loose>>;
|
|
283
397
|
sent: z.ZodOptional<z.ZodISODateTime>;
|
|
@@ -318,10 +432,12 @@ export declare const NotificationQueryInputValidator: z.ZodObject<{
|
|
|
318
432
|
DEVICE_LINK_REQUEST: "DEVICE_LINK_REQUEST";
|
|
319
433
|
GUARDIAN_APPROVAL_PENDING: "GUARDIAN_APPROVAL_PENDING";
|
|
320
434
|
APP_NOTIFICATION: "APP_NOTIFICATION";
|
|
435
|
+
ANNOUNCEMENT: "ANNOUNCEMENT";
|
|
321
436
|
CREDENTIAL_REVOKED: "CREDENTIAL_REVOKED";
|
|
322
437
|
CREDENTIAL_SUSPENDED: "CREDENTIAL_SUSPENDED";
|
|
323
438
|
CREDENTIAL_UNSUSPENDED: "CREDENTIAL_UNSUSPENDED";
|
|
324
439
|
CREDENTIAL_REFRESHED: "CREDENTIAL_REFRESHED";
|
|
440
|
+
CONSENT_FLOW_CONTRACT_UPDATED: "CONSENT_FLOW_CONTRACT_UPDATED";
|
|
325
441
|
}>>;
|
|
326
442
|
'from.did': z.ZodOptional<z.ZodString>;
|
|
327
443
|
'from.profileId': z.ZodOptional<z.ZodString>;
|
|
@@ -88,16 +88,17 @@ explicit deployment approval. There is no runtime silent fallback to the old mod
|
|
|
88
88
|
|
|
89
89
|
All LCA Lambda functions and the native DIDKit layer declare `nodejs24.x`; esbuild
|
|
90
90
|
targets Node 24. The native addon uses stable N-API v4, supported by Node 24.
|
|
91
|
-
Both Node 20 and Node 24 Lambda use AL2023. Before deployment, the
|
|
92
|
-
`verify-node24-layer.cjs` preflight
|
|
91
|
+
Both Node 20 and Node 24 Lambda use AL2023. Before deployment, the shared
|
|
92
|
+
`scripts/verify-node24-didkit-layer.cjs` preflight (also used by brain-service and
|
|
93
|
+
learn-cloud-service) requires the Linux x64 GNU artifact, both
|
|
93
94
|
packaged runtime dependencies, libc symbols no newer than glibc 2.34, and an actual
|
|
94
95
|
Node 24 native key-to-DID smoke check. Missing/incompatible artifacts stop the action
|
|
95
96
|
before Serverless deployment; WASM fallback is not evidence of native compatibility.
|
|
96
97
|
|
|
97
|
-
LCA pins serverless-esbuild 1.57.2 for Node 24 target support. The
|
|
98
|
-
`node24-runtime.cjs` plugin adds Node 24 to Serverless 3.40's older
|
|
99
|
-
without disabling validation
|
|
100
|
-
Node 24
|
|
98
|
+
LCA pins serverless-esbuild 1.57.2 for Node 24 target support. The shared
|
|
99
|
+
`scripts/serverless-node24-runtime.cjs` plugin adds Node 24 to Serverless 3.40's older
|
|
100
|
+
runtime schema without disabling validation. Deployment tools run on
|
|
101
|
+
the repo `.nvmrc` Node 24 in the LCA action. Local offline configuration uses Node 24 too.
|
|
101
102
|
|
|
102
103
|
The `LcaDevBedrockGenerationPolicy` CloudFormation resource attaches the scoped
|
|
103
104
|
policy to `SigningAuthorityExecutionRole` only for stage `dev` in `us-east-1`.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { APIGatewayProxyEventV2, Context } from 'aws-lambda';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
const handlers = vi.hoisted(() => ({
|
|
5
|
+
api: vi.fn(async () => ({ statusCode: 200 })),
|
|
6
|
+
trpc: vi.fn(async () => ({ statusCode: 200 })),
|
|
7
|
+
ensureUserKeysIndexes: vi.fn(async () => undefined),
|
|
8
|
+
createEscrowHoldsIndexes: vi.fn(async () => {
|
|
9
|
+
throw new Error('Escrow hold index initialization failed', {
|
|
10
|
+
cause: { code: 11000, codeName: 'DuplicateKey' },
|
|
11
|
+
});
|
|
12
|
+
}),
|
|
13
|
+
}));
|
|
14
|
+
vi.mock('serverless-http', () => ({ default: () => vi.fn() }));
|
|
15
|
+
vi.mock('@trpc/server/adapters/aws-lambda', () => ({
|
|
16
|
+
awsLambdaRequestHandler: () => handlers.trpc,
|
|
17
|
+
}));
|
|
18
|
+
vi.mock('@sentry/serverless', () => ({
|
|
19
|
+
AWSLambda: { init: vi.fn(), wrapHandler: (handler: unknown) => handler },
|
|
20
|
+
Integrations: { Console: class {}, Http: class {}, ContextLines: class {}, Mongo: class {} },
|
|
21
|
+
}));
|
|
22
|
+
vi.mock('./src/openapi', () => ({ default: {} }));
|
|
23
|
+
vi.mock('./src/dids', () => ({ default: {} }));
|
|
24
|
+
vi.mock('./src/app', () => ({ appRouter: {}, createContext: vi.fn() }));
|
|
25
|
+
vi.mock('./src/helpers/learnCard.helpers', () => ({ getEmptyLearnCard: async () => ({}) }));
|
|
26
|
+
vi.mock('./src/helpers/shim', () => ({ createOpenApiAwsLambdaHandler: () => handlers.api }));
|
|
27
|
+
vi.mock('./src/helpers/sentry.helpers', () => ({
|
|
28
|
+
handleTrpcError: vi.fn(),
|
|
29
|
+
sentryBeforeSend: vi.fn(),
|
|
30
|
+
getTracesSampleRate: () => 0,
|
|
31
|
+
}));
|
|
32
|
+
vi.mock('./src/config/environment', () => ({ environment: {} }));
|
|
33
|
+
vi.mock('./src/helpers/serverlessApplication', () => ({ toServerlessApplication: () => ({}) }));
|
|
34
|
+
vi.mock('./src/models', () => handlers);
|
|
35
|
+
vi.mock('./src/jobs/escrowHoldReminders', () => ({ runEscrowHoldReminders: vi.fn() }));
|
|
36
|
+
vi.mock('./src/jobs/escrowBlobRewrap', () => ({ runEscrowBlobRewrap: vi.fn() }));
|
|
37
|
+
vi.mock('./src/services/escrow-enclave', () => ({ checkEscrowRemoteConfig: vi.fn() }));
|
|
38
|
+
|
|
39
|
+
const event = (method: string): APIGatewayProxyEventV2 => ({
|
|
40
|
+
version: '2.0',
|
|
41
|
+
routeKey: '$default',
|
|
42
|
+
rawPath: '/unrelated',
|
|
43
|
+
rawQueryString: '',
|
|
44
|
+
headers: {},
|
|
45
|
+
isBase64Encoded: false,
|
|
46
|
+
requestContext: {
|
|
47
|
+
accountId: 'test',
|
|
48
|
+
apiId: 'test',
|
|
49
|
+
domainName: 'localhost',
|
|
50
|
+
domainPrefix: 'localhost',
|
|
51
|
+
http: {
|
|
52
|
+
method,
|
|
53
|
+
path: '/unrelated',
|
|
54
|
+
protocol: 'HTTP/1.1',
|
|
55
|
+
sourceIp: '127.0.0.1',
|
|
56
|
+
userAgent: 'test',
|
|
57
|
+
},
|
|
58
|
+
requestId: 'test',
|
|
59
|
+
routeKey: '$default',
|
|
60
|
+
stage: '$default',
|
|
61
|
+
time: '',
|
|
62
|
+
timeEpoch: 0,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const context: Context = {
|
|
66
|
+
callbackWaitsForEmptyEventLoop: false,
|
|
67
|
+
functionName: 'test',
|
|
68
|
+
functionVersion: 'test',
|
|
69
|
+
invokedFunctionArn: 'test',
|
|
70
|
+
memoryLimitInMB: '128',
|
|
71
|
+
awsRequestId: 'test',
|
|
72
|
+
logGroupName: 'test',
|
|
73
|
+
logStreamName: 'test',
|
|
74
|
+
getRemainingTimeInMillis: () => 30_000,
|
|
75
|
+
done: () => undefined,
|
|
76
|
+
fail: () => undefined,
|
|
77
|
+
succeed: () => undefined,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
beforeEach(() => {
|
|
81
|
+
vi.resetModules();
|
|
82
|
+
vi.clearAllMocks();
|
|
83
|
+
});
|
|
84
|
+
describe('Lambda startup isolation', () => {
|
|
85
|
+
it('retries transient non-escrow startup failures on the next request', async () => {
|
|
86
|
+
const diagnostic = vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
87
|
+
handlers.ensureUserKeysIndexes.mockRejectedValueOnce(
|
|
88
|
+
new Error('transient startup failure')
|
|
89
|
+
);
|
|
90
|
+
const app = await import('./lambdaApp');
|
|
91
|
+
await vi.waitFor(() => expect(diagnostic).toHaveBeenCalled());
|
|
92
|
+
await expect(
|
|
93
|
+
app.openApiHandler(event('GET'), context, () => undefined)
|
|
94
|
+
).resolves.toMatchObject({ statusCode: 200 });
|
|
95
|
+
expect(handlers.ensureUserKeysIndexes).toHaveBeenCalledTimes(2);
|
|
96
|
+
expect(handlers.createEscrowHoldsIndexes).not.toHaveBeenCalled();
|
|
97
|
+
diagnostic.mockRestore();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it.each(['openApiHandler', 'trpcHandler'] as const)(
|
|
101
|
+
'%s serves unrelated requests and OPTIONS without migrating escrow indexes',
|
|
102
|
+
async name => {
|
|
103
|
+
const app = await import('./lambdaApp');
|
|
104
|
+
await expect(app[name](event('GET'), context, () => undefined)).resolves.toMatchObject({
|
|
105
|
+
statusCode: 200,
|
|
106
|
+
});
|
|
107
|
+
await expect(
|
|
108
|
+
app[name](event('OPTIONS'), context, () => undefined)
|
|
109
|
+
).resolves.toMatchObject({ statusCode: 200 });
|
|
110
|
+
expect(handlers.ensureUserKeysIndexes).toHaveBeenCalledOnce();
|
|
111
|
+
expect(handlers.createEscrowHoldsIndexes).not.toHaveBeenCalled();
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
});
|
package/lambdaApp.ts
CHANGED
|
@@ -15,15 +15,27 @@ import {
|
|
|
15
15
|
} from './src/helpers/sentry.helpers';
|
|
16
16
|
import { environment } from './src/config/environment';
|
|
17
17
|
import { toServerlessApplication } from './src/helpers/serverlessApplication';
|
|
18
|
-
import { ensureUserKeysIndexes
|
|
18
|
+
import { ensureUserKeysIndexes } from './src/models';
|
|
19
19
|
import { runEscrowHoldReminders } from './src/jobs/escrowHoldReminders';
|
|
20
20
|
import { runEscrowBlobRewrap } from './src/jobs/escrowBlobRewrap';
|
|
21
|
+
import { checkEscrowRemoteConfig } from './src/services/escrow-enclave';
|
|
22
|
+
import { createRetryingOnce } from './src/helpers/retryingOnce';
|
|
23
|
+
|
|
24
|
+
checkEscrowRemoteConfig();
|
|
25
|
+
|
|
26
|
+
// Retry global startup (WASM + user-keys) without caching failures, and without
|
|
27
|
+
// letting an escrow migration reject unrelated calls.
|
|
28
|
+
const ensureStartup = createRetryingOnce(() =>
|
|
29
|
+
Promise.all([
|
|
30
|
+
getEmptyLearnCard(), // Load WASM in for better cold starts
|
|
31
|
+
ensureUserKeysIndexes(),
|
|
32
|
+
])
|
|
33
|
+
);
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
]);
|
|
35
|
+
// Start during init for faster first requests; handlers await (and retry) it.
|
|
36
|
+
ensureStartup().catch(error => {
|
|
37
|
+
console.error('lca-api startup failed; the next request retries', error);
|
|
38
|
+
});
|
|
27
39
|
|
|
28
40
|
const isWarmupEvent = (event: APIGatewayProxyEventV2): boolean =>
|
|
29
41
|
'source' in event && event.source === 'serverless-plugin-warmup';
|
|
@@ -79,7 +91,7 @@ export const _trpcHandler = awsLambdaRequestHandler({
|
|
|
79
91
|
|
|
80
92
|
export const openApiHandler = Sentry.AWSLambda.wrapHandler(
|
|
81
93
|
async (event: APIGatewayProxyEventV2, context: Context): Promise<APIGatewayProxyResultV2> => {
|
|
82
|
-
await
|
|
94
|
+
await ensureStartup();
|
|
83
95
|
|
|
84
96
|
if (isWarmupEvent(event)) {
|
|
85
97
|
console.log('[Warmup] Initializing LearnCard...');
|
|
@@ -105,7 +117,7 @@ export const openApiHandler = Sentry.AWSLambda.wrapHandler(
|
|
|
105
117
|
|
|
106
118
|
export const trpcHandler = Sentry.AWSLambda.wrapHandler(
|
|
107
119
|
async (event: APIGatewayProxyEventV2, context: Context): Promise<APIGatewayProxyResultV2> => {
|
|
108
|
-
await
|
|
120
|
+
await ensureStartup();
|
|
109
121
|
|
|
110
122
|
if (isWarmupEvent(event)) {
|
|
111
123
|
console.log('[Warmup] Initializing LearnCard...');
|
|
@@ -130,9 +142,9 @@ export const trpcHandler = Sentry.AWSLambda.wrapHandler(
|
|
|
130
142
|
);
|
|
131
143
|
|
|
132
144
|
// Scheduled (EventBridge) functions, not API-Gateway-triggered: they share
|
|
133
|
-
//
|
|
145
|
+
// ensureStartup with the handlers above; warmup/OPTIONS handling doesn't apply.
|
|
134
146
|
export const escrowHoldRemindersHandler = Sentry.AWSLambda.wrapHandler(async (): Promise<void> => {
|
|
135
|
-
await
|
|
147
|
+
await ensureStartup();
|
|
136
148
|
const counts = await runEscrowHoldReminders();
|
|
137
149
|
console.log('[escrow-hold-reminders] completed', counts);
|
|
138
150
|
});
|
|
@@ -140,7 +152,7 @@ export const escrowHoldRemindersHandler = Sentry.AWSLambda.wrapHandler(async ():
|
|
|
140
152
|
// P9.3: migrates escrow blobs off a retiring enclave key for accounts that
|
|
141
153
|
// never sign in again (P9.2 already covers accounts that do, on next login).
|
|
142
154
|
export const escrowBlobRewrapHandler = Sentry.AWSLambda.wrapHandler(async (): Promise<void> => {
|
|
143
|
-
await
|
|
155
|
+
await ensureStartup();
|
|
144
156
|
const counts = await runEscrowBlobRewrap();
|
|
145
157
|
console.log('[escrow-blob-rewrap] completed', counts);
|
|
146
158
|
});
|