@zeroxyz/cli 1.26.0 → 1.27.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.
- package/dist/index.js +474 -134
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -78668,7 +78668,7 @@ init_esm_shims();
|
|
|
78668
78668
|
// ../sdk/dist/index.js
|
|
78669
78669
|
init_esm_shims();
|
|
78670
78670
|
|
|
78671
|
-
// ../sdk/dist/chunk-
|
|
78671
|
+
// ../sdk/dist/chunk-MQZT5KEN.js
|
|
78672
78672
|
init_esm_shims();
|
|
78673
78673
|
|
|
78674
78674
|
// ../../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
|
|
@@ -164225,6 +164225,20 @@ var ERC20_BALANCE_ABI = [
|
|
|
164225
164225
|
}
|
|
164226
164226
|
];
|
|
164227
164227
|
var USDC_DECIMALS = 6;
|
|
164228
|
+
var ERROR_MAX = 500;
|
|
164229
|
+
var redactUrl = (raw) => {
|
|
164230
|
+
try {
|
|
164231
|
+
const parsed = new URL(raw);
|
|
164232
|
+
return `${parsed.origin}${parsed.pathname}`;
|
|
164233
|
+
} catch {
|
|
164234
|
+
return "<invalid-url>";
|
|
164235
|
+
}
|
|
164236
|
+
};
|
|
164237
|
+
var truncateError = (raw) => raw.length > ERROR_MAX ? `${raw.slice(0, ERROR_MAX)}\u2026` : raw;
|
|
164238
|
+
var package_default = {
|
|
164239
|
+
version: "0.20.0"
|
|
164240
|
+
};
|
|
164241
|
+
var SDK_VERSION2 = package_default.version;
|
|
164228
164242
|
var ZeroError = class extends Error {
|
|
164229
164243
|
code;
|
|
164230
164244
|
constructor(code, message2, options) {
|
|
@@ -164384,10 +164398,6 @@ var normalizeTransportEnvelopeRequest = (url4, opts) => {
|
|
|
164384
164398
|
body: hasInnerBody ? JSON.stringify(innerBody) : void 0
|
|
164385
164399
|
};
|
|
164386
164400
|
};
|
|
164387
|
-
var package_default = {
|
|
164388
|
-
version: "0.19.0"
|
|
164389
|
-
};
|
|
164390
|
-
var SDK_VERSION2 = package_default.version;
|
|
164391
164401
|
var refreshResponseSchema = external_exports3.object({
|
|
164392
164402
|
accessToken: external_exports3.string(),
|
|
164393
164403
|
refreshToken: external_exports3.string()
|
|
@@ -165044,6 +165054,10 @@ var resolveDefaultPrefund = (displayCostAmount) => {
|
|
|
165044
165054
|
return bounded.toFixed(6).replace(/\.?0+$/, "");
|
|
165045
165055
|
};
|
|
165046
165056
|
var isUintString = (v) => typeof v === "string" && v.length > 0 && v.length <= MAX_AMOUNT_DIGITS && UINT_RE.test(v);
|
|
165057
|
+
var buildTempoPaymentMethods = (parameters) => [
|
|
165058
|
+
tempo2(parameters),
|
|
165059
|
+
tempo2.sessionLegacy.method(parameters)
|
|
165060
|
+
];
|
|
165047
165061
|
var coerceTempoChainId = (raw) => {
|
|
165048
165062
|
const id = typeof raw === "number" && Number.isFinite(raw) ? raw : typeof raw === "string" && /^-?[0-9]+$/.test(raw) ? Number(raw) : null;
|
|
165049
165063
|
if (id === TEMPO_CHAIN_ID2) return { id, chain: "tempo" };
|
|
@@ -165433,43 +165447,44 @@ var Payments = class {
|
|
|
165433
165447
|
let capturedChallenge;
|
|
165434
165448
|
let channelEntry;
|
|
165435
165449
|
let openTimeCumulative;
|
|
165450
|
+
const handleChannelUpdate = (entry) => {
|
|
165451
|
+
let cumulative;
|
|
165452
|
+
if (typeof entry.cumulativeAmount === "bigint") {
|
|
165453
|
+
cumulative = entry.cumulativeAmount;
|
|
165454
|
+
} else {
|
|
165455
|
+
cumulative = 0n;
|
|
165456
|
+
this.client.logger?.({
|
|
165457
|
+
level: "warn",
|
|
165458
|
+
message: "mppx emitted non-bigint cumulativeAmount; coerced to 0n",
|
|
165459
|
+
meta: { actualType: typeof entry.cumulativeAmount }
|
|
165460
|
+
});
|
|
165461
|
+
}
|
|
165462
|
+
if (openTimeCumulative === void 0 && entry.opened) {
|
|
165463
|
+
openTimeCumulative = cumulative;
|
|
165464
|
+
}
|
|
165465
|
+
const wasOpened = channelEntry?.opened ?? false;
|
|
165466
|
+
channelEntry = {
|
|
165467
|
+
channelId: entry.channelId,
|
|
165468
|
+
// mppx >=0.8 renamed the channel-entry escrow field from
|
|
165469
|
+
// `escrowContract` to `escrow` (see SessionManager
|
|
165470
|
+
// entryFromSnapshot); the legacy client still emits
|
|
165471
|
+
// `escrowContract`. Read `escrow` first, fall back to the old
|
|
165472
|
+
// name, then to any value we already latched so a later
|
|
165473
|
+
// escrow-less emit can't blank an open channel's escrow.
|
|
165474
|
+
escrowContract: entry.escrow ?? entry.escrowContract ?? channelEntry?.escrowContract ?? "0x0000000000000000000000000000000000000000",
|
|
165475
|
+
cumulativeAmount: cumulative,
|
|
165476
|
+
opened: wasOpened || entry.opened
|
|
165477
|
+
};
|
|
165478
|
+
};
|
|
165479
|
+
const tempoMethodParams = {
|
|
165480
|
+
account,
|
|
165481
|
+
maxDeposit: input.maxPay ?? resolveDefaultPrefund(input.displayCostAmount),
|
|
165482
|
+
onChannelUpdate: handleChannelUpdate
|
|
165483
|
+
};
|
|
165436
165484
|
const mppx = Mppx_exports.create({
|
|
165437
165485
|
polyfill: false,
|
|
165438
165486
|
fetch: configuredFetch,
|
|
165439
|
-
methods:
|
|
165440
|
-
tempo2({
|
|
165441
|
-
account,
|
|
165442
|
-
maxDeposit: input.maxPay ?? resolveDefaultPrefund(input.displayCostAmount),
|
|
165443
|
-
onChannelUpdate: (entry) => {
|
|
165444
|
-
let cumulative;
|
|
165445
|
-
if (typeof entry.cumulativeAmount === "bigint") {
|
|
165446
|
-
cumulative = entry.cumulativeAmount;
|
|
165447
|
-
} else {
|
|
165448
|
-
cumulative = 0n;
|
|
165449
|
-
this.client.logger?.({
|
|
165450
|
-
level: "warn",
|
|
165451
|
-
message: "mppx emitted non-bigint cumulativeAmount; coerced to 0n",
|
|
165452
|
-
meta: { actualType: typeof entry.cumulativeAmount }
|
|
165453
|
-
});
|
|
165454
|
-
}
|
|
165455
|
-
if (openTimeCumulative === void 0 && entry.opened) {
|
|
165456
|
-
openTimeCumulative = cumulative;
|
|
165457
|
-
}
|
|
165458
|
-
const wasOpened = channelEntry?.opened ?? false;
|
|
165459
|
-
channelEntry = {
|
|
165460
|
-
channelId: entry.channelId,
|
|
165461
|
-
// mppx >=0.8 renamed the channel-entry escrow field from
|
|
165462
|
-
// `escrowContract` to `escrow` (see SessionManager
|
|
165463
|
-
// entryFromSnapshot). Read `escrow` first, fall back to the
|
|
165464
|
-
// old name, then to any value we already latched so a later
|
|
165465
|
-
// escrow-less emit can't blank an open channel's escrow.
|
|
165466
|
-
escrowContract: entry.escrow ?? entry.escrowContract ?? channelEntry?.escrowContract ?? "0x0000000000000000000000000000000000000000",
|
|
165467
|
-
cumulativeAmount: cumulative,
|
|
165468
|
-
opened: wasOpened || entry.opened
|
|
165469
|
-
};
|
|
165470
|
-
}
|
|
165471
|
-
})
|
|
165472
|
-
],
|
|
165487
|
+
methods: buildTempoPaymentMethods(tempoMethodParams),
|
|
165473
165488
|
onChallenge: async (challenge2) => {
|
|
165474
165489
|
capturedChallenge = challenge2;
|
|
165475
165490
|
capturedAmount = await this.prepareTempoFunds(
|
|
@@ -165989,7 +166004,7 @@ var isTextContentType = (contentType) => {
|
|
|
165989
166004
|
const lower = contentType.toLowerCase();
|
|
165990
166005
|
return TEXT_CONTENT_TYPES.some((marker) => lower.includes(marker));
|
|
165991
166006
|
};
|
|
165992
|
-
var
|
|
166007
|
+
var redactUrl2 = (url4) => {
|
|
165993
166008
|
try {
|
|
165994
166009
|
const u = new URL(url4);
|
|
165995
166010
|
return `${u.origin}${u.pathname}`;
|
|
@@ -166301,7 +166316,7 @@ var resolveRecordingClient = (client, opts) => {
|
|
|
166301
166316
|
var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride, requestUrl, requestMethod) => {
|
|
166302
166317
|
const effectiveCapId = capabilityIdOverride ?? opts.capabilityId;
|
|
166303
166318
|
const urlTarget = requestUrl ? {
|
|
166304
|
-
requestUrl:
|
|
166319
|
+
requestUrl: redactUrl2(requestUrl),
|
|
166305
166320
|
...requestMethod && { requestMethod }
|
|
166306
166321
|
} : void 0;
|
|
166307
166322
|
const runTarget = effectiveCapId !== void 0 ? { capabilityId: effectiveCapId, ...urlTarget } : urlTarget ?? null;
|
|
@@ -166386,7 +166401,7 @@ var clientFetch = async (client, url4, opts = {}) => {
|
|
|
166386
166401
|
client,
|
|
166387
166402
|
opts
|
|
166388
166403
|
);
|
|
166389
|
-
const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(
|
|
166404
|
+
const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(redactUrl2(requestUrl), method).catch(() => null) : Promise.resolve(null);
|
|
166390
166405
|
const probeHeaders = withDefaultContentType(opts.headers, requestBody);
|
|
166391
166406
|
const requestInit = {
|
|
166392
166407
|
method,
|
|
@@ -166671,9 +166686,9 @@ var clientFetch = async (client, url4, opts = {}) => {
|
|
|
166671
166686
|
} : { resolved: false } : void 0;
|
|
166672
166687
|
const runTarget = effectiveCapabilityId !== void 0 ? {
|
|
166673
166688
|
capabilityId: effectiveCapabilityId,
|
|
166674
|
-
requestUrl:
|
|
166689
|
+
requestUrl: redactUrl2(requestUrl),
|
|
166675
166690
|
requestMethod: method
|
|
166676
|
-
} : { requestUrl:
|
|
166691
|
+
} : { requestUrl: redactUrl2(requestUrl), requestMethod: method };
|
|
166677
166692
|
const fetchOutcome = computeOutcome(response.status, payment, warnings);
|
|
166678
166693
|
{
|
|
166679
166694
|
const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
|
|
@@ -166740,7 +166755,7 @@ var clientFetch = async (client, url4, opts = {}) => {
|
|
|
166740
166755
|
level: "warn",
|
|
166741
166756
|
message: "Failed to record run for fetch",
|
|
166742
166757
|
meta: {
|
|
166743
|
-
url:
|
|
166758
|
+
url: redactUrl2(url4),
|
|
166744
166759
|
capabilityId: effectiveCapabilityId,
|
|
166745
166760
|
error: errorMessage2,
|
|
166746
166761
|
errorCode: code
|
|
@@ -168069,6 +168084,219 @@ var Wallet = class {
|
|
|
168069
168084
|
var DEFAULT_BASE_URL = "https://api.zero.xyz";
|
|
168070
168085
|
var DEFAULT_TIMEOUT_MS = 18e4;
|
|
168071
168086
|
var DEFAULT_MAX_RETRIES = 2;
|
|
168087
|
+
var QUERY_MAX = 200;
|
|
168088
|
+
var toAnalyticsWallet = (address5) => address5.toLowerCase();
|
|
168089
|
+
var SAFE_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
168090
|
+
"DOMException",
|
|
168091
|
+
"Error",
|
|
168092
|
+
"TypeError",
|
|
168093
|
+
"ZeroAgentAuthError",
|
|
168094
|
+
"ZeroApiError",
|
|
168095
|
+
"ZeroAuthError",
|
|
168096
|
+
"ZeroConfigurationError",
|
|
168097
|
+
"ZeroError",
|
|
168098
|
+
"ZeroInsufficientFundsError",
|
|
168099
|
+
"ZeroPaymentError",
|
|
168100
|
+
"ZeroSessionCloseFailedError",
|
|
168101
|
+
"ZeroTimeoutError",
|
|
168102
|
+
"ZeroValidationError",
|
|
168103
|
+
"ZeroWalletError"
|
|
168104
|
+
]);
|
|
168105
|
+
var SAFE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
168106
|
+
"api_error",
|
|
168107
|
+
"auth_error",
|
|
168108
|
+
"auth_no_credentials",
|
|
168109
|
+
"auth_session_expired",
|
|
168110
|
+
"configuration_error",
|
|
168111
|
+
"insufficient_funds",
|
|
168112
|
+
"payment_error",
|
|
168113
|
+
"payment_session_close_failed",
|
|
168114
|
+
"timeout_error",
|
|
168115
|
+
"validation_error",
|
|
168116
|
+
"wallet_error"
|
|
168117
|
+
]);
|
|
168118
|
+
var safeErrorLabel = (error98, fallback2) => {
|
|
168119
|
+
const record3 = typeof error98 === "object" && error98 !== null ? error98 : null;
|
|
168120
|
+
const name = typeof record3?.name === "string" && SAFE_ERROR_NAMES.has(record3.name) ? record3.name : "Error";
|
|
168121
|
+
const code = typeof record3?.code === "string" && SAFE_ERROR_CODES.has(record3.code) ? record3.code : fallback2;
|
|
168122
|
+
return `${name}:${code}`;
|
|
168123
|
+
};
|
|
168124
|
+
var sanitizeRunTrackingSkipReason = (reason) => reason.split(":", 1)[0] ?? "run_tracking_failed";
|
|
168125
|
+
var outcomeToErrorClass = (outcome, status) => {
|
|
168126
|
+
switch (outcome) {
|
|
168127
|
+
case "insufficient_funds":
|
|
168128
|
+
return "insufficient_funds";
|
|
168129
|
+
case "payment_failed":
|
|
168130
|
+
return "payment_failed";
|
|
168131
|
+
case "payment_rejected":
|
|
168132
|
+
case "payment_close_failed":
|
|
168133
|
+
return "payment_rejected";
|
|
168134
|
+
case "network_error":
|
|
168135
|
+
return "network";
|
|
168136
|
+
case "server_error":
|
|
168137
|
+
if (status !== null && status >= 400 && status < 500)
|
|
168138
|
+
return "upstream_4xx";
|
|
168139
|
+
if (status !== null && status >= 500) return "upstream_5xx";
|
|
168140
|
+
return "unknown";
|
|
168141
|
+
default:
|
|
168142
|
+
return "unknown";
|
|
168143
|
+
}
|
|
168144
|
+
};
|
|
168145
|
+
var classifyFetchError = (error98) => {
|
|
168146
|
+
const record3 = typeof error98 === "object" && error98 !== null ? error98 : null;
|
|
168147
|
+
const status = typeof record3?.status === "number" ? record3.status : null;
|
|
168148
|
+
const code = typeof record3?.code === "string" ? record3.code : null;
|
|
168149
|
+
switch (code) {
|
|
168150
|
+
case "validation_error":
|
|
168151
|
+
return { errorClass: "schema_validation_failed", status };
|
|
168152
|
+
case "timeout_error":
|
|
168153
|
+
return { errorClass: "network", status };
|
|
168154
|
+
case "auth_error":
|
|
168155
|
+
case "auth_session_expired":
|
|
168156
|
+
case "auth_no_credentials":
|
|
168157
|
+
return { errorClass: "auth_missing", status };
|
|
168158
|
+
case "insufficient_funds":
|
|
168159
|
+
return { errorClass: "insufficient_funds", status };
|
|
168160
|
+
case "payment_error":
|
|
168161
|
+
return { errorClass: "payment_failed", status };
|
|
168162
|
+
case "payment_session_close_failed":
|
|
168163
|
+
return { errorClass: "payment_rejected", status };
|
|
168164
|
+
case "api_error":
|
|
168165
|
+
if (status !== null && status >= 400 && status < 500)
|
|
168166
|
+
return { errorClass: "upstream_4xx", status };
|
|
168167
|
+
if (status !== null && status >= 500)
|
|
168168
|
+
return { errorClass: "upstream_5xx", status };
|
|
168169
|
+
return { errorClass: "unknown", status };
|
|
168170
|
+
default:
|
|
168171
|
+
return { errorClass: "unknown", status };
|
|
168172
|
+
}
|
|
168173
|
+
};
|
|
168174
|
+
var isCallerAbort = (error98) => {
|
|
168175
|
+
const record3 = typeof error98 === "object" && error98 !== null ? error98 : null;
|
|
168176
|
+
if (record3?.name === "AbortError") return true;
|
|
168177
|
+
if (record3?.code !== "api_error" || record3.status !== 0) return false;
|
|
168178
|
+
const cause = typeof record3.cause === "object" && record3.cause !== null ? record3.cause : null;
|
|
168179
|
+
return cause?.name === "AbortError";
|
|
168180
|
+
};
|
|
168181
|
+
var AnalyticsEmitter = class {
|
|
168182
|
+
isEnabled;
|
|
168183
|
+
sink;
|
|
168184
|
+
distinctIdOverride;
|
|
168185
|
+
extraProps;
|
|
168186
|
+
// Mutable: session-mode clients don't know their wallet until the managed
|
|
168187
|
+
// account resolves. setWalletAddress stamps it so later events attribute
|
|
168188
|
+
// correctly and the wallet becomes the distinctId fallback.
|
|
168189
|
+
walletAddress;
|
|
168190
|
+
constructor(opts, initialWallet) {
|
|
168191
|
+
this.isEnabled = opts?.enabled === true && typeof opts.capture === "function";
|
|
168192
|
+
this.sink = this.isEnabled ? opts?.capture : void 0;
|
|
168193
|
+
this.distinctIdOverride = opts?.distinctId;
|
|
168194
|
+
this.extraProps = opts?.properties ?? {};
|
|
168195
|
+
this.walletAddress = this.isEnabled && initialWallet ? toAnalyticsWallet(initialWallet) : null;
|
|
168196
|
+
}
|
|
168197
|
+
setWalletAddress(address5) {
|
|
168198
|
+
this.walletAddress = toAnalyticsWallet(address5);
|
|
168199
|
+
}
|
|
168200
|
+
emit(event, properties) {
|
|
168201
|
+
if (!this.sink) return;
|
|
168202
|
+
const distinctId = this.distinctIdOverride ?? this.walletAddress ?? null;
|
|
168203
|
+
try {
|
|
168204
|
+
this.sink({
|
|
168205
|
+
event,
|
|
168206
|
+
distinctId,
|
|
168207
|
+
properties: {
|
|
168208
|
+
...this.extraProps,
|
|
168209
|
+
// SDK-native truth wins over caller enrichment. Per-call/base props
|
|
168210
|
+
// may attach context but cannot rewrite outcomes, IDs, or filters.
|
|
168211
|
+
...properties,
|
|
168212
|
+
// Reserved stamps always win (ZERO-43: a stray same-named prop must
|
|
168213
|
+
// not clobber the cross-surface dimensions).
|
|
168214
|
+
source: "sdk",
|
|
168215
|
+
sdk_version: SDK_VERSION2,
|
|
168216
|
+
wallet_address: this.walletAddress
|
|
168217
|
+
}
|
|
168218
|
+
});
|
|
168219
|
+
} catch {
|
|
168220
|
+
}
|
|
168221
|
+
}
|
|
168222
|
+
search(query, opts, res) {
|
|
168223
|
+
if (!this.sink) return;
|
|
168224
|
+
this.emit("sdk_search", {
|
|
168225
|
+
// Caller-side context is enrichment only: native fields below win if
|
|
168226
|
+
// an adopter accidentally reuses one of their names.
|
|
168227
|
+
...opts.analytics?.props ?? {},
|
|
168228
|
+
// Truncate with a trailing ellipsis — same shape as truncateError and
|
|
168229
|
+
// the CLI's truncateQuery, so a consumer mapping this back to its own
|
|
168230
|
+
// event (e.g. CLI search_executed) is byte-for-byte identical.
|
|
168231
|
+
query: query.length > QUERY_MAX ? `${query.slice(0, QUERY_MAX)}\u2026` : query,
|
|
168232
|
+
query_length: query.length,
|
|
168233
|
+
result_count: res.capabilities.length,
|
|
168234
|
+
search_id: res.searchId,
|
|
168235
|
+
total: res.total,
|
|
168236
|
+
has_more: res.hasMore,
|
|
168237
|
+
offset: opts.offset ?? null,
|
|
168238
|
+
limit: opts.limit ?? null,
|
|
168239
|
+
free_only: opts.freeOnly ?? null,
|
|
168240
|
+
max_cost: opts.maxCost ?? null,
|
|
168241
|
+
protocol: opts.protocol ?? null,
|
|
168242
|
+
availability_status: opts.availabilityStatus ?? null,
|
|
168243
|
+
include_all: opts.includeAll ?? null,
|
|
168244
|
+
listing_source: opts.source ?? null,
|
|
168245
|
+
exclude_listing_source: opts.excludeSource ?? null
|
|
168246
|
+
});
|
|
168247
|
+
}
|
|
168248
|
+
fetchExecuted(url4, opts, res) {
|
|
168249
|
+
if (!this.sink) return;
|
|
168250
|
+
const resolution = res.capabilityResolution;
|
|
168251
|
+
this.emit("fetch_executed", {
|
|
168252
|
+
// Caller-side context is enrichment only; execution truth below wins.
|
|
168253
|
+
...opts.analytics?.props ?? {},
|
|
168254
|
+
url: redactUrl(url4),
|
|
168255
|
+
status: res.status,
|
|
168256
|
+
outcome: res.outcome,
|
|
168257
|
+
error_class: res.outcome === "success" ? null : outcomeToErrorClass(res.outcome, res.status),
|
|
168258
|
+
latency_ms: res.latencyMs,
|
|
168259
|
+
has_payment: res.payment !== null,
|
|
168260
|
+
payment_protocol: res.payment?.protocol ?? null,
|
|
168261
|
+
payment_amount: res.payment?.amount ?? null,
|
|
168262
|
+
// Opaque cap uid / slug / attribution token — not PII, useful for
|
|
168263
|
+
// joining back to the capabilities table in BI.
|
|
168264
|
+
capability_id: opts.capabilityId ?? null,
|
|
168265
|
+
capability_uid: resolution?.resolved ? resolution.capabilityId ?? null : null,
|
|
168266
|
+
capability_slug: resolution?.resolved ? resolution.capabilitySlug ?? null : null,
|
|
168267
|
+
search_id: opts.searchId ?? null,
|
|
168268
|
+
// Always-present correlation key (runId is null exactly when recording
|
|
168269
|
+
// failed), so dashboards can join the event to the execution even then.
|
|
168270
|
+
fetch_id: res.fetchId,
|
|
168271
|
+
run_id: res.runId,
|
|
168272
|
+
run_tracked: res.runId !== null,
|
|
168273
|
+
run_tracking_skipped: res.runTrackingSkipped?.map(sanitizeRunTrackingSkipReason) ?? null,
|
|
168274
|
+
// Upstream response text can contain credentials or user content. Keep
|
|
168275
|
+
// only the already-derived client-side hash/length for clustering.
|
|
168276
|
+
error_snippet_hash: res.upstreamError?.snippetHash ?? null,
|
|
168277
|
+
error_snippet_length: res.upstreamError?.snippetLength ?? null
|
|
168278
|
+
});
|
|
168279
|
+
}
|
|
168280
|
+
fetchError(url4, opts, error98, errorClass, status) {
|
|
168281
|
+
if (!this.sink) return;
|
|
168282
|
+
this.emit("fetch_error", {
|
|
168283
|
+
url: redactUrl(url4),
|
|
168284
|
+
error_class: errorClass,
|
|
168285
|
+
status,
|
|
168286
|
+
capability_id: opts.capabilityId ?? null,
|
|
168287
|
+
search_id: opts.searchId ?? null,
|
|
168288
|
+
error: safeErrorLabel(error98, errorClass)
|
|
168289
|
+
});
|
|
168290
|
+
}
|
|
168291
|
+
walletResolved(address5, walletSource) {
|
|
168292
|
+
if (!this.sink) return;
|
|
168293
|
+
this.setWalletAddress(address5);
|
|
168294
|
+
this.emit("sdk_wallet_resolved", {
|
|
168295
|
+
resolved_wallet_address: toAnalyticsWallet(address5),
|
|
168296
|
+
wallet_source: walletSource
|
|
168297
|
+
});
|
|
168298
|
+
}
|
|
168299
|
+
};
|
|
168072
168300
|
var noopRefresh = async () => {
|
|
168073
168301
|
};
|
|
168074
168302
|
var searchResultSchema = external_exports3.object({
|
|
@@ -168151,6 +168379,13 @@ var ZeroClient = class _ZeroClient {
|
|
|
168151
168379
|
fetchImpl;
|
|
168152
168380
|
fetchOptions;
|
|
168153
168381
|
logger;
|
|
168382
|
+
analyticsOptions;
|
|
168383
|
+
// Opt-in telemetry (ZERO-434). Always constructed; a no-op when analytics
|
|
168384
|
+
// was omitted/disabled (its methods short-circuit before the sink), so the
|
|
168385
|
+
// hot paths carry no branch of their own. Kept private so the supported
|
|
168386
|
+
// public surface is the constructor option + emitted event types, not the
|
|
168387
|
+
// mutable emitter implementation.
|
|
168388
|
+
analytics;
|
|
168154
168389
|
// Private — read via getCredentials(), mutate only via applyRefreshedTokens().
|
|
168155
168390
|
// Keeping a single mutator funnel is what lets the transport replay
|
|
168156
168391
|
// requests with a fresh access token after a 401 → refresh.
|
|
@@ -168209,6 +168444,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168209
168444
|
this.fetchImpl = options.fetch ?? ((...args) => globalThis.fetch(...args));
|
|
168210
168445
|
this.fetchOptions = options.fetchOptions;
|
|
168211
168446
|
this.logger = options.logger;
|
|
168447
|
+
this.analyticsOptions = options.analytics;
|
|
168212
168448
|
this.refreshOverride = options.refresh;
|
|
168213
168449
|
this.withAccountCache = options._sharedAccountCache ?? /* @__PURE__ */ new Map();
|
|
168214
168450
|
this.auth = new Auth(this);
|
|
@@ -168217,6 +168453,11 @@ var ZeroClient = class _ZeroClient {
|
|
|
168217
168453
|
this.payments = new Payments(this);
|
|
168218
168454
|
this.runs = new Runs(this);
|
|
168219
168455
|
this.wallet = new Wallet(this);
|
|
168456
|
+
const initialWallet = this.credentials.kind === "account" ? this.credentials.account.address : null;
|
|
168457
|
+
this.analytics = new AnalyticsEmitter(options.analytics, initialWallet);
|
|
168458
|
+
if (initialWallet && this.analytics.isEnabled) {
|
|
168459
|
+
this.analytics.walletResolved(initialWallet, "self_custody");
|
|
168460
|
+
}
|
|
168220
168461
|
}
|
|
168221
168462
|
// Convenience factory: derives a viem account from a raw 0x-prefixed
|
|
168222
168463
|
// private key and constructs a client in account mode. Equivalent to
|
|
@@ -168324,7 +168565,8 @@ var ZeroClient = class _ZeroClient {
|
|
|
168324
168565
|
defaultHeaders: { ...this.defaultHeaders },
|
|
168325
168566
|
fetch: this.fetchImpl,
|
|
168326
168567
|
fetchOptions: this.fetchOptions ? { ...this.fetchOptions } : void 0,
|
|
168327
|
-
logger: this.logger
|
|
168568
|
+
logger: this.logger,
|
|
168569
|
+
analytics: this.analyticsOptions
|
|
168328
168570
|
});
|
|
168329
168571
|
// Returns a new client bound to a different viem account. Mirrors
|
|
168330
168572
|
// withSession for the self-custody auth path — multi-tenant servers
|
|
@@ -168376,6 +168618,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168376
168618
|
fetch: this.fetchImpl,
|
|
168377
168619
|
fetchOptions: this.fetchOptions ? { ...this.fetchOptions } : void 0,
|
|
168378
168620
|
logger: this.logger,
|
|
168621
|
+
analytics: this.analyticsOptions,
|
|
168379
168622
|
_sharedAccountCache: this.withAccountCache
|
|
168380
168623
|
});
|
|
168381
168624
|
this.withAccountCache.set(key, sub);
|
|
@@ -168436,6 +168679,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168436
168679
|
}
|
|
168437
168680
|
const acc = createManagedAccount(this, getAddress(primary.walletAddress));
|
|
168438
168681
|
this.managedAccount = acc;
|
|
168682
|
+
this.analytics.walletResolved(primary.walletAddress, "privy_embedded");
|
|
168439
168683
|
return acc;
|
|
168440
168684
|
})().finally(() => {
|
|
168441
168685
|
if (this.managedAccountGen === startedAtGen) {
|
|
@@ -168479,6 +168723,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168479
168723
|
explicitWallet: true
|
|
168480
168724
|
});
|
|
168481
168725
|
this.managedAccountByAddress.set(canonical.toLowerCase(), acc);
|
|
168726
|
+
this.analytics.walletResolved(match.walletAddress, "privy_embedded");
|
|
168482
168727
|
return acc;
|
|
168483
168728
|
};
|
|
168484
168729
|
// Per-caller signal gate: each caller can reject on their own abort
|
|
@@ -168519,9 +168764,9 @@ var ZeroClient = class _ZeroClient {
|
|
|
168519
168764
|
// `search` is a flat method, not a namespace — it's the hot path most
|
|
168520
168765
|
// consumers hit first, and Stripe/Anthropic/OpenAI all keep their primary
|
|
168521
168766
|
// entry point flat for the same reason.
|
|
168522
|
-
search = (query, opts = {}) => {
|
|
168523
|
-
const { signal, ...rest } = opts;
|
|
168524
|
-
|
|
168767
|
+
search = async (query, opts = {}) => {
|
|
168768
|
+
const { signal, analytics: _analytics, ...rest } = opts;
|
|
168769
|
+
const response = await request2(
|
|
168525
168770
|
this,
|
|
168526
168771
|
{
|
|
168527
168772
|
method: "POST",
|
|
@@ -168531,11 +168776,25 @@ var ZeroClient = class _ZeroClient {
|
|
|
168531
168776
|
},
|
|
168532
168777
|
searchResponseSchema
|
|
168533
168778
|
);
|
|
168779
|
+
this.analytics.search(query, opts, response);
|
|
168780
|
+
return response;
|
|
168534
168781
|
};
|
|
168535
168782
|
// Paid fetch — search → get → fetch is Zero's canonical loop. The hot
|
|
168536
168783
|
// path is flat on the client, same rationale as `search` above.
|
|
168537
168784
|
// Orchestration lives in fetch.ts so this class stays readable.
|
|
168538
|
-
fetch = (url4, opts = {}) =>
|
|
168785
|
+
fetch = async (url4, opts = {}) => {
|
|
168786
|
+
try {
|
|
168787
|
+
const result = await clientFetch(this, url4, opts);
|
|
168788
|
+
this.analytics.fetchExecuted(url4, opts, result);
|
|
168789
|
+
return result;
|
|
168790
|
+
} catch (error98) {
|
|
168791
|
+
if (this.analytics.isEnabled && !isCallerAbort(error98)) {
|
|
168792
|
+
const { errorClass, status } = classifyFetchError(error98);
|
|
168793
|
+
this.analytics.fetchError(url4, opts, error98, errorClass, status);
|
|
168794
|
+
}
|
|
168795
|
+
throw error98;
|
|
168796
|
+
}
|
|
168797
|
+
};
|
|
168539
168798
|
// Poll the API server's /health endpoint until it responds OK. Useful for
|
|
168540
168799
|
// warming up a cold container before spawning a subprocess that needs the
|
|
168541
168800
|
// API ready. Resolves when healthy, resolves (silently) when maxAttempts
|
|
@@ -168654,16 +168913,6 @@ var tryParseJson2 = (text) => {
|
|
|
168654
168913
|
return null;
|
|
168655
168914
|
}
|
|
168656
168915
|
};
|
|
168657
|
-
var ERROR_MAX = 500;
|
|
168658
|
-
var redactUrl2 = (raw) => {
|
|
168659
|
-
try {
|
|
168660
|
-
const parsed = new URL(raw);
|
|
168661
|
-
return `${parsed.origin}${parsed.pathname}`;
|
|
168662
|
-
} catch {
|
|
168663
|
-
return raw;
|
|
168664
|
-
}
|
|
168665
|
-
};
|
|
168666
|
-
var truncateError = (raw) => raw.length > ERROR_MAX ? `${raw.slice(0, ERROR_MAX)}\u2026` : raw;
|
|
168667
168916
|
var schemaTypeLabel = (node) => {
|
|
168668
168917
|
const t = node.type;
|
|
168669
168918
|
if (typeof t === "string") return t;
|
|
@@ -168777,7 +169026,7 @@ var placeholderFor = (fieldName, propSchema) => String(sampleValueFor(fieldName,
|
|
|
168777
169026
|
|
|
168778
169027
|
// package.json
|
|
168779
169028
|
var package_default2 = {
|
|
168780
|
-
version: "1.
|
|
169029
|
+
version: "1.27.0"};
|
|
168781
169030
|
|
|
168782
169031
|
// src/app.ts
|
|
168783
169032
|
init_esm_shims();
|
|
@@ -170489,7 +170738,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170489
170738
|
const message2 = err instanceof Error ? err.message : "Failed to read request body";
|
|
170490
170739
|
analyticsService.capture("fetch_error", {
|
|
170491
170740
|
cliErrorClass: /exceeds the .* byte local cap/.test(message2) ? "payload_too_large" : "schema_validation_failed",
|
|
170492
|
-
url:
|
|
170741
|
+
url: redactUrl(resolvedUrl),
|
|
170493
170742
|
error: truncateError(message2)
|
|
170494
170743
|
});
|
|
170495
170744
|
console.error(message2);
|
|
@@ -170596,13 +170845,28 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170596
170845
|
}
|
|
170597
170846
|
}
|
|
170598
170847
|
return {};
|
|
170848
|
+
},
|
|
170849
|
+
// fetch_executed is emitted by the SDK (ZERO-434) and mapped
|
|
170850
|
+
// back to the CLI taxonomy in captureSdk. These are the
|
|
170851
|
+
// CLI-only props the SDK can't compute; they ride onto the
|
|
170852
|
+
// emitted event verbatim. The recovered capabilityUid/Slug on
|
|
170853
|
+
// the bare-URL path come from the SDK's own capabilityResolution
|
|
170854
|
+
// (surfaced on the SDK-origin fetch_executed), NOT from here.
|
|
170855
|
+
analytics: {
|
|
170856
|
+
props: {
|
|
170857
|
+
capabilityId: capabilityId ?? void 0,
|
|
170858
|
+
capabilityUid: capabilityUid ?? void 0,
|
|
170859
|
+
capabilitySlug: capabilitySlug ?? void 0,
|
|
170860
|
+
signingSource: appContext.services.signing?.source ?? "none",
|
|
170861
|
+
fetchOrigin
|
|
170862
|
+
}
|
|
170599
170863
|
}
|
|
170600
170864
|
});
|
|
170601
170865
|
} catch (err) {
|
|
170602
170866
|
const message2 = err instanceof Error ? err.message : "Fetch failed";
|
|
170603
170867
|
analyticsService.capture("fetch_error", {
|
|
170604
170868
|
cliErrorClass: "network",
|
|
170605
|
-
url:
|
|
170869
|
+
url: redactUrl(resolvedUrl),
|
|
170606
170870
|
error: truncateError(message2)
|
|
170607
170871
|
});
|
|
170608
170872
|
console.error(` Fetch failed: ${message2}`);
|
|
@@ -170610,7 +170874,6 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170610
170874
|
return;
|
|
170611
170875
|
}
|
|
170612
170876
|
const {
|
|
170613
|
-
fetchId,
|
|
170614
170877
|
runId,
|
|
170615
170878
|
status,
|
|
170616
170879
|
latencyMs,
|
|
@@ -170701,7 +170964,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170701
170964
|
capabilityUid = capabilityResolution.capabilityId ?? capabilityUid;
|
|
170702
170965
|
capabilitySlug = capabilityResolution.capabilitySlug ?? capabilitySlug;
|
|
170703
170966
|
analyticsService.capture("capability_resolution_recovered", {
|
|
170704
|
-
url:
|
|
170967
|
+
url: redactUrl(resolvedUrl),
|
|
170705
170968
|
method,
|
|
170706
170969
|
capabilityUid: capabilityResolution.capabilityId,
|
|
170707
170970
|
capabilitySlug: capabilityResolution.capabilitySlug,
|
|
@@ -170715,42 +170978,11 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170715
170978
|
);
|
|
170716
170979
|
}
|
|
170717
170980
|
analyticsService.capture("capability_resolution_missed", {
|
|
170718
|
-
url:
|
|
170981
|
+
url: redactUrl(resolvedUrl),
|
|
170719
170982
|
method
|
|
170720
170983
|
});
|
|
170721
170984
|
}
|
|
170722
170985
|
}
|
|
170723
|
-
analyticsService.capture("fetch_executed", {
|
|
170724
|
-
// The correlation key: joins this client event to the server's
|
|
170725
|
-
// run_started / run_completed / payment_processed, and to the run
|
|
170726
|
-
// row itself. Works even when runId is null — i.e. exactly when
|
|
170727
|
-
// the run failed to record, which is what we most need to trace.
|
|
170728
|
-
fetchId,
|
|
170729
|
-
url: redactUrl2(resolvedUrl),
|
|
170730
|
-
status: status ?? void 0,
|
|
170731
|
-
outcome,
|
|
170732
|
-
latencyMs,
|
|
170733
|
-
hasPayment: !!payment,
|
|
170734
|
-
paymentProtocol: payment?.protocol,
|
|
170735
|
-
paymentAmount: payment && payment.amount !== "unknown" ? payment.amount : void 0,
|
|
170736
|
-
// Canonical join keys — capabilitySlug is the dashboard
|
|
170737
|
-
// breakdown dimension; capabilityUid is the stable join
|
|
170738
|
-
// key with the capabilities table. capabilityId is the
|
|
170739
|
-
// back-compat alias (same value as capabilityUid when
|
|
170740
|
-
// resolved, else the raw --capability input).
|
|
170741
|
-
capabilityUid: capabilityUid ?? void 0,
|
|
170742
|
-
capabilitySlug: capabilitySlug ?? void 0,
|
|
170743
|
-
capabilityId: capabilityId ?? void 0,
|
|
170744
|
-
searchId: searchId ?? void 0,
|
|
170745
|
-
resultRank: resultRank ?? void 0,
|
|
170746
|
-
runId: runId ?? void 0,
|
|
170747
|
-
runTracked: !!runId,
|
|
170748
|
-
signingSource: signing?.source ?? "none",
|
|
170749
|
-
// A NULL searchId on a direct_slug fetch is correct here,
|
|
170750
|
-
// not a funnel gap to paper over.
|
|
170751
|
-
fetchOrigin,
|
|
170752
|
-
...resultError && { error: truncateError(resultError) }
|
|
170753
|
-
});
|
|
170754
170986
|
const outcomeInfo = OUTCOMES[outcome];
|
|
170755
170987
|
if (outcomeInfo.errorClass !== null) {
|
|
170756
170988
|
const cliErrorClass = cliErrorClassFor(
|
|
@@ -170765,7 +170997,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170765
170997
|
capabilityId: capabilityId ?? void 0,
|
|
170766
170998
|
searchId: searchId ?? void 0,
|
|
170767
170999
|
resultRank: resultRank ?? void 0,
|
|
170768
|
-
url:
|
|
171000
|
+
url: redactUrl(resolvedUrl),
|
|
170769
171001
|
status: typeof status === "number" ? status : void 0,
|
|
170770
171002
|
upstreamErrorMessage: upstreamError?.message,
|
|
170771
171003
|
errorSnippetHash: upstreamError?.snippetHash,
|
|
@@ -170910,7 +171142,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170910
171142
|
try {
|
|
170911
171143
|
appContext.services.analyticsService.capture("fetch_error", {
|
|
170912
171144
|
cliErrorClass: "unknown",
|
|
170913
|
-
url: url4 ?
|
|
171145
|
+
url: url4 ? redactUrl(url4) : "unknown",
|
|
170914
171146
|
error: truncateError(message2)
|
|
170915
171147
|
});
|
|
170916
171148
|
} catch {
|
|
@@ -172514,13 +172746,6 @@ Examples:
|
|
|
172514
172746
|
|
|
172515
172747
|
// src/commands/search-command.ts
|
|
172516
172748
|
init_esm_shims();
|
|
172517
|
-
|
|
172518
|
-
// src/util/redact.ts
|
|
172519
|
-
init_esm_shims();
|
|
172520
|
-
var QUERY_MAX = 200;
|
|
172521
|
-
var truncateQuery = (raw) => raw.length > QUERY_MAX ? `${raw.slice(0, QUERY_MAX)}\u2026` : raw;
|
|
172522
|
-
|
|
172523
|
-
// src/commands/search-command.ts
|
|
172524
172749
|
var DEFAULT_MAX_COST_USD = "30";
|
|
172525
172750
|
var formatStatusBadge = (status) => {
|
|
172526
172751
|
if (!status || !(status in AVAILABILITY_BADGES)) return "";
|
|
@@ -172557,7 +172782,7 @@ var searchCommand = (appContext) => new Command("search").description("Search fo
|
|
|
172557
172782
|
).action(
|
|
172558
172783
|
async (query, options) => {
|
|
172559
172784
|
try {
|
|
172560
|
-
const {
|
|
172785
|
+
const { client } = appContext.services;
|
|
172561
172786
|
if (options.protocol && !["x402", "mpp"].includes(options.protocol)) {
|
|
172562
172787
|
console.error(
|
|
172563
172788
|
`Invalid protocol "${options.protocol}". Must be x402 or mpp.`
|
|
@@ -172586,27 +172811,14 @@ var searchCommand = (appContext) => new Command("search").description("Search fo
|
|
|
172586
172811
|
availabilityStatus: effectiveStatus,
|
|
172587
172812
|
includeAll: options.all,
|
|
172588
172813
|
source: options.source,
|
|
172589
|
-
excludeSource: options.excludeSource
|
|
172590
|
-
|
|
172591
|
-
|
|
172592
|
-
|
|
172593
|
-
|
|
172594
|
-
|
|
172595
|
-
|
|
172596
|
-
|
|
172597
|
-
hasMore: result.hasMore,
|
|
172598
|
-
offset: options.offset,
|
|
172599
|
-
limit: options.limit,
|
|
172600
|
-
freeOnly: options.free ?? false,
|
|
172601
|
-
maxCost: effectiveMaxCost,
|
|
172602
|
-
maxCostDefaulted: appliedDefaultMaxCost,
|
|
172603
|
-
protocol: options.protocol,
|
|
172604
|
-
availabilityStatus: effectiveStatus,
|
|
172605
|
-
availabilityStatusDefaulted: appliedDefaultStatus,
|
|
172606
|
-
includeAll: options.all ?? false,
|
|
172607
|
-
listingSource: options.source,
|
|
172608
|
-
excludeListingSource: options.excludeSource,
|
|
172609
|
-
json: options.json ?? false
|
|
172814
|
+
excludeSource: options.excludeSource,
|
|
172815
|
+
analytics: {
|
|
172816
|
+
props: {
|
|
172817
|
+
maxCostDefaulted: appliedDefaultMaxCost,
|
|
172818
|
+
availabilityStatusDefaulted: appliedDefaultStatus,
|
|
172819
|
+
json: options.json ?? false
|
|
172820
|
+
}
|
|
172821
|
+
}
|
|
172610
172822
|
});
|
|
172611
172823
|
if (options.json) {
|
|
172612
172824
|
console.log(
|
|
@@ -177481,10 +177693,82 @@ var PostHog = class extends PostHogBackendClient {
|
|
|
177481
177693
|
}
|
|
177482
177694
|
};
|
|
177483
177695
|
|
|
177696
|
+
// src/analytics/sdk-event-map.ts
|
|
177697
|
+
init_esm_shims();
|
|
177698
|
+
var orUndef = (value) => value === null ? void 0 : value;
|
|
177699
|
+
var dropUnknownAmount = (value) => value === null || value === "unknown" ? void 0 : value;
|
|
177700
|
+
var mapSdkEventToCliEvent = (event) => {
|
|
177701
|
+
const p = event.properties;
|
|
177702
|
+
switch (event.event) {
|
|
177703
|
+
case "sdk_search":
|
|
177704
|
+
return {
|
|
177705
|
+
event: "search_executed",
|
|
177706
|
+
props: {
|
|
177707
|
+
query: p.query,
|
|
177708
|
+
queryLength: p.query_length,
|
|
177709
|
+
resultCount: p.result_count,
|
|
177710
|
+
searchId: p.search_id,
|
|
177711
|
+
total: p.total,
|
|
177712
|
+
hasMore: p.has_more,
|
|
177713
|
+
offset: orUndef(p.offset),
|
|
177714
|
+
limit: orUndef(p.limit),
|
|
177715
|
+
// The CLI historically defaulted these two booleans (never null).
|
|
177716
|
+
freeOnly: p.free_only ?? false,
|
|
177717
|
+
maxCost: orUndef(p.max_cost),
|
|
177718
|
+
// CLI-only, carried in via the SDK's per-call analytics.props.
|
|
177719
|
+
maxCostDefaulted: p.maxCostDefaulted,
|
|
177720
|
+
protocol: orUndef(p.protocol),
|
|
177721
|
+
availabilityStatus: orUndef(p.availability_status),
|
|
177722
|
+
availabilityStatusDefaulted: p.availabilityStatusDefaulted,
|
|
177723
|
+
includeAll: p.include_all ?? false,
|
|
177724
|
+
listingSource: orUndef(p.listing_source),
|
|
177725
|
+
excludeListingSource: orUndef(p.exclude_listing_source),
|
|
177726
|
+
json: p.json
|
|
177727
|
+
}
|
|
177728
|
+
};
|
|
177729
|
+
case "fetch_executed":
|
|
177730
|
+
return {
|
|
177731
|
+
event: "fetch_executed",
|
|
177732
|
+
props: {
|
|
177733
|
+
// SDK-native execution truth (snake→camel).
|
|
177734
|
+
fetchId: p.fetch_id,
|
|
177735
|
+
url: p.url,
|
|
177736
|
+
status: orUndef(p.status),
|
|
177737
|
+
outcome: p.outcome,
|
|
177738
|
+
latencyMs: p.latency_ms,
|
|
177739
|
+
hasPayment: p.has_payment,
|
|
177740
|
+
paymentProtocol: orUndef(p.payment_protocol),
|
|
177741
|
+
paymentAmount: dropUnknownAmount(p.payment_amount),
|
|
177742
|
+
runId: orUndef(p.run_id),
|
|
177743
|
+
runTracked: p.run_tracked,
|
|
177744
|
+
error: orUndef(p.error),
|
|
177745
|
+
// capabilityUid/Slug: prefer the adopter-supplied value (token /
|
|
177746
|
+
// slug paths, from analytics.props), else the SDK's bare-URL
|
|
177747
|
+
// resolution — mirroring how the CLI recovered them post-fetch.
|
|
177748
|
+
capabilityUid: p.capabilityUid ?? orUndef(p.capability_uid),
|
|
177749
|
+
capabilitySlug: p.capabilitySlug ?? orUndef(p.capability_slug),
|
|
177750
|
+
// CLI-only context carried in via analytics.props.
|
|
177751
|
+
capabilityId: p.capabilityId,
|
|
177752
|
+
signingSource: p.signingSource,
|
|
177753
|
+
fetchOrigin: p.fetchOrigin,
|
|
177754
|
+
// searchId is server-derived (always omitted client-side);
|
|
177755
|
+
// resultRank is likewise dead on the CLI event.
|
|
177756
|
+
searchId: orUndef(p.search_id)
|
|
177757
|
+
}
|
|
177758
|
+
};
|
|
177759
|
+
default:
|
|
177760
|
+
return null;
|
|
177761
|
+
}
|
|
177762
|
+
};
|
|
177763
|
+
|
|
177484
177764
|
// src/services/analytics-service.ts
|
|
177765
|
+
var FORWARDED_SDK_EVENTS = /* @__PURE__ */ new Set([
|
|
177766
|
+
"sdk_wallet_resolved"
|
|
177767
|
+
]);
|
|
177485
177768
|
var POSTHOG_API_KEY = "phc_B2vLyNxAf2mnqvdPQajf4d4b2iXc35dep2ZrvebMJLuX";
|
|
177486
177769
|
var POSTHOG_HOST = "https://us.i.posthog.com";
|
|
177487
|
-
var
|
|
177770
|
+
var resolvePostHogHost = () => process.env.NODE_ENV === "test" && process.env.ZERO_ANALYTICS_TEST_HOST ? process.env.ZERO_ANALYTICS_TEST_HOST : POSTHOG_HOST;
|
|
177771
|
+
var toAnalyticsWallet2 = (walletAddress) => walletAddress.toLowerCase();
|
|
177488
177772
|
var AnalyticsService = class {
|
|
177489
177773
|
posthog;
|
|
177490
177774
|
distinctId;
|
|
@@ -177496,7 +177780,7 @@ var AnalyticsService = class {
|
|
|
177496
177780
|
constructor(opts) {
|
|
177497
177781
|
this.cliVersion = opts.cliVersion;
|
|
177498
177782
|
this.environment = opts.environment;
|
|
177499
|
-
this.walletAddress = opts.walletAddress ?
|
|
177783
|
+
this.walletAddress = opts.walletAddress ? toAnalyticsWallet2(opts.walletAddress) : null;
|
|
177500
177784
|
this.requestId = opts.requestId;
|
|
177501
177785
|
this.agentHost = opts.agentHost;
|
|
177502
177786
|
let telemetryEnabled = true;
|
|
@@ -177519,7 +177803,7 @@ var AnalyticsService = class {
|
|
|
177519
177803
|
return;
|
|
177520
177804
|
}
|
|
177521
177805
|
if (opts.walletAddress) {
|
|
177522
|
-
this.distinctId =
|
|
177806
|
+
this.distinctId = toAnalyticsWallet2(opts.walletAddress);
|
|
177523
177807
|
} else if (persistedAnonId) {
|
|
177524
177808
|
this.distinctId = persistedAnonId;
|
|
177525
177809
|
} else {
|
|
@@ -177547,7 +177831,7 @@ var AnalyticsService = class {
|
|
|
177547
177831
|
originalConsoleError.apply(console, args);
|
|
177548
177832
|
};
|
|
177549
177833
|
this.posthog = new PostHog(POSTHOG_API_KEY, {
|
|
177550
|
-
host:
|
|
177834
|
+
host: resolvePostHogHost(),
|
|
177551
177835
|
flushAt: 1,
|
|
177552
177836
|
flushInterval: 0,
|
|
177553
177837
|
// Vitest spins up many AnalyticsService instances per process; each
|
|
@@ -177561,7 +177845,7 @@ var AnalyticsService = class {
|
|
|
177561
177845
|
this.maybeAliasAnonToWallet(
|
|
177562
177846
|
opts.configPath,
|
|
177563
177847
|
persistedAnonId,
|
|
177564
|
-
|
|
177848
|
+
toAnalyticsWallet2(opts.walletAddress)
|
|
177565
177849
|
);
|
|
177566
177850
|
}
|
|
177567
177851
|
}
|
|
@@ -177602,7 +177886,7 @@ var AnalyticsService = class {
|
|
|
177602
177886
|
// via PostHog alias, when AnalyticsService is constructed with both
|
|
177603
177887
|
// the persisted anonId and the new walletAddress.
|
|
177604
177888
|
setWalletAddress(walletAddress) {
|
|
177605
|
-
this.walletAddress =
|
|
177889
|
+
this.walletAddress = toAnalyticsWallet2(walletAddress);
|
|
177606
177890
|
}
|
|
177607
177891
|
capture(event, properties) {
|
|
177608
177892
|
if (!this.posthog) return;
|
|
@@ -177630,6 +177914,42 @@ var AnalyticsService = class {
|
|
|
177630
177914
|
}
|
|
177631
177915
|
});
|
|
177632
177916
|
}
|
|
177917
|
+
// Sink for the SDK's opt-in analytics (ZERO-434), wired into the ZeroClient
|
|
177918
|
+
// as its `capture` callback in app-services. This is the CLI end of the
|
|
177919
|
+
// injected-sink pattern — the same shape a partner would write. It keeps the
|
|
177920
|
+
// SDK's own `source: "sdk"` stamp (the event genuinely came from the SDK
|
|
177921
|
+
// layer, not a hand-authored CLI event) but adds the CLI's stitching
|
|
177922
|
+
// super-props so it correlates to the rest of the invocation. Overlapping
|
|
177923
|
+
// events are filtered out via FORWARDED_SDK_EVENTS above — the CLI's own
|
|
177924
|
+
// emissions remain the source of truth for search/fetch.
|
|
177925
|
+
captureSdk(event) {
|
|
177926
|
+
if (!this.posthog) return;
|
|
177927
|
+
const mapped = mapSdkEventToCliEvent(event);
|
|
177928
|
+
if (mapped) {
|
|
177929
|
+
this.capture(mapped.event, mapped.props);
|
|
177930
|
+
return;
|
|
177931
|
+
}
|
|
177932
|
+
if (!FORWARDED_SDK_EVENTS.has(event.event)) return;
|
|
177933
|
+
this.posthog.capture({
|
|
177934
|
+
// The SDK resolves the wallet as distinctId; fall back to the CLI's
|
|
177935
|
+
// distinctId (anon UUID before any wallet) so the event still stitches.
|
|
177936
|
+
distinctId: event.distinctId ?? this.distinctId,
|
|
177937
|
+
event: event.event,
|
|
177938
|
+
properties: {
|
|
177939
|
+
// event.properties already carries source:"sdk", sdk_version, and
|
|
177940
|
+
// wallet_address. Add the CLI's correlation super-props (but NOT
|
|
177941
|
+
// source:"cli" — this is an SDK-layer event, honestly stamped).
|
|
177942
|
+
...event.properties,
|
|
177943
|
+
environment: this.environment,
|
|
177944
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
177945
|
+
cli_version: this.cliVersion,
|
|
177946
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
177947
|
+
request_id: this.requestId,
|
|
177948
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
177949
|
+
agent_host: this.agentHost
|
|
177950
|
+
}
|
|
177951
|
+
});
|
|
177952
|
+
}
|
|
177633
177953
|
captureException(error98, properties) {
|
|
177634
177954
|
if (!this.posthog) return;
|
|
177635
177955
|
this.posthog.captureException(error98, this.distinctId, {
|
|
@@ -177715,7 +178035,19 @@ var getServices = async (env) => {
|
|
|
177715
178035
|
const byoAccount = byoPrivateKey ? privateKeyToAccount(byoPrivateKey) : null;
|
|
177716
178036
|
const lowBalanceWarning = typeof config3.lowBalanceWarning === "number" ? config3.lowBalanceWarning : 1;
|
|
177717
178037
|
const onSessionRefreshed = buildOnSessionRefreshed(configPath);
|
|
178038
|
+
let analyticsSink = null;
|
|
178039
|
+
const pendingSdkEvents = [];
|
|
177718
178040
|
const client = new ZeroClient({
|
|
178041
|
+
analytics: config3.telemetry === false ? { enabled: false } : {
|
|
178042
|
+
enabled: true,
|
|
178043
|
+
capture: (event) => {
|
|
178044
|
+
if (analyticsSink) {
|
|
178045
|
+
analyticsSink.captureSdk(event);
|
|
178046
|
+
return;
|
|
178047
|
+
}
|
|
178048
|
+
pendingSdkEvents.push(event);
|
|
178049
|
+
}
|
|
178050
|
+
},
|
|
177719
178051
|
baseUrl: env.ZERO_API_URL,
|
|
177720
178052
|
// The SDK scopes defaultHeaders to same-origin API calls, so this
|
|
177721
178053
|
// never reaches capability URLs.
|
|
@@ -177756,6 +178088,14 @@ var getServices = async (env) => {
|
|
|
177756
178088
|
requestId: randomUUID(),
|
|
177757
178089
|
agentHost: detectAgentHost()
|
|
177758
178090
|
});
|
|
178091
|
+
analyticsSink = analyticsService;
|
|
178092
|
+
for (const event of pendingSdkEvents) {
|
|
178093
|
+
try {
|
|
178094
|
+
analyticsService.captureSdk(event);
|
|
178095
|
+
} catch {
|
|
178096
|
+
}
|
|
178097
|
+
}
|
|
178098
|
+
pendingSdkEvents.length = 0;
|
|
177759
178099
|
return {
|
|
177760
178100
|
analyticsService,
|
|
177761
178101
|
client,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeroxyz/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"zero": "dist/index.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dev": "ZERO_ENV=development tsx src/index.ts",
|
|
20
20
|
"cli": "ZERO_ENV=development ZERO_API_URL=http://localhost:1111 tsx src/index.ts",
|
|
21
21
|
"test:integration": "vitest run --project integration",
|
|
22
|
+
"test:e2e": "tsup && vitest run --project e2e",
|
|
22
23
|
"test:online": "vitest run --project online",
|
|
23
24
|
"test:unit": "vitest run --project unit",
|
|
24
25
|
"test": "pnpm run test:unit && pnpm run test:integration",
|