@zksecurity/zkao-sdk 0.1.0 → 0.2.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/dist/index.d.ts CHANGED
@@ -91,7 +91,8 @@ interface paths {
91
91
  * @description Requires scope: `scans:launch`. Reserves `creditBudget` credits from the
92
92
  * project balance. The repo must be in the token's allowlist (when set) and
93
93
  * ACTIVE. Discover valid `presetRef` / `optInFlowIds` via the discovery
94
- * endpoints. Per-token spend limits and the project plan are enforced.
94
+ * endpoints. Per-token spend limits are enforced, and the project must have
95
+ * enough prepaid credits to cover the budget (otherwise `402`).
95
96
  */
96
97
  post: operations["launchScan"];
97
98
  delete?: never;
@@ -340,13 +341,111 @@ interface paths {
340
341
  patch?: never;
341
342
  trace?: never;
342
343
  };
344
+ "/projects/{projectId}/billing/balance": {
345
+ parameters: {
346
+ query?: never;
347
+ header?: never;
348
+ path?: never;
349
+ cookie?: never;
350
+ };
351
+ /**
352
+ * Current prepaid credit balance
353
+ * @description Requires scope: `read`. All amounts are in credits.
354
+ */
355
+ get: operations["getBillingBalance"];
356
+ put?: never;
357
+ post?: never;
358
+ delete?: never;
359
+ options?: never;
360
+ head?: never;
361
+ patch?: never;
362
+ trace?: never;
363
+ };
364
+ "/projects/{projectId}/billing/usage": {
365
+ parameters: {
366
+ query?: never;
367
+ header?: never;
368
+ path?: never;
369
+ cookie?: never;
370
+ };
371
+ /**
372
+ * Credit usage events
373
+ * @description Requires scope: `read`. Signed credit delta per ledger event. Defaults to the last 30 days; newest first; max 1000 rows.
374
+ */
375
+ get: operations["getBillingUsage"];
376
+ put?: never;
377
+ post?: never;
378
+ delete?: never;
379
+ options?: never;
380
+ head?: never;
381
+ patch?: never;
382
+ trace?: never;
383
+ };
384
+ "/projects/{projectId}/billing/summary": {
385
+ parameters: {
386
+ query?: never;
387
+ header?: never;
388
+ path?: never;
389
+ cookie?: never;
390
+ };
391
+ /**
392
+ * Monthly spend and purchase summary
393
+ * @description Requires scope: `read`. Per-month net scan spend and net purchases, in credits, newest first.
394
+ */
395
+ get: operations["getBillingSummary"];
396
+ put?: never;
397
+ post?: never;
398
+ delete?: never;
399
+ options?: never;
400
+ head?: never;
401
+ patch?: never;
402
+ trace?: never;
403
+ };
343
404
  }
344
405
  interface components {
345
406
  schemas: {
407
+ BillingBalance: {
408
+ /** @description Total prepaid credit balance. */
409
+ balanceCredits: number;
410
+ /** @description Balance minus credits reserved by in-flight scans. */
411
+ availableCredits: number;
412
+ /** @description Credits held by queued/running scans. */
413
+ reservedCredits: number;
414
+ };
415
+ /** @enum {string} */
416
+ UsageEventType: "SCAN_DEDUCTION" | "SCAN_REFUND" | "PURCHASE" | "STRIPE_REFUND" | "ADMIN_ADJUSTMENT";
417
+ UsageEvent: {
418
+ id: string;
419
+ /** Format: date-time */
420
+ at: string;
421
+ type: components["schemas"]["UsageEventType"];
422
+ /** @description Signed credit delta: negative = spent/clawed back, positive = added/refunded. */
423
+ credits: number;
424
+ scanId: string | null;
425
+ description: string;
426
+ };
427
+ BillingUsage: {
428
+ /** Format: date-time */
429
+ from: string;
430
+ /** Format: date-time */
431
+ to: string;
432
+ events: components["schemas"]["UsageEvent"][];
433
+ };
434
+ UsageMonthSummary: {
435
+ /** @description YYYY-MM (UTC). */
436
+ month: string;
437
+ /** @description Net scan spend (deductions less refunds), in credits. */
438
+ spentCredits: number;
439
+ /** @description Net purchases (purchases less clawbacks), in credits. */
440
+ purchasedCredits: number;
441
+ };
442
+ BillingSummary: {
443
+ months: components["schemas"]["UsageMonthSummary"][];
444
+ };
346
445
  Error: {
347
446
  error: {
348
447
  /** @enum {string} */
349
- code: "unauthorized" | "forbidden" | "not_found" | "bad_request" | "conflict" | "plan_inactive" | "rate_limited" | "internal";
448
+ code: "unauthorized" | "forbidden" | "not_found" | "bad_request" | "conflict" | "insufficient_credits" | "rate_limited" | "internal";
350
449
  message: string;
351
450
  };
352
451
  };
@@ -380,6 +479,17 @@ interface components {
380
479
  startedAt?: string | null;
381
480
  /** Format: date-time */
382
481
  completedAt?: string | null;
482
+ /** @description Phase progress while the scan is in flight. Null once the scan reaches a terminal state, and null before it has been dispatched (no phases exist yet). */
483
+ progress?: components["schemas"]["ScanProgress"] | null;
484
+ };
485
+ /** @description How far a running scan has got through its phases. Deliberately not a time estimate: a phase's duration moves with the guidance it was given, the repository, and the model that ran it. */
486
+ ScanProgress: {
487
+ /** @description Phases that reached a terminal state (completed, failed, or skipped). */
488
+ phasesCompleted: number;
489
+ /** @description Phases this scan will run, fixed when it was dispatched. */
490
+ phasesTotal: number;
491
+ /** @description Weighted completion. Each phase counts for its share of the scan budget, so this does not simply equal phasesCompleted / phasesTotal. */
492
+ percent: number;
383
493
  };
384
494
  ScanDetail: components["schemas"]["Scan"] & {
385
495
  branch?: string | null;
@@ -532,6 +642,14 @@ interface components {
532
642
  findingId: string;
533
643
  resolutionStatus: components["schemas"]["ResolutionStatus"];
534
644
  };
645
+ /**
646
+ * @description Short code for why a finding is being closed, chosen from the set offered for the `resolutionStatus` it is sent with; a code belonging to a different status is rejected with 400. Ignored for the open statuses (`NOT_STARTED`, `IN_PROGRESS`) and when `note` is also given. It is not stored as a field: it is recorded as a comment on the finding stating what was chosen, which is returned by the notes endpoints.
647
+ *
648
+ * Codes per status. `RESOLVED`: fixed_in_code, fixed_upstream, code_removed. `MITIGATED`: compensating_control, limited_exposure, monitored. `FALSE_POSITIVE`: not_reachable, guarded_elsewhere, intended_behavior, misread_code, bad_assumption. `WONT_FIX`: risk_accepted, out_of_scope, not_worth_fixing, code_being_removed. `DUPLICATE`: duplicate_of_finding, same_root_cause.
649
+ * @example not_reachable
650
+ * @enum {string}
651
+ */
652
+ ResolutionReason: "fixed_in_code" | "fixed_upstream" | "code_removed" | "compensating_control" | "limited_exposure" | "monitored" | "not_reachable" | "guarded_elsewhere" | "intended_behavior" | "misread_code" | "bad_assumption" | "risk_accepted" | "out_of_scope" | "not_worth_fixing" | "code_being_removed" | "duplicate_of_finding" | "same_root_cause";
535
653
  PublishFindingRequest: {
536
654
  /** @description A note id on the finding to pin as the published note. */
537
655
  noteId?: string;
@@ -569,6 +687,15 @@ interface components {
569
687
  "application/json": components["schemas"]["Error"];
570
688
  };
571
689
  };
690
+ /** @description The project does not have enough prepaid credits to cover the scan budget. Top up credits and retry. (code `insufficient_credits`) */
691
+ InsufficientCredits: {
692
+ headers: {
693
+ [name: string]: unknown;
694
+ };
695
+ content: {
696
+ "application/json": components["schemas"]["Error"];
697
+ };
698
+ };
572
699
  /** @description The token lacks the required scope */
573
700
  Forbidden: {
574
701
  headers: {
@@ -760,6 +887,7 @@ interface operations {
760
887
  };
761
888
  400: components["responses"]["BadRequest"];
762
889
  401: components["responses"]["Unauthorized"];
890
+ 402: components["responses"]["InsufficientCredits"];
763
891
  403: components["responses"]["Forbidden"];
764
892
  404: components["responses"]["NotFound"];
765
893
  429: components["responses"]["RateLimited"];
@@ -1000,6 +1128,7 @@ interface operations {
1000
1128
  "application/json": {
1001
1129
  resolutionStatus: components["schemas"]["ResolutionStatus"];
1002
1130
  note?: components["schemas"]["ChangeNote"];
1131
+ reason?: components["schemas"]["ResolutionReason"];
1003
1132
  };
1004
1133
  };
1005
1134
  };
@@ -1135,6 +1264,88 @@ interface operations {
1135
1264
  404: components["responses"]["NotFound"];
1136
1265
  };
1137
1266
  };
1267
+ getBillingBalance: {
1268
+ parameters: {
1269
+ query?: never;
1270
+ header?: never;
1271
+ path: {
1272
+ projectId: components["parameters"]["ProjectId"];
1273
+ };
1274
+ cookie?: never;
1275
+ };
1276
+ requestBody?: never;
1277
+ responses: {
1278
+ /** @description OK */
1279
+ 200: {
1280
+ headers: {
1281
+ [name: string]: unknown;
1282
+ };
1283
+ content: {
1284
+ "application/json": components["schemas"]["BillingBalance"];
1285
+ };
1286
+ };
1287
+ 401: components["responses"]["Unauthorized"];
1288
+ 403: components["responses"]["Forbidden"];
1289
+ 404: components["responses"]["NotFound"];
1290
+ };
1291
+ };
1292
+ getBillingUsage: {
1293
+ parameters: {
1294
+ query?: {
1295
+ from?: string;
1296
+ to?: string;
1297
+ limit?: number;
1298
+ };
1299
+ header?: never;
1300
+ path: {
1301
+ projectId: components["parameters"]["ProjectId"];
1302
+ };
1303
+ cookie?: never;
1304
+ };
1305
+ requestBody?: never;
1306
+ responses: {
1307
+ /** @description OK */
1308
+ 200: {
1309
+ headers: {
1310
+ [name: string]: unknown;
1311
+ };
1312
+ content: {
1313
+ "application/json": components["schemas"]["BillingUsage"];
1314
+ };
1315
+ };
1316
+ 400: components["responses"]["BadRequest"];
1317
+ 401: components["responses"]["Unauthorized"];
1318
+ 403: components["responses"]["Forbidden"];
1319
+ 404: components["responses"]["NotFound"];
1320
+ };
1321
+ };
1322
+ getBillingSummary: {
1323
+ parameters: {
1324
+ query?: {
1325
+ months?: number;
1326
+ };
1327
+ header?: never;
1328
+ path: {
1329
+ projectId: components["parameters"]["ProjectId"];
1330
+ };
1331
+ cookie?: never;
1332
+ };
1333
+ requestBody?: never;
1334
+ responses: {
1335
+ /** @description OK */
1336
+ 200: {
1337
+ headers: {
1338
+ [name: string]: unknown;
1339
+ };
1340
+ content: {
1341
+ "application/json": components["schemas"]["BillingSummary"];
1342
+ };
1343
+ };
1344
+ 401: components["responses"]["Unauthorized"];
1345
+ 403: components["responses"]["Forbidden"];
1346
+ 404: components["responses"]["NotFound"];
1347
+ };
1348
+ };
1138
1349
  }
1139
1350
 
1140
1351
  type Schemas = components["schemas"];
@@ -1152,11 +1363,18 @@ type CancelScanResult = Schemas["CancelScanResult"];
1152
1363
  type ChangeNote = Schemas["ChangeNote"];
1153
1364
  type Severity = Schemas["Severity"];
1154
1365
  type ResolutionStatus = Schemas["ResolutionStatus"];
1366
+ type ResolutionReason = Schemas["ResolutionReason"];
1155
1367
  type TriageStatus = Schemas["TriageStatus"];
1156
1368
  type ScanStatus = Schemas["ScanStatus"];
1157
1369
  type PublishArtifactResult = Schemas["PublishArtifactResult"];
1158
1370
  type RepositoryGuidance = Schemas["RepositoryGuidance"];
1159
1371
  type SetGuidanceResult = Schemas["SetGuidanceResult"];
1372
+ type BillingBalance = Schemas["BillingBalance"];
1373
+ type BillingUsage = Schemas["BillingUsage"];
1374
+ type UsageEvent = Schemas["UsageEvent"];
1375
+ type UsageEventType = Schemas["UsageEventType"];
1376
+ type BillingSummary = Schemas["BillingSummary"];
1377
+ type UsageMonthSummary = Schemas["UsageMonthSummary"];
1160
1378
  type Paginated<T> = {
1161
1379
  items: T[];
1162
1380
  page: number;
@@ -1263,7 +1481,19 @@ declare class ZkaoClient {
1263
1481
  userSeverity?: Severity | null;
1264
1482
  effectiveSeverity: Severity;
1265
1483
  }>;
1266
- setFindingResolution(findingId: string, resolutionStatus: ResolutionStatus, note?: ChangeNote): Promise<{
1484
+ /**
1485
+ * Change a finding's resolution status (requires the `findings:write` scope).
1486
+ *
1487
+ * `note` attaches free text in the same call. `reason` picks a catalog code
1488
+ * instead, recorded as a generated comment; the codes offered depend on the
1489
+ * status, and a code from another status is rejected with 400. A `note` takes
1490
+ * precedence: pass one or the other. Both are ignored for the open statuses
1491
+ * (`NOT_STARTED`, `IN_PROGRESS`).
1492
+ */
1493
+ setFindingResolution(findingId: string, resolutionStatus: ResolutionStatus, opts?: {
1494
+ note?: ChangeNote;
1495
+ reason?: ResolutionReason;
1496
+ }): Promise<{
1267
1497
  findingId: string;
1268
1498
  resolutionStatus: ResolutionStatus;
1269
1499
  }>;
@@ -1273,6 +1503,31 @@ declare class ZkaoClient {
1273
1503
  }): Promise<PublishArtifactResult>;
1274
1504
  listScanPresets(): Promise<ScanPreset[]>;
1275
1505
  listOptionalFlows(): Promise<OptionalFlow[]>;
1506
+ /**
1507
+ * Get the project's prepaid credit balance (requires the `read` scope). zkao
1508
+ * is pay-as-you-go: `balanceCredits` is the total, `reservedCredits` is held
1509
+ * by active scans, and `availableCredits` is what remains for new scans.
1510
+ */
1511
+ getBillingBalance(): Promise<BillingBalance>;
1512
+ /**
1513
+ * List credit-ledger movements for reconciliation (requires the `read`
1514
+ * scope). `credits` on each event is signed (negative = spent). Defaults to
1515
+ * the last 30 days when `from`/`to` are omitted; the range actually used is
1516
+ * echoed back on the response.
1517
+ */
1518
+ getBillingUsage(opts?: {
1519
+ from?: string;
1520
+ to?: string;
1521
+ limit?: number;
1522
+ }): Promise<BillingUsage>;
1523
+ /**
1524
+ * Per-calendar-month (UTC) totals of net credits spent on scans and net
1525
+ * credits purchased (requires the `read` scope). Quiet months are returned as
1526
+ * zeros; newest month first.
1527
+ */
1528
+ getBillingSummary(opts?: {
1529
+ months?: number;
1530
+ }): Promise<UsageMonthSummary[]>;
1276
1531
  }
1277
1532
 
1278
- export { type CancelScanResult, type ChangeNote, DEFAULT_BASE_URL, type Finding, type FindingDetail, type FindingNote, type LaunchScanRequest, type LaunchScanResult, type OptionalFlow, type Paginated, type PublishArtifactResult, type Repository, type ResolutionStatus, type Scan, type ScanDetail, type ScanPreset, type ScanStatus, type Severity, TERMINAL_SCAN_STATUSES, type TriageStatus, type WaitForScanOptions, ZkaoApiError, ZkaoClient, type ZkaoClientOptions, type components, isTerminalScanStatus, normalizeBaseUrl, type paths, resolveBaseUrlFromEnv };
1533
+ export { type BillingBalance, type BillingSummary, type BillingUsage, type CancelScanResult, type ChangeNote, DEFAULT_BASE_URL, type Finding, type FindingDetail, type FindingNote, type LaunchScanRequest, type LaunchScanResult, type OptionalFlow, type Paginated, type PublishArtifactResult, type Repository, type RepositoryGuidance, type ResolutionReason, type ResolutionStatus, type Scan, type ScanDetail, type ScanPreset, type ScanStatus, type SetGuidanceResult, type Severity, TERMINAL_SCAN_STATUSES, type TriageStatus, type UsageEvent, type UsageEventType, type UsageMonthSummary, type WaitForScanOptions, ZkaoApiError, ZkaoClient, type ZkaoClientOptions, type components, isTerminalScanStatus, normalizeBaseUrl, type paths, resolveBaseUrlFromEnv };
package/dist/index.js CHANGED
@@ -263,10 +263,19 @@ var ZkaoClient = class {
263
263
  });
264
264
  return unwrap(res);
265
265
  }
266
- async setFindingResolution(findingId, resolutionStatus, note) {
266
+ /**
267
+ * Change a finding's resolution status (requires the `findings:write` scope).
268
+ *
269
+ * `note` attaches free text in the same call. `reason` picks a catalog code
270
+ * instead, recorded as a generated comment; the codes offered depend on the
271
+ * status, and a code from another status is rejected with 400. A `note` takes
272
+ * precedence: pass one or the other. Both are ignored for the open statuses
273
+ * (`NOT_STARTED`, `IN_PROGRESS`).
274
+ */
275
+ async setFindingResolution(findingId, resolutionStatus, opts = {}) {
267
276
  const res = await this.http.PATCH("/projects/{projectId}/findings/{findingId}/resolution", {
268
277
  params: { path: { ...this.path, findingId } },
269
- body: { resolutionStatus, note }
278
+ body: { resolutionStatus, note: opts.note, reason: opts.reason }
270
279
  });
271
280
  return unwrap(res);
272
281
  }
@@ -290,6 +299,44 @@ var ZkaoClient = class {
290
299
  });
291
300
  return unwrap(res).optionalFlows;
292
301
  }
302
+ // --- Billing ------------------------------------------------------------
303
+ /**
304
+ * Get the project's prepaid credit balance (requires the `read` scope). zkao
305
+ * is pay-as-you-go: `balanceCredits` is the total, `reservedCredits` is held
306
+ * by active scans, and `availableCredits` is what remains for new scans.
307
+ */
308
+ async getBillingBalance() {
309
+ const res = await this.http.GET("/projects/{projectId}/billing/balance", {
310
+ params: { path: this.path }
311
+ });
312
+ return unwrap(res);
313
+ }
314
+ /**
315
+ * List credit-ledger movements for reconciliation (requires the `read`
316
+ * scope). `credits` on each event is signed (negative = spent). Defaults to
317
+ * the last 30 days when `from`/`to` are omitted; the range actually used is
318
+ * echoed back on the response.
319
+ */
320
+ async getBillingUsage(opts = {}) {
321
+ const res = await this.http.GET("/projects/{projectId}/billing/usage", {
322
+ params: {
323
+ path: this.path,
324
+ query: { from: opts.from, to: opts.to, limit: opts.limit }
325
+ }
326
+ });
327
+ return unwrap(res);
328
+ }
329
+ /**
330
+ * Per-calendar-month (UTC) totals of net credits spent on scans and net
331
+ * credits purchased (requires the `read` scope). Quiet months are returned as
332
+ * zeros; newest month first.
333
+ */
334
+ async getBillingSummary(opts = {}) {
335
+ const res = await this.http.GET("/projects/{projectId}/billing/summary", {
336
+ params: { path: this.path, query: { months: opts.months } }
337
+ });
338
+ return unwrap(res).months;
339
+ }
293
340
  };
294
341
  function throwIfAborted(signal) {
295
342
  if (signal?.aborted) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zksecurity/zkao-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "TypeScript SDK for the zkao Project API",
5
5
  "license": "MIT",
6
6
  "author": "zkSecurity",