@learncard/lca-api-service 1.5.1 → 1.5.2

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.
@@ -28,6 +28,45 @@ export declare const escrowRouter: import("@trpc/server").TRPCBuiltRouter<{
28
28
  };
29
29
  meta: import("trpc-to-openapi").OpenApiMeta;
30
30
  }>;
31
+ getAuthorityState: import("@trpc/server").TRPCMutationProcedure<{
32
+ input: {
33
+ authToken: string;
34
+ providerType: "firebase" | "supertokens" | "keycloak" | "oidc";
35
+ nonce: string;
36
+ };
37
+ output: {
38
+ state: {
39
+ tenant: string;
40
+ authorityGeneration: string;
41
+ did: string;
42
+ enrollmentVersion: number;
43
+ enrollmentEpoch: number;
44
+ status: "empty" | "active" | "disabled";
45
+ envelope: {
46
+ version: 1;
47
+ algorithm: "P-256-HKDF-SHA256-AES-256-GCM";
48
+ keyId: string;
49
+ ephemeralPublicKey: string;
50
+ salt: string;
51
+ iv: string;
52
+ ciphertext: string;
53
+ } | null;
54
+ shareVersion: number | null;
55
+ hasPin: boolean;
56
+ pinGeneration: number;
57
+ attemptsUsed: number;
58
+ };
59
+ proof: {
60
+ version: 1;
61
+ keyId: string;
62
+ measurement: number[];
63
+ payload: string;
64
+ signature: string;
65
+ kind: "snapshot";
66
+ };
67
+ };
68
+ meta: import("trpc-to-openapi").OpenApiMeta;
69
+ }>;
31
70
  enroll: import("@trpc/server").TRPCMutationProcedure<{
32
71
  input: {
33
72
  authToken: string;
@@ -45,10 +84,56 @@ export declare const escrowRouter: import("@trpc/server").TRPCBuiltRouter<{
45
84
  enclaveKeyId: string;
46
85
  pinSalt?: string | undefined;
47
86
  clearPin?: boolean | undefined;
87
+ signedIntent?: {
88
+ intent: {
89
+ version: 2;
90
+ tenant: string;
91
+ did: string;
92
+ authorityGeneration: string;
93
+ expectedEnrollmentVersion: number;
94
+ action: "enroll" | "replace" | "disable" | "carry";
95
+ sourceBlobIdentity: string | null;
96
+ targetBlobIdentity: string | null;
97
+ pinAction: "set" | "change" | "clear" | "keep";
98
+ shareVersion: number;
99
+ enrollmentEpoch: number;
100
+ requestId: string;
101
+ allowRewrap: boolean;
102
+ recoveryEmail: string | null;
103
+ recoveryLanguage: string | null;
104
+ };
105
+ signature: string;
106
+ } | undefined;
107
+ sourceEnvelope?: {
108
+ version: 1;
109
+ algorithm: "P-256-HKDF-SHA256-AES-256-GCM";
110
+ keyId: string;
111
+ ephemeralPublicKey: string;
112
+ salt: string;
113
+ iv: string;
114
+ ciphertext: string;
115
+ } | null | undefined;
48
116
  };
49
117
  output: {
50
118
  success: true;
51
119
  shareVersion: number;
120
+ envelope?: {
121
+ version: 1;
122
+ algorithm: "P-256-HKDF-SHA256-AES-256-GCM";
123
+ keyId: string;
124
+ ephemeralPublicKey: string;
125
+ salt: string;
126
+ iv: string;
127
+ ciphertext: string;
128
+ } | undefined;
129
+ receipt?: {
130
+ version: 1;
131
+ keyId: string;
132
+ measurement: number[];
133
+ signature: string;
134
+ kind: "commit";
135
+ payload: string;
136
+ } | undefined;
52
137
  };
53
138
  meta: import("trpc-to-openapi").OpenApiMeta;
54
139
  }>;
@@ -60,6 +145,62 @@ export declare const escrowRouter: import("@trpc/server").TRPCBuiltRouter<{
60
145
  };
61
146
  output: {
62
147
  success: true;
148
+ receipt?: {
149
+ version: 1;
150
+ keyId: string;
151
+ measurement: number[];
152
+ signature: string;
153
+ kind: "commit";
154
+ payload: string;
155
+ } | undefined;
156
+ };
157
+ meta: import("trpc-to-openapi").OpenApiMeta;
158
+ }>;
159
+ disable: import("@trpc/server").TRPCMutationProcedure<{
160
+ input: {
161
+ authToken: string;
162
+ providerType: "firebase" | "supertokens" | "keycloak" | "oidc";
163
+ optOut: boolean;
164
+ signedIntent: {
165
+ intent: {
166
+ version: 2;
167
+ tenant: string;
168
+ did: string;
169
+ authorityGeneration: string;
170
+ expectedEnrollmentVersion: number;
171
+ action: "enroll" | "replace" | "disable" | "carry";
172
+ sourceBlobIdentity: string | null;
173
+ targetBlobIdentity: string | null;
174
+ pinAction: "set" | "change" | "clear" | "keep";
175
+ shareVersion: number;
176
+ enrollmentEpoch: number;
177
+ requestId: string;
178
+ allowRewrap: boolean;
179
+ recoveryEmail: string | null;
180
+ recoveryLanguage: string | null;
181
+ };
182
+ signature: string;
183
+ };
184
+ sourceEnvelope?: {
185
+ version: 1;
186
+ algorithm: "P-256-HKDF-SHA256-AES-256-GCM";
187
+ keyId: string;
188
+ ephemeralPublicKey: string;
189
+ salt: string;
190
+ iv: string;
191
+ ciphertext: string;
192
+ } | undefined;
193
+ };
194
+ output: {
195
+ success: true;
196
+ receipt?: {
197
+ version: 1;
198
+ keyId: string;
199
+ measurement: number[];
200
+ signature: string;
201
+ kind: "commit";
202
+ payload: string;
203
+ } | undefined;
63
204
  };
64
205
  meta: import("trpc-to-openapi").OpenApiMeta;
65
206
  }>;
@@ -89,10 +230,66 @@ export declare const escrowRouter: import("@trpc/server").TRPCBuiltRouter<{
89
230
  releaseAfter: string;
90
231
  status: "pending";
91
232
  resumeToken: string | null;
233
+ holdRecord?: {
234
+ [x: string]: unknown;
235
+ hold: {
236
+ [x: string]: unknown;
237
+ holdId: string;
238
+ did: string;
239
+ shareVersion: number;
240
+ blobHash: string;
241
+ enrollmentEpoch: number;
242
+ releasePolicy: "pin" | "hold";
243
+ clientEphemeralPublicKey: string;
244
+ createdLo: number;
245
+ createdHi: number;
246
+ policyVersion: number;
247
+ signature: string;
248
+ };
249
+ holdDurationMs: number;
250
+ ledgerSeq: number;
251
+ } | undefined;
252
+ requiresConfirmation?: boolean | undefined;
92
253
  pinSalt?: string | undefined;
93
254
  };
94
255
  meta: import("trpc-to-openapi").OpenApiMeta;
95
256
  }>;
257
+ confirmRecovery: import("@trpc/server").TRPCMutationProcedure<{
258
+ input: {
259
+ holdId: string;
260
+ resumeToken: string;
261
+ code: string;
262
+ };
263
+ output: {
264
+ success: true;
265
+ receipt?: {
266
+ version: 1;
267
+ keyId: string;
268
+ measurement: number[];
269
+ signature: string;
270
+ kind: "commit";
271
+ payload: string;
272
+ } | {
273
+ version: 1;
274
+ keyId: string;
275
+ measurement: number[];
276
+ payload: string;
277
+ signature: string;
278
+ kind: "snapshot";
279
+ } | undefined;
280
+ };
281
+ meta: import("trpc-to-openapi").OpenApiMeta;
282
+ }>;
283
+ resendRecoveryCode: import("@trpc/server").TRPCMutationProcedure<{
284
+ input: {
285
+ holdId: string;
286
+ resumeToken: string;
287
+ };
288
+ output: {
289
+ success: true;
290
+ };
291
+ meta: import("trpc-to-openapi").OpenApiMeta;
292
+ }>;
96
293
  getStatus: import("@trpc/server").TRPCQueryProcedure<{
97
294
  input: {
98
295
  holdId?: string | undefined;
@@ -109,6 +306,27 @@ export declare const escrowRouter: import("@trpc/server").TRPCBuiltRouter<{
109
306
  releasePolicy: "pin" | "hold";
110
307
  cancelledAt?: string | undefined;
111
308
  completedAt?: string | undefined;
309
+ requiresConfirmation?: boolean | undefined;
310
+ confirmed?: boolean | undefined;
311
+ holdRecord?: {
312
+ [x: string]: unknown;
313
+ hold: {
314
+ [x: string]: unknown;
315
+ holdId: string;
316
+ did: string;
317
+ shareVersion: number;
318
+ blobHash: string;
319
+ enrollmentEpoch: number;
320
+ releasePolicy: "pin" | "hold";
321
+ clientEphemeralPublicKey: string;
322
+ createdLo: number;
323
+ createdHi: number;
324
+ policyVersion: number;
325
+ signature: string;
326
+ };
327
+ holdDurationMs: number;
328
+ ledgerSeq: number;
329
+ } | undefined;
112
330
  } | null;
113
331
  };
114
332
  meta: import("trpc-to-openapi").OpenApiMeta;
@@ -35,6 +35,7 @@ export declare const t: import("@trpc/server").TRPCRootObject<Context, OpenApiMe
35
35
  export declare const createContext: (options: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2> | CreateFastifyContextOptions | NodeHTTPCreateContextFnOptions<IncomingMessage, ServerResponse>) => Promise<Context>;
36
36
  export declare const redactSecretFields: (value: unknown, depth?: number, seen?: Set<object>) => unknown;
37
37
  export declare const openRoute: import("@trpc/server").TRPCProcedureBuilder<Context, OpenApiMeta, {
38
+ tenant: ResolvedTenant;
38
39
  debug: boolean | undefined;
39
40
  user: {
40
41
  did: string;
@@ -42,11 +43,11 @@ export declare const openRoute: import("@trpc/server").TRPCProcedureBuilder<Cont
42
43
  authorizedDid?: boolean;
43
44
  } | undefined;
44
45
  domain: string;
45
- tenant: ResolvedTenant;
46
46
  clientIp: string | undefined;
47
47
  providerToken: string | undefined;
48
48
  }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
49
49
  export declare const didRoute: import("@trpc/server").TRPCProcedureBuilder<Context, OpenApiMeta, {
50
+ tenant: ResolvedTenant;
50
51
  debug: boolean | undefined;
51
52
  user: {
52
53
  did: string;
@@ -54,11 +55,11 @@ export declare const didRoute: import("@trpc/server").TRPCProcedureBuilder<Conte
54
55
  authorizedDid?: boolean;
55
56
  };
56
57
  domain: string;
57
- tenant: ResolvedTenant;
58
58
  clientIp: string | undefined;
59
59
  providerToken: string | undefined;
60
60
  }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
61
61
  export declare const authorizedDidRoute: import("@trpc/server").TRPCProcedureBuilder<Context, OpenApiMeta, {
62
+ tenant: ResolvedTenant;
62
63
  debug: boolean | undefined;
63
64
  user: {
64
65
  did: string;
@@ -66,11 +67,11 @@ export declare const authorizedDidRoute: import("@trpc/server").TRPCProcedureBui
66
67
  authorizedDid?: boolean;
67
68
  };
68
69
  domain: string;
69
- tenant: ResolvedTenant;
70
70
  clientIp: string | undefined;
71
71
  providerToken: string | undefined;
72
72
  }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
73
73
  export declare const didAndChallengeRoute: import("@trpc/server").TRPCProcedureBuilder<Context, OpenApiMeta, {
74
+ tenant: ResolvedTenant;
74
75
  debug: boolean | undefined;
75
76
  user: {
76
77
  did: string;
@@ -78,7 +79,6 @@ export declare const didAndChallengeRoute: import("@trpc/server").TRPCProcedureB
78
79
  authorizedDid?: boolean;
79
80
  };
80
81
  domain: string;
81
- tenant: ResolvedTenant;
82
82
  clientIp: string | undefined;
83
83
  providerToken: string | undefined;
84
84
  }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
@@ -67,6 +67,7 @@ export declare const keysRouter: import("@trpc/server").TRPCBuiltRouter<{
67
67
  attemptsRemaining: number;
68
68
  salt?: string | undefined;
69
69
  };
70
+ primaryDid: string | null;
70
71
  };
71
72
  meta: import("trpc-to-openapi").OpenApiMeta;
72
73
  }>;
@@ -152,7 +153,7 @@ export declare const keysRouter: import("@trpc/server").TRPCBuiltRouter<{
152
153
  attemptsRemaining: number;
153
154
  salt?: string | undefined;
154
155
  };
155
- sssActivationState: "provisional" | "active";
156
+ sssActivationState: "active" | "provisional";
156
157
  escrowStale?: "mode-mismatch" | "key-rotated" | undefined;
157
158
  } | null;
158
159
  meta: import("trpc-to-openapi").OpenApiMeta;
@@ -0,0 +1,170 @@
1
+ import { z } from 'zod';
2
+ export declare const safeInteger: z.ZodNumber;
3
+ export declare const AuthorityEnvelopeValidator: z.ZodObject<{
4
+ version: z.ZodLiteral<1>;
5
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
6
+ keyId: z.ZodString;
7
+ ephemeralPublicKey: z.ZodString;
8
+ salt: z.ZodString;
9
+ iv: z.ZodString;
10
+ ciphertext: z.ZodString;
11
+ }, z.core.$strict>;
12
+ export declare const AuthorityRecordValidator: z.ZodObject<{
13
+ version: z.ZodLiteral<1>;
14
+ kind: z.ZodEnum<{
15
+ proposal: "proposal";
16
+ commit: "commit";
17
+ snapshot: "snapshot";
18
+ }>;
19
+ keyId: z.ZodString;
20
+ measurement: z.ZodArray<z.ZodNumber>;
21
+ payload: z.ZodString;
22
+ signature: z.ZodString;
23
+ }, z.core.$strict>;
24
+ export declare const AuthorityCommitValidator: z.ZodObject<{
25
+ version: z.ZodLiteral<1>;
26
+ keyId: z.ZodString;
27
+ measurement: z.ZodArray<z.ZodNumber>;
28
+ signature: z.ZodString;
29
+ kind: z.ZodLiteral<"commit">;
30
+ payload: z.ZodString;
31
+ }, z.core.$strict>;
32
+ export declare const AuthorityHoldSnapshotValidator: z.ZodObject<{
33
+ version: z.ZodLiteral<1>;
34
+ keyId: z.ZodString;
35
+ measurement: z.ZodArray<z.ZodNumber>;
36
+ payload: z.ZodString;
37
+ signature: z.ZodString;
38
+ kind: z.ZodLiteral<"snapshot">;
39
+ }, z.core.$strict>;
40
+ export declare const AuthorityHoldReceiptValidator: z.ZodUnion<readonly [z.ZodObject<{
41
+ version: z.ZodLiteral<1>;
42
+ keyId: z.ZodString;
43
+ measurement: z.ZodArray<z.ZodNumber>;
44
+ signature: z.ZodString;
45
+ kind: z.ZodLiteral<"commit">;
46
+ payload: z.ZodString;
47
+ }, z.core.$strict>, z.ZodObject<{
48
+ version: z.ZodLiteral<1>;
49
+ keyId: z.ZodString;
50
+ measurement: z.ZodArray<z.ZodNumber>;
51
+ payload: z.ZodString;
52
+ signature: z.ZodString;
53
+ kind: z.ZodLiteral<"snapshot">;
54
+ }, z.core.$strict>]>;
55
+ export declare const SignedEnrollmentIntentValidator: z.ZodObject<{
56
+ intent: z.ZodObject<{
57
+ version: z.ZodLiteral<2>;
58
+ tenant: z.ZodString;
59
+ did: z.ZodString;
60
+ authorityGeneration: z.ZodString;
61
+ expectedEnrollmentVersion: z.ZodNumber;
62
+ action: z.ZodEnum<{
63
+ enroll: "enroll";
64
+ replace: "replace";
65
+ disable: "disable";
66
+ carry: "carry";
67
+ }>;
68
+ sourceBlobIdentity: z.ZodNullable<z.ZodString>;
69
+ targetBlobIdentity: z.ZodNullable<z.ZodString>;
70
+ pinAction: z.ZodEnum<{
71
+ set: "set";
72
+ change: "change";
73
+ clear: "clear";
74
+ keep: "keep";
75
+ }>;
76
+ shareVersion: z.ZodNumber;
77
+ enrollmentEpoch: z.ZodNumber;
78
+ requestId: z.ZodString;
79
+ allowRewrap: z.ZodBoolean;
80
+ recoveryEmail: z.ZodNullable<z.ZodString>;
81
+ recoveryLanguage: z.ZodNullable<z.ZodString>;
82
+ }, z.core.$strict>;
83
+ signature: z.ZodString;
84
+ }, z.core.$strict>;
85
+ export declare const AuthorityStateValidator: z.ZodObject<{
86
+ tenant: z.ZodString;
87
+ authorityGeneration: z.ZodString;
88
+ did: z.ZodString;
89
+ enrollmentVersion: z.ZodNumber;
90
+ enrollmentEpoch: z.ZodNumber;
91
+ status: z.ZodEnum<{
92
+ empty: "empty";
93
+ active: "active";
94
+ disabled: "disabled";
95
+ }>;
96
+ envelope: z.ZodNullable<z.ZodObject<{
97
+ version: z.ZodLiteral<1>;
98
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
99
+ keyId: z.ZodString;
100
+ ephemeralPublicKey: z.ZodString;
101
+ salt: z.ZodString;
102
+ iv: z.ZodString;
103
+ ciphertext: z.ZodString;
104
+ }, z.core.$strict>>;
105
+ shareVersion: z.ZodNullable<z.ZodNumber>;
106
+ hasPin: z.ZodBoolean;
107
+ pinGeneration: z.ZodNumber;
108
+ attemptsUsed: z.ZodNumber;
109
+ }, z.core.$strict>;
110
+ export declare const AuthorityStateResponseValidator: z.ZodObject<{
111
+ state: z.ZodObject<{
112
+ tenant: z.ZodString;
113
+ authorityGeneration: z.ZodString;
114
+ did: z.ZodString;
115
+ enrollmentVersion: z.ZodNumber;
116
+ enrollmentEpoch: z.ZodNumber;
117
+ status: z.ZodEnum<{
118
+ empty: "empty";
119
+ active: "active";
120
+ disabled: "disabled";
121
+ }>;
122
+ envelope: z.ZodNullable<z.ZodObject<{
123
+ version: z.ZodLiteral<1>;
124
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
125
+ keyId: z.ZodString;
126
+ ephemeralPublicKey: z.ZodString;
127
+ salt: z.ZodString;
128
+ iv: z.ZodString;
129
+ ciphertext: z.ZodString;
130
+ }, z.core.$strict>>;
131
+ shareVersion: z.ZodNullable<z.ZodNumber>;
132
+ hasPin: z.ZodBoolean;
133
+ pinGeneration: z.ZodNumber;
134
+ attemptsUsed: z.ZodNumber;
135
+ }, z.core.$strict>;
136
+ proof: z.ZodObject<{
137
+ version: z.ZodLiteral<1>;
138
+ keyId: z.ZodString;
139
+ measurement: z.ZodArray<z.ZodNumber>;
140
+ payload: z.ZodString;
141
+ signature: z.ZodString;
142
+ kind: z.ZodLiteral<"snapshot">;
143
+ }, z.core.$strict>;
144
+ }, z.core.$strict>;
145
+ export declare const AuthorityMutationValidator: z.ZodObject<{
146
+ envelope: z.ZodNullable<z.ZodObject<{
147
+ version: z.ZodLiteral<1>;
148
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
149
+ keyId: z.ZodString;
150
+ ephemeralPublicKey: z.ZodString;
151
+ salt: z.ZodString;
152
+ iv: z.ZodString;
153
+ ciphertext: z.ZodString;
154
+ }, z.core.$strict>>;
155
+ receipt: z.ZodObject<{
156
+ version: z.ZodLiteral<1>;
157
+ keyId: z.ZodString;
158
+ measurement: z.ZodArray<z.ZodNumber>;
159
+ signature: z.ZodString;
160
+ kind: z.ZodLiteral<"commit">;
161
+ payload: z.ZodString;
162
+ }, z.core.$strict>;
163
+ authorityGeneration: z.ZodString;
164
+ enrollmentVersion: z.ZodNumber;
165
+ enrollmentEpoch: z.ZodNumber;
166
+ }, z.core.$strict>;
167
+ export type AuthorityRecord = z.infer<typeof AuthorityRecordValidator>;
168
+ export type AuthorityHoldReceipt = z.infer<typeof AuthorityHoldReceiptValidator>;
169
+ export type AuthorityMutationResult = z.infer<typeof AuthorityMutationValidator>;
170
+ export type AuthorityStateResponse = z.infer<typeof AuthorityStateResponseValidator>;
@@ -1,4 +1,10 @@
1
- import type { EscrowEnvelope } from '@learncard/sss-key-manager';
1
+ import type { EscrowEnvelope, SignedEscrowEnrollmentIntent } from '@learncard/sss-key-manager';
2
+ import type { AuthorityRecord, AuthorityHoldReceipt, AuthorityMutationResult, AuthorityStateResponse } from './authorityContract';
3
+ export interface ApplyEnrollmentInput {
4
+ signedIntent: SignedEscrowEnrollmentIntent;
5
+ sourceEnvelope: EscrowEnvelope | null;
6
+ targetEnvelope: EscrowEnvelope | null;
7
+ }
2
8
  export interface EnclaveAttestation {
3
9
  mode: 'software' | 'nitro';
4
10
  keyId: string;
@@ -42,11 +48,21 @@ export interface EnclaveCreateHoldInput {
42
48
  clientEphemeralPublicKey: string;
43
49
  }
44
50
  export interface CancelHoldRequest {
51
+ requestId?: string;
45
52
  envelope: EscrowEnvelope;
46
53
  hold: EscrowHoldRecord;
47
54
  clientEphemeralPublicKey: string;
48
55
  expectedDid: string;
49
56
  }
57
+ export interface ConfirmHoldRequest extends CancelHoldRequest {
58
+ code: string;
59
+ }
60
+ export type ResendCodeRequest = CancelHoldRequest;
61
+ export interface SendReleaseWarningRequest {
62
+ requestId?: string;
63
+ holdId: string;
64
+ expectedDid: string;
65
+ }
50
66
  export interface VerifyEscrowBlobInput {
51
67
  envelope: EscrowEnvelope;
52
68
  expectedDid: string;
@@ -66,6 +82,7 @@ export interface ReleaseRequest extends CancelHoldRequest {
66
82
  }
67
83
  export interface ReleaseResult {
68
84
  sealed: EscrowEnvelope;
85
+ receipt?: AuthorityRecord;
69
86
  }
70
87
  export interface CarryPinVerifierInput {
71
88
  sourceEnvelope: EscrowEnvelope;
@@ -83,6 +100,11 @@ export interface RewrapEscrowBlobInput {
83
100
  sourceEnrollmentEpoch: number;
84
101
  }
85
102
  export interface EscrowEnclave {
103
+ getEnrollmentState?(input: {
104
+ expectedDid: string;
105
+ nonce: string;
106
+ }): Promise<AuthorityStateResponse>;
107
+ applyEnrollmentIntent?(input: ApplyEnrollmentInput): Promise<AuthorityMutationResult>;
86
108
  getAttestation(nonce?: Uint8Array): Promise<EnclaveAttestation>;
87
109
  verifyEscrowBlob(input: VerifyEscrowBlobInput): Promise<VerifyEscrowBlobResult>;
88
110
  carryPinVerifier(input: CarryPinVerifierInput): Promise<{
@@ -90,12 +112,26 @@ export interface EscrowEnclave {
90
112
  }>;
91
113
  rewrapEscrowBlob(input: RewrapEscrowBlobInput): Promise<{
92
114
  envelope: EscrowEnvelope;
115
+ authority?: AuthorityMutationResult;
93
116
  }>;
94
117
  releaseEscrow(input: ReleaseRequest): Promise<ReleaseResult>;
95
118
  createHold(input: EnclaveCreateHoldInput): Promise<{
96
119
  holdRecord: EscrowHoldRecord;
97
120
  }>;
98
- cancelHold(input: CancelHoldRequest): Promise<void>;
121
+ cancelHold(input: CancelHoldRequest): Promise<void | {
122
+ receipt: AuthorityRecord;
123
+ }>;
124
+ confirmHold?(input: ConfirmHoldRequest): Promise<{
125
+ receipt: AuthorityHoldReceipt;
126
+ confirmedAtMs: number;
127
+ }>;
128
+ resendCode?(input: ResendCodeRequest): Promise<{
129
+ receipt: AuthorityRecord;
130
+ }>;
131
+ sendReleaseWarning?(input: SendReleaseWarningRequest): Promise<{
132
+ receipt: AuthorityHoldReceipt;
133
+ releaseWarningSentAtMs: number;
134
+ }>;
99
135
  }
100
136
  export declare class EscrowPolicyError extends Error {
101
137
  constructor();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@learncard/lca-api-service",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "",
5
5
  "engines": {
6
6
  "node": ">=24.12 <25"
@@ -63,15 +63,15 @@
63
63
  "@fastify/formbody": "^8.0.2",
64
64
  "@fastify/rate-limit": "^10.2.0",
65
65
  "@fastify/static": "^10.1.1",
66
- "@learncard/core": "9.4.38",
67
- "@learncard/did-web-plugin": "1.1.38",
68
- "@learncard/didkit-plugin": "1.10.3",
69
- "@learncard/didkit-plugin-node": "0.3.3",
66
+ "@learncard/core": "9.4.39",
67
+ "@learncard/did-web-plugin": "1.1.39",
68
+ "@learncard/didkit-plugin": "1.10.4",
69
+ "@learncard/didkit-plugin-node": "0.3.4",
70
70
  "@learncard/email-templates": "1.2.1",
71
- "@learncard/helpers": "1.6.2",
72
- "@learncard/init": "2.5.3",
73
- "@learncard/types": "5.23.0",
74
- "@learncard/sss-key-manager": "0.2.1",
71
+ "@learncard/helpers": "1.6.3",
72
+ "@learncard/init": "2.5.4",
73
+ "@learncard/types": "5.23.1",
74
+ "@learncard/sss-key-manager": "0.2.2",
75
75
  "@sentry/serverless": "^7.61.0",
76
76
  "@trpc/server": "11.8.0",
77
77
  "@types/jsonwebtoken": "^9.0.8",
@@ -64,7 +64,7 @@ export const lcaApiEnvironmentShape = {
64
64
  * silently DoS recovery. See services/escrow-ledger-monitor/README.md. */
65
65
  ESCROW_RELEASE_KILL_SWITCH: optionalEnvironmentBoolean,
66
66
  ESCROW_ENCLAVE_REMOTE_TIMEOUT_MS: optionalEnvironmentString
67
- .transform(value => (value === undefined ? 10_000 : Number(value)))
67
+ .transform(value => (value === undefined ? 15_000 : Number(value)))
68
68
  .pipe(z.number().int().positive().max(30_000)),
69
69
  ESCROW_HOLD_DURATION_MS: optionalEnvironmentString
70
70
  .transform(value => (value === undefined ? 604_800_000 : Number(value)))
@@ -101,6 +101,14 @@ describe('escrow deployment wiring', () => {
101
101
  );
102
102
  });
103
103
 
104
+ it('keeps every checked-in enclave timeout above the host forwarding deadline', () => {
105
+ // enclave 10s < host 12s < lca-api; an equal or shorter value races the response.
106
+ for (const [stage, config] of Object.entries(stages)) {
107
+ const value = (config as Record<string, string>).ESCROW_ENCLAVE_REMOTE_TIMEOUT_MS;
108
+ if (value !== undefined) expect(Number(value), stage).toBeGreaterThan(12_000);
109
+ }
110
+ });
111
+
104
112
  it('never checks in escrow credentials', () => {
105
113
  for (const [stage, config] of Object.entries(stages)) {
106
114
  for (const name of [...SOURCES.bundle, ...SOURCES.toggle]) {