@kortyx/usage-telemetry 0.3.0 → 0.5.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.
@@ -23,8 +23,10 @@ __export(browser_node_exports, {
23
23
  configureUsageTelemetry: () => configureUsageTelemetry,
24
24
  createNodeUsageTelemetry: () => createNodeUsageTelemetry,
25
25
  createUsageTelemetry: () => createUsageTelemetry,
26
+ flushUsageTelemetry: () => flushUsageTelemetry,
26
27
  getUsageTelemetry: () => getUsageTelemetry,
27
28
  publicUsageConfiguration: () => publicUsageConfiguration,
29
+ runtimeUsageContext: () => runtimeUsageContext,
28
30
  scale: () => scale,
29
31
  usageDisabled: () => usageDisabled
30
32
  });
@@ -58,6 +60,8 @@ var operations = [
58
60
  "sdk.checkpoint.rollback",
59
61
  "sdk.export",
60
62
  "studio.setup",
63
+ "studio.sample",
64
+ "studio.help",
61
65
  "studio.connection",
62
66
  "studio.read",
63
67
  "studio.render",
@@ -72,6 +76,11 @@ var operations = [
72
76
  "studio.settings",
73
77
  "studio.update",
74
78
  "studio.ingest",
79
+ "cli.command",
80
+ "studio.eval.execution",
81
+ "studio.diagnostic",
82
+ "studio.table.layout",
83
+ "studio.help",
75
84
  "cli.topology",
76
85
  "cli.eval"
77
86
  ];
@@ -86,9 +95,256 @@ var outcomes = [
86
95
  "ungraded"
87
96
  ];
88
97
  var publicCatalog = {
89
- products: ["sdk", "oss_studio"],
98
+ products: ["sdk", "oss_studio", "cli"],
90
99
  operations,
91
100
  properties: {
101
+ help_action: [
102
+ "open",
103
+ "documentation",
104
+ "start",
105
+ "step",
106
+ "complete",
107
+ "skip",
108
+ "exit",
109
+ "error",
110
+ "example_request",
111
+ "example_accept",
112
+ "example_cancel"
113
+ ],
114
+ help_page: [
115
+ "runs",
116
+ "run",
117
+ "sessions",
118
+ "session",
119
+ "workflows",
120
+ "interrupts",
121
+ "interrupt",
122
+ "prompts",
123
+ "prompt",
124
+ "prompt-groups",
125
+ "prompt-group",
126
+ "evals",
127
+ "eval-suites",
128
+ "eval-suite",
129
+ "evaluation",
130
+ "eval-run",
131
+ "eval-case",
132
+ "eval-comparison",
133
+ "eval-case-comparison",
134
+ "diagnostic",
135
+ "settings",
136
+ "onboarding",
137
+ "other"
138
+ ],
139
+ help_context: ["sample", "real"],
140
+ help_step: [
141
+ "overview",
142
+ "controls",
143
+ "records",
144
+ "tabs",
145
+ "content",
146
+ "navigation",
147
+ "state"
148
+ ],
149
+ sample_action: [
150
+ "select",
151
+ "view",
152
+ "hide",
153
+ "show",
154
+ "tour_start",
155
+ "tour_complete",
156
+ "tour_skip",
157
+ "tour_error",
158
+ "tour_step",
159
+ "tour_hub",
160
+ "tour_resume",
161
+ "tour_exit",
162
+ "tour_full_start",
163
+ "tour_full_complete",
164
+ "tour_full_partial",
165
+ "tour_reset"
166
+ ],
167
+ tour_chapter: [
168
+ "sample-execution",
169
+ "debug-execution",
170
+ "conversation",
171
+ "approvals",
172
+ "prompt-versions",
173
+ "evaluation-results",
174
+ "error-diagnostics",
175
+ "evaluation-progress",
176
+ "personalize"
177
+ ],
178
+ tour_step: [
179
+ "project-selector",
180
+ "sample-run",
181
+ "execution-details",
182
+ "find-failed-run",
183
+ "failure-summary",
184
+ "failure-trace",
185
+ "failure-model-io",
186
+ "session-history",
187
+ "session-runs",
188
+ "workflow-topology",
189
+ "workflow-system",
190
+ "approval-decision",
191
+ "approval-timeline",
192
+ "approval-result",
193
+ "prompt-original",
194
+ "prompt-updated",
195
+ "prompt-diff",
196
+ "suite-definition",
197
+ "evaluation-summary",
198
+ "case-evidence",
199
+ "saved-comparison",
200
+ "diagnostic-exception",
201
+ "diagnostic-capture",
202
+ "diagnostic-context",
203
+ "evaluation-progress-summary",
204
+ "evaluation-grading",
205
+ "evaluation-pending-evidence",
206
+ "appearance",
207
+ "sample-visibility"
208
+ ],
209
+ tour_failure: ["load", "target", "entry"],
210
+ tour_mode: ["chapter", "full"],
211
+ tour_version: ["1"],
212
+ help_placement: ["card", "button"],
213
+ measurement_version: ["2"],
214
+ measurement_kind: [
215
+ "invocation",
216
+ "stage",
217
+ "execution",
218
+ "attempt",
219
+ "chunk",
220
+ "output",
221
+ "update",
222
+ "poll",
223
+ "request",
224
+ "call",
225
+ "feature",
226
+ "observation"
227
+ ],
228
+ traffic_source: ["internal", "synthetic", "external", "unknown"],
229
+ layout_action: [
230
+ "visibility",
231
+ "show_all",
232
+ "reset",
233
+ "apply",
234
+ "reset_width",
235
+ "pin",
236
+ "unpin",
237
+ "resize",
238
+ "reorder"
239
+ ],
240
+ eval_phase: [
241
+ "params",
242
+ "setup",
243
+ "execute",
244
+ "responder",
245
+ "reference",
246
+ "grading",
247
+ "verification",
248
+ "cleanup",
249
+ "reporting"
250
+ ],
251
+ cli_resource: ["evals.runs", "evals.suites"],
252
+ retryable: "boolean",
253
+ retried: "boolean",
254
+ recovered: "boolean",
255
+ retry_attempt: ["1", "2-5", "6-20", "21-100", "101+"],
256
+ batch_size: ["1", "2-5", "6-20", "21-100", "101+"],
257
+ http_status_class: ["1xx", "2xx", "3xx", "4xx", "5xx"],
258
+ cause_category: [
259
+ "configuration",
260
+ "provider",
261
+ "validation",
262
+ "domain",
263
+ "workflow",
264
+ "persistence",
265
+ "request",
266
+ "transport",
267
+ "internal",
268
+ "unknown"
269
+ ],
270
+ cli_command: [
271
+ "studio.start",
272
+ "studio.stop",
273
+ "studio.restart",
274
+ "studio.status",
275
+ "studio.logs",
276
+ "studio.credentials",
277
+ "studio.reset",
278
+ "studio.prompts",
279
+ "studio.evals",
280
+ "studio.runs",
281
+ "studio.sessions",
282
+ "studio.interrupts",
283
+ "studio.workflows",
284
+ "studio.diagnostics",
285
+ "studio.inspect",
286
+ "studio.doctor",
287
+ "studio.catalogs",
288
+ "connections",
289
+ "evals.run",
290
+ "evals.list",
291
+ "topology.push",
292
+ "help",
293
+ "unknown"
294
+ ],
295
+ cli_action: [
296
+ "start",
297
+ "stop",
298
+ "restart",
299
+ "status",
300
+ "logs",
301
+ "credentials",
302
+ "reset",
303
+ "run",
304
+ "list",
305
+ "get",
306
+ "show",
307
+ "inspect",
308
+ "analyze",
309
+ "download",
310
+ "doctor",
311
+ "cancel",
312
+ "compare",
313
+ "create",
314
+ "update",
315
+ "delete",
316
+ "import",
317
+ "export",
318
+ "pull",
319
+ "push",
320
+ "add",
321
+ "remove",
322
+ "use",
323
+ "verify",
324
+ "versions",
325
+ "diff",
326
+ "validate",
327
+ "action",
328
+ "tag",
329
+ "untag",
330
+ "rollback",
331
+ "promote",
332
+ "archive",
333
+ "restore",
334
+ "test",
335
+ "copy",
336
+ "apply",
337
+ "wait",
338
+ "catalogs",
339
+ "help",
340
+ "unknown"
341
+ ],
342
+ dry_run: "boolean",
343
+ json_output: "boolean",
344
+ topology_strict: "boolean",
345
+ settings_override: "boolean",
346
+ case_timeout_override: "boolean",
347
+ run_timeout_override: "boolean",
92
348
  phase: [
93
349
  "admission",
94
350
  "execution",
@@ -233,6 +489,7 @@ var publicCatalog = {
233
489
  "pending",
234
490
  "expired"
235
491
  ],
492
+ match: ["all", "any"],
236
493
  filter: [
237
494
  "search",
238
495
  "status",
@@ -265,6 +522,7 @@ var publicCatalog = {
265
522
  "401",
266
523
  "403",
267
524
  "404",
525
+ "408",
268
526
  "409",
269
527
  "413",
270
528
  "422",
@@ -288,6 +546,48 @@ var publicCatalog = {
288
546
  },
289
547
  // Built-in contracts only; application codes and provider response text are excluded.
290
548
  errorCodes: [
549
+ "UNCLASSIFIED_FAILURE",
550
+ "HTTP_UNAUTHORIZED",
551
+ "HTTP_FORBIDDEN",
552
+ "HTTP_NOT_FOUND",
553
+ "HTTP_TIMEOUT",
554
+ "HTTP_CONFLICT",
555
+ "HTTP_TOO_LARGE",
556
+ "HTTP_RATE_LIMITED",
557
+ "HTTP_SERVER_ERROR",
558
+ "HTTP_INVALID_REQUEST",
559
+ "NETWORK_DNS_FAILED",
560
+ "NETWORK_CONNECTION_REFUSED",
561
+ "NETWORK_CONNECTION_RESET",
562
+ "NETWORK_TIMEOUT",
563
+ "NETWORK_TLS_FAILED",
564
+ "CLI_ARGUMENT_INVALID",
565
+ "CLI_EXIT_FAILED",
566
+ "KTX_TOPOLOGY_INCOMPLETE",
567
+ "STUDIO_NOT_CONFIGURED",
568
+ "STUDIO_RESPONSE_INVALID",
569
+ "EVAL_CONCURRENCY_CHANGED",
570
+ "EVAL_CONSUMER_FAILED",
571
+ "EVAL_CONTRACT_CHANGED",
572
+ "EVAL_DISCOVERY_REJECTED",
573
+ "EVAL_EXECUTION_CONFLICT",
574
+ "EVAL_EXECUTION_STORE_CHANGED",
575
+ "EVAL_EXECUTION_UNKNOWN",
576
+ "EVAL_EXECUTOR_BUSY",
577
+ "EVAL_EXECUTOR_FAILED",
578
+ "EVAL_EXECUTOR_REJECTED",
579
+ "EVAL_EXECUTOR_UNAUTHORIZED",
580
+ "EVAL_GRADING_FAILED",
581
+ "EVAL_GRADING_TIMEOUT",
582
+ "EVAL_JUDGE_UNAVAILABLE",
583
+ "EVAL_LEASE_LOST",
584
+ "EVAL_RETRY_DELAY_EXCEEDED",
585
+ "EVAL_SETUP_TIMEOUT",
586
+ "EVAL_TRANSPORT_UNAVAILABLE",
587
+ "EVAL_VERIFICATION_TIMEOUT",
588
+ "EVAL_RESULT_INVALID",
589
+ "EVAL_RUN_TIMEOUT",
590
+ "EVAL_SETTINGS_INVALID",
291
591
  "EXECUTION_FAILED",
292
592
  "INVALID_REQUEST",
293
593
  "INVALID_RESUME",
@@ -355,8 +655,8 @@ function scale(value) {
355
655
  return value <= 1 ? "1" : value <= 5 ? "2-5" : value <= 20 ? "6-20" : value <= 100 ? "21-100" : "101+";
356
656
  }
357
657
 
358
- // src/client.ts
359
- function property(value, key) {
658
+ // src/failure.ts
659
+ function usageErrorProperty(value, key) {
360
660
  try {
361
661
  if (!value || typeof value !== "object") return void 0;
362
662
  const descriptor = Object.getOwnPropertyDescriptor(value, key);
@@ -365,40 +665,201 @@ function property(value, key) {
365
665
  return void 0;
366
666
  }
367
667
  }
368
- function classifyUsageError(error, catalog = publicCatalog) {
369
- const name = property(error, "name");
370
- const code = property(error, "code") ?? property(property(error, "failure"), "code");
371
- if (name === "AbortError" || code === "EXECUTION_CANCELLED")
668
+ var networkCodes = {
669
+ ENOTFOUND: "NETWORK_DNS_FAILED",
670
+ EAI_AGAIN: "NETWORK_DNS_FAILED",
671
+ ECONNREFUSED: "NETWORK_CONNECTION_REFUSED",
672
+ ECONNRESET: "NETWORK_CONNECTION_RESET",
673
+ EPIPE: "NETWORK_CONNECTION_RESET",
674
+ ETIMEDOUT: "NETWORK_TIMEOUT",
675
+ UND_ERR_CONNECT_TIMEOUT: "NETWORK_TIMEOUT",
676
+ UND_ERR_HEADERS_TIMEOUT: "NETWORK_TIMEOUT",
677
+ UND_ERR_BODY_TIMEOUT: "NETWORK_TIMEOUT",
678
+ CERT_HAS_EXPIRED: "NETWORK_TLS_FAILED",
679
+ DEPTH_ZERO_SELF_SIGNED_CERT: "NETWORK_TLS_FAILED",
680
+ UNABLE_TO_VERIFY_LEAF_SIGNATURE: "NETWORK_TLS_FAILED"
681
+ };
682
+ function classifyUsageHttpStatus(status) {
683
+ if (!Number.isInteger(status) || status < 100 || status > 599)
684
+ return {
685
+ outcome: "failed",
686
+ properties: {
687
+ error_code: "UNCLASSIFIED_FAILURE",
688
+ error_category: "unknown"
689
+ }
690
+ };
691
+ if (status < 400)
692
+ return {
693
+ outcome: "success",
694
+ properties: { http_status_class: `${Math.floor(status / 100)}xx` }
695
+ };
696
+ const code = status === 401 ? "HTTP_UNAUTHORIZED" : status === 403 ? "HTTP_FORBIDDEN" : status === 404 ? "HTTP_NOT_FOUND" : status === 408 || status === 504 ? "HTTP_TIMEOUT" : status === 409 ? "HTTP_CONFLICT" : status === 413 ? "HTTP_TOO_LARGE" : status === 429 ? "HTTP_RATE_LIMITED" : status >= 500 ? "HTTP_SERVER_ERROR" : "HTTP_INVALID_REQUEST";
697
+ return {
698
+ outcome: "failed",
699
+ properties: {
700
+ error_code: code,
701
+ error_category: status >= 500 || status === 408 ? "transport" : "request",
702
+ http_status: String(status),
703
+ http_status_class: `${Math.floor(status / 100)}xx`,
704
+ retryable: status === 408 || status === 429 || status >= 500
705
+ }
706
+ };
707
+ }
708
+ function nativeExceptionName(value) {
709
+ try {
710
+ if (typeof DOMException !== "undefined")
711
+ return Object.getOwnPropertyDescriptor(
712
+ DOMException.prototype,
713
+ "name"
714
+ )?.get?.call(value);
715
+ } catch {
716
+ }
717
+ return void 0;
718
+ }
719
+ function classifyOne(error, catalog) {
720
+ const read = (key) => usageErrorProperty(error, key);
721
+ let name = read("name") ?? nativeExceptionName(error);
722
+ try {
723
+ if (name === void 0 && error instanceof SyntaxError)
724
+ name = "SyntaxError";
725
+ } catch {
726
+ }
727
+ const code = read("code");
728
+ if (name === "AbortError" || code === "EXECUTION_CANCELLED" || code === "ABORT_ERR")
372
729
  return { outcome: "cancelled", properties: {} };
373
730
  if (code === "EXECUTION_LIMIT_REACHED" || name === "ExecutionLimitReached")
374
731
  return { outcome: "limit_reached", properties: {} };
375
- if (name === "GraphInterrupt" || name === "NodeInterrupt" || name === "Interrupt")
732
+ if (typeof name === "string" && [
733
+ "GraphInterrupt",
734
+ "NodeInterrupt",
735
+ "Interrupt",
736
+ "ParallelChildWaiting"
737
+ ].includes(name))
376
738
  return { outcome: "suspended", properties: {} };
377
- const known = typeof code === "string" && catalog.errorCodes.includes(code);
378
- const category = known && code !== "EXECUTION_FAILED" ? property(error, "category") ?? property(property(error, "failure"), "category") ?? "unknown" : "unknown";
379
- const status = property(error, "status") ?? property(property(error, "failure"), "status");
380
- return {
381
- outcome: "failed",
382
- properties: {
383
- error_code: known ? code : "other",
384
- error_category: category,
385
- ...typeof status === "number" ? { http_status: String(status) } : {}
739
+ if (name === "EvalConfigurationError")
740
+ return {
741
+ outcome: "failed",
742
+ properties: {
743
+ error_code: "EVAL_SETTINGS_INVALID",
744
+ error_category: "configuration",
745
+ retryable: false
746
+ }
747
+ };
748
+ if (name === "TimeoutError")
749
+ return {
750
+ outcome: "failed",
751
+ properties: {
752
+ error_code: "NETWORK_TIMEOUT",
753
+ error_category: "transport",
754
+ retryable: true
755
+ }
756
+ };
757
+ if (typeof code === "string" && Object.hasOwn(networkCodes, code))
758
+ return {
759
+ outcome: "failed",
760
+ properties: {
761
+ error_code: networkCodes[code] ?? "UNCLASSIFIED_FAILURE",
762
+ error_category: "transport",
763
+ retryable: true
764
+ }
765
+ };
766
+ if (typeof code === "string" && catalog.errorCodes.includes(code)) {
767
+ const failure = usageErrorProperty(error, "failure");
768
+ const category = read("category") ?? usageErrorProperty(failure, "category");
769
+ const retryable = read("retryable") ?? usageErrorProperty(failure, "retryable");
770
+ const status2 = read("status") ?? usageErrorProperty(failure, "status");
771
+ return {
772
+ outcome: "failed",
773
+ properties: {
774
+ ...typeof status2 === "number" ? classifyUsageHttpStatus(status2).properties : {},
775
+ // The framework code is more specific than its HTTP projection.
776
+ error_code: code,
777
+ error_category: code !== "EXECUTION_FAILED" && typeof category === "string" && Array.isArray(catalog.properties.error_category) && catalog.properties.error_category.includes(category) ? category : "unknown",
778
+ ...typeof retryable === "boolean" ? { retryable } : {}
779
+ }
780
+ };
781
+ }
782
+ const status = read("status") ?? read("statusCode");
783
+ if (typeof status === "number" && Number.isInteger(status) && status >= 400 && status <= 599)
784
+ return classifyUsageHttpStatus(status);
785
+ if (name === "ZodError" || name === "SyntaxError")
786
+ return {
787
+ outcome: "failed",
788
+ properties: {
789
+ error_code: "SCHEMA_VALIDATION",
790
+ error_category: "validation"
791
+ }
792
+ };
793
+ return void 0;
794
+ }
795
+ function classifyUsageError(error, catalog = publicCatalog) {
796
+ const seen = /* @__PURE__ */ new Set();
797
+ const pending = [{ value: error, depth: 0 }];
798
+ let result;
799
+ while (pending.length && seen.size < 8) {
800
+ const current = pending.shift();
801
+ if (!current || seen.has(current.value)) continue;
802
+ seen.add(current.value);
803
+ const found = classifyOne(current.value, catalog);
804
+ if (found) {
805
+ if (!result) result = found;
806
+ else if (found.properties.error_code && found.outcome === "failed" && found.properties.error_code !== result.properties.error_code) {
807
+ result.properties.cause_code = found.properties.error_code;
808
+ result.properties.cause_category = found.properties.error_category ?? "unknown";
809
+ if (result.properties.retryable === void 0 && typeof found.properties.retryable === "boolean")
810
+ result.properties.retryable = found.properties.retryable;
811
+ break;
812
+ }
813
+ if (result === found && found.outcome !== "failed") return found;
386
814
  }
815
+ if (current.depth < 3)
816
+ for (const key of ["failure", "cause", "error"]) {
817
+ const value = usageErrorProperty(current.value, key);
818
+ if (value && typeof value === "object")
819
+ pending.push({ value, depth: current.depth + 1 });
820
+ }
821
+ }
822
+ return result ?? {
823
+ outcome: "failed",
824
+ properties: { error_code: "other", error_category: "unknown" }
387
825
  };
388
826
  }
827
+
828
+ // src/measurement.ts
829
+ function usageMeasurement(event, operation, input) {
830
+ if (event === "usage.feature")
831
+ return usageErrorProperty(input, "origin") === "background" || usageErrorProperty(input, "origin") === "server" ? "observation" : "feature";
832
+ if (operation === "cli.command" || operation === "sdk.eval")
833
+ return "invocation";
834
+ if (operation === "studio.setup") return "stage";
835
+ if (operation === "sdk.execution" || operation === "studio.eval.execution")
836
+ return "execution";
837
+ if (operation === "sdk.export" || operation === "sdk.model") return "attempt";
838
+ if (operation === "sdk.structured") {
839
+ const format = usageErrorProperty(input, "format");
840
+ return format === "text-delta" ? "chunk" : format === "final" ? "output" : "update";
841
+ }
842
+ if (usageErrorProperty(input, "origin") === "background") return "poll";
843
+ if (operation.startsWith("studio.")) return "request";
844
+ return "call";
845
+ }
846
+
847
+ // src/client.ts
389
848
  function sanitizeProperties(input, catalog = publicCatalog) {
390
849
  const safe = {};
391
850
  for (const [key, rule] of Object.entries(catalog.properties)) {
392
- const value = property(input, key);
851
+ const value = usageErrorProperty(input, key);
393
852
  if (value === void 0) continue;
394
853
  if (rule === "boolean") {
395
854
  if (typeof value === "boolean") safe[key] = value;
396
855
  } else if (typeof value === "string")
397
856
  safe[key] = rule.includes(value) ? value : "other";
398
857
  }
399
- const code = property(input, "error_code");
400
- if (typeof code === "string")
401
- safe.error_code = catalog.errorCodes.includes(code) ? code : "other";
858
+ for (const key of ["error_code", "cause_code"]) {
859
+ const code = usageErrorProperty(input, key);
860
+ if (typeof code === "string")
861
+ safe[key] = catalog.errorCodes.includes(code) ? code : "other";
862
+ }
402
863
  return safe;
403
864
  }
404
865
  var durationBounds = [10, 100, 1e3, 1e4, 6e4];
@@ -419,6 +880,16 @@ function createUsageTelemetry(options) {
419
880
  let disposed = false;
420
881
  let dropped = 0;
421
882
  let delivered = 0;
883
+ let lostObservations = 0;
884
+ let failedBatches = 0;
885
+ let reportedLoss = 0;
886
+ let reportedFailures = 0;
887
+ const lose = (count) => {
888
+ lostObservations = Math.min(
889
+ Number.MAX_SAFE_INTEGER,
890
+ lostObservations + count
891
+ );
892
+ };
422
893
  let hour = Math.floor(now() / 36e5);
423
894
  let sent = 0;
424
895
  const active = () => {
@@ -454,6 +925,10 @@ function createUsageTelemetry(options) {
454
925
  pending.clear();
455
926
  if (!records.length) return;
456
927
  let attempted = records.length;
928
+ let attemptedObservations = records.reduce(
929
+ (total, record2) => total + record2.count,
930
+ 0
931
+ );
457
932
  flight = (async () => {
458
933
  try {
459
934
  if (options.debug?.()) {
@@ -471,7 +946,14 @@ function createUsageTelemetry(options) {
471
946
  );
472
947
  const batch = records.slice(0, allowance);
473
948
  dropped += records.length - batch.length;
949
+ lose(
950
+ records.slice(allowance).reduce((total, record2) => total + record2.count, 0)
951
+ );
474
952
  attempted = batch.length;
953
+ attemptedObservations = batch.reduce(
954
+ (total, record2) => total + record2.count,
955
+ 0
956
+ );
475
957
  if (!batch.length || !active()) return;
476
958
  const identified = await options.identity();
477
959
  const identity = typeof identified === "string" ? identified : identified.id;
@@ -482,13 +964,25 @@ function createUsageTelemetry(options) {
482
964
  identity
483
965
  )) {
484
966
  dropped += batch.length;
967
+ lose(attemptedObservations);
485
968
  return;
486
969
  }
487
970
  sent += batch.length;
971
+ const lossSnapshot = lostObservations;
972
+ const failureSnapshot = failedBatches;
973
+ if (batch[0] && (lossSnapshot > reportedLoss || failureSnapshot > reportedFailures))
974
+ batch[0].delivery_health = {
975
+ dropped_observations: lossSnapshot - reportedLoss,
976
+ failed_batches: failureSnapshot - reportedFailures
977
+ };
488
978
  await options.transport(batch, identity);
979
+ reportedLoss = lossSnapshot;
980
+ reportedFailures = failureSnapshot;
489
981
  delivered += batch.length;
490
982
  } catch {
491
983
  dropped += attempted;
984
+ lose(attemptedObservations);
985
+ failedBatches = Math.min(Number.MAX_SAFE_INTEGER, failedBatches + 1);
492
986
  }
493
987
  })().finally(() => {
494
988
  flight = void 0;
@@ -512,12 +1006,29 @@ function createUsageTelemetry(options) {
512
1006
  }
513
1007
  if (!configured || !catalog.operations.includes(operation) || !outcomes.includes(outcome))
514
1008
  return;
515
- const properties = sanitizeProperties(input, catalog);
1009
+ const failed = outcome === "failed";
1010
+ const status = usageErrorProperty(input, "http_status");
1011
+ const http = typeof status === "string" && /^\d{3}$/.test(status) ? classifyUsageHttpStatus(Number(status)).properties : {};
1012
+ const properties = sanitizeProperties(
1013
+ {
1014
+ measurement_version: "2",
1015
+ measurement_kind: usageMeasurement(event, operation, input),
1016
+ ...failed ? {
1017
+ error_code: "UNCLASSIFIED_FAILURE",
1018
+ error_category: "unknown",
1019
+ ...http
1020
+ } : {},
1021
+ ...sanitizeProperties(input, catalog),
1022
+ traffic_source: options.context.trafficSource ?? "unknown"
1023
+ },
1024
+ catalog
1025
+ );
516
1026
  const key = JSON.stringify([event, operation, outcome, properties]);
517
1027
  let existing = pending.get(key);
518
1028
  if (!existing) {
519
1029
  if (pending.size >= (options.maxGroups ?? 64)) {
520
1030
  dropped++;
1031
+ lose(1);
521
1032
  return;
522
1033
  }
523
1034
  existing = {
@@ -529,7 +1040,9 @@ function createUsageTelemetry(options) {
529
1040
  component: options.context.component,
530
1041
  version: options.context.version,
531
1042
  analytics_environment: options.context.environment ?? "production",
532
- runtime_mode: options.context.runtimeMode ?? "unknown",
1043
+ runtime_mode: ["development", "production", "ci"].includes(
1044
+ options.context.runtimeMode ?? ""
1045
+ ) ? options.context.runtimeMode ?? "unknown" : "unknown",
533
1046
  identity_scope: options.context.identityScope ?? "installation",
534
1047
  operation,
535
1048
  outcome,
@@ -574,8 +1087,11 @@ function createUsageTelemetry(options) {
574
1087
  if (ended) return;
575
1088
  ended = true;
576
1089
  try {
1090
+ const status = usageErrorProperty(extra, "http_status");
1091
+ const http = outcome === "failed" && typeof status === "string" && /^\d{3}$/.test(status) ? classifyUsageHttpStatus(Number(status)).properties : {};
577
1092
  record("usage.operation", operation, outcome, now() - began, {
578
1093
  ...initial,
1094
+ ...http,
579
1095
  ...sanitizeProperties(extra, catalog)
580
1096
  });
581
1097
  } catch {
@@ -629,6 +1145,9 @@ function createUsageTelemetry(options) {
629
1145
 
630
1146
  // src/browser-node.ts
631
1147
  var clients = /* @__PURE__ */ new Map();
1148
+ async function flushUsageTelemetry() {
1149
+ await Promise.all([...clients.values()].map((client) => client.flush()));
1150
+ }
632
1151
  function createNodeUsageTelemetry(options) {
633
1152
  return createUsageTelemetry({
634
1153
  ...options,
@@ -656,9 +1175,14 @@ function getUsageTelemetry(component, version = "unknown", product = "sdk") {
656
1175
  function usageDisabled() {
657
1176
  return true;
658
1177
  }
1178
+ function runtimeUsageContext() {
1179
+ return { runtimeMode: "unknown", trafficSource: "unknown" };
1180
+ }
659
1181
  function publicUsageConfiguration() {
660
1182
  return {
661
1183
  enabled: false,
1184
+ runtimeMode: "unknown",
1185
+ trafficSource: "unknown",
662
1186
  debug: false,
663
1187
  environment: "production",
664
1188
  key: "",
@@ -670,8 +1194,10 @@ function publicUsageConfiguration() {
670
1194
  configureUsageTelemetry,
671
1195
  createNodeUsageTelemetry,
672
1196
  createUsageTelemetry,
1197
+ flushUsageTelemetry,
673
1198
  getUsageTelemetry,
674
1199
  publicUsageConfiguration,
1200
+ runtimeUsageContext,
675
1201
  scale,
676
1202
  usageDisabled
677
1203
  });