orchajs 0.21.0 → 0.22.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.
@@ -4,6 +4,10 @@ import type { AgentRuntime, CompiledBundle, OrchaInitConfiguration } from "../ty
4
4
  export interface Orcha {
5
5
  init(configuration: OrchaInitConfiguration): OrchaClient;
6
6
  isInitialized(): boolean;
7
+ /** Flushes queued Amarsia telemetry without blocking normal agent runs. */
8
+ flushTelemetry(options?: {
9
+ timeoutMs?: number;
10
+ }): Promise<void>;
7
11
  /** @internal Used by the development compiler. */
8
12
  getCompiledBundle(): CompiledBundle;
9
13
  }
@@ -1,9 +1,11 @@
1
1
  import { RuntimeAgent } from "./agent.js";
2
+ import { AmarsiaTelemetryClient, withAmarsiaTelemetry, } from "../amarsia/analytics.js";
2
3
  import { setOrchaRuntimeContext } from "./context.js";
3
4
  class OrchaRuntimeCore {
4
5
  #agents = new Map();
5
6
  #bundle;
6
7
  #client;
8
+ #telemetry;
7
9
  #activeSessions = new Set();
8
10
  #sessionControls = new Map();
9
11
  #resolveBundle;
@@ -18,6 +20,9 @@ class OrchaRuntimeCore {
18
20
  this.#client = client;
19
21
  }
20
22
  init(configuration) {
23
+ if (this.#telemetry) {
24
+ void this.#telemetry.close();
25
+ }
21
26
  const projectRoot = this.#platform.projectRoot(configuration);
22
27
  const bundle = configuration.bundle ?? this.#resolveBundle(configuration);
23
28
  if (configuration.amarsia?.key && this.#platform.syncProject) {
@@ -47,6 +52,16 @@ class OrchaRuntimeCore {
47
52
  projectRoot,
48
53
  manifest,
49
54
  });
55
+ const telemetry = configuration.amarsia?.key
56
+ ? new AmarsiaTelemetryClient(configuration.amarsia)
57
+ : undefined;
58
+ this.#telemetry = telemetry;
59
+ const createRuntimeStore = (manifest) => {
60
+ const store = createStore(manifest);
61
+ return telemetry
62
+ ? withAmarsiaTelemetry({ store, manifest, client: telemetry })
63
+ : store;
64
+ };
50
65
  const agents = new Map();
51
66
  for (const [name, manifest] of Object.entries(bundle.agents)) {
52
67
  const subagents = Object.fromEntries(Object.entries(manifest.subagents ?? {}).map(([subagentName, subagentManifest]) => [
@@ -54,7 +69,7 @@ class OrchaRuntimeCore {
54
69
  new RuntimeAgent({
55
70
  manifest: subagentManifest,
56
71
  configuration: runtimeConfiguration,
57
- store: createStore(subagentManifest),
72
+ store: createRuntimeStore(subagentManifest),
58
73
  activeSessions: this.#activeSessions,
59
74
  sessionControls: this.#sessionControls,
60
75
  generateProviderResponse: this.#generateProviderResponse,
@@ -66,7 +81,7 @@ class OrchaRuntimeCore {
66
81
  agents.set(name, new RuntimeAgent({
67
82
  manifest,
68
83
  configuration: runtimeConfiguration,
69
- store: createStore(manifest),
84
+ store: createRuntimeStore(manifest),
70
85
  activeSessions: this.#activeSessions,
71
86
  sessionControls: this.#sessionControls,
72
87
  generateProviderResponse: this.#generateProviderResponse,
@@ -89,6 +104,9 @@ class OrchaRuntimeCore {
89
104
  isInitialized() {
90
105
  return this.#bundle !== undefined;
91
106
  }
107
+ async flushTelemetry(options) {
108
+ await this.#telemetry?.drain(options);
109
+ }
92
110
  getCompiledBundle() {
93
111
  if (!this.#bundle) {
94
112
  throw new Error("Orcha has not been initialized.");
package/dist/types.d.ts CHANGED
@@ -64,6 +64,57 @@ export interface OrchaInitConfiguration {
64
64
  storage?: ProjectConfiguration["storage"];
65
65
  root?: string;
66
66
  }
67
+ /** Privacy-safe, versioned run fact sent to Amarsia when `amarsia.key` is set. */
68
+ export interface AmarsiaTelemetryRunV1 {
69
+ event_id: string;
70
+ agent_external_id: string;
71
+ session_id: string;
72
+ run_number: number;
73
+ parent_agent_external_id?: string;
74
+ parent_session_id?: string;
75
+ status: string;
76
+ provider: string;
77
+ model: string;
78
+ region?: string;
79
+ output_type?: string;
80
+ stop_reason?: string;
81
+ started_at: string;
82
+ ended_at?: string;
83
+ duration_ms?: number;
84
+ model_duration_ms: number;
85
+ action_duration_ms: number;
86
+ input_tokens: number;
87
+ output_tokens: number;
88
+ reasoning_tokens?: number;
89
+ cache_read_tokens: number;
90
+ cache_write_tokens: number;
91
+ user_message_count: number;
92
+ assistant_message_count: number;
93
+ action_count: number;
94
+ action_success_count: number;
95
+ action_failure_count: number;
96
+ subagent_count: number;
97
+ actions: AmarsiaTelemetryActionV1[];
98
+ evaluation_count: number;
99
+ evaluation_pass_count: number;
100
+ error_code?: string;
101
+ error_message?: string;
102
+ error_retryable?: boolean;
103
+ }
104
+ export interface AmarsiaTelemetryActionV1 {
105
+ call_id: string;
106
+ name: string;
107
+ status: "completed" | "failed";
108
+ started_at: string;
109
+ ended_at: string;
110
+ duration_ms: number;
111
+ error_code?: string;
112
+ error_message?: string;
113
+ }
114
+ export interface AmarsiaTelemetryBatchV1 {
115
+ schema_version: 1;
116
+ runs: AmarsiaTelemetryRunV1[];
117
+ }
67
118
  export interface SubagentConfiguration {
68
119
  maxPerRun?: number;
69
120
  }
@@ -0,0 +1,447 @@
1
+ "use strict"; const __orchaImportMetaUrl = require("url").pathToFileURL(__filename).href;
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var analytics_exports = {};
21
+ __export(analytics_exports, {
22
+ AmarsiaTelemetryClient: () => AmarsiaTelemetryClient,
23
+ withAmarsiaTelemetry: () => withAmarsiaTelemetry
24
+ });
25
+ module.exports = __toCommonJS(analytics_exports);
26
+ var import_endpoint = require("./endpoint.js");
27
+ const RELEVANT_EVENTS = /* @__PURE__ */ new Set([
28
+ "run.started",
29
+ "run.completed",
30
+ "run.failed",
31
+ "run.paused",
32
+ "evaluation.completed",
33
+ "evaluation.failed"
34
+ ]);
35
+ const MAX_BATCH_RUNS = 100;
36
+ const MAX_KEEPALIVE_BYTES = 48 * 1024;
37
+ const HEARTBEAT_INTERVAL_MS = 3e4;
38
+ class AmarsiaTelemetryClient {
39
+ #key;
40
+ #baseUrl;
41
+ #queue = /* @__PURE__ */ new Map();
42
+ #activeRuns = /* @__PURE__ */ new Map();
43
+ #timer;
44
+ #heartbeatTimer;
45
+ #attempt = 0;
46
+ #flushPromise;
47
+ constructor(options) {
48
+ this.#key = options.key;
49
+ this.#baseUrl = (0, import_endpoint.resolveAmarsiaEndpoint)(options.endpoint);
50
+ }
51
+ enqueue(fact) {
52
+ this.#queue.set(fact.event_id, fact);
53
+ if (fact.status === "running") {
54
+ this.#activeRuns.set(fact.event_id, fact);
55
+ this.#scheduleHeartbeat();
56
+ } else {
57
+ this.#activeRuns.delete(fact.event_id);
58
+ if (this.#activeRuns.size === 0 && this.#heartbeatTimer) {
59
+ clearTimeout(this.#heartbeatTimer);
60
+ this.#heartbeatTimer = void 0;
61
+ }
62
+ }
63
+ if (fact.status !== "running") {
64
+ this.#scheduleTerminal();
65
+ return;
66
+ }
67
+ if (this.#queue.size >= 20) {
68
+ void this.#flush();
69
+ return;
70
+ }
71
+ this.#schedule(250);
72
+ }
73
+ #schedule(delay) {
74
+ if (this.#timer) return;
75
+ this.#timer = setTimeout(() => {
76
+ this.#timer = void 0;
77
+ void this.#flush();
78
+ }, delay);
79
+ const timer = this.#timer;
80
+ timer.unref?.();
81
+ }
82
+ #scheduleTerminal() {
83
+ if (this.#timer) clearTimeout(this.#timer);
84
+ this.#timer = setTimeout(() => {
85
+ this.#timer = void 0;
86
+ void this.#flush();
87
+ }, 0);
88
+ }
89
+ #scheduleHeartbeat() {
90
+ if (this.#heartbeatTimer || this.#activeRuns.size === 0) return;
91
+ this.#heartbeatTimer = setTimeout(() => {
92
+ this.#heartbeatTimer = void 0;
93
+ for (const fact of this.#activeRuns.values()) {
94
+ this.#queue.set(fact.event_id, fact);
95
+ }
96
+ void this.#flush();
97
+ this.#scheduleHeartbeat();
98
+ }, HEARTBEAT_INTERVAL_MS);
99
+ const timer = this.#heartbeatTimer;
100
+ timer.unref?.();
101
+ }
102
+ async drain(options = {}) {
103
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 2e3);
104
+ const deadline = Date.now() + timeoutMs;
105
+ if (this.#timer) {
106
+ clearTimeout(this.#timer);
107
+ this.#timer = void 0;
108
+ }
109
+ while (this.#queue.size > 0 || this.#flushPromise) {
110
+ const remaining = deadline - Date.now();
111
+ if (remaining <= 0) return;
112
+ await Promise.race([
113
+ this.#flush(),
114
+ new Promise((resolve) => setTimeout(resolve, remaining))
115
+ ]);
116
+ }
117
+ }
118
+ async close(options = {}) {
119
+ if (this.#heartbeatTimer) {
120
+ clearTimeout(this.#heartbeatTimer);
121
+ this.#heartbeatTimer = void 0;
122
+ }
123
+ this.#activeRuns.clear();
124
+ await this.drain(options);
125
+ }
126
+ async #flush() {
127
+ if (this.#flushPromise) return this.#flushPromise;
128
+ if (this.#queue.size === 0) return;
129
+ this.#flushPromise = this.#performFlush();
130
+ try {
131
+ await this.#flushPromise;
132
+ } finally {
133
+ this.#flushPromise = void 0;
134
+ if (this.#queue.size > 0 && !this.#timer) {
135
+ const hasTerminalFact = [...this.#queue.values()].some(
136
+ (fact) => fact.status !== "running"
137
+ );
138
+ if (hasTerminalFact) {
139
+ void this.#flush();
140
+ } else {
141
+ this.#schedule(250);
142
+ }
143
+ }
144
+ }
145
+ }
146
+ async #performFlush() {
147
+ const batch = takeBatch(this.#queue);
148
+ if (batch.length === 0) return;
149
+ const body = JSON.stringify({
150
+ schema_version: 1,
151
+ runs: batch
152
+ });
153
+ for (const fact of batch) this.#queue.delete(fact.event_id);
154
+ try {
155
+ const response = await fetch(
156
+ `${this.#baseUrl}/v3/project-analytics/runs/batch`,
157
+ {
158
+ method: "POST",
159
+ headers: {
160
+ "content-type": "application/json",
161
+ "x-amarsia-project-key": this.#key
162
+ },
163
+ keepalive: utf8ByteLength(body) <= MAX_KEEPALIVE_BYTES,
164
+ body
165
+ }
166
+ );
167
+ if (!response.ok) {
168
+ throw new Error(`HTTP ${response.status}`);
169
+ }
170
+ this.#attempt = 0;
171
+ } catch {
172
+ this.#attempt += 1;
173
+ if (this.#attempt <= 6) {
174
+ for (const fact of batch) {
175
+ if (!this.#queue.has(fact.event_id)) {
176
+ this.#queue.set(fact.event_id, fact);
177
+ }
178
+ }
179
+ this.#schedule(Math.min(3e4, 500 * 2 ** this.#attempt));
180
+ } else {
181
+ this.#attempt = 0;
182
+ console.warn(
183
+ `Amarsia telemetry delivery failed after 6 retries; dropping ${batch.length} run update(s).`
184
+ );
185
+ }
186
+ }
187
+ }
188
+ }
189
+ function withAmarsiaTelemetry(options) {
190
+ const { store, manifest, client } = options;
191
+ const projections = /* @__PURE__ */ new Map();
192
+ const pending = /* @__PURE__ */ new Map();
193
+ return {
194
+ read: (sessionId) => store.read(sessionId),
195
+ listSessionIds: () => store.listSessionIds(),
196
+ describeLocation: store.describeLocation?.bind(store),
197
+ subscribe: store.subscribe?.bind(store),
198
+ subscribeAll: store.subscribeAll?.bind(store),
199
+ async append(sessionId, events) {
200
+ await store.append(sessionId, events);
201
+ const runs = relevantRuns(events);
202
+ if (runs.size === 0 && !projections.has(sessionId) && !pending.has(sessionId)) {
203
+ return;
204
+ }
205
+ const previous = pending.get(sessionId) ?? Promise.resolve();
206
+ const processing = previous.then(async () => {
207
+ let projection = projections.get(sessionId);
208
+ if (!projection) {
209
+ projection = createProjection(await store.read(sessionId));
210
+ projections.set(sessionId, projection);
211
+ } else {
212
+ appendToProjection(projection, events);
213
+ }
214
+ if (projection.isTest) return;
215
+ for (const run of runs) {
216
+ const fact = projectRunFact(
217
+ manifest,
218
+ sessionId,
219
+ run,
220
+ projection
221
+ );
222
+ if (fact) client.enqueue(fact);
223
+ }
224
+ }).catch(() => void 0);
225
+ pending.set(sessionId, processing);
226
+ void processing.finally(() => {
227
+ if (pending.get(sessionId) === processing) {
228
+ pending.delete(sessionId);
229
+ }
230
+ });
231
+ }
232
+ };
233
+ }
234
+ function createProjection(events) {
235
+ const projection = {
236
+ seenSequences: /* @__PURE__ */ new Set(),
237
+ runs: /* @__PURE__ */ new Map(),
238
+ isTest: false
239
+ };
240
+ appendToProjection(projection, events);
241
+ return projection;
242
+ }
243
+ function appendToProjection(projection, events) {
244
+ for (const event of events) {
245
+ if (projection.seenSequences.has(event.sequence)) continue;
246
+ projection.seenSequences.add(event.sequence);
247
+ if (event.type === "session.created") {
248
+ projection.sessionCreated = event;
249
+ const metadata = asRecord(event.data.metadata);
250
+ projection.isTest = metadata?.orchaTest === true;
251
+ }
252
+ if (typeof event.run !== "number") continue;
253
+ const runEvents = projection.runs.get(event.run);
254
+ if (runEvents) {
255
+ runEvents.push(event);
256
+ } else {
257
+ projection.runs.set(event.run, [event]);
258
+ }
259
+ }
260
+ }
261
+ function relevantRuns(events) {
262
+ const runs = /* @__PURE__ */ new Set();
263
+ for (const event of events) {
264
+ if (typeof event.run === "number" && RELEVANT_EVENTS.has(event.type)) {
265
+ runs.add(event.run);
266
+ }
267
+ }
268
+ return runs;
269
+ }
270
+ function projectRunFact(manifest, sessionId, run, projection) {
271
+ const runEvents = projection.runs.get(run);
272
+ if (!runEvents) return void 0;
273
+ const started = runEvents.find((event) => event.type === "run.started");
274
+ if (!started) return void 0;
275
+ const terminal = [...runEvents].reverse().find(
276
+ (event) => ["run.completed", "run.failed", "run.paused"].includes(event.type)
277
+ );
278
+ const lineage = asRecord(projection.sessionCreated?.data.lineage);
279
+ const assistants = runEvents.filter(
280
+ (event) => event.type === "message.created" && event.data.role === "assistant"
281
+ );
282
+ const usage = normalizeUsage(terminal?.data.usage, assistants);
283
+ const completedActions = runEvents.filter(
284
+ (event) => event.type === "action.completed"
285
+ );
286
+ const failedActions = runEvents.filter(
287
+ (event) => event.type === "action.failed"
288
+ );
289
+ const evaluations = runEvents.filter(
290
+ (event) => event.type === "evaluation.completed" || event.type === "evaluation.failed"
291
+ );
292
+ const error = asRecord(terminal?.data.error);
293
+ const lastAssistant = assistants.at(-1);
294
+ const status = terminal?.type === "run.completed" ? "completed" : terminal?.type === "run.failed" ? "failed" : terminal?.type === "run.paused" ? "paused" : "running";
295
+ return {
296
+ event_id: `${manifest.key}:${sessionId}:${run}`,
297
+ agent_external_id: manifest.key,
298
+ session_id: sessionId,
299
+ run_number: run,
300
+ ...typeof lineage?.parentAgent === "string" ? { parent_agent_external_id: lineage.parentAgent } : {},
301
+ ...typeof lineage?.parentSessionId === "string" ? { parent_session_id: lineage.parentSessionId } : {},
302
+ status,
303
+ provider: typeof started.data.provider === "string" ? started.data.provider : manifest.provider,
304
+ model: typeof started.data.model === "string" ? started.data.model : manifest.model,
305
+ ...typeof started.data.region === "string" ? { region: started.data.region } : {},
306
+ ...typeof started.data.outputType === "string" ? { output_type: started.data.outputType } : {},
307
+ ...typeof lastAssistant?.data.stopReason === "string" ? { stop_reason: lastAssistant.data.stopReason } : {},
308
+ started_at: started.timestamp,
309
+ ...terminal ? { ended_at: terminal.timestamp } : {},
310
+ ...typeof terminal?.data.durationMs === "number" ? { duration_ms: terminal.data.durationMs } : {},
311
+ model_duration_ms: sumNumber(assistants, "durationMs"),
312
+ action_duration_ms: sumNumber(
313
+ [...completedActions, ...failedActions],
314
+ "durationMs"
315
+ ),
316
+ ...usage,
317
+ user_message_count: runEvents.filter(
318
+ (event) => event.type === "message.created" && event.data.role === "user"
319
+ ).length,
320
+ assistant_message_count: assistants.length,
321
+ action_count: runEvents.filter(
322
+ (event) => event.type === "action.requested"
323
+ ).length,
324
+ action_success_count: completedActions.length,
325
+ action_failure_count: failedActions.length,
326
+ subagent_count: runEvents.filter(
327
+ (event) => event.type === "subagent.initiated"
328
+ ).length,
329
+ actions: projectActionLogs(runEvents),
330
+ evaluation_count: evaluations.length,
331
+ evaluation_pass_count: evaluations.filter(
332
+ (event) => event.type === "evaluation.completed" && event.data.status === "passed"
333
+ ).length,
334
+ ...typeof error?.code === "string" ? { error_code: error.code } : {},
335
+ ...typeof error?.message === "string" ? { error_message: sanitizeErrorMessage(error.message) } : {},
336
+ ...typeof error?.retryable === "boolean" ? { error_retryable: error.retryable } : {}
337
+ };
338
+ }
339
+ function normalizeUsage(terminalUsage, assistants) {
340
+ const direct = asRecord(terminalUsage);
341
+ if (direct) {
342
+ return usageFields(direct);
343
+ }
344
+ const total = {
345
+ inputTokens: 0,
346
+ outputTokens: 0,
347
+ reasoningTokens: 0,
348
+ cacheReadTokens: 0,
349
+ cacheWriteTokens: 0
350
+ };
351
+ for (const event of assistants) {
352
+ const usage = asRecord(event.data.usage);
353
+ if (!usage) continue;
354
+ total.inputTokens += numberValue(usage.inputTokens);
355
+ total.outputTokens += numberValue(usage.outputTokens);
356
+ total.reasoningTokens = (total.reasoningTokens ?? 0) + numberValue(usage.reasoningTokens);
357
+ total.cacheReadTokens += numberValue(usage.cacheReadTokens);
358
+ total.cacheWriteTokens += numberValue(usage.cacheWriteTokens);
359
+ }
360
+ return usageFields(total);
361
+ }
362
+ function usageFields(usage) {
363
+ const reasoning = numberValue(usage.reasoningTokens);
364
+ return {
365
+ input_tokens: numberValue(usage.inputTokens),
366
+ output_tokens: numberValue(usage.outputTokens),
367
+ ...reasoning > 0 ? { reasoning_tokens: reasoning } : {},
368
+ cache_read_tokens: numberValue(usage.cacheReadTokens),
369
+ cache_write_tokens: numberValue(usage.cacheWriteTokens)
370
+ };
371
+ }
372
+ function sumNumber(events, key) {
373
+ return events.reduce((sum, event) => sum + numberValue(event.data[key]), 0);
374
+ }
375
+ function projectActionLogs(events) {
376
+ const requestedByCallId = /* @__PURE__ */ new Map();
377
+ for (const event of events) {
378
+ if (event.type === "action.requested" && typeof event.data.callId === "string") {
379
+ requestedByCallId.set(event.data.callId, event);
380
+ }
381
+ }
382
+ return events.filter(
383
+ (event) => event.type === "action.completed" || event.type === "action.failed"
384
+ ).slice(0, 100).map((event) => {
385
+ const error = asRecord(event.data.error);
386
+ const requested = typeof event.data.callId === "string" ? requestedByCallId.get(event.data.callId) : void 0;
387
+ return {
388
+ call_id: typeof event.data.callId === "string" ? event.data.callId : `action-${event.sequence}`,
389
+ name: typeof event.data.name === "string" ? event.data.name : "unknown",
390
+ status: event.type === "action.completed" ? "completed" : "failed",
391
+ started_at: requested?.timestamp ?? event.timestamp,
392
+ ended_at: event.timestamp,
393
+ duration_ms: numberValue(event.data.durationMs),
394
+ ...typeof error?.code === "string" ? { error_code: error.code } : {},
395
+ ...typeof error?.message === "string" ? { error_message: sanitizeErrorMessage(error.message) } : {}
396
+ };
397
+ });
398
+ }
399
+ function takeBatch(queue) {
400
+ const batch = [];
401
+ let bytes = utf8ByteLength('{"schema_version":1,"runs":[]}');
402
+ for (const fact of queue.values()) {
403
+ const factBytes = utf8ByteLength(JSON.stringify(fact)) + 1;
404
+ if (batch.length > 0 && (batch.length >= MAX_BATCH_RUNS || bytes + factBytes > MAX_KEEPALIVE_BYTES)) {
405
+ break;
406
+ }
407
+ batch.push(fact);
408
+ bytes += factBytes;
409
+ }
410
+ return batch;
411
+ }
412
+ function utf8ByteLength(value) {
413
+ if (typeof TextEncoder !== "undefined") {
414
+ return new TextEncoder().encode(value).byteLength;
415
+ }
416
+ let bytes = 0;
417
+ for (let index = 0; index < value.length; index += 1) {
418
+ const code = value.charCodeAt(index);
419
+ if (code < 128) bytes += 1;
420
+ else if (code < 2048) bytes += 2;
421
+ else if (code >= 55296 && code <= 56319) {
422
+ bytes += 4;
423
+ index += 1;
424
+ } else bytes += 3;
425
+ }
426
+ return bytes;
427
+ }
428
+ function numberValue(value) {
429
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
430
+ }
431
+ function asRecord(value) {
432
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
433
+ }
434
+ function sanitizeErrorMessage(value) {
435
+ return value.replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, "Bearer [redacted]").replace(
436
+ /\b(authorization|api[-_ ]?key|token|secret|password)\b\s*[:=]\s*[^\s,;]+/gi,
437
+ "$1=[redacted]"
438
+ ).replace(
439
+ /\b(?:sk|pk|amarsia)_[A-Za-z0-9_-]{12,}\b/gi,
440
+ "[redacted]"
441
+ ).slice(0, 8e3);
442
+ }
443
+ // Annotate the CommonJS export names for ESM import in node:
444
+ 0 && (module.exports = {
445
+ AmarsiaTelemetryClient,
446
+ withAmarsiaTelemetry
447
+ });
@@ -0,0 +1,32 @@
1
+ "use strict"; const __orchaImportMetaUrl = require("url").pathToFileURL(__filename).href;
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var endpoint_exports = {};
21
+ __export(endpoint_exports, {
22
+ resolveAmarsiaEndpoint: () => resolveAmarsiaEndpoint
23
+ });
24
+ module.exports = __toCommonJS(endpoint_exports);
25
+ const DEFAULT_AMARSIA_API_URL = "https://api.amarsia.com";
26
+ function resolveAmarsiaEndpoint(endpoint) {
27
+ return (endpoint?.trim() || (typeof process !== "undefined" ? process.env?.AMARSIA_API_URL : void 0) || DEFAULT_AMARSIA_API_URL).replace(/\/$/, "");
28
+ }
29
+ // Annotate the CommonJS export names for ESM import in node:
30
+ 0 && (module.exports = {
31
+ resolveAmarsiaEndpoint
32
+ });
@@ -23,14 +23,14 @@ __export(sync_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(sync_exports);
25
25
  var import_metadata = require("./metadata.js");
26
- const DEFAULT_AMARSIA_API_URL = "https://api.amarsia.com";
26
+ var import_endpoint = require("./endpoint.js");
27
27
  const syncedHashes = /* @__PURE__ */ new Map();
28
28
  function syncAmarsiaProject(options) {
29
29
  const metadata = (0, import_metadata.createAmarsiaProjectMetadata)(
30
30
  options.bundle,
31
31
  options.projectRoot
32
32
  );
33
- const baseUrl = resolveAmarsiaEndpoint(options.endpoint);
33
+ const baseUrl = (0, import_endpoint.resolveAmarsiaEndpoint)(options.endpoint);
34
34
  const dedupeKey = `${baseUrl}:${options.key}`;
35
35
  if (syncedHashes.get(dedupeKey) === metadata.content_hash) {
36
36
  return;
@@ -46,9 +46,6 @@ function syncAmarsiaProject(options) {
46
46
  console.warn(`[orcha] Amarsia project sync failed: ${message}`);
47
47
  });
48
48
  }
49
- function resolveAmarsiaEndpoint(endpoint) {
50
- return (endpoint?.trim() || process.env.AMARSIA_API_URL || DEFAULT_AMARSIA_API_URL).replace(/\/$/, "");
51
- }
52
49
  async function postProjectMetadata(options) {
53
50
  const response = await fetch(`${options.baseUrl}/v3/project-sync`, {
54
51
  method: "PUT",