burnledger 0.2.2 → 0.3.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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/cjs/index.browser.d.ts +2 -1
- package/dist/cjs/index.browser.d.ts.map +1 -1
- package/dist/cjs/index.browser.js +7 -1
- package/dist/cjs/index.browser.js.map +1 -1
- package/dist/cjs/index.d.ts +9 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +17 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/models.d.ts +28 -1
- package/dist/cjs/models.d.ts.map +1 -1
- package/dist/cjs/models.js +8 -0
- package/dist/cjs/models.js.map +1 -1
- package/dist/cjs/verify.d.ts +55 -1
- package/dist/cjs/verify.d.ts.map +1 -1
- package/dist/cjs/verify.js +414 -104
- package/dist/cjs/verify.js.map +1 -1
- package/dist/cjs/web-verifier.d.ts +29 -0
- package/dist/cjs/web-verifier.d.ts.map +1 -0
- package/dist/cjs/web-verifier.js +70 -0
- package/dist/cjs/web-verifier.js.map +1 -0
- package/dist/esm/cli.d.ts.map +1 -1
- package/dist/esm/cli.js +12 -5
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/index.browser.d.ts +2 -1
- package/dist/esm/index.browser.d.ts.map +1 -1
- package/dist/esm/index.browser.js +3 -0
- package/dist/esm/index.browser.js.map +1 -1
- package/dist/esm/index.d.ts +9 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +13 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/models.d.ts +28 -1
- package/dist/esm/models.d.ts.map +1 -1
- package/dist/esm/models.js +8 -0
- package/dist/esm/models.js.map +1 -1
- package/dist/esm/verify.d.ts +55 -1
- package/dist/esm/verify.d.ts.map +1 -1
- package/dist/esm/verify.js +411 -105
- package/dist/esm/verify.js.map +1 -1
- package/dist/esm/web-verifier.d.ts +29 -0
- package/dist/esm/web-verifier.d.ts.map +1 -0
- package/dist/esm/web-verifier.js +63 -0
- package/dist/esm/web-verifier.js.map +1 -0
- package/package.json +12 -11
- package/src/cli.ts +207 -0
- package/src/client.ts +555 -0
- package/src/crypto-browser.ts +49 -0
- package/src/crypto-node.ts +40 -0
- package/src/crypto.ts +10 -0
- package/src/errors.ts +154 -0
- package/src/http.ts +209 -0
- package/src/index.browser.ts +110 -0
- package/src/index.ts +134 -0
- package/src/keys.ts +18 -0
- package/src/models.ts +558 -0
- package/src/pagination.ts +64 -0
- package/src/verify.ts +956 -0
- package/src/web-verifier.ts +89 -0
- package/src/webhooks.ts +76 -0
package/src/models.ts
ADDED
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
/** Readonly interfaces and parser functions for all BurnLedger API types.
|
|
2
|
+
*
|
|
3
|
+
* String literal unions for enums (no runtime cost).
|
|
4
|
+
* Parser functions are pure — snake_case JSON to camelCase with Date parsing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Enum types (string literal unions)
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
export type ProofMode = "count" | "merkle";
|
|
12
|
+
export type AttestationStatus =
|
|
13
|
+
| "PENDING_VERIFICATION"
|
|
14
|
+
| "VERIFICATION_FAILED"
|
|
15
|
+
| "CERTIFIED";
|
|
16
|
+
export type CertificateStatus = "ACTIVE" | "REVOKED";
|
|
17
|
+
export type TransparencyStatus = "INCLUDED" | "PENDING" | "FAILED";
|
|
18
|
+
export type HealthStatus = "HEALTHY" | "UNHEALTHY" | "UNKNOWN";
|
|
19
|
+
/** Transport a system's connection achieves, classified at registration.
|
|
20
|
+
*
|
|
21
|
+
* Under "plaintext" and "encrypted" (TLS whose certificate is never verified)
|
|
22
|
+
* an on-path attacker can alter the record count this system contributes to a
|
|
23
|
+
* certificate. "unknown" means the config could not be classified, and is
|
|
24
|
+
* never to be read as secure.
|
|
25
|
+
*/
|
|
26
|
+
export type TransportSecurity =
|
|
27
|
+
| "unknown"
|
|
28
|
+
| "plaintext"
|
|
29
|
+
| "encrypted"
|
|
30
|
+
| "verified";
|
|
31
|
+
/**
|
|
32
|
+
* How BurnLedger established that a system's credential cannot write.
|
|
33
|
+
*
|
|
34
|
+
* Every connector refuses write-capable credentials, but they do not all
|
|
35
|
+
* establish it the same way, and the difference is evidentiary.
|
|
36
|
+
* "verified_by_introspection" means the engine's own privilege catalog was
|
|
37
|
+
* queried and showed no write capability — evidence an auditor can re-derive.
|
|
38
|
+
* "operator_asserted" means no privilege introspection was available and the
|
|
39
|
+
* credential was admitted on the read_only flag in the connector config, which
|
|
40
|
+
* is a management attestation and is exactly what California's proposed CPPA
|
|
41
|
+
* audit rule (11 CCR 7632(d)) will not let an audit finding rest on.
|
|
42
|
+
* "write_access_detected" means the credential CAN write. "unknown" means
|
|
43
|
+
* nothing was established — never read it as a guarantee.
|
|
44
|
+
*/
|
|
45
|
+
export type ReadOnlyEnforcement =
|
|
46
|
+
| "unknown"
|
|
47
|
+
| "verified_by_introspection"
|
|
48
|
+
| "operator_asserted"
|
|
49
|
+
| "write_access_detected";
|
|
50
|
+
// Every connector the server accepts (core/types.go). This list was six entries
|
|
51
|
+
// long and included "custom", which the server rejects — so the dashboard could
|
|
52
|
+
// not offer a connector picker without colliding with its own SDK on the first
|
|
53
|
+
// render.
|
|
54
|
+
export type ConnectorType =
|
|
55
|
+
| "postgresql"
|
|
56
|
+
| "mysql"
|
|
57
|
+
| "sqlserver"
|
|
58
|
+
| "oracle"
|
|
59
|
+
| "redshift"
|
|
60
|
+
| "teradata"
|
|
61
|
+
| "snowflake"
|
|
62
|
+
| "databricks"
|
|
63
|
+
| "mongodb"
|
|
64
|
+
| "neo4j"
|
|
65
|
+
| "redis"
|
|
66
|
+
| "cassandra"
|
|
67
|
+
| "hbase"
|
|
68
|
+
| "marklogic"
|
|
69
|
+
| "elasticsearch"
|
|
70
|
+
| "s3"
|
|
71
|
+
| "dynamodb"
|
|
72
|
+
| "gcs"
|
|
73
|
+
| "bigquery"
|
|
74
|
+
| "azure_blob";
|
|
75
|
+
export type HashScope = "full" | "existence";
|
|
76
|
+
export type LogEntryType = "CERTIFICATE" | "REVOCATION";
|
|
77
|
+
|
|
78
|
+
/** Result of offline certificate signature verification. */
|
|
79
|
+
export type VerificationResult = "VALID" | "INVALID";
|
|
80
|
+
|
|
81
|
+
/** Result of transparency proof verification. */
|
|
82
|
+
export type TransparencyResult = "INCLUDED" | "INVALID" | "NOT_AVAILABLE";
|
|
83
|
+
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Model interfaces
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
export interface System {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly name: string;
|
|
91
|
+
readonly connectorType: ConnectorType;
|
|
92
|
+
readonly subjectQuery: string;
|
|
93
|
+
readonly hashScope: HashScope;
|
|
94
|
+
readonly maxRecords: number;
|
|
95
|
+
readonly maxBytes: number;
|
|
96
|
+
readonly queryTimeout: string;
|
|
97
|
+
readonly createdAt: Date;
|
|
98
|
+
readonly healthStatus: HealthStatus;
|
|
99
|
+
readonly healthCheckedAt: Date | undefined;
|
|
100
|
+
readonly healthError: string | undefined;
|
|
101
|
+
readonly transportSecurity: TransportSecurity;
|
|
102
|
+
readonly readOnlyEnforcement: ReadOnlyEnforcement;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface SystemAttestation {
|
|
106
|
+
readonly systemId: string;
|
|
107
|
+
readonly systemName: string;
|
|
108
|
+
readonly recordCount: number;
|
|
109
|
+
readonly hashScope: HashScope;
|
|
110
|
+
readonly observedAt: Date;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface Attestation {
|
|
114
|
+
readonly id: string;
|
|
115
|
+
readonly subjectHash: string;
|
|
116
|
+
readonly proofMode: ProofMode;
|
|
117
|
+
readonly status: AttestationStatus;
|
|
118
|
+
readonly systems: readonly SystemAttestation[];
|
|
119
|
+
readonly attestedAt: Date;
|
|
120
|
+
readonly expiresAt: Date;
|
|
121
|
+
readonly certificateId: string | undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface VerificationSystem {
|
|
125
|
+
readonly systemId: string;
|
|
126
|
+
readonly systemName: string;
|
|
127
|
+
readonly recordCount: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface VerifyResult {
|
|
131
|
+
readonly attestationId: string;
|
|
132
|
+
readonly status: AttestationStatus;
|
|
133
|
+
readonly systems: readonly VerificationSystem[];
|
|
134
|
+
readonly certificate: CertificateResponse | undefined;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface CertificateResponse {
|
|
138
|
+
readonly id: string;
|
|
139
|
+
readonly attestationId: string;
|
|
140
|
+
readonly formatVersion: string;
|
|
141
|
+
readonly issuedAt: Date;
|
|
142
|
+
readonly status: CertificateStatus;
|
|
143
|
+
readonly transparencyStatus: TransparencyStatus;
|
|
144
|
+
readonly revokedAt: Date | undefined;
|
|
145
|
+
readonly revocationReason: string | undefined;
|
|
146
|
+
readonly certificate: Record<string, unknown>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface RevocationStatus {
|
|
150
|
+
readonly certificateId: string;
|
|
151
|
+
readonly status: CertificateStatus;
|
|
152
|
+
readonly revokedAt: Date | undefined;
|
|
153
|
+
readonly reason: string | undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface Webhook {
|
|
157
|
+
readonly id: string;
|
|
158
|
+
readonly url: string;
|
|
159
|
+
readonly secret: string | undefined;
|
|
160
|
+
readonly createdAt: Date;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface SignedTreeHead {
|
|
164
|
+
readonly treeSize: number;
|
|
165
|
+
readonly rootHash: string;
|
|
166
|
+
readonly timestamp: Date;
|
|
167
|
+
readonly signature: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface LogEntry {
|
|
171
|
+
readonly index: number;
|
|
172
|
+
readonly entryType: LogEntryType;
|
|
173
|
+
readonly certificateId: string;
|
|
174
|
+
readonly hash: string;
|
|
175
|
+
readonly appendedAt: Date;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface InclusionProof {
|
|
179
|
+
readonly index: number;
|
|
180
|
+
readonly treeSize: number;
|
|
181
|
+
readonly inclusionProof: readonly string[];
|
|
182
|
+
readonly signedTreeHead: SignedTreeHead;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface ConsistencyProof {
|
|
186
|
+
readonly oldSize: number;
|
|
187
|
+
readonly newSize: number;
|
|
188
|
+
readonly proof: readonly string[];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Profile types
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
|
|
195
|
+
export interface PlanUsage {
|
|
196
|
+
readonly certificatesUsed: number;
|
|
197
|
+
readonly certificatesLimit: number;
|
|
198
|
+
readonly systemsUsed: number;
|
|
199
|
+
readonly systemsLimit: number;
|
|
200
|
+
readonly trialExpiresAt: string | undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface Profile {
|
|
204
|
+
readonly id: string;
|
|
205
|
+
readonly name: string;
|
|
206
|
+
readonly email: string;
|
|
207
|
+
readonly plan: string;
|
|
208
|
+
readonly planStartedAt: string | undefined;
|
|
209
|
+
readonly createdAt: string;
|
|
210
|
+
readonly planUsage: PlanUsage | undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// System health types
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
|
|
217
|
+
export interface SystemHealth {
|
|
218
|
+
readonly systemId: string;
|
|
219
|
+
readonly status: HealthStatus;
|
|
220
|
+
readonly lastCheckAt: string | undefined;
|
|
221
|
+
readonly error: string | undefined;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
// Batch attestation types
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
|
|
228
|
+
export interface BatchAttestationResponse {
|
|
229
|
+
readonly attestations: readonly Attestation[];
|
|
230
|
+
readonly errors: readonly BatchAttestationError[];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface BatchAttestationError {
|
|
234
|
+
readonly subjectIdentifier: string;
|
|
235
|
+
readonly error: string;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// Certificate stats types
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
export interface MonthlyCount {
|
|
243
|
+
readonly month: string;
|
|
244
|
+
readonly count: number;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface CertificateStats {
|
|
248
|
+
readonly total: number;
|
|
249
|
+
readonly active: number;
|
|
250
|
+
readonly revoked: number;
|
|
251
|
+
readonly transparencyIncluded: number;
|
|
252
|
+
readonly transparencyPending: number;
|
|
253
|
+
/** Certificates that will never be logged. Absent from older servers, 0 then. */
|
|
254
|
+
readonly transparencyFailed: number;
|
|
255
|
+
readonly issuedLast30Days: number;
|
|
256
|
+
readonly monthlyIssuance: readonly MonthlyCount[];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// Webhook delivery types
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
export interface WebhookRotateResponse {
|
|
264
|
+
readonly id: string;
|
|
265
|
+
readonly url: string;
|
|
266
|
+
readonly newSecret: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface WebhookDelivery {
|
|
270
|
+
readonly id: string;
|
|
271
|
+
readonly webhookId: string;
|
|
272
|
+
readonly eventType: string;
|
|
273
|
+
readonly errorMessage: string;
|
|
274
|
+
readonly attempts: number;
|
|
275
|
+
readonly createdAt: Date;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// API key types
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
|
|
282
|
+
export type ApiKeyRole = "read_only" | "read_write";
|
|
283
|
+
|
|
284
|
+
export interface ApiKeyListItem {
|
|
285
|
+
readonly id: string;
|
|
286
|
+
readonly prefix: string;
|
|
287
|
+
readonly role: ApiKeyRole;
|
|
288
|
+
readonly createdAt: Date;
|
|
289
|
+
readonly revokedAt: Date | undefined;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface ApiKeyResponse {
|
|
293
|
+
readonly id: string;
|
|
294
|
+
readonly prefix: string;
|
|
295
|
+
readonly key: string;
|
|
296
|
+
readonly createdAt: Date;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
// Timestamp parsing
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
|
|
303
|
+
function parseDt(raw: string): Date {
|
|
304
|
+
return new Date(raw);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function parseDtOpt(raw: string | null | undefined): Date | undefined {
|
|
308
|
+
if (raw == null) return undefined;
|
|
309
|
+
return parseDt(raw);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ---------------------------------------------------------------------------
|
|
313
|
+
// Parsers — one per type, pure dict → interface
|
|
314
|
+
// ---------------------------------------------------------------------------
|
|
315
|
+
|
|
316
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
317
|
+
type Raw = Record<string, any>;
|
|
318
|
+
|
|
319
|
+
export function parseSystem(d: Raw): System {
|
|
320
|
+
return {
|
|
321
|
+
id: d.id,
|
|
322
|
+
name: d.name,
|
|
323
|
+
connectorType: d.connector_type as ConnectorType,
|
|
324
|
+
subjectQuery: d.subject_query,
|
|
325
|
+
hashScope: d.hash_scope as HashScope,
|
|
326
|
+
maxRecords: d.max_records,
|
|
327
|
+
maxBytes: d.max_bytes,
|
|
328
|
+
queryTimeout: d.query_timeout,
|
|
329
|
+
createdAt: parseDt(d.created_at),
|
|
330
|
+
healthStatus: (d.health_status ?? "UNKNOWN") as HealthStatus,
|
|
331
|
+
healthCheckedAt: parseDtOpt(d.health_checked_at),
|
|
332
|
+
healthError: d.health_error ?? undefined,
|
|
333
|
+
// A server too old to classify the transport has not measured it, so the
|
|
334
|
+
// absent field is "unknown" and never "verified".
|
|
335
|
+
transportSecurity: (d.transport_security ?? "unknown") as TransportSecurity,
|
|
336
|
+
// A server too old to record how the read-only guarantee was established
|
|
337
|
+
// has established nothing, so the absent field is "unknown" and never
|
|
338
|
+
// "verified_by_introspection".
|
|
339
|
+
readOnlyEnforcement: (d.read_only_enforcement ?? "unknown") as ReadOnlyEnforcement,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function parseSystemAttestation(d: Raw): SystemAttestation {
|
|
344
|
+
return {
|
|
345
|
+
systemId: d.system_id,
|
|
346
|
+
systemName: d.system_name,
|
|
347
|
+
recordCount: d.record_count,
|
|
348
|
+
hashScope: d.hash_scope as HashScope,
|
|
349
|
+
observedAt: parseDt(d.observed_at),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export function parseAttestation(d: Raw): Attestation {
|
|
354
|
+
return {
|
|
355
|
+
id: d.id,
|
|
356
|
+
subjectHash: d.subject_hash,
|
|
357
|
+
proofMode: d.proof_mode as ProofMode,
|
|
358
|
+
status: d.status as AttestationStatus,
|
|
359
|
+
systems: (d.systems ?? []).map(parseSystemAttestation),
|
|
360
|
+
attestedAt: parseDt(d.attested_at),
|
|
361
|
+
expiresAt: parseDt(d.expires_at),
|
|
362
|
+
certificateId: d.certificate_id ?? undefined,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function parseVerificationSystem(d: Raw): VerificationSystem {
|
|
367
|
+
return {
|
|
368
|
+
systemId: d.system_id,
|
|
369
|
+
systemName: d.system_name,
|
|
370
|
+
recordCount: d.record_count,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function parseVerifyResult(d: Raw): VerifyResult {
|
|
375
|
+
return {
|
|
376
|
+
attestationId: d.attestation_id,
|
|
377
|
+
status: d.status as AttestationStatus,
|
|
378
|
+
systems: (d.systems ?? []).map(parseVerificationSystem),
|
|
379
|
+
certificate: d.certificate
|
|
380
|
+
? parseCertificateResponse(d.certificate)
|
|
381
|
+
: undefined,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export function parseCertificateResponse(d: Raw): CertificateResponse {
|
|
386
|
+
return {
|
|
387
|
+
id: d.id,
|
|
388
|
+
attestationId: d.attestation_id,
|
|
389
|
+
formatVersion: d.format_version,
|
|
390
|
+
issuedAt: parseDt(d.issued_at),
|
|
391
|
+
status: d.status as CertificateStatus,
|
|
392
|
+
transparencyStatus: d.transparency_status as TransparencyStatus,
|
|
393
|
+
revokedAt: parseDtOpt(d.revoked_at),
|
|
394
|
+
revocationReason: d.revocation_reason ?? undefined,
|
|
395
|
+
certificate: d.certificate,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export function parseRevocationStatus(d: Raw): RevocationStatus {
|
|
400
|
+
return {
|
|
401
|
+
certificateId: d.certificate_id,
|
|
402
|
+
status: d.status as CertificateStatus,
|
|
403
|
+
revokedAt: parseDtOpt(d.revoked_at),
|
|
404
|
+
reason: d.reason ?? undefined,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export function parseWebhook(d: Raw): Webhook {
|
|
409
|
+
return {
|
|
410
|
+
id: d.id,
|
|
411
|
+
url: d.url,
|
|
412
|
+
secret: d.secret ?? undefined,
|
|
413
|
+
createdAt: parseDt(d.created_at),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export function parseSignedTreeHead(d: Raw): SignedTreeHead {
|
|
418
|
+
return {
|
|
419
|
+
treeSize: d.tree_size,
|
|
420
|
+
rootHash: d.root_hash,
|
|
421
|
+
timestamp: parseDt(d.timestamp),
|
|
422
|
+
signature: d.signature,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export function parseLogEntry(d: Raw): LogEntry {
|
|
427
|
+
return {
|
|
428
|
+
index: d.index,
|
|
429
|
+
entryType: d.entry_type as LogEntryType,
|
|
430
|
+
certificateId: d.certificate_id,
|
|
431
|
+
hash: d.hash,
|
|
432
|
+
appendedAt: parseDt(d.appended_at),
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export function parseInclusionProof(d: Raw): InclusionProof {
|
|
437
|
+
return {
|
|
438
|
+
index: d.index,
|
|
439
|
+
treeSize: d.tree_size,
|
|
440
|
+
inclusionProof: d.inclusion_proof ?? [],
|
|
441
|
+
signedTreeHead: parseSignedTreeHead(d.signed_tree_head),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export function parseConsistencyProof(d: Raw): ConsistencyProof {
|
|
446
|
+
return {
|
|
447
|
+
oldSize: d.old_size,
|
|
448
|
+
newSize: d.new_size,
|
|
449
|
+
proof: d.proof ?? [],
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function parseBatchAttestationError(d: Raw): BatchAttestationError {
|
|
454
|
+
return {
|
|
455
|
+
subjectIdentifier: d.subject_identifier,
|
|
456
|
+
error: d.error,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export function parseBatchAttestationResponse(d: Raw): BatchAttestationResponse {
|
|
461
|
+
return {
|
|
462
|
+
attestations: (d.attestations ?? []).map(parseAttestation),
|
|
463
|
+
errors: (d.errors ?? []).map(parseBatchAttestationError),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function parseMonthlyCount(d: Raw): MonthlyCount {
|
|
468
|
+
return {
|
|
469
|
+
month: d.month,
|
|
470
|
+
count: d.count,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export function parseCertificateStats(d: Raw): CertificateStats {
|
|
475
|
+
return {
|
|
476
|
+
total: d.total,
|
|
477
|
+
active: d.active,
|
|
478
|
+
revoked: d.revoked,
|
|
479
|
+
transparencyIncluded: d.transparency_included,
|
|
480
|
+
transparencyPending: d.transparency_pending,
|
|
481
|
+
transparencyFailed: (d.transparency_failed as number | undefined) ?? 0,
|
|
482
|
+
issuedLast30Days: d.issued_last_30_days,
|
|
483
|
+
monthlyIssuance: (d.monthly_issuance ?? []).map(parseMonthlyCount),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export function parseWebhookRotateResponse(d: Raw): WebhookRotateResponse {
|
|
488
|
+
return {
|
|
489
|
+
id: d.id,
|
|
490
|
+
url: d.url,
|
|
491
|
+
newSecret: d.new_secret,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export function parseWebhookDelivery(d: Raw): WebhookDelivery {
|
|
496
|
+
return {
|
|
497
|
+
id: d.id,
|
|
498
|
+
webhookId: d.webhook_id,
|
|
499
|
+
eventType: d.event_type,
|
|
500
|
+
errorMessage: d.error_message,
|
|
501
|
+
attempts: d.attempts,
|
|
502
|
+
createdAt: parseDt(d.created_at),
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export function parseApiKeyListItem(d: Raw): ApiKeyListItem {
|
|
507
|
+
return {
|
|
508
|
+
id: d.id,
|
|
509
|
+
prefix: d.prefix,
|
|
510
|
+
role: d.role as ApiKeyRole,
|
|
511
|
+
createdAt: parseDt(d.created_at),
|
|
512
|
+
revokedAt: parseDtOpt(d.revoked_at),
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export function parseApiKeyResponse(d: Raw): ApiKeyResponse {
|
|
517
|
+
return {
|
|
518
|
+
id: d.id,
|
|
519
|
+
prefix: d.prefix,
|
|
520
|
+
key: d.key,
|
|
521
|
+
createdAt: parseDt(d.created_at),
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// ---------------------------------------------------------------------------
|
|
526
|
+
// Profile / SystemHealth parsers
|
|
527
|
+
// ---------------------------------------------------------------------------
|
|
528
|
+
|
|
529
|
+
function parsePlanUsage(d: Raw): PlanUsage {
|
|
530
|
+
return {
|
|
531
|
+
certificatesUsed: d.certificates_used,
|
|
532
|
+
certificatesLimit: d.certificates_limit,
|
|
533
|
+
systemsUsed: d.systems_used,
|
|
534
|
+
systemsLimit: d.systems_limit,
|
|
535
|
+
trialExpiresAt: d.trial_expires_at ?? undefined,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export function parseProfile(d: Raw): Profile {
|
|
540
|
+
return {
|
|
541
|
+
id: d.id,
|
|
542
|
+
name: d.name,
|
|
543
|
+
email: d.email,
|
|
544
|
+
plan: d.plan,
|
|
545
|
+
planStartedAt: d.plan_started_at ?? undefined,
|
|
546
|
+
createdAt: d.created_at,
|
|
547
|
+
planUsage: d.plan_usage ? parsePlanUsage(d.plan_usage) : undefined,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export function parseSystemHealth(d: Raw): SystemHealth {
|
|
552
|
+
return {
|
|
553
|
+
systemId: d.system_id,
|
|
554
|
+
status: d.status as HealthStatus,
|
|
555
|
+
lastCheckAt: d.last_check_at ?? undefined,
|
|
556
|
+
error: d.error ?? undefined,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Cursor-based auto-pagination using AsyncIterable.
|
|
2
|
+
*
|
|
3
|
+
* Lazily fetches pages on first iteration and follows `next_cursor`
|
|
4
|
+
* until the server omits it.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Transport } from "./http.js";
|
|
8
|
+
|
|
9
|
+
type Raw = Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
export class Paginator<T> implements AsyncIterable<T> {
|
|
12
|
+
private readonly transport: Transport;
|
|
13
|
+
private readonly path: string;
|
|
14
|
+
private readonly parser: (d: Raw) => T;
|
|
15
|
+
private readonly params: Record<string, string | number>;
|
|
16
|
+
private readonly authenticated: boolean;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
transport: Transport,
|
|
20
|
+
path: string,
|
|
21
|
+
parser: (d: Raw) => T,
|
|
22
|
+
opts: {
|
|
23
|
+
params: Record<string, string | number>;
|
|
24
|
+
authenticated?: boolean;
|
|
25
|
+
},
|
|
26
|
+
) {
|
|
27
|
+
this.transport = transport;
|
|
28
|
+
this.path = path;
|
|
29
|
+
this.parser = parser;
|
|
30
|
+
this.params = opts.params;
|
|
31
|
+
this.authenticated = opts.authenticated ?? true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async *[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
|
35
|
+
let cursor: string | undefined;
|
|
36
|
+
let started = false;
|
|
37
|
+
|
|
38
|
+
while (true) {
|
|
39
|
+
const params: Record<string, string | number> = { ...this.params };
|
|
40
|
+
if (cursor !== undefined) {
|
|
41
|
+
params["cursor"] = cursor;
|
|
42
|
+
} else if (started) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const envelope = await this.transport.requestRaw("GET", this.path, {
|
|
47
|
+
params,
|
|
48
|
+
authenticated: this.authenticated,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const items = (envelope.data ?? []) as Raw[];
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
yield this.parser(item);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
cursor = envelope.next_cursor as string | undefined;
|
|
57
|
+
started = true;
|
|
58
|
+
|
|
59
|
+
if (cursor == null) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|