@zksecurity/zkao-sdk 0.25.0-next.17 → 0.28.0-next.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,6 +28,13 @@ Every method is fully typed from the OpenAPI spec. Non-2xx responses throw
28
28
  Cancel a running or queued scan with `zkao.cancelScan(scanId)`; you are charged
29
29
  only for analysis already done and the rest of the reserved budget is released.
30
30
 
31
+ Check `scan.triage` before relying on the results of a completed scan.
32
+ Its `resume` offer provides the allowed credit budgets when triage stopped on budget.
33
+ Resume with `resumeTriage(scanId, { creditBudget }, { idempotencyKey })`.
34
+ Reuse the same key and budget when retrying that request.
35
+ Track the returned run with `getTriageRun` or `waitForTriageRun`.
36
+ Read the scan's `triage` again afterward to check for unfinished findings.
37
+
31
38
  Full docs, the CLI (`@zksecurity/zkao-cli`), and the OpenAPI contract:
32
39
  **https://github.com/zksecurity/zkao-sdk**
33
40
 
package/dist/index.d.ts CHANGED
@@ -280,6 +280,46 @@ interface paths {
280
280
  patch?: never;
281
281
  trace?: never;
282
282
  };
283
+ "/projects/{projectId}/scans/{scanId}/triage/resume": {
284
+ parameters: {
285
+ query?: never;
286
+ header?: never;
287
+ path?: never;
288
+ cookie?: never;
289
+ };
290
+ get?: never;
291
+ put?: never;
292
+ /**
293
+ * Resume triage after a budget stop
294
+ * @description Requires scope: `scans:launch`. The scan must be completed and settled, with unfinished findings and a latest triage run that stopped on budget. Uses the scan's settings and reserves the explicit budget in credits. The token's repository restrictions and spend allowance apply. Reusing the same idempotency key and budget returns the original run, including after it finishes, without reserving or spending again. A different budget with the same key returns 409. A new attempt requires a new key. Poll getTriageRun because the parent scan remains COMPLETED.
295
+ */
296
+ post: operations["resumeTriage"];
297
+ delete?: never;
298
+ options?: never;
299
+ head?: never;
300
+ patch?: never;
301
+ trace?: never;
302
+ };
303
+ "/projects/{projectId}/scans/{scanId}/triage/runs/{runId}": {
304
+ parameters: {
305
+ query?: never;
306
+ header?: never;
307
+ path?: never;
308
+ cookie?: never;
309
+ };
310
+ /**
311
+ * Get one triage run
312
+ * @description Requires scope: `read`. Follows this run independently of the scan status. A COMPLETED run can still leave findings unfinished. Check scan.triage after it ends. Failed attempts awaiting retry remain QUEUED.
313
+ */
314
+ get: operations["getTriageRun"];
315
+ put?: never;
316
+ post?: never;
317
+ delete?: never;
318
+ options?: never;
319
+ head?: never;
320
+ patch?: never;
321
+ trace?: never;
322
+ };
283
323
  "/projects/{projectId}/reports": {
284
324
  parameters: {
285
325
  query?: never;
@@ -762,8 +802,10 @@ interface components {
762
802
  Error: {
763
803
  error: {
764
804
  /** @enum {string} */
765
- code: "unauthorized" | "forbidden" | "not_found" | "bad_request" | "conflict" | "insufficient_credits" | "repository_initializing" | "diff_base_required" | "diff_base_not_allowed" | "diff_base_invalid" | "diff_empty" | "rate_limited" | "internal";
805
+ code: "unauthorized" | "forbidden" | "not_found" | "bad_request" | "conflict" | "insufficient_credits" | "budget_below_minimum" | "repository_initializing" | "diff_base_required" | "diff_base_not_allowed" | "diff_base_invalid" | "diff_empty" | "rate_limited" | "internal";
766
806
  message: string;
807
+ /** @description budget_below_minimum only: the least the launch could have reserved, in credits. A diff scan's first scan of a repository also builds its overview, so its minimum is higher. */
808
+ minimumCredits?: number;
767
809
  };
768
810
  };
769
811
  /** @enum {string} */
@@ -848,7 +890,35 @@ interface components {
848
890
  /** @description Weighted completion. Each phase counts for its share of the scan budget, so this does not simply equal phasesCompleted / phasesTotal. */
849
891
  percent: number;
850
892
  };
893
+ TriageResumeBudget: {
894
+ minCredits: number;
895
+ recommendedCredits: number;
896
+ maxCredits: number;
897
+ };
898
+ /** @description Completeness of triage, independent of whether the scan succeeded. */
899
+ ScanTriage: {
900
+ /** @enum {string} */
901
+ status: "pending" | "running" | "complete" | "budget_exhausted" | "blocked";
902
+ untriagedCount: number;
903
+ activeRunId: string | null;
904
+ resume: components["schemas"]["TriageResumeBudget"] | null;
905
+ };
906
+ TriageRun: {
907
+ id: string;
908
+ scanId: string;
909
+ /** @enum {string} */
910
+ status: "QUEUED" | "RUNNING" | "COMPLETED" | "FAILED" | "CANCELLED";
911
+ /** @description Number of findings selected when this run started. */
912
+ findingCount: number;
913
+ /** Format: date-time */
914
+ createdAt: string;
915
+ /** Format: date-time */
916
+ completedAt: string | null;
917
+ /** @description Whether this run reached its budget cap. Check scan.triage for remaining work. */
918
+ budgetExhausted: boolean;
919
+ };
851
920
  ScanDetail: components["schemas"]["Scan"] & {
921
+ triage: components["schemas"]["ScanTriage"];
852
922
  branch?: string | null;
853
923
  /** @description Reserved budget for the scan, in credits. */
854
924
  creditBudget?: number | null;
@@ -1070,7 +1140,7 @@ interface components {
1070
1140
  };
1071
1141
  LaunchScanRequest: {
1072
1142
  repositoryId: string;
1073
- /** @description Max budget for the scan, in credits. Reserved at launch. Omit it to launch at the budget zkao recommends for this scan type and scope on this repository. That is the last such scan's budget, or half again when that scan ran short of it, never above twice the scan type's minimum. A first scan starts at twice the minimum. A diff scan is sized from its change instead: the minimum for up to 500 changed lines, then in proportion, up to three times the minimum. */
1143
+ /** @description Max budget for the scan, in credits. Reserved at launch. Omit it to launch at the budget zkao recommends for this scan type and scope on this repository. A Flash or Max scan of the code is sized from the audit areas it reads: the selected areas, or every area in the repository map. One area gets the minimum, and the budget grows with the square root of the area count. With no map, or with `auditScope`, it is twice the minimum. It is half again the last budget when the last scan of the same scope ran short of it. A diff scan is sized from its change instead: the minimum for up to 500 changed lines, then in proportion, up to three times the minimum. Other scan types use the last such scan's budget, or half again when that scan ran short of it, and a first scan starts at twice the minimum. Except for a diff, the recommendation never exceeds twice the minimum. A budget below the minimum is refused with `400` `budget_below_minimum`, whose `minimumCredits` names it. */
1074
1144
  creditBudget?: number;
1075
1145
  /** @description A preset ref from /scan-presets. Defaults to the first active preset. */
1076
1146
  presetRef?: string;
@@ -1079,7 +1149,7 @@ interface components {
1079
1149
  /** @description Pin a specific commit SHA (7-40 hex chars). */
1080
1150
  commitHash?: string | null;
1081
1151
  commitMessage?: string | null;
1082
- /** @description What a diff scan's change is measured from: a commit SHA, branch, or tag. Required by a diff scan preset and refused by every other. The scan records the merge base of this and the scanned commit. */
1152
+ /** @description What a diff scan's change is measured from: a commit SHA, branch, or tag. Required by a diff scan preset and refused by every other. The scan records the merge base of this and the scanned commit. When no earlier scan of the repository built its overview, the diff scan builds one first, and its minimum and recommended budgets rise. */
1083
1153
  baseCommit?: string | null;
1084
1154
  /** @description Options for Recheck open findings. Omit to reassess eligible Not started findings on the selected branch. Fresh rechecks require the branch's latest commit and reject a pinned commit or audit scope. */
1085
1155
  backlogRecheck?: {
@@ -1104,6 +1174,8 @@ interface components {
1104
1174
  queued: boolean;
1105
1175
  /** @description The budget the scan was launched with, in credits. */
1106
1176
  creditBudget: number;
1177
+ /** @description True when no earlier scan of the repository built its overview, so this diff scan builds one first. It takes longer, and its minimum and recommended budgets are higher. */
1178
+ buildsOverview: boolean;
1107
1179
  };
1108
1180
  RepositoryGuidance: {
1109
1181
  repositoryId: string;
@@ -1864,6 +1936,80 @@ interface operations {
1864
1936
  429: components["responses"]["RateLimited"];
1865
1937
  };
1866
1938
  };
1939
+ resumeTriage: {
1940
+ parameters: {
1941
+ query?: never;
1942
+ header: {
1943
+ /** @description Stable request key. Reuse it with the same budget when retrying. */
1944
+ "Idempotency-Key": string;
1945
+ };
1946
+ path: {
1947
+ projectId: components["parameters"]["ProjectId"];
1948
+ scanId: components["parameters"]["ScanId"];
1949
+ };
1950
+ cookie?: never;
1951
+ };
1952
+ requestBody: {
1953
+ content: {
1954
+ "application/json": {
1955
+ creditBudget: number;
1956
+ };
1957
+ };
1958
+ };
1959
+ responses: {
1960
+ /** @description The new or previously created triage run. */
1961
+ 200: {
1962
+ headers: {
1963
+ [name: string]: unknown;
1964
+ };
1965
+ content: {
1966
+ "application/json": {
1967
+ run: components["schemas"]["TriageRun"];
1968
+ replayed: boolean;
1969
+ };
1970
+ };
1971
+ };
1972
+ 400: components["responses"]["BadRequest"];
1973
+ 401: components["responses"]["Unauthorized"];
1974
+ 402: components["responses"]["InsufficientCredits"];
1975
+ 403: components["responses"]["Forbidden"];
1976
+ 404: components["responses"]["NotFound"];
1977
+ 409: components["responses"]["Conflict"];
1978
+ 429: components["responses"]["RateLimited"];
1979
+ };
1980
+ };
1981
+ getTriageRun: {
1982
+ parameters: {
1983
+ query?: never;
1984
+ header?: never;
1985
+ path: {
1986
+ projectId: components["parameters"]["ProjectId"];
1987
+ scanId: components["parameters"]["ScanId"];
1988
+ runId: string;
1989
+ };
1990
+ cookie?: never;
1991
+ };
1992
+ requestBody?: never;
1993
+ responses: {
1994
+ /** @description OK */
1995
+ 200: {
1996
+ headers: {
1997
+ /** @description Advisory seconds before polling an active run again. */
1998
+ "Retry-After"?: number;
1999
+ [name: string]: unknown;
2000
+ };
2001
+ content: {
2002
+ "application/json": {
2003
+ run: components["schemas"]["TriageRun"];
2004
+ };
2005
+ };
2006
+ };
2007
+ 401: components["responses"]["Unauthorized"];
2008
+ 403: components["responses"]["Forbidden"];
2009
+ 404: components["responses"]["NotFound"];
2010
+ 429: components["responses"]["RateLimited"];
2011
+ };
2012
+ };
1867
2013
  listReports: {
1868
2014
  parameters: {
1869
2015
  query?: {
@@ -2546,6 +2692,11 @@ type ScanPreset = Schemas["ScanPreset"];
2546
2692
  type LaunchScanRequest = Schemas["LaunchScanRequest"];
2547
2693
  type LaunchScanResult = Schemas["LaunchScanResult"];
2548
2694
  type CancelScanResult = Schemas["CancelScanResult"];
2695
+ type ScanTriage = Schemas["ScanTriage"];
2696
+ type TriageRun = Schemas["TriageRun"];
2697
+ type ResumeTriageOperation = paths["/projects/{projectId}/scans/{scanId}/triage/resume"]["post"];
2698
+ type ResumeTriageRequest = ResumeTriageOperation["requestBody"]["content"]["application/json"];
2699
+ type ResumeTriageResult = ResumeTriageOperation["responses"][200]["content"]["application/json"];
2549
2700
  type ChangeNote = Schemas["ChangeNote"];
2550
2701
  type Severity = Schemas["Severity"];
2551
2702
  type ResolutionStatus = Schemas["ResolutionStatus"];
@@ -2673,11 +2824,17 @@ type WaitForScanOptions = {
2673
2824
  /** Called with the latest detail on each non-terminal poll (for progress UI). */
2674
2825
  onPoll?: (scan: ScanDetail) => void;
2675
2826
  };
2827
+ type WaitForTriageRunOptions = Omit<WaitForScanOptions, "onPoll"> & {
2828
+ /** Called with the requested triage run on each non-terminal poll. */
2829
+ onPoll?: (run: TriageRun) => void;
2830
+ };
2676
2831
  /** Thrown for any non-2xx response, carrying the API error envelope. */
2677
2832
  declare class ZkaoApiError extends Error {
2678
2833
  readonly status: number;
2679
2834
  readonly code: string;
2680
- constructor(status: number, code: string, message: string);
2835
+ /** `budget_below_minimum` only: the least the launch could reserve, in credits. */
2836
+ readonly minimumCredits?: number;
2837
+ constructor(status: number, code: string, message: string, minimumCredits?: number);
2681
2838
  }
2682
2839
  /**
2683
2840
  * Typed client for one zkao project. Every call is scoped to the project the
@@ -2790,6 +2947,13 @@ declare class ZkaoClient {
2790
2947
  */
2791
2948
  waitForScan(scanId: string, opts?: WaitForScanOptions): Promise<ScanDetail>;
2792
2949
  launchScan(body: LaunchScanRequest): Promise<LaunchScanResult>;
2950
+ /** Resume budget-stopped triage. Reuse the key and budget when retrying. */
2951
+ resumeTriage(scanId: string, body: ResumeTriageRequest, opts: {
2952
+ idempotencyKey: string;
2953
+ }): Promise<ResumeTriageResult>;
2954
+ getTriageRun(scanId: string, runId: string): Promise<TriageRun>;
2955
+ /** Wait for one run. Read scan.triage afterward to check result completeness. */
2956
+ waitForTriageRun(scanId: string, runId: string, opts?: WaitForTriageRunOptions): Promise<TriageRun>;
2793
2957
  /**
2794
2958
  * Cancel a running or queued scan. Signals in-flight jobs to stop, marks the
2795
2959
  * scan CANCELLED, and releases its reserved credits. A scan already in a
@@ -2988,4 +3152,4 @@ declare class ZkaoClient {
2988
3152
  }): Promise<UsageMonthSummary[]>;
2989
3153
  }
2990
3154
 
2991
- export { type Advisory, type AdvisoryAffected, type AdvisoryAffectedInput, type AdvisoryContact, type AdvisoryContactInput, type AdvisoryDetail, type AdvisoryNotice, type AdvisoryStatus, type BillingBalance, type BillingSummary, type BillingUsage, type CancelScanResult, type ChangeNote, type ContactStatus, type ContactTier, type ContinuousTesting, DEFAULT_BASE_URL, type Finding, type FindingDetail, type FindingNote, type LaunchScanRequest, type LaunchScanResult, type ManualAuditRequest, type ManualAuditResult, type Paginated, type PublishArtifactResult, type RemoveContinuousTestingResult, type Report, type ReportStatus, type Repository, type RepositoryGuidance, type ResolutionReason, type ResolutionStatus, type Scan, type ScanDetail, type ScanPreset, type ScanStatus, type SetContinuousTestingRequest, type SetGuidanceResult, type Severity, TERMINAL_SCAN_STATUSES, type TokenInfo, type TriageStatus, type UsageEvent, type UsageEventType, type UsageMonthSummary, type WaitForRepositoryReadyOptions, type WaitForScanOptions, ZkaoApiError, ZkaoClient, type ZkaoClientOptions, type components, getTokenInfo, isTerminalScanStatus, normalizeBaseUrl, type paths, resolveBaseUrlFromEnv };
3155
+ export { type Advisory, type AdvisoryAffected, type AdvisoryAffectedInput, type AdvisoryContact, type AdvisoryContactInput, type AdvisoryDetail, type AdvisoryNotice, type AdvisoryStatus, type BillingBalance, type BillingSummary, type BillingUsage, type CancelScanResult, type ChangeNote, type ContactStatus, type ContactTier, type ContinuousTesting, DEFAULT_BASE_URL, type Finding, type FindingDetail, type FindingNote, type LaunchScanRequest, type LaunchScanResult, type ManualAuditRequest, type ManualAuditResult, type Paginated, type PublishArtifactResult, type RemoveContinuousTestingResult, type Report, type ReportStatus, type Repository, type RepositoryGuidance, type ResolutionReason, type ResolutionStatus, type ResumeTriageRequest, type ResumeTriageResult, type Scan, type ScanDetail, type ScanPreset, type ScanStatus, type ScanTriage, type SetContinuousTestingRequest, type SetGuidanceResult, type Severity, TERMINAL_SCAN_STATUSES, type TokenInfo, type TriageRun, type TriageStatus, type UsageEvent, type UsageEventType, type UsageMonthSummary, type WaitForRepositoryReadyOptions, type WaitForScanOptions, type WaitForTriageRunOptions, ZkaoApiError, ZkaoClient, type ZkaoClientOptions, type components, getTokenInfo, isTerminalScanStatus, normalizeBaseUrl, type paths, resolveBaseUrlFromEnv };
package/dist/index.js CHANGED
@@ -81,11 +81,16 @@ function isTerminalScanStatus(status) {
81
81
  var ZkaoApiError = class extends Error {
82
82
  status;
83
83
  code;
84
- constructor(status, code, message) {
84
+ /** `budget_below_minimum` only: the least the launch could reserve, in credits. */
85
+ minimumCredits;
86
+ constructor(status, code, message, minimumCredits) {
85
87
  super(message);
86
88
  this.name = "ZkaoApiError";
87
89
  this.status = status;
88
90
  this.code = code;
91
+ if (minimumCredits !== void 0) {
92
+ this.minimumCredits = minimumCredits;
93
+ }
89
94
  }
90
95
  };
91
96
  function unwrap(result) {
@@ -93,10 +98,12 @@ function unwrap(result) {
93
98
  return result.data;
94
99
  }
95
100
  const envelope = result.error;
101
+ const minimumCredits = envelope?.error?.minimumCredits;
96
102
  throw new ZkaoApiError(
97
103
  result.response.status,
98
104
  envelope?.error?.code ?? "error",
99
- envelope?.error?.message ?? result.response.statusText
105
+ envelope?.error?.message ?? result.response.statusText,
106
+ typeof minimumCredits === "number" ? minimumCredits : void 0
100
107
  );
101
108
  }
102
109
  async function getTokenInfo(options) {
@@ -400,6 +407,52 @@ var ZkaoClient = class {
400
407
  });
401
408
  return unwrap(res);
402
409
  }
410
+ /** Resume budget-stopped triage. Reuse the key and budget when retrying. */
411
+ async resumeTriage(scanId, body, opts) {
412
+ const res = await this.http.POST("/projects/{projectId}/scans/{scanId}/triage/resume", {
413
+ params: {
414
+ path: { ...this.path, scanId },
415
+ header: { "Idempotency-Key": opts.idempotencyKey }
416
+ },
417
+ body
418
+ });
419
+ return unwrap(res);
420
+ }
421
+ async getTriageRun(scanId, runId) {
422
+ const res = await this.http.GET("/projects/{projectId}/scans/{scanId}/triage/runs/{runId}", {
423
+ params: { path: { ...this.path, scanId, runId } }
424
+ });
425
+ return unwrap(res).run;
426
+ }
427
+ /** Wait for one run. Read scan.triage afterward to check result completeness. */
428
+ async waitForTriageRun(scanId, runId, opts = {}) {
429
+ const intervalMs = opts.intervalMs ?? 5e3;
430
+ const maxIntervalMs = opts.maxIntervalMs ?? 3e4;
431
+ const timeoutMs = opts.timeoutMs ?? 60 * 60 * 1e3;
432
+ const deadline = Date.now() + timeoutMs;
433
+ for (let attempt = 0; ; attempt++) {
434
+ throwIfAborted(opts.signal);
435
+ const res = await this.http.GET("/projects/{projectId}/scans/{scanId}/triage/runs/{runId}", {
436
+ params: { path: { ...this.path, scanId, runId } },
437
+ signal: opts.signal
438
+ });
439
+ const retryAfterMs = parseRetryAfterMs(res.response.headers.get("retry-after"));
440
+ if (res.response.status !== 429) {
441
+ const run = unwrap(res).run;
442
+ if (run.status === "COMPLETED" || run.status === "FAILED" || run.status === "CANCELLED") {
443
+ return run;
444
+ }
445
+ opts.onPoll?.(run);
446
+ }
447
+ const backoffMs = Math.min(maxIntervalMs, Math.round(intervalMs * 1.5 ** attempt));
448
+ const baseMs = retryAfterMs ?? backoffMs;
449
+ const delayMs = baseMs + Math.round(Math.random() * baseMs * 0.2);
450
+ if (Date.now() + delayMs > deadline) {
451
+ throw new Error(`Timed out waiting for triage run ${runId} to finish after ${timeoutMs}ms`);
452
+ }
453
+ await sleep(delayMs, opts.signal);
454
+ }
455
+ }
403
456
  /**
404
457
  * Cancel a running or queued scan. Signals in-flight jobs to stop, marks the
405
458
  * scan CANCELLED, and releases its reserved credits. A scan already in a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zksecurity/zkao-sdk",
3
- "version": "0.25.0-next.17",
3
+ "version": "0.28.0-next.19",
4
4
  "description": "TypeScript SDK for the zkao Project API",
5
5
  "license": "MIT",
6
6
  "author": "zkSecurity",