@clickraft/cli 0.8.4 → 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 -1
- package/dist/cli.js +459 -455
- package/dist/cli.js.map +1 -1
- package/dist/index.js +459 -455
- 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) {
|
|
@@ -202,432 +206,6 @@ function composeIterationSignal(userSignal, remainingMs) {
|
|
|
202
206
|
const deadlineSignal = AbortSignal.timeout(Math.max(remainingMs, 0));
|
|
203
207
|
return userSignal ? AbortSignal.any([userSignal, deadlineSignal]) : deadlineSignal;
|
|
204
208
|
}
|
|
205
|
-
|
|
206
|
-
// src/api/client.ts
|
|
207
|
-
import { request as undiciRequest } from "undici";
|
|
208
|
-
import { z as z6 } from "zod";
|
|
209
|
-
|
|
210
|
-
// src/errors/codes.ts
|
|
211
|
-
var LOGIN_HINT = "Run `clickraft login` to authenticate.";
|
|
212
|
-
var RELOGIN_HINT = "Run `clickraft login` to refresh.";
|
|
213
|
-
var EXIT_CODE_MAP = {
|
|
214
|
-
// --- 37 Phase 8 Q7 codes ----------------------------------------------------
|
|
215
|
-
AUTH_TOKEN_MISSING: {
|
|
216
|
-
exitCode: 3,
|
|
217
|
-
category: "auth",
|
|
218
|
-
retryable: false,
|
|
219
|
-
hint: "Set `CLICKRAFT_TOKEN` or run `clickraft login`."
|
|
220
|
-
},
|
|
221
|
-
AUTH_TOKEN_INVALID: {
|
|
222
|
-
exitCode: 3,
|
|
223
|
-
category: "auth",
|
|
224
|
-
retryable: false,
|
|
225
|
-
hint: "The token is malformed or unknown. Run `clickraft login`."
|
|
226
|
-
},
|
|
227
|
-
AUTH_TOKEN_EXPIRED: {
|
|
228
|
-
exitCode: 3,
|
|
229
|
-
category: "auth",
|
|
230
|
-
retryable: false,
|
|
231
|
-
hint: RELOGIN_HINT
|
|
232
|
-
},
|
|
233
|
-
AUTH_TOKEN_REVOKED: {
|
|
234
|
-
exitCode: 3,
|
|
235
|
-
category: "auth",
|
|
236
|
-
retryable: false,
|
|
237
|
-
hint: "Token was revoked. Run `clickraft login` to mint a new one."
|
|
238
|
-
},
|
|
239
|
-
AUTH_TOKEN_SCOPE_INSUFFICIENT: {
|
|
240
|
-
exitCode: 4,
|
|
241
|
-
category: "permission",
|
|
242
|
-
retryable: false,
|
|
243
|
-
hint: "This token does not have the required scope. Re-run `clickraft login` selecting the needed scopes."
|
|
244
|
-
},
|
|
245
|
-
AUTH_ORG_MISMATCH: {
|
|
246
|
-
exitCode: 4,
|
|
247
|
-
category: "permission",
|
|
248
|
-
retryable: false,
|
|
249
|
-
hint: "This token's org no longer exists or you have been removed."
|
|
250
|
-
},
|
|
251
|
-
AUTH_DEVICE_CODE_PENDING: {
|
|
252
|
-
exitCode: 0,
|
|
253
|
-
category: "success",
|
|
254
|
-
retryable: false,
|
|
255
|
-
hint: "Continue polling."
|
|
256
|
-
},
|
|
257
|
-
AUTH_DEVICE_CODE_EXPIRED: {
|
|
258
|
-
exitCode: 3,
|
|
259
|
-
category: "auth",
|
|
260
|
-
retryable: false,
|
|
261
|
-
hint: "Device code expired. Re-run `clickraft login`."
|
|
262
|
-
},
|
|
263
|
-
AUTH_DEVICE_CODE_SLOW_DOWN: {
|
|
264
|
-
exitCode: 0,
|
|
265
|
-
category: "success",
|
|
266
|
-
retryable: false,
|
|
267
|
-
hint: "Increase polling interval (Retry-After)."
|
|
268
|
-
},
|
|
269
|
-
IDEMPOTENCY_KEY_MISSING: {
|
|
270
|
-
exitCode: 2,
|
|
271
|
-
category: "usage",
|
|
272
|
-
retryable: false,
|
|
273
|
-
hint: "Add `X-Idempotency-Key` header (or `--idempotency-key`)."
|
|
274
|
-
},
|
|
275
|
-
IDEMPOTENCY_KEY_CONFLICT: {
|
|
276
|
-
exitCode: 7,
|
|
277
|
-
category: "conflict",
|
|
278
|
-
retryable: false,
|
|
279
|
-
hint: "Same key was used with a different request body. Use a new key."
|
|
280
|
-
},
|
|
281
|
-
PLAN_FEATURE_LOCKED: {
|
|
282
|
-
exitCode: 4,
|
|
283
|
-
category: "permission",
|
|
284
|
-
retryable: false,
|
|
285
|
-
hint: "API access is not enabled on your plan. Visit billing settings."
|
|
286
|
-
},
|
|
287
|
-
PLAN_QUOTA_EXCEEDED: {
|
|
288
|
-
exitCode: 5,
|
|
289
|
-
category: "quota",
|
|
290
|
-
retryable: false,
|
|
291
|
-
hint: "Daily API quota exhausted. Wait, or upgrade your plan."
|
|
292
|
-
},
|
|
293
|
-
INSUFFICIENT_CREDITS: {
|
|
294
|
-
exitCode: 5,
|
|
295
|
-
category: "quota",
|
|
296
|
-
retryable: false,
|
|
297
|
-
hint: "Top up credits to retry."
|
|
298
|
-
},
|
|
299
|
-
CREDIT_DEDUCTION_FAILED: {
|
|
300
|
-
exitCode: 1,
|
|
301
|
-
category: "runtime",
|
|
302
|
-
retryable: true,
|
|
303
|
-
hint: "Could not charge credits. Retry; no charge was made."
|
|
304
|
-
},
|
|
305
|
-
RATE_LIMITED: {
|
|
306
|
-
exitCode: 5,
|
|
307
|
-
category: "quota",
|
|
308
|
-
retryable: true,
|
|
309
|
-
hint: "Slow down. Honor Retry-After."
|
|
310
|
-
},
|
|
311
|
-
INPUT_INVALID_FORMAT: {
|
|
312
|
-
exitCode: 2,
|
|
313
|
-
category: "usage",
|
|
314
|
-
retryable: false,
|
|
315
|
-
hint: "Check input format and try again."
|
|
316
|
-
},
|
|
317
|
-
INPUT_TOO_LONG: {
|
|
318
|
-
exitCode: 2,
|
|
319
|
-
category: "usage",
|
|
320
|
-
retryable: false,
|
|
321
|
-
hint: "Field exceeded max length."
|
|
322
|
-
},
|
|
323
|
-
WORKFLOW_VALIDATION_FAILED: {
|
|
324
|
-
exitCode: 2,
|
|
325
|
-
category: "usage",
|
|
326
|
-
retryable: false,
|
|
327
|
-
hint: "Run `workflow validate` for the full list of errors."
|
|
328
|
-
},
|
|
329
|
-
WORKFLOW_NODE_TYPE_UNKNOWN: {
|
|
330
|
-
exitCode: 2,
|
|
331
|
-
category: "usage",
|
|
332
|
-
retryable: false,
|
|
333
|
-
hint: "Run `clickraft nodes list` for the current set of node types."
|
|
334
|
-
},
|
|
335
|
-
CANVAS_REV_MISMATCH: {
|
|
336
|
-
exitCode: 7,
|
|
337
|
-
category: "conflict",
|
|
338
|
-
retryable: false,
|
|
339
|
-
hint: "The workflow was updated elsewhere. Re-fetch and retry with the current canvas_rev."
|
|
340
|
-
},
|
|
341
|
-
CANVAS_REV_REQUIRED: {
|
|
342
|
-
exitCode: 2,
|
|
343
|
-
category: "usage",
|
|
344
|
-
retryable: false,
|
|
345
|
-
hint: "Include --canvas-rev or use --auto-rev."
|
|
346
|
-
},
|
|
347
|
-
WORKER_UNREACHABLE: {
|
|
348
|
-
exitCode: 6,
|
|
349
|
-
category: "network",
|
|
350
|
-
retryable: true,
|
|
351
|
-
hint: "Collaboration service temporarily unavailable. Retry."
|
|
352
|
-
},
|
|
353
|
-
IDEMPOTENCY_IN_PROGRESS: {
|
|
354
|
-
exitCode: 7,
|
|
355
|
-
category: "conflict",
|
|
356
|
-
retryable: false,
|
|
357
|
-
hint: "A request with this idempotency key is currently in-flight. Retry in a moment."
|
|
358
|
-
},
|
|
359
|
-
TOKEN_NAME_INVALID: {
|
|
360
|
-
exitCode: 2,
|
|
361
|
-
category: "usage",
|
|
362
|
-
retryable: false,
|
|
363
|
-
hint: "Agent token name is malformed."
|
|
364
|
-
},
|
|
365
|
-
WORKFLOW_NOT_FOUND: {
|
|
366
|
-
exitCode: 2,
|
|
367
|
-
category: "usage",
|
|
368
|
-
retryable: false,
|
|
369
|
-
hint: "No workflow with that ID in your org."
|
|
370
|
-
},
|
|
371
|
-
NOT_FOUND: {
|
|
372
|
-
exitCode: 2,
|
|
373
|
-
category: "usage",
|
|
374
|
-
retryable: false,
|
|
375
|
-
hint: "Resource not found."
|
|
376
|
-
},
|
|
377
|
-
NODE_TYPE_NOT_FOUND: {
|
|
378
|
-
exitCode: 2,
|
|
379
|
-
category: "usage",
|
|
380
|
-
retryable: false,
|
|
381
|
-
hint: "Run `clickraft nodes list` for the current set of node types."
|
|
382
|
-
},
|
|
383
|
-
FEATURE_DISABLED: {
|
|
384
|
-
exitCode: 2,
|
|
385
|
-
category: "usage",
|
|
386
|
-
retryable: false,
|
|
387
|
-
hint: "This endpoint is not enabled. Contact support if you believe this is in error."
|
|
388
|
-
},
|
|
389
|
-
FORBIDDEN: {
|
|
390
|
-
exitCode: 4,
|
|
391
|
-
category: "permission",
|
|
392
|
-
retryable: false,
|
|
393
|
-
hint: "Your role does not permit this action."
|
|
394
|
-
},
|
|
395
|
-
MODEL_NOT_FOUND: {
|
|
396
|
-
exitCode: 2,
|
|
397
|
-
category: "usage",
|
|
398
|
-
retryable: false,
|
|
399
|
-
hint: "Unknown `modelSlug`. Run `brand-model list` for the current set."
|
|
400
|
-
},
|
|
401
|
-
PROVIDER_UNAVAILABLE: {
|
|
402
|
-
exitCode: 6,
|
|
403
|
-
category: "network",
|
|
404
|
-
retryable: true,
|
|
405
|
-
hint: "Provider is temporarily unavailable. Retry shortly."
|
|
406
|
-
},
|
|
407
|
-
STORAGE_UPLOAD_FAILED: {
|
|
408
|
-
exitCode: 1,
|
|
409
|
-
category: "runtime",
|
|
410
|
-
retryable: true,
|
|
411
|
-
hint: "Upload failed mid-stream. Retry."
|
|
412
|
-
},
|
|
413
|
-
STORAGE_QUOTA_EXCEEDED: {
|
|
414
|
-
exitCode: 5,
|
|
415
|
-
category: "quota",
|
|
416
|
-
retryable: false,
|
|
417
|
-
hint: "Org storage quota exceeded. Free space or upgrade."
|
|
418
|
-
},
|
|
419
|
-
GEN_CONTENT_REFUSAL: {
|
|
420
|
-
exitCode: 1,
|
|
421
|
-
category: "runtime",
|
|
422
|
-
retryable: false,
|
|
423
|
-
hint: "The model declined the request via safety policy."
|
|
424
|
-
},
|
|
425
|
-
GEN_OUTPUT_SCHEMA_MISMATCH: {
|
|
426
|
-
exitCode: 1,
|
|
427
|
-
category: "runtime",
|
|
428
|
-
retryable: true,
|
|
429
|
-
hint: "Provider returned malformed output. Full refund issued. Retry."
|
|
430
|
-
},
|
|
431
|
-
GEN_EMPTY_OUTPUT: {
|
|
432
|
-
exitCode: 1,
|
|
433
|
-
category: "runtime",
|
|
434
|
-
retryable: true,
|
|
435
|
-
hint: "Provider returned no usable output. Full refund issued. Retry."
|
|
436
|
-
},
|
|
437
|
-
GEN_ITEM_COUNT_MISMATCH: {
|
|
438
|
-
exitCode: 0,
|
|
439
|
-
category: "success",
|
|
440
|
-
retryable: false,
|
|
441
|
-
hint: "Partial output kept; no refund."
|
|
442
|
-
},
|
|
443
|
-
AGENT_FINGERPRINT_REJECTED: {
|
|
444
|
-
exitCode: 4,
|
|
445
|
-
category: "permission",
|
|
446
|
-
retryable: false,
|
|
447
|
-
hint: "This client identification is not permitted. Contact support."
|
|
448
|
-
},
|
|
449
|
-
INTERNAL_ERROR: {
|
|
450
|
-
exitCode: 1,
|
|
451
|
-
category: "runtime",
|
|
452
|
-
retryable: true,
|
|
453
|
-
hint: "Server error. Retry; if it persists, contact support with the request ID."
|
|
454
|
-
},
|
|
455
|
-
CREDENTIALS_LOCKED: {
|
|
456
|
-
exitCode: 1,
|
|
457
|
-
category: "runtime",
|
|
458
|
-
retryable: true,
|
|
459
|
-
hint: "Another CLI invocation holds the credentials lock. Retry shortly."
|
|
460
|
-
},
|
|
461
|
-
CREDENTIALS_PERMISSIONS_LOOSE: {
|
|
462
|
-
exitCode: 0,
|
|
463
|
-
category: "success",
|
|
464
|
-
retryable: false,
|
|
465
|
-
hint: "Credentials file mode is wider than 0600; continuing."
|
|
466
|
-
},
|
|
467
|
-
// --- 5 additional codes introduced by 1A.1 ---------------------------------
|
|
468
|
-
AUTH_ACCESS_DENIED: {
|
|
469
|
-
exitCode: 3,
|
|
470
|
-
category: "auth",
|
|
471
|
-
retryable: false,
|
|
472
|
-
hint: "You denied the OAuth grant. Re-run `clickraft login` to retry."
|
|
473
|
-
},
|
|
474
|
-
AUTH_FLOW_CANCELLED: {
|
|
475
|
-
exitCode: 3,
|
|
476
|
-
category: "auth",
|
|
477
|
-
retryable: false,
|
|
478
|
-
hint: "Authentication was cancelled. Re-run `clickraft login`."
|
|
479
|
-
},
|
|
480
|
-
CREDENTIALS_CORRUPT: {
|
|
481
|
-
exitCode: 1,
|
|
482
|
-
category: "runtime",
|
|
483
|
-
retryable: false,
|
|
484
|
-
hint: "Credentials file is unreadable. Remove it and run `clickraft login`."
|
|
485
|
-
},
|
|
486
|
-
CREDENTIALS_NOT_FOUND: {
|
|
487
|
-
exitCode: 3,
|
|
488
|
-
category: "auth",
|
|
489
|
-
retryable: false,
|
|
490
|
-
hint: LOGIN_HINT
|
|
491
|
-
},
|
|
492
|
-
CREDENTIALS_PROFILE_NOT_FOUND: {
|
|
493
|
-
exitCode: 2,
|
|
494
|
-
category: "usage",
|
|
495
|
-
retryable: false,
|
|
496
|
-
hint: "No such profile. Use `clickraft auth profiles` to list available profiles."
|
|
497
|
-
},
|
|
498
|
-
// --- 8 brand model resolution codes -----------------------------------------
|
|
499
|
-
BRAND_MODEL_NOT_FOUND: {
|
|
500
|
-
exitCode: 1,
|
|
501
|
-
category: "runtime",
|
|
502
|
-
retryable: false,
|
|
503
|
-
hint: "No brand model with that ID. Run `clickraft brand-model list`."
|
|
504
|
-
},
|
|
505
|
-
BRAND_MODEL_NOT_A_MODEL: {
|
|
506
|
-
exitCode: 1,
|
|
507
|
-
category: "runtime",
|
|
508
|
-
retryable: false,
|
|
509
|
-
hint: "The specified asset is not a brand model."
|
|
510
|
-
},
|
|
511
|
-
BRAND_MODEL_NOT_ACTIVE: {
|
|
512
|
-
exitCode: 1,
|
|
513
|
-
category: "runtime",
|
|
514
|
-
retryable: false,
|
|
515
|
-
hint: "Brand model is not active. Check its status in the dashboard."
|
|
516
|
-
},
|
|
517
|
-
BRAND_MODEL_NO_REFERENCES: {
|
|
518
|
-
exitCode: 1,
|
|
519
|
-
category: "runtime",
|
|
520
|
-
retryable: false,
|
|
521
|
-
hint: "Brand model has no reference images. Upload references first."
|
|
522
|
-
},
|
|
523
|
-
BRAND_MODEL_POSE_NOT_FOUND: {
|
|
524
|
-
exitCode: 1,
|
|
525
|
-
category: "runtime",
|
|
526
|
-
retryable: false,
|
|
527
|
-
hint: "Requested pose not found. Valid: front, 3/4-right, right, left, 3/4-left, back, approved."
|
|
528
|
-
},
|
|
529
|
-
BRAND_MODEL_DUPLICATE_ID: {
|
|
530
|
-
exitCode: 2,
|
|
531
|
-
category: "usage",
|
|
532
|
-
retryable: false,
|
|
533
|
-
hint: "Same brand model ID appears more than once."
|
|
534
|
-
},
|
|
535
|
-
MODEL_DOES_NOT_SUPPORT_REFERENCES: {
|
|
536
|
-
exitCode: 2,
|
|
537
|
-
category: "usage",
|
|
538
|
-
retryable: false,
|
|
539
|
-
hint: "This model does not support brand model references."
|
|
540
|
-
},
|
|
541
|
-
REFERENCE_LIMIT_EXCEEDED: {
|
|
542
|
-
exitCode: 2,
|
|
543
|
-
category: "usage",
|
|
544
|
-
retryable: false,
|
|
545
|
-
hint: "Too many reference images. Check model limits."
|
|
546
|
-
},
|
|
547
|
-
// --- 8 product reference resolver codes -------------------------------------
|
|
548
|
-
PRODUCT_NOT_FOUND: {
|
|
549
|
-
exitCode: 1,
|
|
550
|
-
category: "runtime",
|
|
551
|
-
retryable: false,
|
|
552
|
-
hint: "No product with that ID in your org. Run `clickraft product list`."
|
|
553
|
-
},
|
|
554
|
-
PRODUCT_DUPLICATE_REFERENCE: {
|
|
555
|
-
exitCode: 2,
|
|
556
|
-
category: "usage",
|
|
557
|
-
retryable: false,
|
|
558
|
-
hint: "Same (productId, imageId) tuple appears twice in the request."
|
|
559
|
-
},
|
|
560
|
-
PRODUCT_IMAGE_NOT_FOUND: {
|
|
561
|
-
exitCode: 1,
|
|
562
|
-
category: "runtime",
|
|
563
|
-
retryable: false,
|
|
564
|
-
hint: "imageId does not exist in the product images."
|
|
565
|
-
},
|
|
566
|
-
PRODUCT_IMAGE_MISMATCH: {
|
|
567
|
-
exitCode: 2,
|
|
568
|
-
category: "usage",
|
|
569
|
-
retryable: false,
|
|
570
|
-
hint: "imageId belongs to a different product."
|
|
571
|
-
},
|
|
572
|
-
PRODUCT_SYNC_ERROR: {
|
|
573
|
-
exitCode: 1,
|
|
574
|
-
category: "runtime",
|
|
575
|
-
retryable: false,
|
|
576
|
-
hint: "Product sync status is 'error'. Re-sync or use a different product."
|
|
577
|
-
},
|
|
578
|
-
PRODUCT_DELETED_UPSTREAM: {
|
|
579
|
-
exitCode: 1,
|
|
580
|
-
category: "runtime",
|
|
581
|
-
retryable: false,
|
|
582
|
-
hint: "Product was deleted upstream. Remove it or re-sync."
|
|
583
|
-
},
|
|
584
|
-
PRODUCT_NO_PRIMARY_IMAGE: {
|
|
585
|
-
exitCode: 1,
|
|
586
|
-
category: "runtime",
|
|
587
|
-
retryable: false,
|
|
588
|
-
hint: "Product has no primary image. Specify --product <id>:<imageId> explicitly."
|
|
589
|
-
},
|
|
590
|
-
PRODUCT_SOURCE_MANAGED: {
|
|
591
|
-
exitCode: 4,
|
|
592
|
-
category: "permission",
|
|
593
|
-
retryable: false,
|
|
594
|
-
hint: "Product is managed by an external integration."
|
|
595
|
-
},
|
|
596
|
-
// --- 4 CLI-synthetic codes --------------------------------------------------
|
|
597
|
-
NETWORK_ERROR: {
|
|
598
|
-
exitCode: 6,
|
|
599
|
-
category: "network",
|
|
600
|
-
retryable: true,
|
|
601
|
-
hint: "Network connection failed. Check connectivity and retry."
|
|
602
|
-
},
|
|
603
|
-
TIMEOUT: {
|
|
604
|
-
exitCode: 6,
|
|
605
|
-
category: "network",
|
|
606
|
-
retryable: true,
|
|
607
|
-
hint: "Request timed out. Retry; consider increasing the timeout."
|
|
608
|
-
},
|
|
609
|
-
PARSE_ERROR: {
|
|
610
|
-
exitCode: 1,
|
|
611
|
-
category: "runtime",
|
|
612
|
-
retryable: false,
|
|
613
|
-
hint: "Server returned an unexpected response. Contact support with the request ID."
|
|
614
|
-
},
|
|
615
|
-
SCHEMA_MISMATCH: {
|
|
616
|
-
exitCode: 1,
|
|
617
|
-
category: "runtime",
|
|
618
|
-
retryable: false,
|
|
619
|
-
hint: "Server response did not match the expected schema. Update the CLI."
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
function getExitCode(code) {
|
|
623
|
-
return EXIT_CODE_MAP[code]?.exitCode ?? 1;
|
|
624
|
-
}
|
|
625
|
-
function toEnvelopeCode(code) {
|
|
626
|
-
return code.startsWith("E_") ? code : `E_${code}`;
|
|
627
|
-
}
|
|
628
|
-
var SIGINT_EXIT_CODE = 130;
|
|
629
|
-
|
|
630
|
-
// src/errors/schema-mismatch.ts
|
|
631
209
|
var MAX_ISSUES = 5;
|
|
632
210
|
function formatSchemaIssues(error) {
|
|
633
211
|
const issues = error.issues;
|
|
@@ -651,9 +229,6 @@ function formatPath(path) {
|
|
|
651
229
|
if (path.length === 0) return "(root)";
|
|
652
230
|
return path.map(String).join(".");
|
|
653
231
|
}
|
|
654
|
-
|
|
655
|
-
// src/api/idempotency.ts
|
|
656
|
-
import { createHash, randomUUID } from "crypto";
|
|
657
232
|
function generateIdempotencyKey() {
|
|
658
233
|
return randomUUID();
|
|
659
234
|
}
|
|
@@ -661,8 +236,6 @@ function generateUploadIdempotencyKey(content, scope) {
|
|
|
661
236
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
662
237
|
return `upload-${scope}-${hash}`;
|
|
663
238
|
}
|
|
664
|
-
|
|
665
|
-
// src/api/retry.ts
|
|
666
239
|
var DEFAULT_RETRY_OPTIONS = {
|
|
667
240
|
maxAttempts: 3,
|
|
668
241
|
baseDelayMs: 200,
|
|
@@ -676,7 +249,7 @@ function computeBackoffMs(attempt, baseDelayMs, maxDelayMs, jitterFraction) {
|
|
|
676
249
|
return Math.max(0, Math.round(exp + jitter));
|
|
677
250
|
}
|
|
678
251
|
function decideRetry(params) {
|
|
679
|
-
const { attempt, options, serverRetryAfterMs, isNetworkError, isRetryable } = params;
|
|
252
|
+
const { attempt, options, serverRetryAfterMs, isNetworkError, isRetryable, onWarning: onWarning2 } = params;
|
|
680
253
|
if (options.signal?.aborted) {
|
|
681
254
|
return { shouldRetry: false, delayMs: 0, reason: "aborted" };
|
|
682
255
|
}
|
|
@@ -689,7 +262,7 @@ function decideRetry(params) {
|
|
|
689
262
|
if (typeof serverRetryAfterMs === "number" && serverRetryAfterMs >= 0) {
|
|
690
263
|
let delayMs2 = serverRetryAfterMs;
|
|
691
264
|
if (delayMs2 > ABSOLUTE_MAX_RETRY_AFTER_MS) {
|
|
692
|
-
|
|
265
|
+
onWarning2?.(`Server Retry-After exceeded ${ABSOLUTE_MAX_RETRY_AFTER_MS}ms; clipping.`);
|
|
693
266
|
delayMs2 = ABSOLUTE_MAX_RETRY_AFTER_MS;
|
|
694
267
|
}
|
|
695
268
|
return { shouldRetry: true, delayMs: delayMs2, reason: "rate_limited" };
|
|
@@ -729,9 +302,6 @@ function signalToAbortError(signal) {
|
|
|
729
302
|
err.name = "AbortError";
|
|
730
303
|
return err;
|
|
731
304
|
}
|
|
732
|
-
|
|
733
|
-
// src/api/types.ts
|
|
734
|
-
import { z as z5 } from "zod";
|
|
735
305
|
var ServerSuccessSchema = (payload) => z5.object({ data: payload }).strict();
|
|
736
306
|
var ServerErrorBodySchema = z5.object({
|
|
737
307
|
error: z5.object({
|
|
@@ -742,8 +312,6 @@ var ServerErrorBodySchema = z5.object({
|
|
|
742
312
|
details: z5.unknown().optional()
|
|
743
313
|
}).strict()
|
|
744
314
|
}).strict();
|
|
745
|
-
|
|
746
|
-
// src/api/client.ts
|
|
747
315
|
var REDACT_BODY_LIMIT = 1024;
|
|
748
316
|
var REDACT_INPUT_CAP = 100 * 1024;
|
|
749
317
|
var DEFAULT_USER_AGENT = "clickraft-cli";
|
|
@@ -800,7 +368,8 @@ var ApiClient = class {
|
|
|
800
368
|
options: { ...retry, signal },
|
|
801
369
|
serverRetryAfterMs: err.meta.retryAfterMs,
|
|
802
370
|
isNetworkError,
|
|
803
|
-
isRetryable
|
|
371
|
+
isRetryable,
|
|
372
|
+
onWarning: this.options.onWarning
|
|
804
373
|
});
|
|
805
374
|
if (!decision.shouldRetry) throw err;
|
|
806
375
|
try {
|
|
@@ -888,10 +457,15 @@ var ApiClient = class {
|
|
|
888
457
|
bodyText,
|
|
889
458
|
statusCode,
|
|
890
459
|
requestId,
|
|
891
|
-
retryAfterHeader: pickHeader(responseHeaders, "retry-after")
|
|
460
|
+
retryAfterHeader: pickHeader(responseHeaders, "retry-after"),
|
|
461
|
+
onWarning: this.options.onWarning,
|
|
462
|
+
isRetryableServerCode: this.options.isRetryableServerCode
|
|
892
463
|
});
|
|
893
464
|
}
|
|
894
465
|
};
|
|
466
|
+
function createClient(options) {
|
|
467
|
+
return new ApiClient(options);
|
|
468
|
+
}
|
|
895
469
|
function parseSuccessBody(args) {
|
|
896
470
|
let parsed;
|
|
897
471
|
try {
|
|
@@ -960,7 +534,9 @@ function parseErrorBody(args) {
|
|
|
960
534
|
statusCode: args.statusCode,
|
|
961
535
|
requestId: args.requestId,
|
|
962
536
|
retryAfterHeader: args.retryAfterHeader,
|
|
963
|
-
redactedBody
|
|
537
|
+
redactedBody,
|
|
538
|
+
onWarning: args.onWarning,
|
|
539
|
+
isRetryableServerCode: args.isRetryableServerCode
|
|
964
540
|
});
|
|
965
541
|
}
|
|
966
542
|
function apiErrorFromServerBody(args) {
|
|
@@ -972,12 +548,11 @@ function apiErrorFromServerBody(args) {
|
|
|
972
548
|
safeMessage = redactTokenLikeFields(error.message);
|
|
973
549
|
} else {
|
|
974
550
|
const redactedRawCode = redactTokenLikeFields(error.code);
|
|
975
|
-
|
|
551
|
+
args.onWarning?.(`Unknown server error code: ${redactedRawCode}. Treating as INTERNAL_ERROR.`);
|
|
976
552
|
code = "INTERNAL_ERROR";
|
|
977
553
|
safeMessage = `Unknown server error code: ${redactedRawCode}.`;
|
|
978
554
|
}
|
|
979
|
-
const
|
|
980
|
-
const retryable = mapping?.retryable ?? (args.statusCode >= 500 || args.statusCode === 429);
|
|
555
|
+
const retryable = args.isRetryableServerCode?.(code) ?? (args.statusCode >= 500 || args.statusCode === 429);
|
|
981
556
|
const retryAfterMs = typeof error.retryAfter === "number" ? error.retryAfter * 1e3 : parseRetryAfterHeader(args.retryAfterHeader);
|
|
982
557
|
return new ApiError(code, safeMessage, {
|
|
983
558
|
status: args.statusCode,
|
|
@@ -1062,6 +637,435 @@ function errorMessage(err) {
|
|
|
1062
637
|
return String(err);
|
|
1063
638
|
}
|
|
1064
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;
|
|
1054
|
+
}
|
|
1055
|
+
function toEnvelopeCode(code) {
|
|
1056
|
+
return code.startsWith("E_") ? code : `E_${code}`;
|
|
1057
|
+
}
|
|
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 });
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1065
1069
|
// src/auth/errors.ts
|
|
1066
1070
|
var AuthError = class extends Error {
|
|
1067
1071
|
code;
|
|
@@ -1488,7 +1492,7 @@ async function getBalance(options) {
|
|
|
1488
1492
|
if (!config.accessToken) {
|
|
1489
1493
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
1490
1494
|
}
|
|
1491
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
1495
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
1492
1496
|
apiBaseUrl,
|
|
1493
1497
|
accessToken,
|
|
1494
1498
|
signal: options.signal,
|
|
@@ -1514,7 +1518,7 @@ async function listBrandModels(options) {
|
|
|
1514
1518
|
if (!config.accessToken) {
|
|
1515
1519
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
1516
1520
|
}
|
|
1517
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
1521
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
1518
1522
|
apiBaseUrl,
|
|
1519
1523
|
accessToken,
|
|
1520
1524
|
signal: options.signal,
|
|
@@ -1679,7 +1683,7 @@ async function buildClient(opts) {
|
|
|
1679
1683
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
1680
1684
|
flagToken: opts.token
|
|
1681
1685
|
});
|
|
1682
|
-
return
|
|
1686
|
+
return createApiClient({
|
|
1683
1687
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
1684
1688
|
accessToken: cfg.accessToken,
|
|
1685
1689
|
signal: opts.signal,
|
|
@@ -1846,7 +1850,7 @@ async function buildGenerateClient(opts) {
|
|
|
1846
1850
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
1847
1851
|
flagToken: opts.token
|
|
1848
1852
|
});
|
|
1849
|
-
return
|
|
1853
|
+
return createApiClient({
|
|
1850
1854
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
1851
1855
|
accessToken: cfg.accessToken,
|
|
1852
1856
|
signal: opts.signal,
|
|
@@ -2618,7 +2622,7 @@ async function logout(options) {
|
|
|
2618
2622
|
let serverRevoked = false;
|
|
2619
2623
|
let revokeFailureMessage;
|
|
2620
2624
|
if (options.revoke) {
|
|
2621
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
2625
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
2622
2626
|
apiBaseUrl,
|
|
2623
2627
|
accessToken,
|
|
2624
2628
|
signal: options.signal,
|
|
@@ -2703,7 +2707,7 @@ async function buildModelClient(opts) {
|
|
|
2703
2707
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
2704
2708
|
flagToken: opts.token
|
|
2705
2709
|
});
|
|
2706
|
-
return
|
|
2710
|
+
return createApiClient({
|
|
2707
2711
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
2708
2712
|
accessToken: cfg.accessToken,
|
|
2709
2713
|
signal: opts.signal,
|
|
@@ -2756,7 +2760,7 @@ async function buildNodesClient(opts) {
|
|
|
2756
2760
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
2757
2761
|
flagToken: opts.token
|
|
2758
2762
|
});
|
|
2759
|
-
return
|
|
2763
|
+
return createApiClient({
|
|
2760
2764
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
2761
2765
|
accessToken: cfg.accessToken,
|
|
2762
2766
|
signal: opts.signal,
|
|
@@ -2800,7 +2804,7 @@ async function listProducts(options) {
|
|
|
2800
2804
|
if (!config.accessToken) {
|
|
2801
2805
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
2802
2806
|
}
|
|
2803
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
2807
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
2804
2808
|
apiBaseUrl,
|
|
2805
2809
|
accessToken,
|
|
2806
2810
|
signal: options.signal,
|
|
@@ -2909,7 +2913,7 @@ async function buildTemplateClient(opts) {
|
|
|
2909
2913
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
2910
2914
|
flagToken: opts.token
|
|
2911
2915
|
});
|
|
2912
|
-
return
|
|
2916
|
+
return createApiClient({
|
|
2913
2917
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
2914
2918
|
accessToken: cfg.accessToken,
|
|
2915
2919
|
signal: opts.signal,
|
|
@@ -3003,7 +3007,7 @@ async function listTokens(options) {
|
|
|
3003
3007
|
if (!config.accessToken) {
|
|
3004
3008
|
throw new AuthError("AUTH_TOKEN_MISSING", `Not authenticated. Run \`clickraft login\` first.`);
|
|
3005
3009
|
}
|
|
3006
|
-
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) =>
|
|
3010
|
+
const factory = options.apiClientFactory ?? ((apiBaseUrl, accessToken) => createApiClient({
|
|
3007
3011
|
apiBaseUrl,
|
|
3008
3012
|
accessToken,
|
|
3009
3013
|
signal: options.signal,
|
|
@@ -3075,7 +3079,7 @@ async function buildWorkflowClient(opts) {
|
|
|
3075
3079
|
flagApiBaseUrl: opts.apiBaseUrl,
|
|
3076
3080
|
flagToken: opts.token
|
|
3077
3081
|
});
|
|
3078
|
-
return
|
|
3082
|
+
return createApiClient({
|
|
3079
3083
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
3080
3084
|
accessToken: cfg.accessToken,
|
|
3081
3085
|
signal: opts.signal,
|