@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 +7 -0
- package/dist/index.d.ts +169 -5
- package/dist/index.js +55 -2
- package/package.json +1 -1
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|