@clickraft/cli 0.8.3 → 0.8.5
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/CHANGELOG.md +1 -5
- package/dist/cli.js +738 -686
- package/dist/cli.js.map +1 -1
- package/dist/index.js +738 -686
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10,6 +10,10 @@ import { z } from "zod";
|
|
|
10
10
|
import { z as z2 } from "zod";
|
|
11
11
|
import { z as z3 } from "zod";
|
|
12
12
|
import { z as z4 } from "zod";
|
|
13
|
+
import { request as undiciRequest } from "undici";
|
|
14
|
+
import { z as z6 } from "zod";
|
|
15
|
+
import { createHash, randomUUID } from "crypto";
|
|
16
|
+
import { z as z5 } from "zod";
|
|
13
17
|
var TOKEN_FIELD_PATTERN = /"(access_token|refresh_token|device_code|user_code|code_verifier|client_secret)"\s*:\s*"[^"]*"/gi;
|
|
14
18
|
var BARE_TOKEN_PATTERN = /\bck_(?:live|dev|test)_[A-Za-z0-9_-]+/gi;
|
|
15
19
|
function redactTokenLikeFields(input) {
|
|
@@ -81,441 +85,127 @@ var TokenRowSchema = z4.object({
|
|
|
81
85
|
createdAt: z4.string()
|
|
82
86
|
}).strict();
|
|
83
87
|
var TokensListResponseSchema = z4.array(TokenRowSchema);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
154
|
-
IDEMPOTENCY_KEY_CONFLICT: {
|
|
155
|
-
exitCode: 7,
|
|
156
|
-
category: "conflict",
|
|
157
|
-
retryable: false,
|
|
158
|
-
hint: "Same key was used with a different request body. Use a new key."
|
|
159
|
-
},
|
|
160
|
-
PLAN_FEATURE_LOCKED: {
|
|
161
|
-
exitCode: 4,
|
|
162
|
-
category: "permission",
|
|
163
|
-
retryable: false,
|
|
164
|
-
hint: "API access is not enabled on your plan. Visit billing settings."
|
|
165
|
-
},
|
|
166
|
-
PLAN_QUOTA_EXCEEDED: {
|
|
167
|
-
exitCode: 5,
|
|
168
|
-
category: "quota",
|
|
169
|
-
retryable: false,
|
|
170
|
-
hint: "Daily API quota exhausted. Wait, or upgrade your plan."
|
|
171
|
-
},
|
|
172
|
-
INSUFFICIENT_CREDITS: {
|
|
173
|
-
exitCode: 5,
|
|
174
|
-
category: "quota",
|
|
175
|
-
retryable: false,
|
|
176
|
-
hint: "Top up credits to retry."
|
|
177
|
-
},
|
|
178
|
-
CREDIT_DEDUCTION_FAILED: {
|
|
179
|
-
exitCode: 1,
|
|
180
|
-
category: "runtime",
|
|
181
|
-
retryable: true,
|
|
182
|
-
hint: "Could not charge credits. Retry; no charge was made."
|
|
183
|
-
},
|
|
184
|
-
RATE_LIMITED: {
|
|
185
|
-
exitCode: 5,
|
|
186
|
-
category: "quota",
|
|
187
|
-
retryable: true,
|
|
188
|
-
hint: "Slow down. Honor Retry-After."
|
|
189
|
-
},
|
|
190
|
-
INPUT_INVALID_FORMAT: {
|
|
191
|
-
exitCode: 2,
|
|
192
|
-
category: "usage",
|
|
193
|
-
retryable: false,
|
|
194
|
-
hint: "Check input format and try again."
|
|
195
|
-
},
|
|
196
|
-
INPUT_TOO_LONG: {
|
|
197
|
-
exitCode: 2,
|
|
198
|
-
category: "usage",
|
|
199
|
-
retryable: false,
|
|
200
|
-
hint: "Field exceeded max length."
|
|
201
|
-
},
|
|
202
|
-
WORKFLOW_VALIDATION_FAILED: {
|
|
203
|
-
exitCode: 2,
|
|
204
|
-
category: "usage",
|
|
205
|
-
retryable: false,
|
|
206
|
-
hint: "Run `workflow validate` for the full list of errors."
|
|
207
|
-
},
|
|
208
|
-
WORKFLOW_NODE_TYPE_UNKNOWN: {
|
|
209
|
-
exitCode: 2,
|
|
210
|
-
category: "usage",
|
|
211
|
-
retryable: false,
|
|
212
|
-
hint: "Run `clickraft nodes list` for the current set of node types."
|
|
213
|
-
},
|
|
214
|
-
CANVAS_REV_MISMATCH: {
|
|
215
|
-
exitCode: 7,
|
|
216
|
-
category: "conflict",
|
|
217
|
-
retryable: false,
|
|
218
|
-
hint: "The workflow was updated elsewhere. Re-fetch and retry with the current canvas_rev."
|
|
219
|
-
},
|
|
220
|
-
CANVAS_REV_REQUIRED: {
|
|
221
|
-
exitCode: 2,
|
|
222
|
-
category: "usage",
|
|
223
|
-
retryable: false,
|
|
224
|
-
hint: "Include --canvas-rev or use --auto-rev."
|
|
225
|
-
},
|
|
226
|
-
WORKER_UNREACHABLE: {
|
|
227
|
-
exitCode: 6,
|
|
228
|
-
category: "network",
|
|
229
|
-
retryable: true,
|
|
230
|
-
hint: "Collaboration service temporarily unavailable. Retry."
|
|
231
|
-
},
|
|
232
|
-
IDEMPOTENCY_IN_PROGRESS: {
|
|
233
|
-
exitCode: 7,
|
|
234
|
-
category: "conflict",
|
|
235
|
-
retryable: false,
|
|
236
|
-
hint: "A request with this idempotency key is currently in-flight. Retry in a moment."
|
|
237
|
-
},
|
|
238
|
-
TOKEN_NAME_INVALID: {
|
|
239
|
-
exitCode: 2,
|
|
240
|
-
category: "usage",
|
|
241
|
-
retryable: false,
|
|
242
|
-
hint: "Agent token name is malformed."
|
|
243
|
-
},
|
|
244
|
-
WORKFLOW_NOT_FOUND: {
|
|
245
|
-
exitCode: 2,
|
|
246
|
-
category: "usage",
|
|
247
|
-
retryable: false,
|
|
248
|
-
hint: "No workflow with that ID in your org."
|
|
249
|
-
},
|
|
250
|
-
NOT_FOUND: {
|
|
251
|
-
exitCode: 2,
|
|
252
|
-
category: "usage",
|
|
253
|
-
retryable: false,
|
|
254
|
-
hint: "Resource not found."
|
|
255
|
-
},
|
|
256
|
-
NODE_TYPE_NOT_FOUND: {
|
|
257
|
-
exitCode: 2,
|
|
258
|
-
category: "usage",
|
|
259
|
-
retryable: false,
|
|
260
|
-
hint: "Run `clickraft nodes list` for the current set of node types."
|
|
261
|
-
},
|
|
262
|
-
FEATURE_DISABLED: {
|
|
263
|
-
exitCode: 2,
|
|
264
|
-
category: "usage",
|
|
265
|
-
retryable: false,
|
|
266
|
-
hint: "This endpoint is not enabled. Contact support if you believe this is in error."
|
|
267
|
-
},
|
|
268
|
-
FORBIDDEN: {
|
|
269
|
-
exitCode: 4,
|
|
270
|
-
category: "permission",
|
|
271
|
-
retryable: false,
|
|
272
|
-
hint: "Your role does not permit this action."
|
|
273
|
-
},
|
|
274
|
-
MODEL_NOT_FOUND: {
|
|
275
|
-
exitCode: 2,
|
|
276
|
-
category: "usage",
|
|
277
|
-
retryable: false,
|
|
278
|
-
hint: "Unknown `modelSlug`. Run `brand-model list` for the current set."
|
|
279
|
-
},
|
|
280
|
-
PROVIDER_UNAVAILABLE: {
|
|
281
|
-
exitCode: 6,
|
|
282
|
-
category: "network",
|
|
283
|
-
retryable: true,
|
|
284
|
-
hint: "Provider is temporarily unavailable. Retry shortly."
|
|
285
|
-
},
|
|
286
|
-
STORAGE_UPLOAD_FAILED: {
|
|
287
|
-
exitCode: 1,
|
|
288
|
-
category: "runtime",
|
|
289
|
-
retryable: true,
|
|
290
|
-
hint: "Upload failed mid-stream. Retry."
|
|
291
|
-
},
|
|
292
|
-
STORAGE_QUOTA_EXCEEDED: {
|
|
293
|
-
exitCode: 5,
|
|
294
|
-
category: "quota",
|
|
295
|
-
retryable: false,
|
|
296
|
-
hint: "Org storage quota exceeded. Free space or upgrade."
|
|
297
|
-
},
|
|
298
|
-
GEN_CONTENT_REFUSAL: {
|
|
299
|
-
exitCode: 1,
|
|
300
|
-
category: "runtime",
|
|
301
|
-
retryable: false,
|
|
302
|
-
hint: "The model declined the request via safety policy."
|
|
303
|
-
},
|
|
304
|
-
GEN_OUTPUT_SCHEMA_MISMATCH: {
|
|
305
|
-
exitCode: 1,
|
|
306
|
-
category: "runtime",
|
|
307
|
-
retryable: true,
|
|
308
|
-
hint: "Provider returned malformed output. Full refund issued. Retry."
|
|
309
|
-
},
|
|
310
|
-
GEN_EMPTY_OUTPUT: {
|
|
311
|
-
exitCode: 1,
|
|
312
|
-
category: "runtime",
|
|
313
|
-
retryable: true,
|
|
314
|
-
hint: "Provider returned no usable output. Full refund issued. Retry."
|
|
315
|
-
},
|
|
316
|
-
GEN_ITEM_COUNT_MISMATCH: {
|
|
317
|
-
exitCode: 0,
|
|
318
|
-
category: "success",
|
|
319
|
-
retryable: false,
|
|
320
|
-
hint: "Partial output kept; no refund."
|
|
321
|
-
},
|
|
322
|
-
AGENT_FINGERPRINT_REJECTED: {
|
|
323
|
-
exitCode: 4,
|
|
324
|
-
category: "permission",
|
|
325
|
-
retryable: false,
|
|
326
|
-
hint: "This client identification is not permitted. Contact support."
|
|
327
|
-
},
|
|
328
|
-
INTERNAL_ERROR: {
|
|
329
|
-
exitCode: 1,
|
|
330
|
-
category: "runtime",
|
|
331
|
-
retryable: true,
|
|
332
|
-
hint: "Server error. Retry; if it persists, contact support with the request ID."
|
|
333
|
-
},
|
|
334
|
-
CREDENTIALS_LOCKED: {
|
|
335
|
-
exitCode: 1,
|
|
336
|
-
category: "runtime",
|
|
337
|
-
retryable: true,
|
|
338
|
-
hint: "Another CLI invocation holds the credentials lock. Retry shortly."
|
|
339
|
-
},
|
|
340
|
-
CREDENTIALS_PERMISSIONS_LOOSE: {
|
|
341
|
-
exitCode: 0,
|
|
342
|
-
category: "success",
|
|
343
|
-
retryable: false,
|
|
344
|
-
hint: "Credentials file mode is wider than 0600; continuing."
|
|
345
|
-
},
|
|
346
|
-
// --- 5 additional codes introduced by 1A.1 ---------------------------------
|
|
347
|
-
AUTH_ACCESS_DENIED: {
|
|
348
|
-
exitCode: 3,
|
|
349
|
-
category: "auth",
|
|
350
|
-
retryable: false,
|
|
351
|
-
hint: "You denied the OAuth grant. Re-run `clickraft login` to retry."
|
|
352
|
-
},
|
|
353
|
-
AUTH_FLOW_CANCELLED: {
|
|
354
|
-
exitCode: 3,
|
|
355
|
-
category: "auth",
|
|
356
|
-
retryable: false,
|
|
357
|
-
hint: "Authentication was cancelled. Re-run `clickraft login`."
|
|
358
|
-
},
|
|
359
|
-
CREDENTIALS_CORRUPT: {
|
|
360
|
-
exitCode: 1,
|
|
361
|
-
category: "runtime",
|
|
362
|
-
retryable: false,
|
|
363
|
-
hint: "Credentials file is unreadable. Remove it and run `clickraft login`."
|
|
364
|
-
},
|
|
365
|
-
CREDENTIALS_NOT_FOUND: {
|
|
366
|
-
exitCode: 3,
|
|
367
|
-
category: "auth",
|
|
368
|
-
retryable: false,
|
|
369
|
-
hint: LOGIN_HINT
|
|
370
|
-
},
|
|
371
|
-
CREDENTIALS_PROFILE_NOT_FOUND: {
|
|
372
|
-
exitCode: 2,
|
|
373
|
-
category: "usage",
|
|
374
|
-
retryable: false,
|
|
375
|
-
hint: "No such profile. Use `clickraft auth profiles` to list available profiles."
|
|
376
|
-
},
|
|
377
|
-
// --- 8 brand model resolution codes -----------------------------------------
|
|
378
|
-
BRAND_MODEL_NOT_FOUND: {
|
|
379
|
-
exitCode: 1,
|
|
380
|
-
category: "runtime",
|
|
381
|
-
retryable: false,
|
|
382
|
-
hint: "No brand model with that ID. Run `clickraft brand-model list`."
|
|
383
|
-
},
|
|
384
|
-
BRAND_MODEL_NOT_A_MODEL: {
|
|
385
|
-
exitCode: 1,
|
|
386
|
-
category: "runtime",
|
|
387
|
-
retryable: false,
|
|
388
|
-
hint: "The specified asset is not a brand model."
|
|
389
|
-
},
|
|
390
|
-
BRAND_MODEL_NOT_ACTIVE: {
|
|
391
|
-
exitCode: 1,
|
|
392
|
-
category: "runtime",
|
|
393
|
-
retryable: false,
|
|
394
|
-
hint: "Brand model is not active. Check its status in the dashboard."
|
|
395
|
-
},
|
|
396
|
-
BRAND_MODEL_NO_REFERENCES: {
|
|
397
|
-
exitCode: 1,
|
|
398
|
-
category: "runtime",
|
|
399
|
-
retryable: false,
|
|
400
|
-
hint: "Brand model has no reference images. Upload references first."
|
|
401
|
-
},
|
|
402
|
-
BRAND_MODEL_POSE_NOT_FOUND: {
|
|
403
|
-
exitCode: 1,
|
|
404
|
-
category: "runtime",
|
|
405
|
-
retryable: false,
|
|
406
|
-
hint: "Requested pose not found. Valid: front, 3/4-right, right, left, 3/4-left, back, approved."
|
|
407
|
-
},
|
|
408
|
-
BRAND_MODEL_DUPLICATE_ID: {
|
|
409
|
-
exitCode: 2,
|
|
410
|
-
category: "usage",
|
|
411
|
-
retryable: false,
|
|
412
|
-
hint: "Same brand model ID appears more than once."
|
|
413
|
-
},
|
|
414
|
-
MODEL_DOES_NOT_SUPPORT_REFERENCES: {
|
|
415
|
-
exitCode: 2,
|
|
416
|
-
category: "usage",
|
|
417
|
-
retryable: false,
|
|
418
|
-
hint: "This model does not support brand model references."
|
|
419
|
-
},
|
|
420
|
-
REFERENCE_LIMIT_EXCEEDED: {
|
|
421
|
-
exitCode: 2,
|
|
422
|
-
category: "usage",
|
|
423
|
-
retryable: false,
|
|
424
|
-
hint: "Too many reference images. Check model limits."
|
|
425
|
-
},
|
|
426
|
-
// --- 8 product reference resolver codes -------------------------------------
|
|
427
|
-
PRODUCT_NOT_FOUND: {
|
|
428
|
-
exitCode: 1,
|
|
429
|
-
category: "runtime",
|
|
430
|
-
retryable: false,
|
|
431
|
-
hint: "No product with that ID in your org. Run `clickraft product list`."
|
|
432
|
-
},
|
|
433
|
-
PRODUCT_DUPLICATE_REFERENCE: {
|
|
434
|
-
exitCode: 2,
|
|
435
|
-
category: "usage",
|
|
436
|
-
retryable: false,
|
|
437
|
-
hint: "Same (productId, imageId) tuple appears twice in the request."
|
|
438
|
-
},
|
|
439
|
-
PRODUCT_IMAGE_NOT_FOUND: {
|
|
440
|
-
exitCode: 1,
|
|
441
|
-
category: "runtime",
|
|
442
|
-
retryable: false,
|
|
443
|
-
hint: "imageId does not exist in the product images."
|
|
444
|
-
},
|
|
445
|
-
PRODUCT_IMAGE_MISMATCH: {
|
|
446
|
-
exitCode: 2,
|
|
447
|
-
category: "usage",
|
|
448
|
-
retryable: false,
|
|
449
|
-
hint: "imageId belongs to a different product."
|
|
450
|
-
},
|
|
451
|
-
PRODUCT_SYNC_ERROR: {
|
|
452
|
-
exitCode: 1,
|
|
453
|
-
category: "runtime",
|
|
454
|
-
retryable: false,
|
|
455
|
-
hint: "Product sync status is 'error'. Re-sync or use a different product."
|
|
456
|
-
},
|
|
457
|
-
PRODUCT_DELETED_UPSTREAM: {
|
|
458
|
-
exitCode: 1,
|
|
459
|
-
category: "runtime",
|
|
460
|
-
retryable: false,
|
|
461
|
-
hint: "Product was deleted upstream. Remove it or re-sync."
|
|
462
|
-
},
|
|
463
|
-
PRODUCT_NO_PRIMARY_IMAGE: {
|
|
464
|
-
exitCode: 1,
|
|
465
|
-
category: "runtime",
|
|
466
|
-
retryable: false,
|
|
467
|
-
hint: "Product has no primary image. Specify --product <id>:<imageId> explicitly."
|
|
468
|
-
},
|
|
469
|
-
PRODUCT_SOURCE_MANAGED: {
|
|
470
|
-
exitCode: 4,
|
|
471
|
-
category: "permission",
|
|
472
|
-
retryable: false,
|
|
473
|
-
hint: "Product is managed by an external integration."
|
|
474
|
-
},
|
|
475
|
-
// --- 4 CLI-synthetic codes --------------------------------------------------
|
|
476
|
-
NETWORK_ERROR: {
|
|
477
|
-
exitCode: 6,
|
|
478
|
-
category: "network",
|
|
479
|
-
retryable: true,
|
|
480
|
-
hint: "Network connection failed. Check connectivity and retry."
|
|
481
|
-
},
|
|
482
|
-
TIMEOUT: {
|
|
483
|
-
exitCode: 6,
|
|
484
|
-
category: "network",
|
|
485
|
-
retryable: true,
|
|
486
|
-
hint: "Request timed out. Retry; consider increasing the timeout."
|
|
487
|
-
},
|
|
488
|
-
PARSE_ERROR: {
|
|
489
|
-
exitCode: 1,
|
|
490
|
-
category: "runtime",
|
|
491
|
-
retryable: false,
|
|
492
|
-
hint: "Server returned an unexpected response. Contact support with the request ID."
|
|
493
|
-
},
|
|
494
|
-
SCHEMA_MISMATCH: {
|
|
495
|
-
exitCode: 1,
|
|
496
|
-
category: "runtime",
|
|
497
|
-
retryable: false,
|
|
498
|
-
hint: "Server response did not match the expected schema. Update the CLI."
|
|
88
|
+
var SERVER_ERROR_CODES = [
|
|
89
|
+
"AUTH_TOKEN_MISSING",
|
|
90
|
+
"AUTH_TOKEN_INVALID",
|
|
91
|
+
"AUTH_TOKEN_EXPIRED",
|
|
92
|
+
"AUTH_TOKEN_REVOKED",
|
|
93
|
+
"AUTH_TOKEN_SCOPE_INSUFFICIENT",
|
|
94
|
+
"AUTH_ORG_MISMATCH",
|
|
95
|
+
"AUTH_DEVICE_CODE_PENDING",
|
|
96
|
+
"AUTH_DEVICE_CODE_EXPIRED",
|
|
97
|
+
"AUTH_DEVICE_CODE_SLOW_DOWN",
|
|
98
|
+
"IDEMPOTENCY_KEY_MISSING",
|
|
99
|
+
"IDEMPOTENCY_KEY_CONFLICT",
|
|
100
|
+
"PLAN_FEATURE_LOCKED",
|
|
101
|
+
"PLAN_QUOTA_EXCEEDED",
|
|
102
|
+
"INSUFFICIENT_CREDITS",
|
|
103
|
+
"CREDIT_DEDUCTION_FAILED",
|
|
104
|
+
"RATE_LIMITED",
|
|
105
|
+
"INPUT_INVALID_FORMAT",
|
|
106
|
+
"INPUT_TOO_LONG",
|
|
107
|
+
"WORKFLOW_VALIDATION_FAILED",
|
|
108
|
+
"WORKFLOW_NODE_TYPE_UNKNOWN",
|
|
109
|
+
"CANVAS_REV_MISMATCH",
|
|
110
|
+
"CANVAS_REV_REQUIRED",
|
|
111
|
+
"WORKER_UNREACHABLE",
|
|
112
|
+
"IDEMPOTENCY_IN_PROGRESS",
|
|
113
|
+
"TOKEN_NAME_INVALID",
|
|
114
|
+
"WORKFLOW_NOT_FOUND",
|
|
115
|
+
"NOT_FOUND",
|
|
116
|
+
"NODE_TYPE_NOT_FOUND",
|
|
117
|
+
"FEATURE_DISABLED",
|
|
118
|
+
"FORBIDDEN",
|
|
119
|
+
"MODEL_NOT_FOUND",
|
|
120
|
+
"PROVIDER_UNAVAILABLE",
|
|
121
|
+
"STORAGE_UPLOAD_FAILED",
|
|
122
|
+
"STORAGE_QUOTA_EXCEEDED",
|
|
123
|
+
"GEN_CONTENT_REFUSAL",
|
|
124
|
+
"GEN_OUTPUT_SCHEMA_MISMATCH",
|
|
125
|
+
"GEN_EMPTY_OUTPUT",
|
|
126
|
+
"GEN_ITEM_COUNT_MISMATCH",
|
|
127
|
+
"AGENT_FINGERPRINT_REJECTED",
|
|
128
|
+
"INTERNAL_ERROR",
|
|
129
|
+
"BRAND_MODEL_NOT_FOUND",
|
|
130
|
+
"BRAND_MODEL_NOT_A_MODEL",
|
|
131
|
+
"BRAND_MODEL_NOT_ACTIVE",
|
|
132
|
+
"BRAND_MODEL_NO_REFERENCES",
|
|
133
|
+
"BRAND_MODEL_POSE_NOT_FOUND",
|
|
134
|
+
"BRAND_MODEL_DUPLICATE_ID",
|
|
135
|
+
"MODEL_DOES_NOT_SUPPORT_REFERENCES",
|
|
136
|
+
"REFERENCE_LIMIT_EXCEEDED",
|
|
137
|
+
"PRODUCT_NOT_FOUND",
|
|
138
|
+
"PRODUCT_DUPLICATE_REFERENCE",
|
|
139
|
+
"PRODUCT_IMAGE_NOT_FOUND",
|
|
140
|
+
"PRODUCT_IMAGE_MISMATCH",
|
|
141
|
+
"PRODUCT_SYNC_ERROR",
|
|
142
|
+
"PRODUCT_DELETED_UPSTREAM",
|
|
143
|
+
"PRODUCT_NO_PRIMARY_IMAGE",
|
|
144
|
+
"PRODUCT_SOURCE_MANAGED"
|
|
145
|
+
];
|
|
146
|
+
var KNOWN_SERVER_CODES = new Set(SERVER_ERROR_CODES);
|
|
147
|
+
var ApiError = class extends Error {
|
|
148
|
+
code;
|
|
149
|
+
meta;
|
|
150
|
+
cause;
|
|
151
|
+
constructor(code, message, meta, cause) {
|
|
152
|
+
super(message);
|
|
153
|
+
this.name = "ApiError";
|
|
154
|
+
this.code = code;
|
|
155
|
+
this.meta = meta;
|
|
156
|
+
this.cause = cause;
|
|
499
157
|
}
|
|
500
158
|
};
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
)
|
|
510
|
-
|
|
511
|
-
|
|
159
|
+
async function longPoll(opts) {
|
|
160
|
+
const now = opts.now ?? Date.now;
|
|
161
|
+
const started = now();
|
|
162
|
+
for (; ; ) {
|
|
163
|
+
if (opts.signal?.aborted) {
|
|
164
|
+
throw new ApiError("TIMEOUT", "Wait was aborted.", { retryable: true });
|
|
165
|
+
}
|
|
166
|
+
const elapsedBefore = now() - started;
|
|
167
|
+
if (elapsedBefore >= opts.timeoutMs) {
|
|
168
|
+
throw new ApiError(
|
|
169
|
+
"TIMEOUT",
|
|
170
|
+
`Wait exceeded ${opts.timeoutMs}ms without reaching a terminal state.`,
|
|
171
|
+
{ retryable: true }
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const remainingMs = opts.timeoutMs - elapsedBefore;
|
|
175
|
+
const iterationSignal = composeIterationSignal(opts.signal, remainingMs);
|
|
176
|
+
let result;
|
|
177
|
+
try {
|
|
178
|
+
result = await opts.fetcher({ signal: iterationSignal });
|
|
179
|
+
} catch (err) {
|
|
180
|
+
if (opts.signal?.aborted || now() - started >= opts.timeoutMs) {
|
|
181
|
+
throw new ApiError(
|
|
182
|
+
"TIMEOUT",
|
|
183
|
+
`Wait exceeded ${opts.timeoutMs}ms without reaching a terminal state.`,
|
|
184
|
+
{ retryable: true }
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
if (opts.signal?.aborted) {
|
|
190
|
+
throw new ApiError("TIMEOUT", "Wait was aborted.", { retryable: true });
|
|
191
|
+
}
|
|
192
|
+
const elapsedAfter = now() - started;
|
|
193
|
+
if (elapsedAfter >= opts.timeoutMs) {
|
|
194
|
+
throw new ApiError(
|
|
195
|
+
"TIMEOUT",
|
|
196
|
+
`Wait exceeded ${opts.timeoutMs}ms without reaching a terminal state.`,
|
|
197
|
+
{ retryable: true }
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
if (opts.isTerminal(result)) {
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
512
204
|
}
|
|
513
|
-
function
|
|
514
|
-
|
|
205
|
+
function composeIterationSignal(userSignal, remainingMs) {
|
|
206
|
+
const deadlineSignal = AbortSignal.timeout(Math.max(remainingMs, 0));
|
|
207
|
+
return userSignal ? AbortSignal.any([userSignal, deadlineSignal]) : deadlineSignal;
|
|
515
208
|
}
|
|
516
|
-
var SIGINT_EXIT_CODE = 130;
|
|
517
|
-
|
|
518
|
-
// src/errors/schema-mismatch.ts
|
|
519
209
|
var MAX_ISSUES = 5;
|
|
520
210
|
function formatSchemaIssues(error) {
|
|
521
211
|
const issues = error.issues;
|
|
@@ -539,9 +229,6 @@ function formatPath(path) {
|
|
|
539
229
|
if (path.length === 0) return "(root)";
|
|
540
230
|
return path.map(String).join(".");
|
|
541
231
|
}
|
|
542
|
-
|
|
543
|
-
// src/api/idempotency.ts
|
|
544
|
-
import { createHash, randomUUID } from "crypto";
|
|
545
232
|
function generateIdempotencyKey() {
|
|
546
233
|
return randomUUID();
|
|
547
234
|
}
|
|
@@ -549,8 +236,6 @@ function generateUploadIdempotencyKey(content, scope) {
|
|
|
549
236
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
550
237
|
return `upload-${scope}-${hash}`;
|
|
551
238
|
}
|
|
552
|
-
|
|
553
|
-
// src/api/retry.ts
|
|
554
239
|
var DEFAULT_RETRY_OPTIONS = {
|
|
555
240
|
maxAttempts: 3,
|
|
556
241
|
baseDelayMs: 200,
|
|
@@ -564,7 +249,7 @@ function computeBackoffMs(attempt, baseDelayMs, maxDelayMs, jitterFraction) {
|
|
|
564
249
|
return Math.max(0, Math.round(exp + jitter));
|
|
565
250
|
}
|
|
566
251
|
function decideRetry(params) {
|
|
567
|
-
const { attempt, options, serverRetryAfterMs, isNetworkError, isRetryable } = params;
|
|
252
|
+
const { attempt, options, serverRetryAfterMs, isNetworkError, isRetryable, onWarning: onWarning2 } = params;
|
|
568
253
|
if (options.signal?.aborted) {
|
|
569
254
|
return { shouldRetry: false, delayMs: 0, reason: "aborted" };
|
|
570
255
|
}
|
|
@@ -577,7 +262,7 @@ function decideRetry(params) {
|
|
|
577
262
|
if (typeof serverRetryAfterMs === "number" && serverRetryAfterMs >= 0) {
|
|
578
263
|
let delayMs2 = serverRetryAfterMs;
|
|
579
264
|
if (delayMs2 > ABSOLUTE_MAX_RETRY_AFTER_MS) {
|
|
580
|
-
|
|
265
|
+
onWarning2?.(`Server Retry-After exceeded ${ABSOLUTE_MAX_RETRY_AFTER_MS}ms; clipping.`);
|
|
581
266
|
delayMs2 = ABSOLUTE_MAX_RETRY_AFTER_MS;
|
|
582
267
|
}
|
|
583
268
|
return { shouldRetry: true, delayMs: delayMs2, reason: "rate_limited" };
|
|
@@ -617,9 +302,6 @@ function signalToAbortError(signal) {
|
|
|
617
302
|
err.name = "AbortError";
|
|
618
303
|
return err;
|
|
619
304
|
}
|
|
620
|
-
|
|
621
|
-
// src/api/types.ts
|
|
622
|
-
import { z as z5 } from "zod";
|
|
623
305
|
var ServerSuccessSchema = (payload) => z5.object({ data: payload }).strict();
|
|
624
306
|
var ServerErrorBodySchema = z5.object({
|
|
625
307
|
error: z5.object({
|
|
@@ -630,20 +312,6 @@ var ServerErrorBodySchema = z5.object({
|
|
|
630
312
|
details: z5.unknown().optional()
|
|
631
313
|
}).strict()
|
|
632
314
|
}).strict();
|
|
633
|
-
|
|
634
|
-
// src/api/client.ts
|
|
635
|
-
var ApiError = class extends Error {
|
|
636
|
-
code;
|
|
637
|
-
meta;
|
|
638
|
-
cause;
|
|
639
|
-
constructor(code, message, meta, cause) {
|
|
640
|
-
super(message);
|
|
641
|
-
this.name = "ApiError";
|
|
642
|
-
this.code = code;
|
|
643
|
-
this.meta = meta;
|
|
644
|
-
this.cause = cause;
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
315
|
var REDACT_BODY_LIMIT = 1024;
|
|
648
316
|
var REDACT_INPUT_CAP = 100 * 1024;
|
|
649
317
|
var DEFAULT_USER_AGENT = "clickraft-cli";
|
|
@@ -700,7 +368,8 @@ var ApiClient = class {
|
|
|
700
368
|
options: { ...retry, signal },
|
|
701
369
|
serverRetryAfterMs: err.meta.retryAfterMs,
|
|
702
370
|
isNetworkError,
|
|
703
|
-
isRetryable
|
|
371
|
+
isRetryable,
|
|
372
|
+
onWarning: this.options.onWarning
|
|
704
373
|
});
|
|
705
374
|
if (!decision.shouldRetry) throw err;
|
|
706
375
|
try {
|
|
@@ -788,178 +457,613 @@ var ApiClient = class {
|
|
|
788
457
|
bodyText,
|
|
789
458
|
statusCode,
|
|
790
459
|
requestId,
|
|
791
|
-
retryAfterHeader: pickHeader(responseHeaders, "retry-after")
|
|
460
|
+
retryAfterHeader: pickHeader(responseHeaders, "retry-after"),
|
|
461
|
+
onWarning: this.options.onWarning,
|
|
462
|
+
isRetryableServerCode: this.options.isRetryableServerCode
|
|
792
463
|
});
|
|
793
464
|
}
|
|
794
465
|
};
|
|
795
|
-
function
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
code =
|
|
877
|
-
safeMessage =
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
return
|
|
466
|
+
function createClient(options) {
|
|
467
|
+
return new ApiClient(options);
|
|
468
|
+
}
|
|
469
|
+
function parseSuccessBody(args) {
|
|
470
|
+
let parsed;
|
|
471
|
+
try {
|
|
472
|
+
parsed = JSON.parse(args.bodyText);
|
|
473
|
+
} catch (err) {
|
|
474
|
+
throw new ApiError(
|
|
475
|
+
"PARSE_ERROR",
|
|
476
|
+
"Server returned a non-JSON response.",
|
|
477
|
+
{
|
|
478
|
+
status: args.statusCode,
|
|
479
|
+
requestId: args.requestId,
|
|
480
|
+
retryable: false,
|
|
481
|
+
redactedBody: redactAndTruncate(args.bodyText)
|
|
482
|
+
},
|
|
483
|
+
err
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
const envelope = ServerSuccessSchema(args.responseSchema ?? z6.unknown()).safeParse(parsed);
|
|
487
|
+
if (!envelope.success) {
|
|
488
|
+
const issues = formatSchemaIssues(envelope.error);
|
|
489
|
+
throw new ApiError(
|
|
490
|
+
"SCHEMA_MISMATCH",
|
|
491
|
+
`Server response did not match the expected schema. Issues: ${issues}`,
|
|
492
|
+
{
|
|
493
|
+
status: args.statusCode,
|
|
494
|
+
requestId: args.requestId,
|
|
495
|
+
retryable: false,
|
|
496
|
+
redactedBody: redactAndTruncate(args.bodyText)
|
|
497
|
+
}
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
return envelope.data.data;
|
|
501
|
+
}
|
|
502
|
+
function parseErrorBody(args) {
|
|
503
|
+
const redactedBody = redactAndTruncate(args.bodyText);
|
|
504
|
+
let parsed;
|
|
505
|
+
try {
|
|
506
|
+
parsed = JSON.parse(args.bodyText);
|
|
507
|
+
} catch {
|
|
508
|
+
return new ApiError(
|
|
509
|
+
"PARSE_ERROR",
|
|
510
|
+
`Server returned a ${args.statusCode} response with a non-JSON body.`,
|
|
511
|
+
{
|
|
512
|
+
status: args.statusCode,
|
|
513
|
+
requestId: args.requestId,
|
|
514
|
+
retryable: args.statusCode >= 500,
|
|
515
|
+
redactedBody
|
|
516
|
+
}
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
const envelope = ServerErrorBodySchema.safeParse(parsed);
|
|
520
|
+
if (!envelope.success) {
|
|
521
|
+
return new ApiError(
|
|
522
|
+
"PARSE_ERROR",
|
|
523
|
+
`Server returned ${args.statusCode} but body did not match the error envelope.`,
|
|
524
|
+
{
|
|
525
|
+
status: args.statusCode,
|
|
526
|
+
requestId: args.requestId,
|
|
527
|
+
retryable: args.statusCode >= 500,
|
|
528
|
+
redactedBody
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
return apiErrorFromServerBody({
|
|
533
|
+
body: envelope.data,
|
|
534
|
+
statusCode: args.statusCode,
|
|
535
|
+
requestId: args.requestId,
|
|
536
|
+
retryAfterHeader: args.retryAfterHeader,
|
|
537
|
+
redactedBody,
|
|
538
|
+
onWarning: args.onWarning,
|
|
539
|
+
isRetryableServerCode: args.isRetryableServerCode
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
function apiErrorFromServerBody(args) {
|
|
543
|
+
const { error } = args.body;
|
|
544
|
+
let code;
|
|
545
|
+
let safeMessage;
|
|
546
|
+
if (KNOWN_SERVER_CODES.has(error.code)) {
|
|
547
|
+
code = error.code;
|
|
548
|
+
safeMessage = redactTokenLikeFields(error.message);
|
|
549
|
+
} else {
|
|
550
|
+
const redactedRawCode = redactTokenLikeFields(error.code);
|
|
551
|
+
args.onWarning?.(`Unknown server error code: ${redactedRawCode}. Treating as INTERNAL_ERROR.`);
|
|
552
|
+
code = "INTERNAL_ERROR";
|
|
553
|
+
safeMessage = `Unknown server error code: ${redactedRawCode}.`;
|
|
554
|
+
}
|
|
555
|
+
const retryable = args.isRetryableServerCode?.(code) ?? (args.statusCode >= 500 || args.statusCode === 429);
|
|
556
|
+
const retryAfterMs = typeof error.retryAfter === "number" ? error.retryAfter * 1e3 : parseRetryAfterHeader(args.retryAfterHeader);
|
|
557
|
+
return new ApiError(code, safeMessage, {
|
|
558
|
+
status: args.statusCode,
|
|
559
|
+
requestId: error.correlationId ?? args.requestId,
|
|
560
|
+
retryable,
|
|
561
|
+
retryAfterMs,
|
|
562
|
+
redactedBody: args.redactedBody,
|
|
563
|
+
details: error.details
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
function parseRetryAfterHeader(headerValue) {
|
|
567
|
+
if (!headerValue) return void 0;
|
|
568
|
+
const trimmed = headerValue.trim();
|
|
569
|
+
if (/^\d+$/.test(trimmed)) {
|
|
570
|
+
return Number.parseInt(trimmed, 10) * 1e3;
|
|
571
|
+
}
|
|
572
|
+
if (/[A-Za-z]/.test(trimmed)) {
|
|
573
|
+
const parsed = Date.parse(trimmed);
|
|
574
|
+
if (!Number.isNaN(parsed)) {
|
|
575
|
+
return Math.max(0, parsed - Date.now());
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return void 0;
|
|
579
|
+
}
|
|
580
|
+
function buildUrl(baseUrl, path, query) {
|
|
581
|
+
const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
582
|
+
const relative = path.startsWith("/") ? path.slice(1) : path;
|
|
583
|
+
const url = new URL(relative, base);
|
|
584
|
+
if (query) {
|
|
585
|
+
for (const [key, value] of Object.entries(query)) {
|
|
586
|
+
if (value === void 0) continue;
|
|
587
|
+
if (Array.isArray(value)) {
|
|
588
|
+
for (const item of value) url.searchParams.append(key, item);
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
url.searchParams.append(key, String(value));
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return url.toString();
|
|
595
|
+
}
|
|
596
|
+
function serializeBody(opts) {
|
|
597
|
+
if (opts.body === void 0) return void 0;
|
|
598
|
+
if (opts.method === "GET") return void 0;
|
|
599
|
+
return JSON.stringify(opts.body);
|
|
600
|
+
}
|
|
601
|
+
function composeSignals(signals) {
|
|
602
|
+
const present = signals.filter((s) => s !== void 0);
|
|
603
|
+
if (present.length === 0) return new AbortController().signal;
|
|
604
|
+
if (present.length === 1) return present[0];
|
|
605
|
+
const any = AbortSignal.any;
|
|
606
|
+
if (typeof any === "function") return any(present);
|
|
607
|
+
const ctrl = new AbortController();
|
|
608
|
+
for (const s of present) {
|
|
609
|
+
if (s.aborted) {
|
|
610
|
+
ctrl.abort(s.reason);
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
s.addEventListener("abort", () => ctrl.abort(s.reason), { once: true });
|
|
614
|
+
}
|
|
615
|
+
return ctrl.signal;
|
|
616
|
+
}
|
|
617
|
+
function pickHeader(headers, name) {
|
|
618
|
+
const value = headers[name] ?? headers[name.toLowerCase()];
|
|
619
|
+
if (Array.isArray(value)) return value[0];
|
|
620
|
+
return value;
|
|
621
|
+
}
|
|
622
|
+
function redactAndTruncate(body) {
|
|
623
|
+
const input = body.length > REDACT_INPUT_CAP ? body.slice(0, REDACT_INPUT_CAP) : body;
|
|
624
|
+
const redacted = redactTokenLikeFields(input);
|
|
625
|
+
return redacted.length > REDACT_BODY_LIMIT ? `${redacted.slice(0, REDACT_BODY_LIMIT)}\u2026` : redacted;
|
|
626
|
+
}
|
|
627
|
+
function isAbortError(err) {
|
|
628
|
+
if (!(err instanceof Error)) return false;
|
|
629
|
+
return err.name === "AbortError" || /aborted/i.test(err.message);
|
|
630
|
+
}
|
|
631
|
+
function toAbortApiError(signal, cause) {
|
|
632
|
+
const reasonMessage = signal.reason instanceof Error ? signal.reason.message : "Request was aborted.";
|
|
633
|
+
return new ApiError("TIMEOUT", reasonMessage, { retryable: true }, cause);
|
|
634
|
+
}
|
|
635
|
+
function errorMessage(err) {
|
|
636
|
+
if (err instanceof Error) return err.message;
|
|
637
|
+
return String(err);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// src/errors/codes.ts
|
|
641
|
+
var LOGIN_HINT = "Run `clickraft login` to authenticate.";
|
|
642
|
+
var RELOGIN_HINT = "Run `clickraft login` to refresh.";
|
|
643
|
+
var EXIT_CODE_MAP = {
|
|
644
|
+
// --- 37 Phase 8 Q7 codes ----------------------------------------------------
|
|
645
|
+
AUTH_TOKEN_MISSING: {
|
|
646
|
+
exitCode: 3,
|
|
647
|
+
category: "auth",
|
|
648
|
+
retryable: false,
|
|
649
|
+
hint: "Set `CLICKRAFT_TOKEN` or run `clickraft login`."
|
|
650
|
+
},
|
|
651
|
+
AUTH_TOKEN_INVALID: {
|
|
652
|
+
exitCode: 3,
|
|
653
|
+
category: "auth",
|
|
654
|
+
retryable: false,
|
|
655
|
+
hint: "The token is malformed or unknown. Run `clickraft login`."
|
|
656
|
+
},
|
|
657
|
+
AUTH_TOKEN_EXPIRED: {
|
|
658
|
+
exitCode: 3,
|
|
659
|
+
category: "auth",
|
|
660
|
+
retryable: false,
|
|
661
|
+
hint: RELOGIN_HINT
|
|
662
|
+
},
|
|
663
|
+
AUTH_TOKEN_REVOKED: {
|
|
664
|
+
exitCode: 3,
|
|
665
|
+
category: "auth",
|
|
666
|
+
retryable: false,
|
|
667
|
+
hint: "Token was revoked. Run `clickraft login` to mint a new one."
|
|
668
|
+
},
|
|
669
|
+
AUTH_TOKEN_SCOPE_INSUFFICIENT: {
|
|
670
|
+
exitCode: 4,
|
|
671
|
+
category: "permission",
|
|
672
|
+
retryable: false,
|
|
673
|
+
hint: "This token does not have the required scope. Re-run `clickraft login` selecting the needed scopes."
|
|
674
|
+
},
|
|
675
|
+
AUTH_ORG_MISMATCH: {
|
|
676
|
+
exitCode: 4,
|
|
677
|
+
category: "permission",
|
|
678
|
+
retryable: false,
|
|
679
|
+
hint: "This token's org no longer exists or you have been removed."
|
|
680
|
+
},
|
|
681
|
+
AUTH_DEVICE_CODE_PENDING: {
|
|
682
|
+
exitCode: 0,
|
|
683
|
+
category: "success",
|
|
684
|
+
retryable: false,
|
|
685
|
+
hint: "Continue polling."
|
|
686
|
+
},
|
|
687
|
+
AUTH_DEVICE_CODE_EXPIRED: {
|
|
688
|
+
exitCode: 3,
|
|
689
|
+
category: "auth",
|
|
690
|
+
retryable: false,
|
|
691
|
+
hint: "Device code expired. Re-run `clickraft login`."
|
|
692
|
+
},
|
|
693
|
+
AUTH_DEVICE_CODE_SLOW_DOWN: {
|
|
694
|
+
exitCode: 0,
|
|
695
|
+
category: "success",
|
|
696
|
+
retryable: false,
|
|
697
|
+
hint: "Increase polling interval (Retry-After)."
|
|
698
|
+
},
|
|
699
|
+
IDEMPOTENCY_KEY_MISSING: {
|
|
700
|
+
exitCode: 2,
|
|
701
|
+
category: "usage",
|
|
702
|
+
retryable: false,
|
|
703
|
+
hint: "Add `X-Idempotency-Key` header (or `--idempotency-key`)."
|
|
704
|
+
},
|
|
705
|
+
IDEMPOTENCY_KEY_CONFLICT: {
|
|
706
|
+
exitCode: 7,
|
|
707
|
+
category: "conflict",
|
|
708
|
+
retryable: false,
|
|
709
|
+
hint: "Same key was used with a different request body. Use a new key."
|
|
710
|
+
},
|
|
711
|
+
PLAN_FEATURE_LOCKED: {
|
|
712
|
+
exitCode: 4,
|
|
713
|
+
category: "permission",
|
|
714
|
+
retryable: false,
|
|
715
|
+
hint: "API access is not enabled on your plan. Visit billing settings."
|
|
716
|
+
},
|
|
717
|
+
PLAN_QUOTA_EXCEEDED: {
|
|
718
|
+
exitCode: 5,
|
|
719
|
+
category: "quota",
|
|
720
|
+
retryable: false,
|
|
721
|
+
hint: "Daily API quota exhausted. Wait, or upgrade your plan."
|
|
722
|
+
},
|
|
723
|
+
INSUFFICIENT_CREDITS: {
|
|
724
|
+
exitCode: 5,
|
|
725
|
+
category: "quota",
|
|
726
|
+
retryable: false,
|
|
727
|
+
hint: "Top up credits to retry."
|
|
728
|
+
},
|
|
729
|
+
CREDIT_DEDUCTION_FAILED: {
|
|
730
|
+
exitCode: 1,
|
|
731
|
+
category: "runtime",
|
|
732
|
+
retryable: true,
|
|
733
|
+
hint: "Could not charge credits. Retry; no charge was made."
|
|
734
|
+
},
|
|
735
|
+
RATE_LIMITED: {
|
|
736
|
+
exitCode: 5,
|
|
737
|
+
category: "quota",
|
|
738
|
+
retryable: true,
|
|
739
|
+
hint: "Slow down. Honor Retry-After."
|
|
740
|
+
},
|
|
741
|
+
INPUT_INVALID_FORMAT: {
|
|
742
|
+
exitCode: 2,
|
|
743
|
+
category: "usage",
|
|
744
|
+
retryable: false,
|
|
745
|
+
hint: "Check input format and try again."
|
|
746
|
+
},
|
|
747
|
+
INPUT_TOO_LONG: {
|
|
748
|
+
exitCode: 2,
|
|
749
|
+
category: "usage",
|
|
750
|
+
retryable: false,
|
|
751
|
+
hint: "Field exceeded max length."
|
|
752
|
+
},
|
|
753
|
+
WORKFLOW_VALIDATION_FAILED: {
|
|
754
|
+
exitCode: 2,
|
|
755
|
+
category: "usage",
|
|
756
|
+
retryable: false,
|
|
757
|
+
hint: "Run `workflow validate` for the full list of errors."
|
|
758
|
+
},
|
|
759
|
+
WORKFLOW_NODE_TYPE_UNKNOWN: {
|
|
760
|
+
exitCode: 2,
|
|
761
|
+
category: "usage",
|
|
762
|
+
retryable: false,
|
|
763
|
+
hint: "Run `clickraft nodes list` for the current set of node types."
|
|
764
|
+
},
|
|
765
|
+
CANVAS_REV_MISMATCH: {
|
|
766
|
+
exitCode: 7,
|
|
767
|
+
category: "conflict",
|
|
768
|
+
retryable: false,
|
|
769
|
+
hint: "The workflow was updated elsewhere. Re-fetch and retry with the current canvas_rev."
|
|
770
|
+
},
|
|
771
|
+
CANVAS_REV_REQUIRED: {
|
|
772
|
+
exitCode: 2,
|
|
773
|
+
category: "usage",
|
|
774
|
+
retryable: false,
|
|
775
|
+
hint: "Include --canvas-rev or use --auto-rev."
|
|
776
|
+
},
|
|
777
|
+
WORKER_UNREACHABLE: {
|
|
778
|
+
exitCode: 6,
|
|
779
|
+
category: "network",
|
|
780
|
+
retryable: true,
|
|
781
|
+
hint: "Collaboration service temporarily unavailable. Retry."
|
|
782
|
+
},
|
|
783
|
+
IDEMPOTENCY_IN_PROGRESS: {
|
|
784
|
+
exitCode: 7,
|
|
785
|
+
category: "conflict",
|
|
786
|
+
retryable: false,
|
|
787
|
+
hint: "A request with this idempotency key is currently in-flight. Retry in a moment."
|
|
788
|
+
},
|
|
789
|
+
TOKEN_NAME_INVALID: {
|
|
790
|
+
exitCode: 2,
|
|
791
|
+
category: "usage",
|
|
792
|
+
retryable: false,
|
|
793
|
+
hint: "Agent token name is malformed."
|
|
794
|
+
},
|
|
795
|
+
WORKFLOW_NOT_FOUND: {
|
|
796
|
+
exitCode: 2,
|
|
797
|
+
category: "usage",
|
|
798
|
+
retryable: false,
|
|
799
|
+
hint: "No workflow with that ID in your org."
|
|
800
|
+
},
|
|
801
|
+
NOT_FOUND: {
|
|
802
|
+
exitCode: 2,
|
|
803
|
+
category: "usage",
|
|
804
|
+
retryable: false,
|
|
805
|
+
hint: "Resource not found."
|
|
806
|
+
},
|
|
807
|
+
NODE_TYPE_NOT_FOUND: {
|
|
808
|
+
exitCode: 2,
|
|
809
|
+
category: "usage",
|
|
810
|
+
retryable: false,
|
|
811
|
+
hint: "Run `clickraft nodes list` for the current set of node types."
|
|
812
|
+
},
|
|
813
|
+
FEATURE_DISABLED: {
|
|
814
|
+
exitCode: 2,
|
|
815
|
+
category: "usage",
|
|
816
|
+
retryable: false,
|
|
817
|
+
hint: "This endpoint is not enabled. Contact support if you believe this is in error."
|
|
818
|
+
},
|
|
819
|
+
FORBIDDEN: {
|
|
820
|
+
exitCode: 4,
|
|
821
|
+
category: "permission",
|
|
822
|
+
retryable: false,
|
|
823
|
+
hint: "Your role does not permit this action."
|
|
824
|
+
},
|
|
825
|
+
MODEL_NOT_FOUND: {
|
|
826
|
+
exitCode: 2,
|
|
827
|
+
category: "usage",
|
|
828
|
+
retryable: false,
|
|
829
|
+
hint: "Unknown `modelSlug`. Run `brand-model list` for the current set."
|
|
830
|
+
},
|
|
831
|
+
PROVIDER_UNAVAILABLE: {
|
|
832
|
+
exitCode: 6,
|
|
833
|
+
category: "network",
|
|
834
|
+
retryable: true,
|
|
835
|
+
hint: "Provider is temporarily unavailable. Retry shortly."
|
|
836
|
+
},
|
|
837
|
+
STORAGE_UPLOAD_FAILED: {
|
|
838
|
+
exitCode: 1,
|
|
839
|
+
category: "runtime",
|
|
840
|
+
retryable: true,
|
|
841
|
+
hint: "Upload failed mid-stream. Retry."
|
|
842
|
+
},
|
|
843
|
+
STORAGE_QUOTA_EXCEEDED: {
|
|
844
|
+
exitCode: 5,
|
|
845
|
+
category: "quota",
|
|
846
|
+
retryable: false,
|
|
847
|
+
hint: "Org storage quota exceeded. Free space or upgrade."
|
|
848
|
+
},
|
|
849
|
+
GEN_CONTENT_REFUSAL: {
|
|
850
|
+
exitCode: 1,
|
|
851
|
+
category: "runtime",
|
|
852
|
+
retryable: false,
|
|
853
|
+
hint: "The model declined the request via safety policy."
|
|
854
|
+
},
|
|
855
|
+
GEN_OUTPUT_SCHEMA_MISMATCH: {
|
|
856
|
+
exitCode: 1,
|
|
857
|
+
category: "runtime",
|
|
858
|
+
retryable: true,
|
|
859
|
+
hint: "Provider returned malformed output. Full refund issued. Retry."
|
|
860
|
+
},
|
|
861
|
+
GEN_EMPTY_OUTPUT: {
|
|
862
|
+
exitCode: 1,
|
|
863
|
+
category: "runtime",
|
|
864
|
+
retryable: true,
|
|
865
|
+
hint: "Provider returned no usable output. Full refund issued. Retry."
|
|
866
|
+
},
|
|
867
|
+
GEN_ITEM_COUNT_MISMATCH: {
|
|
868
|
+
exitCode: 0,
|
|
869
|
+
category: "success",
|
|
870
|
+
retryable: false,
|
|
871
|
+
hint: "Partial output kept; no refund."
|
|
872
|
+
},
|
|
873
|
+
AGENT_FINGERPRINT_REJECTED: {
|
|
874
|
+
exitCode: 4,
|
|
875
|
+
category: "permission",
|
|
876
|
+
retryable: false,
|
|
877
|
+
hint: "This client identification is not permitted. Contact support."
|
|
878
|
+
},
|
|
879
|
+
INTERNAL_ERROR: {
|
|
880
|
+
exitCode: 1,
|
|
881
|
+
category: "runtime",
|
|
882
|
+
retryable: true,
|
|
883
|
+
hint: "Server error. Retry; if it persists, contact support with the request ID."
|
|
884
|
+
},
|
|
885
|
+
CREDENTIALS_LOCKED: {
|
|
886
|
+
exitCode: 1,
|
|
887
|
+
category: "runtime",
|
|
888
|
+
retryable: true,
|
|
889
|
+
hint: "Another CLI invocation holds the credentials lock. Retry shortly."
|
|
890
|
+
},
|
|
891
|
+
CREDENTIALS_PERMISSIONS_LOOSE: {
|
|
892
|
+
exitCode: 0,
|
|
893
|
+
category: "success",
|
|
894
|
+
retryable: false,
|
|
895
|
+
hint: "Credentials file mode is wider than 0600; continuing."
|
|
896
|
+
},
|
|
897
|
+
// --- 5 additional codes introduced by 1A.1 ---------------------------------
|
|
898
|
+
AUTH_ACCESS_DENIED: {
|
|
899
|
+
exitCode: 3,
|
|
900
|
+
category: "auth",
|
|
901
|
+
retryable: false,
|
|
902
|
+
hint: "You denied the OAuth grant. Re-run `clickraft login` to retry."
|
|
903
|
+
},
|
|
904
|
+
AUTH_FLOW_CANCELLED: {
|
|
905
|
+
exitCode: 3,
|
|
906
|
+
category: "auth",
|
|
907
|
+
retryable: false,
|
|
908
|
+
hint: "Authentication was cancelled. Re-run `clickraft login`."
|
|
909
|
+
},
|
|
910
|
+
CREDENTIALS_CORRUPT: {
|
|
911
|
+
exitCode: 1,
|
|
912
|
+
category: "runtime",
|
|
913
|
+
retryable: false,
|
|
914
|
+
hint: "Credentials file is unreadable. Remove it and run `clickraft login`."
|
|
915
|
+
},
|
|
916
|
+
CREDENTIALS_NOT_FOUND: {
|
|
917
|
+
exitCode: 3,
|
|
918
|
+
category: "auth",
|
|
919
|
+
retryable: false,
|
|
920
|
+
hint: LOGIN_HINT
|
|
921
|
+
},
|
|
922
|
+
CREDENTIALS_PROFILE_NOT_FOUND: {
|
|
923
|
+
exitCode: 2,
|
|
924
|
+
category: "usage",
|
|
925
|
+
retryable: false,
|
|
926
|
+
hint: "No such profile. Use `clickraft auth profiles` to list available profiles."
|
|
927
|
+
},
|
|
928
|
+
// --- 8 brand model resolution codes -----------------------------------------
|
|
929
|
+
BRAND_MODEL_NOT_FOUND: {
|
|
930
|
+
exitCode: 1,
|
|
931
|
+
category: "runtime",
|
|
932
|
+
retryable: false,
|
|
933
|
+
hint: "No brand model with that ID. Run `clickraft brand-model list`."
|
|
934
|
+
},
|
|
935
|
+
BRAND_MODEL_NOT_A_MODEL: {
|
|
936
|
+
exitCode: 1,
|
|
937
|
+
category: "runtime",
|
|
938
|
+
retryable: false,
|
|
939
|
+
hint: "The specified asset is not a brand model."
|
|
940
|
+
},
|
|
941
|
+
BRAND_MODEL_NOT_ACTIVE: {
|
|
942
|
+
exitCode: 1,
|
|
943
|
+
category: "runtime",
|
|
944
|
+
retryable: false,
|
|
945
|
+
hint: "Brand model is not active. Check its status in the dashboard."
|
|
946
|
+
},
|
|
947
|
+
BRAND_MODEL_NO_REFERENCES: {
|
|
948
|
+
exitCode: 1,
|
|
949
|
+
category: "runtime",
|
|
950
|
+
retryable: false,
|
|
951
|
+
hint: "Brand model has no reference images. Upload references first."
|
|
952
|
+
},
|
|
953
|
+
BRAND_MODEL_POSE_NOT_FOUND: {
|
|
954
|
+
exitCode: 1,
|
|
955
|
+
category: "runtime",
|
|
956
|
+
retryable: false,
|
|
957
|
+
hint: "Requested pose not found. Valid: front, 3/4-right, right, left, 3/4-left, back, approved."
|
|
958
|
+
},
|
|
959
|
+
BRAND_MODEL_DUPLICATE_ID: {
|
|
960
|
+
exitCode: 2,
|
|
961
|
+
category: "usage",
|
|
962
|
+
retryable: false,
|
|
963
|
+
hint: "Same brand model ID appears more than once."
|
|
964
|
+
},
|
|
965
|
+
MODEL_DOES_NOT_SUPPORT_REFERENCES: {
|
|
966
|
+
exitCode: 2,
|
|
967
|
+
category: "usage",
|
|
968
|
+
retryable: false,
|
|
969
|
+
hint: "This model does not support brand model references."
|
|
970
|
+
},
|
|
971
|
+
REFERENCE_LIMIT_EXCEEDED: {
|
|
972
|
+
exitCode: 2,
|
|
973
|
+
category: "usage",
|
|
974
|
+
retryable: false,
|
|
975
|
+
hint: "Too many reference images. Check model limits."
|
|
976
|
+
},
|
|
977
|
+
// --- 8 product reference resolver codes -------------------------------------
|
|
978
|
+
PRODUCT_NOT_FOUND: {
|
|
979
|
+
exitCode: 1,
|
|
980
|
+
category: "runtime",
|
|
981
|
+
retryable: false,
|
|
982
|
+
hint: "No product with that ID in your org. Run `clickraft product list`."
|
|
983
|
+
},
|
|
984
|
+
PRODUCT_DUPLICATE_REFERENCE: {
|
|
985
|
+
exitCode: 2,
|
|
986
|
+
category: "usage",
|
|
987
|
+
retryable: false,
|
|
988
|
+
hint: "Same (productId, imageId) tuple appears twice in the request."
|
|
989
|
+
},
|
|
990
|
+
PRODUCT_IMAGE_NOT_FOUND: {
|
|
991
|
+
exitCode: 1,
|
|
992
|
+
category: "runtime",
|
|
993
|
+
retryable: false,
|
|
994
|
+
hint: "imageId does not exist in the product images."
|
|
995
|
+
},
|
|
996
|
+
PRODUCT_IMAGE_MISMATCH: {
|
|
997
|
+
exitCode: 2,
|
|
998
|
+
category: "usage",
|
|
999
|
+
retryable: false,
|
|
1000
|
+
hint: "imageId belongs to a different product."
|
|
1001
|
+
},
|
|
1002
|
+
PRODUCT_SYNC_ERROR: {
|
|
1003
|
+
exitCode: 1,
|
|
1004
|
+
category: "runtime",
|
|
1005
|
+
retryable: false,
|
|
1006
|
+
hint: "Product sync status is 'error'. Re-sync or use a different product."
|
|
1007
|
+
},
|
|
1008
|
+
PRODUCT_DELETED_UPSTREAM: {
|
|
1009
|
+
exitCode: 1,
|
|
1010
|
+
category: "runtime",
|
|
1011
|
+
retryable: false,
|
|
1012
|
+
hint: "Product was deleted upstream. Remove it or re-sync."
|
|
1013
|
+
},
|
|
1014
|
+
PRODUCT_NO_PRIMARY_IMAGE: {
|
|
1015
|
+
exitCode: 1,
|
|
1016
|
+
category: "runtime",
|
|
1017
|
+
retryable: false,
|
|
1018
|
+
hint: "Product has no primary image. Specify --product <id>:<imageId> explicitly."
|
|
1019
|
+
},
|
|
1020
|
+
PRODUCT_SOURCE_MANAGED: {
|
|
1021
|
+
exitCode: 4,
|
|
1022
|
+
category: "permission",
|
|
1023
|
+
retryable: false,
|
|
1024
|
+
hint: "Product is managed by an external integration."
|
|
1025
|
+
},
|
|
1026
|
+
// --- 4 CLI-synthetic codes --------------------------------------------------
|
|
1027
|
+
NETWORK_ERROR: {
|
|
1028
|
+
exitCode: 6,
|
|
1029
|
+
category: "network",
|
|
1030
|
+
retryable: true,
|
|
1031
|
+
hint: "Network connection failed. Check connectivity and retry."
|
|
1032
|
+
},
|
|
1033
|
+
TIMEOUT: {
|
|
1034
|
+
exitCode: 6,
|
|
1035
|
+
category: "network",
|
|
1036
|
+
retryable: true,
|
|
1037
|
+
hint: "Request timed out. Retry; consider increasing the timeout."
|
|
1038
|
+
},
|
|
1039
|
+
PARSE_ERROR: {
|
|
1040
|
+
exitCode: 1,
|
|
1041
|
+
category: "runtime",
|
|
1042
|
+
retryable: false,
|
|
1043
|
+
hint: "Server returned an unexpected response. Contact support with the request ID."
|
|
1044
|
+
},
|
|
1045
|
+
SCHEMA_MISMATCH: {
|
|
1046
|
+
exitCode: 1,
|
|
1047
|
+
category: "runtime",
|
|
1048
|
+
retryable: false,
|
|
1049
|
+
hint: "Server response did not match the expected schema. Update the CLI."
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
function getExitCode(code) {
|
|
1053
|
+
return EXIT_CODE_MAP[code]?.exitCode ?? 1;
|
|
955
1054
|
}
|
|
956
|
-
function
|
|
957
|
-
|
|
958
|
-
return new ApiError("TIMEOUT", reasonMessage, { retryable: true }, cause);
|
|
1055
|
+
function toEnvelopeCode(code) {
|
|
1056
|
+
return code.startsWith("E_") ? code : `E_${code}`;
|
|
959
1057
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1058
|
+
var SIGINT_EXIT_CODE = 130;
|
|
1059
|
+
|
|
1060
|
+
// src/api/client.ts
|
|
1061
|
+
var isRetryableServerCode = (code) => EXIT_CODE_MAP[code].retryable;
|
|
1062
|
+
var onWarning = (msg) => {
|
|
1063
|
+
console.warn(msg);
|
|
1064
|
+
};
|
|
1065
|
+
function createApiClient(opts) {
|
|
1066
|
+
return createClient({ ...opts, onWarning, isRetryableServerCode });
|
|
963
1067
|
}
|
|
964
1068
|
|
|
965
1069
|
// src/auth/errors.ts
|
|
@@ -1388,7 +1492,7 @@ async function getBalance(options) {
|
|
|
1388
1492
|
if (!config.accessToken) {
|
|
1389
1493
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
1390
1494
|
}
|
|
1391
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
1495
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
1392
1496
|
apiBaseUrl,
|
|
1393
1497
|
accessToken,
|
|
1394
1498
|
signal: options.signal,
|
|
@@ -1414,7 +1518,7 @@ async function listBrandModels(options) {
|
|
|
1414
1518
|
if (!config.accessToken) {
|
|
1415
1519
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
1416
1520
|
}
|
|
1417
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
1521
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
1418
1522
|
apiBaseUrl,
|
|
1419
1523
|
accessToken,
|
|
1420
1524
|
signal: options.signal,
|
|
@@ -1579,7 +1683,7 @@ async function buildClient(opts) {
|
|
|
1579
1683
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
1580
1684
|
flagToken: opts.token
|
|
1581
1685
|
});
|
|
1582
|
-
return
|
|
1686
|
+
return createApiClient({
|
|
1583
1687
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
1584
1688
|
accessToken: cfg.accessToken,
|
|
1585
1689
|
signal: opts.signal,
|
|
@@ -1746,7 +1850,7 @@ async function buildGenerateClient(opts) {
|
|
|
1746
1850
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
1747
1851
|
flagToken: opts.token
|
|
1748
1852
|
});
|
|
1749
|
-
return
|
|
1853
|
+
return createApiClient({
|
|
1750
1854
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
1751
1855
|
accessToken: cfg.accessToken,
|
|
1752
1856
|
signal: opts.signal,
|
|
@@ -1757,58 +1861,6 @@ function isUrlLike(value) {
|
|
|
1757
1861
|
return value.startsWith("http://") || value.startsWith("https://");
|
|
1758
1862
|
}
|
|
1759
1863
|
|
|
1760
|
-
// src/cli/long-poll.ts
|
|
1761
|
-
async function longPoll(opts) {
|
|
1762
|
-
const now = opts.now ?? Date.now;
|
|
1763
|
-
const started = now();
|
|
1764
|
-
for (; ; ) {
|
|
1765
|
-
if (opts.signal?.aborted) {
|
|
1766
|
-
throw new ApiError("TIMEOUT", "Wait was aborted.", { retryable: true });
|
|
1767
|
-
}
|
|
1768
|
-
const elapsedBefore = now() - started;
|
|
1769
|
-
if (elapsedBefore >= opts.timeoutMs) {
|
|
1770
|
-
throw new ApiError(
|
|
1771
|
-
"TIMEOUT",
|
|
1772
|
-
`Wait exceeded ${opts.timeoutMs}ms without reaching a terminal state.`,
|
|
1773
|
-
{ retryable: true }
|
|
1774
|
-
);
|
|
1775
|
-
}
|
|
1776
|
-
const remainingMs = opts.timeoutMs - elapsedBefore;
|
|
1777
|
-
const iterationSignal = composeIterationSignal(opts.signal, remainingMs);
|
|
1778
|
-
let result;
|
|
1779
|
-
try {
|
|
1780
|
-
result = await opts.fetcher({ signal: iterationSignal });
|
|
1781
|
-
} catch (err) {
|
|
1782
|
-
if (opts.signal?.aborted || now() - started >= opts.timeoutMs) {
|
|
1783
|
-
throw new ApiError(
|
|
1784
|
-
"TIMEOUT",
|
|
1785
|
-
`Wait exceeded ${opts.timeoutMs}ms without reaching a terminal state.`,
|
|
1786
|
-
{ retryable: true }
|
|
1787
|
-
);
|
|
1788
|
-
}
|
|
1789
|
-
throw err;
|
|
1790
|
-
}
|
|
1791
|
-
if (opts.signal?.aborted) {
|
|
1792
|
-
throw new ApiError("TIMEOUT", "Wait was aborted.", { retryable: true });
|
|
1793
|
-
}
|
|
1794
|
-
const elapsedAfter = now() - started;
|
|
1795
|
-
if (elapsedAfter >= opts.timeoutMs) {
|
|
1796
|
-
throw new ApiError(
|
|
1797
|
-
"TIMEOUT",
|
|
1798
|
-
`Wait exceeded ${opts.timeoutMs}ms without reaching a terminal state.`,
|
|
1799
|
-
{ retryable: true }
|
|
1800
|
-
);
|
|
1801
|
-
}
|
|
1802
|
-
if (opts.isTerminal(result)) {
|
|
1803
|
-
return result;
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
function composeIterationSignal(userSignal, remainingMs) {
|
|
1808
|
-
const deadlineSignal = AbortSignal.timeout(Math.max(remainingMs, 0));
|
|
1809
|
-
return userSignal ? AbortSignal.any([userSignal, deadlineSignal]) : deadlineSignal;
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
1864
|
// src/commands/generate/get.ts
|
|
1813
1865
|
async function generateGet(opts) {
|
|
1814
1866
|
const client = opts.client ?? await buildGenerateClient(opts);
|
|
@@ -2570,7 +2622,7 @@ async function logout(options) {
|
|
|
2570
2622
|
let serverRevoked = false;
|
|
2571
2623
|
let revokeFailureMessage;
|
|
2572
2624
|
if (options.revoke) {
|
|
2573
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
2625
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
2574
2626
|
apiBaseUrl,
|
|
2575
2627
|
accessToken,
|
|
2576
2628
|
signal: options.signal,
|
|
@@ -2655,7 +2707,7 @@ async function buildModelClient(opts) {
|
|
|
2655
2707
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
2656
2708
|
flagToken: opts.token
|
|
2657
2709
|
});
|
|
2658
|
-
return
|
|
2710
|
+
return createApiClient({
|
|
2659
2711
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
2660
2712
|
accessToken: cfg.accessToken,
|
|
2661
2713
|
signal: opts.signal,
|
|
@@ -2708,7 +2760,7 @@ async function buildNodesClient(opts) {
|
|
|
2708
2760
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
2709
2761
|
flagToken: opts.token
|
|
2710
2762
|
});
|
|
2711
|
-
return
|
|
2763
|
+
return createApiClient({
|
|
2712
2764
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
2713
2765
|
accessToken: cfg.accessToken,
|
|
2714
2766
|
signal: opts.signal,
|
|
@@ -2752,7 +2804,7 @@ async function listProducts(options) {
|
|
|
2752
2804
|
if (!config.accessToken) {
|
|
2753
2805
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
2754
2806
|
}
|
|
2755
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
2807
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
2756
2808
|
apiBaseUrl,
|
|
2757
2809
|
accessToken,
|
|
2758
2810
|
signal: options.signal,
|
|
@@ -2861,7 +2913,7 @@ async function buildTemplateClient(opts) {
|
|
|
2861
2913
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
2862
2914
|
flagToken: opts.token
|
|
2863
2915
|
});
|
|
2864
|
-
return
|
|
2916
|
+
return createApiClient({
|
|
2865
2917
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
2866
2918
|
accessToken: cfg.accessToken,
|
|
2867
2919
|
signal: opts.signal,
|
|
@@ -2955,7 +3007,7 @@ async function listTokens(options) {
|
|
|
2955
3007
|
if (!config.accessToken) {
|
|
2956
3008
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
2957
3009
|
}
|
|
2958
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
3010
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
2959
3011
|
apiBaseUrl,
|
|
2960
3012
|
accessToken,
|
|
2961
3013
|
signal: options.signal,
|
|
@@ -3027,7 +3079,7 @@ async function buildWorkflowClient(opts) {
|
|
|
3027
3079
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
3028
3080
|
flagToken: opts.token
|
|
3029
3081
|
});
|
|
3030
|
-
return
|
|
3082
|
+
return createApiClient({
|
|
3031
3083
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
3032
3084
|
accessToken: cfg.accessToken,
|
|
3033
3085
|
signal: opts.signal,
|