@zeroxyz/cli 1.23.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +200 -38
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -78449,7 +78449,7 @@ init_esm_shims();
78449
78449
  // ../sdk/dist/index.js
78450
78450
  init_esm_shims();
78451
78451
 
78452
- // ../sdk/dist/chunk-I3HO6Z42.js
78452
+ // ../sdk/dist/chunk-76JAOSJC.js
78453
78453
  init_esm_shims();
78454
78454
 
78455
78455
  // ../../node_modules/.pnpm/viem@2.52.2_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@6.0.6_zod@4.3.6/node_modules/viem/_esm/index.js
@@ -143768,7 +143768,7 @@ config(en_default2());
143768
143768
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/index.js
143769
143769
  var zod_default = external_exports3;
143770
143770
 
143771
- // ../sdk/dist/chunk-I3HO6Z42.js
143771
+ // ../sdk/dist/chunk-76JAOSJC.js
143772
143772
  var createManagedAccount = (client, address2, opts = {}) => {
143773
143773
  const signOptions = {
143774
143774
  // expectedAddress pins verification to this adapter's frozen address.
@@ -144269,7 +144269,13 @@ var tempoChainLabelFromId = (chainId2) => {
144269
144269
  };
144270
144270
  var paymentHasAnchor = (payment) => payment !== null && (payment.txHash !== null || payment.session !== void 0);
144271
144271
  var FETCH_WARNINGS = Object.freeze({
144272
- paidButStill402NotRecorded: "paid_but_still_402_not_recorded",
144272
+ // Settlement landed on-chain but upstream still answered 402 (facilitator
144273
+ // lag / race). Still a warning worth surfacing for reconciliation — but the
144274
+ // run IS now recorded (it was the most expensive hole in run capture: a
144275
+ // confirmed txHash with nothing pointing at what it bought). The old key
144276
+ // was `paid_but_still_402_not_recorded`; the "not_recorded" half is no
144277
+ // longer true.
144278
+ paidButStill402: "paid_but_still_402",
144273
144279
  paymentSettlementUnconfirmed: "payment_settlement_unconfirmed",
144274
144280
  paymentAmountUnknown: "payment_amount_unknown",
144275
144281
  mppSessionCloseFailed: "mpp_session_close_failed",
@@ -144283,9 +144289,12 @@ var FETCH_WARNINGS = Object.freeze({
144283
144289
  bodyTruncated: "body_truncated"
144284
144290
  });
144285
144291
  var FETCH_SKIP_REASONS = Object.freeze({
144292
+ // The body was lost, but the capability executed (and may have charged) —
144293
+ // so this is a warning ON a recorded run now, not a reason to drop it.
144286
144294
  bodyReadFailed: "body_read_failed",
144287
- mppSessionCloseFailedNotRecorded: "mpp_session_close_failed_not_recorded",
144288
- paidButStill402NotRecorded: FETCH_WARNINGS.paidButStill402NotRecorded,
144295
+ // The paid leg threw something other than a typed timeout/payment error —
144296
+ // most importantly a caller abort, which can land after the money moved.
144297
+ paidLegFailed: "paid_leg_failed",
144289
144298
  paymentSettlementUnconfirmed: FETCH_WARNINGS.paymentSettlementUnconfirmed,
144290
144299
  // Pre-sign abort: deliberately NOT recorded as a run — the wallet was
144291
144300
  // empty before we reached the capability, so charging it as a 402 would
@@ -145383,8 +145392,9 @@ var computeOutcome = (status, payment, warnings) => {
145383
145392
  if (status >= 400) return "server_error";
145384
145393
  return "success";
145385
145394
  };
145386
- var errorFetchResult = (startedAt, error48, skipReason, capabilityIdRequested, outcome, status = null) => {
145395
+ var errorFetchResult = (fetchId, startedAt, error48, skipReason, capabilityIdRequested, outcome, status = null) => {
145387
145396
  const result = {
145397
+ fetchId,
145388
145398
  runId: null,
145389
145399
  ok: false,
145390
145400
  status,
@@ -145398,6 +145408,20 @@ var errorFetchResult = (startedAt, error48, skipReason, capabilityIdRequested, o
145398
145408
  if (capabilityIdRequested) result.runTrackingSkipped = [skipReason];
145399
145409
  return result;
145400
145410
  };
145411
+ var settlementFields = (payment) => {
145412
+ if (payment === null) return {};
145413
+ const knownAmount = payment.amount !== "unknown";
145414
+ return {
145415
+ ...knownAmount && {
145416
+ costAmount: payment.amount,
145417
+ costAsset: payment.asset
145418
+ },
145419
+ paymentProtocol: payment.protocol,
145420
+ paymentChain: payment.chain,
145421
+ paymentTxHash: payment.txHash ?? void 0,
145422
+ paymentMode: payment.session ? "session" : "charge"
145423
+ };
145424
+ };
145401
145425
  var resolveRecordingClient = (client, opts) => {
145402
145426
  const credentials = client.getCredentials();
145403
145427
  const recordingClient = opts.account ? client.withAccount(opts.account) : client;
@@ -145405,11 +145429,12 @@ var resolveRecordingClient = (client, opts) => {
145405
145429
  return { recordingClient, canRecord };
145406
145430
  };
145407
145431
  var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride, requestUrl, requestMethod) => {
145408
- const effectiveCapId = opts.capabilityId;
145409
- const runTarget = effectiveCapId !== void 0 ? { capabilityId: effectiveCapId } : requestUrl ? {
145432
+ const effectiveCapId = capabilityIdOverride ?? opts.capabilityId;
145433
+ const urlTarget = requestUrl ? {
145410
145434
  requestUrl: redactUrl(requestUrl),
145411
145435
  ...requestMethod && { requestMethod }
145412
- } : null;
145436
+ } : void 0;
145437
+ const runTarget = effectiveCapId !== void 0 ? { capabilityId: effectiveCapId, ...urlTarget } : urlTarget ?? null;
145413
145438
  if (runTarget === null) return;
145414
145439
  const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
145415
145440
  if (!canRecord) return;
@@ -145417,10 +145442,16 @@ var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride, req
145417
145442
  try {
145418
145443
  const created = await recordingClient.runs.create({
145419
145444
  ...runTarget,
145445
+ fetchId: result.fetchId,
145420
145446
  ...opts.searchId && { searchId: opts.searchId },
145421
145447
  ...fetchOriginForRecord && { fetchOrigin: fetchOriginForRecord },
145422
145448
  ...result.status !== null && { status: result.status },
145449
+ // The SDK's verdict. HTTP status alone can't say "the capability
145450
+ // answered 200 but the caller got nothing" — outcome can.
145451
+ outcome: result.outcome,
145423
145452
  latencyMs: result.latencyMs,
145453
+ // Carry the settlement when the failure happened AFTER we paid.
145454
+ ...settlementFields(result.payment),
145424
145455
  ...opts.requestSchema && { requestSchema: opts.requestSchema },
145425
145456
  ...opts.walletAddress && !opts.account && { walletAddress: opts.walletAddress }
145426
145457
  });
@@ -145429,8 +145460,9 @@ var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride, req
145429
145460
  } catch {
145430
145461
  }
145431
145462
  };
145432
- var recordTimeoutRun = async (client, opts, err, startedAt, capabilityIdRequested, capabilityIdOverride, requestUrl, requestMethod) => {
145463
+ var recordTimeoutRun = async (client, opts, fetchId, err, startedAt, capabilityIdRequested, capabilityIdOverride, requestUrl, requestMethod) => {
145433
145464
  const result = errorFetchResult(
145465
+ fetchId,
145434
145466
  startedAt,
145435
145467
  err.message,
145436
145468
  "timeout",
@@ -145471,6 +145503,7 @@ var withDefaultContentType = (headers, body) => {
145471
145503
  };
145472
145504
  var clientFetch = async (client, url4, opts = {}) => {
145473
145505
  const startedAt = Date.now();
145506
+ const fetchId = randomUUID();
145474
145507
  const capabilityIdRequested = opts.capabilityId !== void 0;
145475
145508
  const normalized = normalizeTransportEnvelopeRequest(url4, {
145476
145509
  method: opts.method,
@@ -145505,6 +145538,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145505
145538
  await recordTimeoutRun(
145506
145539
  client,
145507
145540
  opts,
145541
+ fetchId,
145508
145542
  err,
145509
145543
  startedAt,
145510
145544
  capabilityIdRequested,
@@ -145517,6 +145551,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145517
145551
  if (err instanceof ZeroError) throw err;
145518
145552
  const errMessage = err instanceof Error ? err.message : String(err);
145519
145553
  const result2 = errorFetchResult(
145554
+ fetchId,
145520
145555
  startedAt,
145521
145556
  errMessage,
145522
145557
  "fetch_failed_before_response",
@@ -145575,6 +145610,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145575
145610
  warnings.push(FETCH_WARNINGS.mppSessionCloseFailed);
145576
145611
  } else if (err instanceof ZeroInsufficientFundsError) {
145577
145612
  return errorFetchResult(
145613
+ fetchId,
145578
145614
  startedAt,
145579
145615
  err.message,
145580
145616
  FETCH_SKIP_REASONS.insufficientFunds,
@@ -145584,6 +145620,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145584
145620
  );
145585
145621
  } else if (err instanceof ZeroPaymentError || err instanceof ZeroAuthError) {
145586
145622
  const result2 = errorFetchResult(
145623
+ fetchId,
145587
145624
  startedAt,
145588
145625
  err.message,
145589
145626
  "payment_failed",
@@ -145604,6 +145641,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145604
145641
  await recordTimeoutRun(
145605
145642
  client,
145606
145643
  opts,
145644
+ fetchId,
145607
145645
  err,
145608
145646
  startedAt,
145609
145647
  capabilityIdRequested,
@@ -145613,11 +145651,28 @@ var clientFetch = async (client, url4, opts = {}) => {
145613
145651
  );
145614
145652
  throw err;
145615
145653
  } else {
145654
+ const failed = errorFetchResult(
145655
+ fetchId,
145656
+ startedAt,
145657
+ err instanceof Error ? err.message : String(err),
145658
+ FETCH_SKIP_REASONS.paidLegFailed,
145659
+ capabilityIdRequested,
145660
+ "network_error"
145661
+ );
145662
+ await recordErrorFetchRun(
145663
+ client,
145664
+ opts,
145665
+ failed,
145666
+ void 0,
145667
+ requestUrl,
145668
+ method
145669
+ );
145616
145670
  throw err;
145617
145671
  }
145618
145672
  }
145619
145673
  } else if (requirement?.protocol === "unknown") {
145620
145674
  const result2 = errorFetchResult(
145675
+ fetchId,
145621
145676
  startedAt,
145622
145677
  opts.paymentProtocol ? `Capability did not advertise the requested ${opts.paymentProtocol} payment protocol.` : "Capability returned 402 with an unrecognized payment protocol. Neither x402 nor MPP markers were detected in the response headers or body.",
145623
145678
  "unrecognized_402_protocol",
@@ -145649,6 +145704,26 @@ var clientFetch = async (client, url4, opts = {}) => {
145649
145704
  if (parsed.truncated) warnings.push(FETCH_WARNINGS.bodyTruncated);
145650
145705
  } catch (err) {
145651
145706
  if (err instanceof Error && err.name === "AbortError") {
145707
+ const aborted2 = {
145708
+ fetchId,
145709
+ runId: null,
145710
+ ok: false,
145711
+ status: response.status,
145712
+ latencyMs: Date.now() - startedAt,
145713
+ payment,
145714
+ outcome: "network_error",
145715
+ body: null,
145716
+ bodyRaw: null,
145717
+ error: "Request aborted by caller"
145718
+ };
145719
+ await recordErrorFetchRun(
145720
+ client,
145721
+ opts,
145722
+ aborted2,
145723
+ (await resolvePromise.catch(() => null))?.capabilityId,
145724
+ requestUrl,
145725
+ method
145726
+ );
145652
145727
  throw new ZeroApiError("Request aborted by caller", {
145653
145728
  status: 0,
145654
145729
  cause: err
@@ -145658,8 +145733,8 @@ var clientFetch = async (client, url4, opts = {}) => {
145658
145733
  const skips = [];
145659
145734
  const settledLocally = paymentHasAnchor(payment);
145660
145735
  if (settledLocally && response.status === 402) {
145661
- warnings.push(FETCH_WARNINGS.paidButStill402NotRecorded);
145662
- skips.push(FETCH_WARNINGS.paidButStill402NotRecorded);
145736
+ warnings.push(FETCH_WARNINGS.paidButStill402);
145737
+ skips.push(FETCH_WARNINGS.paidButStill402);
145663
145738
  }
145664
145739
  if (payment !== null && !settledLocally) {
145665
145740
  warnings.push(FETCH_WARNINGS.paymentSettlementUnconfirmed);
@@ -145670,42 +145745,52 @@ var clientFetch = async (client, url4, opts = {}) => {
145670
145745
  }
145671
145746
  skips.push(FETCH_SKIP_REASONS.bodyReadFailed);
145672
145747
  const result2 = {
145748
+ fetchId,
145673
145749
  runId: null,
145674
145750
  ok: false,
145675
145751
  status: response.status,
145676
145752
  latencyMs: Date.now() - startedAt,
145677
145753
  payment,
145678
- outcome: computeOutcome(response.status, payment, warnings),
145754
+ // The body never arrived, so this is NOT a success even when the wire
145755
+ // said 2xx — `ok: false` with `outcome: "success"` was a contradiction,
145756
+ // and it's what let these rows land in the DB as clean successes.
145757
+ // Only the bogus "success" is overridden: a more specific verdict (an
145758
+ // MPP close-fail whose body then dropped) must survive intact.
145759
+ outcome: (() => {
145760
+ const computed = computeOutcome(response.status, payment, warnings);
145761
+ return computed === "success" ? "network_error" : computed;
145762
+ })(),
145679
145763
  body: null,
145680
145764
  bodyRaw: null,
145681
145765
  error: message2
145682
145766
  };
145683
145767
  if (capabilityIdRequested) result2.runTrackingSkipped = skips;
145684
145768
  if (warnings.length > 0) result2.warnings = warnings;
145769
+ await recordErrorFetchRun(
145770
+ client,
145771
+ opts,
145772
+ result2,
145773
+ (await resolvePromise.catch(() => null))?.capabilityId,
145774
+ requestUrl,
145775
+ method
145776
+ );
145685
145777
  return result2;
145686
145778
  }
145687
145779
  const settled = paymentHasAnchor(payment);
145688
145780
  const paidButStill402 = settled && response.status === 402;
145689
145781
  const settlementUnconfirmed = payment !== null && !settled;
145690
- if (paidButStill402) warnings.push(FETCH_WARNINGS.paidButStill402NotRecorded);
145782
+ if (paidButStill402) warnings.push(FETCH_WARNINGS.paidButStill402);
145691
145783
  if (settlementUnconfirmed)
145692
145784
  warnings.push(FETCH_WARNINGS.paymentSettlementUnconfirmed);
145693
145785
  if (payment !== null && payment.amount === "unknown") {
145694
145786
  warnings.push(FETCH_WARNINGS.paymentAmountUnknown);
145695
145787
  }
145696
145788
  let runId = null;
145697
- const closeFailed = warnings.includes(FETCH_WARNINGS.mppSessionCloseFailed);
145698
145789
  const upstreamErrorForRecord = buildUpstreamError(
145699
145790
  response.status,
145700
145791
  bodyRaw,
145701
145792
  bodyEncoding
145702
145793
  );
145703
- if (capabilityIdRequested) {
145704
- if (paidButStill402)
145705
- skipReasons.push(FETCH_WARNINGS.paidButStill402NotRecorded);
145706
- else if (closeFailed)
145707
- skipReasons.push(FETCH_SKIP_REASONS.mppSessionCloseFailedNotRecorded);
145708
- }
145709
145794
  const resolvedCap = await resolvePromise;
145710
145795
  const effectiveCapabilityId = opts.capabilityId ?? resolvedCap?.capabilityId;
145711
145796
  const capabilityResolution = !capabilityIdRequested && canRecordForResolve ? resolvedCap !== null ? {
@@ -145714,8 +145799,13 @@ var clientFetch = async (client, url4, opts = {}) => {
145714
145799
  capabilitySlug: resolvedCap.capabilitySlug,
145715
145800
  matchedVia: resolvedCap.matchedVia
145716
145801
  } : { resolved: false } : void 0;
145717
- const runTarget = effectiveCapabilityId !== void 0 ? { capabilityId: effectiveCapabilityId } : { requestUrl: redactUrl(requestUrl), requestMethod: method };
145718
- if (!paidButStill402 && !closeFailed) {
145802
+ const runTarget = effectiveCapabilityId !== void 0 ? {
145803
+ capabilityId: effectiveCapabilityId,
145804
+ requestUrl: redactUrl(requestUrl),
145805
+ requestMethod: method
145806
+ } : { requestUrl: redactUrl(requestUrl), requestMethod: method };
145807
+ const fetchOutcome = computeOutcome(response.status, payment, warnings);
145808
+ {
145719
145809
  const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
145720
145810
  if (!canRecord) {
145721
145811
  skipReasons.push("no_credentials");
@@ -145736,11 +145826,16 @@ var clientFetch = async (client, url4, opts = {}) => {
145736
145826
  }
145737
145827
  const result2 = await recordingClient.runs.create({
145738
145828
  ...runTarget,
145829
+ fetchId,
145739
145830
  searchId: opts.searchId,
145740
145831
  // Auto-resolved runs are always direct_url — they only fire when
145741
145832
  // no capabilityId was supplied (the direct_url path by definition).
145742
145833
  ...opts.capabilityId === void 0 ? { fetchOrigin: "direct_url" } : opts.fetchOrigin && { fetchOrigin: opts.fetchOrigin },
145743
145834
  status: response.status,
145835
+ // The SDK's verdict alongside the raw status. A close-fail or a
145836
+ // dropped body answers 200 while the caller got nothing — the
145837
+ // server must not read that as a clean success.
145838
+ outcome: fetchOutcome,
145744
145839
  latencyMs,
145745
145840
  // Attribute to the selected wallet in session mode. Skipped when a
145746
145841
  // per-call `account` override records the run — that account's own
@@ -145785,12 +145880,13 @@ var clientFetch = async (client, url4, opts = {}) => {
145785
145880
  }
145786
145881
  }
145787
145882
  const result = {
145883
+ fetchId,
145788
145884
  runId,
145789
145885
  ok: response.ok,
145790
145886
  status: response.status,
145791
145887
  latencyMs,
145792
145888
  payment,
145793
- outcome: computeOutcome(response.status, payment, warnings),
145889
+ outcome: fetchOutcome,
145794
145890
  body,
145795
145891
  bodyRaw
145796
145892
  };
@@ -145800,7 +145896,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145800
145896
  result.error = candidate !== null && !requestBodyEchoed(candidate, opts.body) ? candidate : `HTTP ${response.status}`;
145801
145897
  if (upstreamErrorForRecord) result.upstreamError = upstreamErrorForRecord;
145802
145898
  }
145803
- if (capabilityIdRequested && skipReasons.length > 0) {
145899
+ if (skipReasons.length > 0) {
145804
145900
  result.runTrackingSkipped = skipReasons;
145805
145901
  }
145806
145902
  if (warnings.length > 0) result.warnings = warnings;
@@ -145809,7 +145905,7 @@ var clientFetch = async (client, url4, opts = {}) => {
145809
145905
  return result;
145810
145906
  };
145811
145907
  var package_default = {
145812
- version: "0.16.0"
145908
+ version: "0.17.0"
145813
145909
  };
145814
145910
  var SDK_VERSION2 = package_default.version;
145815
145911
  var agentAuthMetadataSchema = external_exports3.object({
@@ -146914,20 +147010,80 @@ var batchReviewResponseSchema = external_exports3.object({
146914
147010
  failed: external_exports3.number()
146915
147011
  })
146916
147012
  });
146917
- var Runs = class {
147013
+ var Runs = class _Runs {
146918
147014
  constructor(client) {
146919
147015
  this.client = client;
146920
147016
  }
146921
- create = (input, opts = {}) => request2(
146922
- this.client,
146923
- {
146924
- method: "POST",
146925
- path: "/v1/runs",
146926
- body: input,
146927
- signal: opts.signal
146928
- },
146929
- createRunResponseSchema
146930
- );
147017
+ /**
147018
+ * Field generations, newest first. `/v1/runs` validates `.strict()`, so an
147019
+ * unknown key is a 400 — not a warning. An SDK newer than its API would
147020
+ * therefore have its run REJECTED and lost, which is precisely backwards:
147021
+ * these fields exist to stop losing runs.
147022
+ *
147023
+ * So we degrade one generation at a time rather than all at once — an API
147024
+ * that knows `requestUrl` (ZERO-536) but not `fetchId` must keep recording
147025
+ * unattributed runs, which it can't do if we strip the target as well.
147026
+ */
147027
+ static FIELD_GENERATIONS = [
147028
+ // Newest: correlation + honest classification.
147029
+ ["fetchId", "outcome"],
147030
+ // ZERO-536: the direct-URL target. Dropping this loses attribution for an
147031
+ // unattributed run entirely — only worth trying against a truly old API.
147032
+ ["requestUrl", "requestMethod"]
147033
+ ];
147034
+ /**
147035
+ * Record a run, degrading to whatever the server actually understands.
147036
+ *
147037
+ * On a 400/422 we peel off one generation of newer fields and retry, so SDK
147038
+ * and API can be deployed in ANY order (and a self-hosted or staging API that
147039
+ * lags still records runs). The only unrescuable case is an unattributed run
147040
+ * against an API that predates ZERO-536: strip `requestUrl` and there is no
147041
+ * target left to name, so that server could never have recorded it.
147042
+ */
147043
+ create = async (input, opts = {}) => {
147044
+ const post = (body) => request2(
147045
+ this.client,
147046
+ {
147047
+ method: "POST",
147048
+ path: "/v1/runs",
147049
+ body,
147050
+ signal: opts.signal
147051
+ },
147052
+ createRunResponseSchema
147053
+ );
147054
+ let payload = { ...input };
147055
+ let generation = 0;
147056
+ for (; ; ) {
147057
+ try {
147058
+ return await post(payload);
147059
+ } catch (err) {
147060
+ const rejected = err instanceof ZeroApiError && (err.status === 400 || err.status === 422);
147061
+ if (!rejected) throw err;
147062
+ let next = null;
147063
+ let dropped = [];
147064
+ while (generation < _Runs.FIELD_GENERATIONS.length) {
147065
+ const fields = _Runs.FIELD_GENERATIONS[generation++];
147066
+ const present = (fields ?? []).filter(
147067
+ (f) => payload[f] !== void 0
147068
+ );
147069
+ if (present.length === 0) continue;
147070
+ next = { ...payload };
147071
+ for (const field of present) delete next[field];
147072
+ dropped = present;
147073
+ break;
147074
+ }
147075
+ if (!next || next.capabilityId === void 0 && next.requestUrl === void 0) {
147076
+ throw err;
147077
+ }
147078
+ payload = next;
147079
+ this.client.logger?.({
147080
+ level: "warn",
147081
+ message: "runs.create rejected by an older Zero API; retrying without newer fields",
147082
+ meta: { droppedFields: dropped }
147083
+ });
147084
+ }
147085
+ }
147086
+ };
146931
147087
  list = (params = {}, opts = {}) => {
146932
147088
  if (params.limit === 0) {
146933
147089
  if (opts.signal?.aborted) {
@@ -147951,7 +148107,7 @@ var placeholderFor = (fieldName, propSchema) => String(sampleValueFor(fieldName,
147951
148107
 
147952
148108
  // package.json
147953
148109
  var package_default2 = {
147954
- version: "1.23.0"};
148110
+ version: "1.24.0"};
147955
148111
 
147956
148112
  // src/app.ts
147957
148113
  init_esm_shims();
@@ -149784,6 +149940,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
149784
149940
  return;
149785
149941
  }
149786
149942
  const {
149943
+ fetchId,
149787
149944
  runId,
149788
149945
  status,
149789
149946
  latencyMs,
@@ -149894,6 +150051,11 @@ var fetchCommand = (appContext) => new Command("fetch").description(
149894
150051
  }
149895
150052
  }
149896
150053
  analyticsService.capture("fetch_executed", {
150054
+ // The correlation key: joins this client event to the server's
150055
+ // run_started / run_completed / payment_processed, and to the run
150056
+ // row itself. Works even when runId is null — i.e. exactly when
150057
+ // the run failed to record, which is what we most need to trace.
150058
+ fetchId,
149897
150059
  url: redactUrl2(resolvedUrl),
149898
150060
  status: status ?? void 0,
149899
150061
  outcome,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxyz/cli",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zero": "dist/index.js",