@zeroxyz/cli 1.26.1 → 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 +435 -100
- 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.1"
|
|
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()
|
|
@@ -165994,7 +166004,7 @@ var isTextContentType = (contentType) => {
|
|
|
165994
166004
|
const lower = contentType.toLowerCase();
|
|
165995
166005
|
return TEXT_CONTENT_TYPES.some((marker) => lower.includes(marker));
|
|
165996
166006
|
};
|
|
165997
|
-
var
|
|
166007
|
+
var redactUrl2 = (url4) => {
|
|
165998
166008
|
try {
|
|
165999
166009
|
const u = new URL(url4);
|
|
166000
166010
|
return `${u.origin}${u.pathname}`;
|
|
@@ -166306,7 +166316,7 @@ var resolveRecordingClient = (client, opts) => {
|
|
|
166306
166316
|
var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride, requestUrl, requestMethod) => {
|
|
166307
166317
|
const effectiveCapId = capabilityIdOverride ?? opts.capabilityId;
|
|
166308
166318
|
const urlTarget = requestUrl ? {
|
|
166309
|
-
requestUrl:
|
|
166319
|
+
requestUrl: redactUrl2(requestUrl),
|
|
166310
166320
|
...requestMethod && { requestMethod }
|
|
166311
166321
|
} : void 0;
|
|
166312
166322
|
const runTarget = effectiveCapId !== void 0 ? { capabilityId: effectiveCapId, ...urlTarget } : urlTarget ?? null;
|
|
@@ -166391,7 +166401,7 @@ var clientFetch = async (client, url4, opts = {}) => {
|
|
|
166391
166401
|
client,
|
|
166392
166402
|
opts
|
|
166393
166403
|
);
|
|
166394
|
-
const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(
|
|
166404
|
+
const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(redactUrl2(requestUrl), method).catch(() => null) : Promise.resolve(null);
|
|
166395
166405
|
const probeHeaders = withDefaultContentType(opts.headers, requestBody);
|
|
166396
166406
|
const requestInit = {
|
|
166397
166407
|
method,
|
|
@@ -166676,9 +166686,9 @@ var clientFetch = async (client, url4, opts = {}) => {
|
|
|
166676
166686
|
} : { resolved: false } : void 0;
|
|
166677
166687
|
const runTarget = effectiveCapabilityId !== void 0 ? {
|
|
166678
166688
|
capabilityId: effectiveCapabilityId,
|
|
166679
|
-
requestUrl:
|
|
166689
|
+
requestUrl: redactUrl2(requestUrl),
|
|
166680
166690
|
requestMethod: method
|
|
166681
|
-
} : { requestUrl:
|
|
166691
|
+
} : { requestUrl: redactUrl2(requestUrl), requestMethod: method };
|
|
166682
166692
|
const fetchOutcome = computeOutcome(response.status, payment, warnings);
|
|
166683
166693
|
{
|
|
166684
166694
|
const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
|
|
@@ -166745,7 +166755,7 @@ var clientFetch = async (client, url4, opts = {}) => {
|
|
|
166745
166755
|
level: "warn",
|
|
166746
166756
|
message: "Failed to record run for fetch",
|
|
166747
166757
|
meta: {
|
|
166748
|
-
url:
|
|
166758
|
+
url: redactUrl2(url4),
|
|
166749
166759
|
capabilityId: effectiveCapabilityId,
|
|
166750
166760
|
error: errorMessage2,
|
|
166751
166761
|
errorCode: code
|
|
@@ -168074,6 +168084,219 @@ var Wallet = class {
|
|
|
168074
168084
|
var DEFAULT_BASE_URL = "https://api.zero.xyz";
|
|
168075
168085
|
var DEFAULT_TIMEOUT_MS = 18e4;
|
|
168076
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
|
+
};
|
|
168077
168300
|
var noopRefresh = async () => {
|
|
168078
168301
|
};
|
|
168079
168302
|
var searchResultSchema = external_exports3.object({
|
|
@@ -168156,6 +168379,13 @@ var ZeroClient = class _ZeroClient {
|
|
|
168156
168379
|
fetchImpl;
|
|
168157
168380
|
fetchOptions;
|
|
168158
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;
|
|
168159
168389
|
// Private — read via getCredentials(), mutate only via applyRefreshedTokens().
|
|
168160
168390
|
// Keeping a single mutator funnel is what lets the transport replay
|
|
168161
168391
|
// requests with a fresh access token after a 401 → refresh.
|
|
@@ -168214,6 +168444,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168214
168444
|
this.fetchImpl = options.fetch ?? ((...args) => globalThis.fetch(...args));
|
|
168215
168445
|
this.fetchOptions = options.fetchOptions;
|
|
168216
168446
|
this.logger = options.logger;
|
|
168447
|
+
this.analyticsOptions = options.analytics;
|
|
168217
168448
|
this.refreshOverride = options.refresh;
|
|
168218
168449
|
this.withAccountCache = options._sharedAccountCache ?? /* @__PURE__ */ new Map();
|
|
168219
168450
|
this.auth = new Auth(this);
|
|
@@ -168222,6 +168453,11 @@ var ZeroClient = class _ZeroClient {
|
|
|
168222
168453
|
this.payments = new Payments(this);
|
|
168223
168454
|
this.runs = new Runs(this);
|
|
168224
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
|
+
}
|
|
168225
168461
|
}
|
|
168226
168462
|
// Convenience factory: derives a viem account from a raw 0x-prefixed
|
|
168227
168463
|
// private key and constructs a client in account mode. Equivalent to
|
|
@@ -168329,7 +168565,8 @@ var ZeroClient = class _ZeroClient {
|
|
|
168329
168565
|
defaultHeaders: { ...this.defaultHeaders },
|
|
168330
168566
|
fetch: this.fetchImpl,
|
|
168331
168567
|
fetchOptions: this.fetchOptions ? { ...this.fetchOptions } : void 0,
|
|
168332
|
-
logger: this.logger
|
|
168568
|
+
logger: this.logger,
|
|
168569
|
+
analytics: this.analyticsOptions
|
|
168333
168570
|
});
|
|
168334
168571
|
// Returns a new client bound to a different viem account. Mirrors
|
|
168335
168572
|
// withSession for the self-custody auth path — multi-tenant servers
|
|
@@ -168381,6 +168618,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168381
168618
|
fetch: this.fetchImpl,
|
|
168382
168619
|
fetchOptions: this.fetchOptions ? { ...this.fetchOptions } : void 0,
|
|
168383
168620
|
logger: this.logger,
|
|
168621
|
+
analytics: this.analyticsOptions,
|
|
168384
168622
|
_sharedAccountCache: this.withAccountCache
|
|
168385
168623
|
});
|
|
168386
168624
|
this.withAccountCache.set(key, sub);
|
|
@@ -168441,6 +168679,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168441
168679
|
}
|
|
168442
168680
|
const acc = createManagedAccount(this, getAddress(primary.walletAddress));
|
|
168443
168681
|
this.managedAccount = acc;
|
|
168682
|
+
this.analytics.walletResolved(primary.walletAddress, "privy_embedded");
|
|
168444
168683
|
return acc;
|
|
168445
168684
|
})().finally(() => {
|
|
168446
168685
|
if (this.managedAccountGen === startedAtGen) {
|
|
@@ -168484,6 +168723,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
168484
168723
|
explicitWallet: true
|
|
168485
168724
|
});
|
|
168486
168725
|
this.managedAccountByAddress.set(canonical.toLowerCase(), acc);
|
|
168726
|
+
this.analytics.walletResolved(match.walletAddress, "privy_embedded");
|
|
168487
168727
|
return acc;
|
|
168488
168728
|
};
|
|
168489
168729
|
// Per-caller signal gate: each caller can reject on their own abort
|
|
@@ -168524,9 +168764,9 @@ var ZeroClient = class _ZeroClient {
|
|
|
168524
168764
|
// `search` is a flat method, not a namespace — it's the hot path most
|
|
168525
168765
|
// consumers hit first, and Stripe/Anthropic/OpenAI all keep their primary
|
|
168526
168766
|
// entry point flat for the same reason.
|
|
168527
|
-
search = (query, opts = {}) => {
|
|
168528
|
-
const { signal, ...rest } = opts;
|
|
168529
|
-
|
|
168767
|
+
search = async (query, opts = {}) => {
|
|
168768
|
+
const { signal, analytics: _analytics, ...rest } = opts;
|
|
168769
|
+
const response = await request2(
|
|
168530
168770
|
this,
|
|
168531
168771
|
{
|
|
168532
168772
|
method: "POST",
|
|
@@ -168536,11 +168776,25 @@ var ZeroClient = class _ZeroClient {
|
|
|
168536
168776
|
},
|
|
168537
168777
|
searchResponseSchema
|
|
168538
168778
|
);
|
|
168779
|
+
this.analytics.search(query, opts, response);
|
|
168780
|
+
return response;
|
|
168539
168781
|
};
|
|
168540
168782
|
// Paid fetch — search → get → fetch is Zero's canonical loop. The hot
|
|
168541
168783
|
// path is flat on the client, same rationale as `search` above.
|
|
168542
168784
|
// Orchestration lives in fetch.ts so this class stays readable.
|
|
168543
|
-
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
|
+
};
|
|
168544
168798
|
// Poll the API server's /health endpoint until it responds OK. Useful for
|
|
168545
168799
|
// warming up a cold container before spawning a subprocess that needs the
|
|
168546
168800
|
// API ready. Resolves when healthy, resolves (silently) when maxAttempts
|
|
@@ -168659,16 +168913,6 @@ var tryParseJson2 = (text) => {
|
|
|
168659
168913
|
return null;
|
|
168660
168914
|
}
|
|
168661
168915
|
};
|
|
168662
|
-
var ERROR_MAX = 500;
|
|
168663
|
-
var redactUrl2 = (raw) => {
|
|
168664
|
-
try {
|
|
168665
|
-
const parsed = new URL(raw);
|
|
168666
|
-
return `${parsed.origin}${parsed.pathname}`;
|
|
168667
|
-
} catch {
|
|
168668
|
-
return raw;
|
|
168669
|
-
}
|
|
168670
|
-
};
|
|
168671
|
-
var truncateError = (raw) => raw.length > ERROR_MAX ? `${raw.slice(0, ERROR_MAX)}\u2026` : raw;
|
|
168672
168916
|
var schemaTypeLabel = (node) => {
|
|
168673
168917
|
const t = node.type;
|
|
168674
168918
|
if (typeof t === "string") return t;
|
|
@@ -168782,7 +169026,7 @@ var placeholderFor = (fieldName, propSchema) => String(sampleValueFor(fieldName,
|
|
|
168782
169026
|
|
|
168783
169027
|
// package.json
|
|
168784
169028
|
var package_default2 = {
|
|
168785
|
-
version: "1.
|
|
169029
|
+
version: "1.27.0"};
|
|
168786
169030
|
|
|
168787
169031
|
// src/app.ts
|
|
168788
169032
|
init_esm_shims();
|
|
@@ -170494,7 +170738,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170494
170738
|
const message2 = err instanceof Error ? err.message : "Failed to read request body";
|
|
170495
170739
|
analyticsService.capture("fetch_error", {
|
|
170496
170740
|
cliErrorClass: /exceeds the .* byte local cap/.test(message2) ? "payload_too_large" : "schema_validation_failed",
|
|
170497
|
-
url:
|
|
170741
|
+
url: redactUrl(resolvedUrl),
|
|
170498
170742
|
error: truncateError(message2)
|
|
170499
170743
|
});
|
|
170500
170744
|
console.error(message2);
|
|
@@ -170601,13 +170845,28 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170601
170845
|
}
|
|
170602
170846
|
}
|
|
170603
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
|
+
}
|
|
170604
170863
|
}
|
|
170605
170864
|
});
|
|
170606
170865
|
} catch (err) {
|
|
170607
170866
|
const message2 = err instanceof Error ? err.message : "Fetch failed";
|
|
170608
170867
|
analyticsService.capture("fetch_error", {
|
|
170609
170868
|
cliErrorClass: "network",
|
|
170610
|
-
url:
|
|
170869
|
+
url: redactUrl(resolvedUrl),
|
|
170611
170870
|
error: truncateError(message2)
|
|
170612
170871
|
});
|
|
170613
170872
|
console.error(` Fetch failed: ${message2}`);
|
|
@@ -170615,7 +170874,6 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170615
170874
|
return;
|
|
170616
170875
|
}
|
|
170617
170876
|
const {
|
|
170618
|
-
fetchId,
|
|
170619
170877
|
runId,
|
|
170620
170878
|
status,
|
|
170621
170879
|
latencyMs,
|
|
@@ -170706,7 +170964,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170706
170964
|
capabilityUid = capabilityResolution.capabilityId ?? capabilityUid;
|
|
170707
170965
|
capabilitySlug = capabilityResolution.capabilitySlug ?? capabilitySlug;
|
|
170708
170966
|
analyticsService.capture("capability_resolution_recovered", {
|
|
170709
|
-
url:
|
|
170967
|
+
url: redactUrl(resolvedUrl),
|
|
170710
170968
|
method,
|
|
170711
170969
|
capabilityUid: capabilityResolution.capabilityId,
|
|
170712
170970
|
capabilitySlug: capabilityResolution.capabilitySlug,
|
|
@@ -170720,42 +170978,11 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170720
170978
|
);
|
|
170721
170979
|
}
|
|
170722
170980
|
analyticsService.capture("capability_resolution_missed", {
|
|
170723
|
-
url:
|
|
170981
|
+
url: redactUrl(resolvedUrl),
|
|
170724
170982
|
method
|
|
170725
170983
|
});
|
|
170726
170984
|
}
|
|
170727
170985
|
}
|
|
170728
|
-
analyticsService.capture("fetch_executed", {
|
|
170729
|
-
// The correlation key: joins this client event to the server's
|
|
170730
|
-
// run_started / run_completed / payment_processed, and to the run
|
|
170731
|
-
// row itself. Works even when runId is null — i.e. exactly when
|
|
170732
|
-
// the run failed to record, which is what we most need to trace.
|
|
170733
|
-
fetchId,
|
|
170734
|
-
url: redactUrl2(resolvedUrl),
|
|
170735
|
-
status: status ?? void 0,
|
|
170736
|
-
outcome,
|
|
170737
|
-
latencyMs,
|
|
170738
|
-
hasPayment: !!payment,
|
|
170739
|
-
paymentProtocol: payment?.protocol,
|
|
170740
|
-
paymentAmount: payment && payment.amount !== "unknown" ? payment.amount : void 0,
|
|
170741
|
-
// Canonical join keys — capabilitySlug is the dashboard
|
|
170742
|
-
// breakdown dimension; capabilityUid is the stable join
|
|
170743
|
-
// key with the capabilities table. capabilityId is the
|
|
170744
|
-
// back-compat alias (same value as capabilityUid when
|
|
170745
|
-
// resolved, else the raw --capability input).
|
|
170746
|
-
capabilityUid: capabilityUid ?? void 0,
|
|
170747
|
-
capabilitySlug: capabilitySlug ?? void 0,
|
|
170748
|
-
capabilityId: capabilityId ?? void 0,
|
|
170749
|
-
searchId: searchId ?? void 0,
|
|
170750
|
-
resultRank: resultRank ?? void 0,
|
|
170751
|
-
runId: runId ?? void 0,
|
|
170752
|
-
runTracked: !!runId,
|
|
170753
|
-
signingSource: signing?.source ?? "none",
|
|
170754
|
-
// A NULL searchId on a direct_slug fetch is correct here,
|
|
170755
|
-
// not a funnel gap to paper over.
|
|
170756
|
-
fetchOrigin,
|
|
170757
|
-
...resultError && { error: truncateError(resultError) }
|
|
170758
|
-
});
|
|
170759
170986
|
const outcomeInfo = OUTCOMES[outcome];
|
|
170760
170987
|
if (outcomeInfo.errorClass !== null) {
|
|
170761
170988
|
const cliErrorClass = cliErrorClassFor(
|
|
@@ -170770,7 +170997,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170770
170997
|
capabilityId: capabilityId ?? void 0,
|
|
170771
170998
|
searchId: searchId ?? void 0,
|
|
170772
170999
|
resultRank: resultRank ?? void 0,
|
|
170773
|
-
url:
|
|
171000
|
+
url: redactUrl(resolvedUrl),
|
|
170774
171001
|
status: typeof status === "number" ? status : void 0,
|
|
170775
171002
|
upstreamErrorMessage: upstreamError?.message,
|
|
170776
171003
|
errorSnippetHash: upstreamError?.snippetHash,
|
|
@@ -170915,7 +171142,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
|
|
|
170915
171142
|
try {
|
|
170916
171143
|
appContext.services.analyticsService.capture("fetch_error", {
|
|
170917
171144
|
cliErrorClass: "unknown",
|
|
170918
|
-
url: url4 ?
|
|
171145
|
+
url: url4 ? redactUrl(url4) : "unknown",
|
|
170919
171146
|
error: truncateError(message2)
|
|
170920
171147
|
});
|
|
170921
171148
|
} catch {
|
|
@@ -172519,13 +172746,6 @@ Examples:
|
|
|
172519
172746
|
|
|
172520
172747
|
// src/commands/search-command.ts
|
|
172521
172748
|
init_esm_shims();
|
|
172522
|
-
|
|
172523
|
-
// src/util/redact.ts
|
|
172524
|
-
init_esm_shims();
|
|
172525
|
-
var QUERY_MAX = 200;
|
|
172526
|
-
var truncateQuery = (raw) => raw.length > QUERY_MAX ? `${raw.slice(0, QUERY_MAX)}\u2026` : raw;
|
|
172527
|
-
|
|
172528
|
-
// src/commands/search-command.ts
|
|
172529
172749
|
var DEFAULT_MAX_COST_USD = "30";
|
|
172530
172750
|
var formatStatusBadge = (status) => {
|
|
172531
172751
|
if (!status || !(status in AVAILABILITY_BADGES)) return "";
|
|
@@ -172562,7 +172782,7 @@ var searchCommand = (appContext) => new Command("search").description("Search fo
|
|
|
172562
172782
|
).action(
|
|
172563
172783
|
async (query, options) => {
|
|
172564
172784
|
try {
|
|
172565
|
-
const {
|
|
172785
|
+
const { client } = appContext.services;
|
|
172566
172786
|
if (options.protocol && !["x402", "mpp"].includes(options.protocol)) {
|
|
172567
172787
|
console.error(
|
|
172568
172788
|
`Invalid protocol "${options.protocol}". Must be x402 or mpp.`
|
|
@@ -172591,27 +172811,14 @@ var searchCommand = (appContext) => new Command("search").description("Search fo
|
|
|
172591
172811
|
availabilityStatus: effectiveStatus,
|
|
172592
172812
|
includeAll: options.all,
|
|
172593
172813
|
source: options.source,
|
|
172594
|
-
excludeSource: options.excludeSource
|
|
172595
|
-
|
|
172596
|
-
|
|
172597
|
-
|
|
172598
|
-
|
|
172599
|
-
|
|
172600
|
-
|
|
172601
|
-
|
|
172602
|
-
hasMore: result.hasMore,
|
|
172603
|
-
offset: options.offset,
|
|
172604
|
-
limit: options.limit,
|
|
172605
|
-
freeOnly: options.free ?? false,
|
|
172606
|
-
maxCost: effectiveMaxCost,
|
|
172607
|
-
maxCostDefaulted: appliedDefaultMaxCost,
|
|
172608
|
-
protocol: options.protocol,
|
|
172609
|
-
availabilityStatus: effectiveStatus,
|
|
172610
|
-
availabilityStatusDefaulted: appliedDefaultStatus,
|
|
172611
|
-
includeAll: options.all ?? false,
|
|
172612
|
-
listingSource: options.source,
|
|
172613
|
-
excludeListingSource: options.excludeSource,
|
|
172614
|
-
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
|
+
}
|
|
172615
172822
|
});
|
|
172616
172823
|
if (options.json) {
|
|
172617
172824
|
console.log(
|
|
@@ -177486,10 +177693,82 @@ var PostHog = class extends PostHogBackendClient {
|
|
|
177486
177693
|
}
|
|
177487
177694
|
};
|
|
177488
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
|
+
|
|
177489
177764
|
// src/services/analytics-service.ts
|
|
177765
|
+
var FORWARDED_SDK_EVENTS = /* @__PURE__ */ new Set([
|
|
177766
|
+
"sdk_wallet_resolved"
|
|
177767
|
+
]);
|
|
177490
177768
|
var POSTHOG_API_KEY = "phc_B2vLyNxAf2mnqvdPQajf4d4b2iXc35dep2ZrvebMJLuX";
|
|
177491
177769
|
var POSTHOG_HOST = "https://us.i.posthog.com";
|
|
177492
|
-
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();
|
|
177493
177772
|
var AnalyticsService = class {
|
|
177494
177773
|
posthog;
|
|
177495
177774
|
distinctId;
|
|
@@ -177501,7 +177780,7 @@ var AnalyticsService = class {
|
|
|
177501
177780
|
constructor(opts) {
|
|
177502
177781
|
this.cliVersion = opts.cliVersion;
|
|
177503
177782
|
this.environment = opts.environment;
|
|
177504
|
-
this.walletAddress = opts.walletAddress ?
|
|
177783
|
+
this.walletAddress = opts.walletAddress ? toAnalyticsWallet2(opts.walletAddress) : null;
|
|
177505
177784
|
this.requestId = opts.requestId;
|
|
177506
177785
|
this.agentHost = opts.agentHost;
|
|
177507
177786
|
let telemetryEnabled = true;
|
|
@@ -177524,7 +177803,7 @@ var AnalyticsService = class {
|
|
|
177524
177803
|
return;
|
|
177525
177804
|
}
|
|
177526
177805
|
if (opts.walletAddress) {
|
|
177527
|
-
this.distinctId =
|
|
177806
|
+
this.distinctId = toAnalyticsWallet2(opts.walletAddress);
|
|
177528
177807
|
} else if (persistedAnonId) {
|
|
177529
177808
|
this.distinctId = persistedAnonId;
|
|
177530
177809
|
} else {
|
|
@@ -177552,7 +177831,7 @@ var AnalyticsService = class {
|
|
|
177552
177831
|
originalConsoleError.apply(console, args);
|
|
177553
177832
|
};
|
|
177554
177833
|
this.posthog = new PostHog(POSTHOG_API_KEY, {
|
|
177555
|
-
host:
|
|
177834
|
+
host: resolvePostHogHost(),
|
|
177556
177835
|
flushAt: 1,
|
|
177557
177836
|
flushInterval: 0,
|
|
177558
177837
|
// Vitest spins up many AnalyticsService instances per process; each
|
|
@@ -177566,7 +177845,7 @@ var AnalyticsService = class {
|
|
|
177566
177845
|
this.maybeAliasAnonToWallet(
|
|
177567
177846
|
opts.configPath,
|
|
177568
177847
|
persistedAnonId,
|
|
177569
|
-
|
|
177848
|
+
toAnalyticsWallet2(opts.walletAddress)
|
|
177570
177849
|
);
|
|
177571
177850
|
}
|
|
177572
177851
|
}
|
|
@@ -177607,7 +177886,7 @@ var AnalyticsService = class {
|
|
|
177607
177886
|
// via PostHog alias, when AnalyticsService is constructed with both
|
|
177608
177887
|
// the persisted anonId and the new walletAddress.
|
|
177609
177888
|
setWalletAddress(walletAddress) {
|
|
177610
|
-
this.walletAddress =
|
|
177889
|
+
this.walletAddress = toAnalyticsWallet2(walletAddress);
|
|
177611
177890
|
}
|
|
177612
177891
|
capture(event, properties) {
|
|
177613
177892
|
if (!this.posthog) return;
|
|
@@ -177635,6 +177914,42 @@ var AnalyticsService = class {
|
|
|
177635
177914
|
}
|
|
177636
177915
|
});
|
|
177637
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
|
+
}
|
|
177638
177953
|
captureException(error98, properties) {
|
|
177639
177954
|
if (!this.posthog) return;
|
|
177640
177955
|
this.posthog.captureException(error98, this.distinctId, {
|
|
@@ -177720,7 +178035,19 @@ var getServices = async (env) => {
|
|
|
177720
178035
|
const byoAccount = byoPrivateKey ? privateKeyToAccount(byoPrivateKey) : null;
|
|
177721
178036
|
const lowBalanceWarning = typeof config3.lowBalanceWarning === "number" ? config3.lowBalanceWarning : 1;
|
|
177722
178037
|
const onSessionRefreshed = buildOnSessionRefreshed(configPath);
|
|
178038
|
+
let analyticsSink = null;
|
|
178039
|
+
const pendingSdkEvents = [];
|
|
177723
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
|
+
},
|
|
177724
178051
|
baseUrl: env.ZERO_API_URL,
|
|
177725
178052
|
// The SDK scopes defaultHeaders to same-origin API calls, so this
|
|
177726
178053
|
// never reaches capability URLs.
|
|
@@ -177761,6 +178088,14 @@ var getServices = async (env) => {
|
|
|
177761
178088
|
requestId: randomUUID(),
|
|
177762
178089
|
agentHost: detectAgentHost()
|
|
177763
178090
|
});
|
|
178091
|
+
analyticsSink = analyticsService;
|
|
178092
|
+
for (const event of pendingSdkEvents) {
|
|
178093
|
+
try {
|
|
178094
|
+
analyticsService.captureSdk(event);
|
|
178095
|
+
} catch {
|
|
178096
|
+
}
|
|
178097
|
+
}
|
|
178098
|
+
pendingSdkEvents.length = 0;
|
|
177764
178099
|
return {
|
|
177765
178100
|
analyticsService,
|
|
177766
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",
|