@genn-inc/cluebase-frontend-sdk 0.0.3 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +21 -0
  2. package/dist/_generated/correlation-attribute-keys.d.ts +3 -0
  3. package/dist/_generated/correlation-attribute-keys.js +34 -0
  4. package/dist/_generated/diagnostic-codes.d.ts +4 -0
  5. package/dist/_generated/diagnostic-codes.js +48 -0
  6. package/dist/_generated/drop-reasons.d.ts +2 -0
  7. package/dist/_generated/drop-reasons.js +25 -0
  8. package/dist/_generated/{identity-pii-policy.d.ts → identity-pii-policy-text-contains.d.ts} +1 -1
  9. package/dist/_generated/{identity-pii-policy.js → identity-pii-policy-text-contains.js} +1 -1
  10. package/dist/_generated/identity-pii-policy-whole-value.d.ts +37 -0
  11. package/dist/_generated/identity-pii-policy-whole-value.js +106 -0
  12. package/dist/_generated/ingest-routes.d.ts +5 -0
  13. package/dist/_generated/ingest-routes.js +12 -0
  14. package/dist/_generated/otel-span-conversion.js +1 -9
  15. package/dist/context/browser-storage.js +1 -2
  16. package/dist/context/environment.js +5 -3
  17. package/dist/context/identity.js +5 -9
  18. package/dist/context/organization.d.ts +1 -1
  19. package/dist/context/organization.js +6 -8
  20. package/dist/context/session.js +6 -8
  21. package/dist/context/tab.js +8 -12
  22. package/dist/context/trace.js +4 -5
  23. package/dist/exporter/batch.d.ts +26 -27
  24. package/dist/exporter/batch.js +248 -294
  25. package/dist/exporter/browser-outbox-records.d.ts +8 -25
  26. package/dist/exporter/browser-outbox-records.js +21 -100
  27. package/dist/exporter/browser-outbox.d.ts +23 -25
  28. package/dist/exporter/browser-outbox.js +106 -181
  29. package/dist/exporter/client.d.ts +25 -35
  30. package/dist/exporter/client.js +107 -335
  31. package/dist/exporter/delivery-pipeline.d.ts +71 -0
  32. package/dist/exporter/delivery-pipeline.js +196 -0
  33. package/dist/exporter/delivery-response-contract.d.ts +1 -81
  34. package/dist/exporter/delivery-response-contract.js +0 -118
  35. package/dist/exporter/delivery-response.d.ts +9 -4
  36. package/dist/exporter/delivery-response.js +59 -122
  37. package/dist/exporter/diagnostics.d.ts +3 -2
  38. package/dist/exporter/diagnostics.js +5 -26
  39. package/dist/exporter/event-id.d.ts +1 -0
  40. package/dist/exporter/event-id.js +4 -3
  41. package/dist/exporter/frontend-resource.js +5 -4
  42. package/dist/exporter/observation-source-event-exporter.d.ts +2 -1
  43. package/dist/exporter/observation-source-event-exporter.js +7 -4
  44. package/dist/exporter/path-template.js +3 -1
  45. package/dist/exporter/raw-event-to-source-signal.js +4 -2
  46. package/dist/exporter/sanitize.d.ts +3 -2
  47. package/dist/exporter/sanitize.js +4 -3
  48. package/dist/exporter/sdk-core-delivery.d.ts +225 -0
  49. package/dist/exporter/sdk-core-delivery.js +97 -0
  50. package/dist/exporter/sdk-core-wasm.d.ts +11 -0
  51. package/dist/exporter/sdk-core-wasm.js +39 -0
  52. package/dist/exporter/source-event.d.ts +3 -0
  53. package/dist/exporter/source-event.js +17 -0
  54. package/dist/exporter/span-to-source-signal.d.ts +2 -2
  55. package/dist/exporter/span-to-source-signal.js +45 -125
  56. package/dist/index.d.ts +5 -4
  57. package/dist/index.js +18 -6
  58. package/dist/instrumentation/action.js +9 -8
  59. package/dist/instrumentation/dom.js +13 -21
  60. package/dist/instrumentation/drag.js +0 -3
  61. package/dist/instrumentation/error.js +3 -1
  62. package/dist/instrumentation/form.js +5 -6
  63. package/dist/instrumentation/input.js +4 -8
  64. package/dist/instrumentation/location.js +3 -1
  65. package/dist/instrumentation/network-request.js +1 -1
  66. package/dist/instrumentation/network-span-attributes.js +2 -2
  67. package/dist/instrumentation/network.d.ts +1 -1
  68. package/dist/instrumentation/network.js +24 -3
  69. package/dist/instrumentation/performance.js +1 -2
  70. package/dist/internal/internal-log.js +2 -1
  71. package/dist/provider/_version.d.ts +1 -1
  72. package/dist/provider/_version.js +1 -1
  73. package/dist/provider/config.js +16 -4
  74. package/dist/provider/constants.d.ts +1 -1
  75. package/dist/provider/constants.js +0 -2
  76. package/dist/provider/lifecycle-event-dedup.d.ts +7 -0
  77. package/dist/provider/lifecycle-event-dedup.js +31 -0
  78. package/dist/provider/sdk-event-pipeline.d.ts +3 -4
  79. package/dist/provider/sdk-event-pipeline.js +5 -17
  80. package/dist/provider/sdk-input-normalization.js +2 -2
  81. package/dist/provider/sdk-otel-pipeline.d.ts +2 -1
  82. package/dist/provider/sdk-otel-pipeline.js +7 -15
  83. package/dist/provider/sdk-runtime-surfaces.d.ts +17 -13
  84. package/dist/provider/sdk-runtime-surfaces.js +15 -13
  85. package/dist/provider/sdk.js +137 -48
  86. package/dist/provider/types.d.ts +18 -24
  87. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.d.ts +44 -0
  88. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.js +355 -0
  89. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm +0 -0
  90. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm.d.ts +11 -0
  91. package/dist/wasm/pkg-web/package.json +15 -0
  92. package/package.json +62 -53
  93. package/dist/provider/usage-governor.d.ts +0 -7
  94. package/dist/provider/usage-governor.js +0 -114
@@ -1,14 +1,14 @@
1
+ import { canonicalize as canonicalJsonStringify } from "json-canonicalize";
2
+ import { addStorageListener, consentRecordKey, createConsentChannel, createConsentRecord, createDraft, createGeneration, createLegacyTombstone, createPending, draftRecordKey, LEGACY_TOMBSTONE_LIMIT, nowIso, outboxEventCount, parseRecord, pendingRecordKey, readLocks, readStorage, sentByteLength, sha256Hex, tombstoneRecordKey, UNANCHORED_COLLECTION_GENERATION, verifyHash, } from "./browser-outbox-records.js";
1
3
  import { DiagnosticStore } from "./diagnostics.js";
2
4
  import { isBrowserSourceSignalEvent } from "./source-event.js";
3
- import { canonicalize as canonicalJsonStringify } from "json-canonicalize";
4
- import { addStorageListener, browserEventsByteLength, createConsentChannel, createConsentRecord, createDraft, createGeneration, createLegacyTombstone, createPending, consentRecordKey, draftRecordKey, hasLegacyTombstone, largestFittingPrefix, nowIso, outboxEventCount, parseRecord, readLocks, readStorage, recordBatchId, sha256Hex, toHeadBatch, splitPendingRecord, pendingRecordKey, tombstoneRecordKey, UNANCHORED_COLLECTION_GENERATION, verifyHash, withChecksum, withoutChecksum, LEGACY_TOMBSTONE_LIMIT, } from "./browser-outbox-records.js";
5
5
  export class BrowserOutbox {
6
6
  constructor(options) {
7
7
  this.drafts = [];
8
8
  this.pending = [];
9
+ this.pendingByBatchId = new Map();
9
10
  this.tombstones = [];
10
11
  this.nextOrdinal = 1;
11
- this.nextPermitOrdinal = 1;
12
12
  this.legacyImportBlocked = false;
13
13
  this.consentAnchorEstablished = false;
14
14
  this.memoryOnly = false;
@@ -21,10 +21,9 @@ export class BrowserOutbox {
21
21
  this.consentKey = consentRecordKey(this.prefix);
22
22
  this.legacyKey = `cluebase:source_event_outbox:${options.projectKey}`;
23
23
  this.lockName = `cluebase:source-event-outbox:v2:${this.projectHash}`;
24
- this.storage = "storage" in options ? options.storage ?? null : readStorage();
24
+ this.storage =
25
+ "storage" in options ? (options.storage ?? null) : readStorage();
25
26
  this.durableOutboxSupported = readLocks() !== null;
26
- this.maxBytes = Math.max(1024, options.maxBytes);
27
- this.maxEvents = Math.max(1, options.maxEvents);
28
27
  this.metrics = options.metrics ?? null;
29
28
  this.diagnostics = options.diagnostics ?? new DiagnosticStore();
30
29
  this.onConsentRevoked = options.onConsentRevoked ?? (() => undefined);
@@ -50,19 +49,10 @@ export class BrowserOutbox {
50
49
  currentConsent() {
51
50
  return this.consent;
52
51
  }
53
- capturePermit() {
54
- return Object.freeze({
55
- generation: this.consentAnchorEstablished
56
- ? this.generation
57
- : UNANCHORED_COLLECTION_GENERATION,
58
- permittedAtStart: this.consent !== "denied",
59
- captureOrdinal: this.nextPermitOrdinal++,
60
- });
61
- }
62
- permits(permit) {
63
- return (permit.permittedAtStart &&
64
- this.consent !== "denied" &&
65
- permit.generation === this.generation);
52
+ collectionGeneration() {
53
+ return this.consentAnchorEstablished
54
+ ? this.generation
55
+ : UNANCHORED_COLLECTION_GENERATION;
66
56
  }
67
57
  setConsent(next) {
68
58
  const recoveryExpectedRaw = this.consentStateUnavailable
@@ -78,7 +68,10 @@ export class BrowserOutbox {
78
68
  this.generation = createGeneration();
79
69
  this.legacyImportBlocked = true;
80
70
  this.diagnostics.rotateForConsentPurge(purged);
81
- this.consentChannel?.postMessage({ type: "denied", generation: this.generation });
71
+ this.consentChannel?.postMessage({
72
+ type: "denied",
73
+ generation: this.generation,
74
+ });
82
75
  this.clearMemory();
83
76
  return Object.freeze({
84
77
  state: this.consent,
@@ -181,149 +174,124 @@ export class BrowserOutbox {
181
174
  const purged = transition.purge ? this.purgeAll() : true;
182
175
  return persisted && purged;
183
176
  }
184
- addDraft(event, permit = this.capturePermit()) {
185
- const resolvedPermit = this.resolvePermit(permit);
186
- if (!resolvedPermit)
187
- return false;
177
+ holdDraft(event) {
178
+ if (this.consent === "denied" || !this.consentAnchorEstablished)
179
+ return null;
188
180
  const draft = createDraft({
189
181
  event,
190
- permit: resolvedPermit,
182
+ permit: { generation: this.generation, permittedAtStart: true },
191
183
  projectHash: this.projectHash,
192
184
  createdAt: nowIso(),
193
185
  });
194
186
  if (!draft)
195
- return false;
187
+ return null;
196
188
  const key = draftRecordKey(this.prefix, draft.eventKeyHash);
197
189
  const existing = this.readRecord(key);
198
190
  if (existing) {
199
191
  if (existing.kind === "draft" &&
200
192
  existing.recordVerifierSha256 === draft.recordVerifierSha256) {
201
- return true;
193
+ return draft;
202
194
  }
203
195
  this.diagnostics.record({ code: "outbox_key_collision" });
204
- return false;
196
+ return null;
205
197
  }
206
198
  this.drafts.push(draft);
207
- this.enforceCapacity();
208
199
  if (!this.writeRecord(key, draft)) {
209
200
  this.memoryOnly = true;
210
201
  this.warnDurableUnavailable();
211
202
  }
212
- return this.drafts.some((item) => item.eventId === draft.eventId);
213
- }
214
- estimatedDraftBytes(measure, metadata) {
215
- return measure(this.drafts.map((draft) => draft.event), metadata);
216
- }
217
- prepareFence(input) {
218
- const claimedEventKeyHashes = new Set(this.pending.flatMap((record) => record.eventKeyHashes));
219
- const candidates = this.drafts.filter((draft) => !claimedEventKeyHashes.has(draft.eventKeyHash) &&
220
- this.permits({
221
- generation: draft.collectionGeneration,
222
- permittedAtStart: draft.permittedAtStart,
223
- captureOrdinal: 0,
224
- }) &&
225
- (draft.origin !== "legacy_v1" ||
226
- hasLegacyTombstone(draft, this.tombstones)));
227
- let oversized = 0;
228
- let cursor = 0;
229
- let targetOrdinal = this.pending[this.pending.length - 1]?.ordinal ?? 0;
230
- while (cursor < candidates.length) {
231
- const remaining = candidates.slice(cursor);
232
- const metadata = input.createMetadata();
233
- const count = largestFittingPrefix(remaining, input.maxPayloadBytes, metadata, input.measure);
234
- if (count === 0) {
235
- const draft = remaining[0];
236
- if (draft) {
237
- this.removeDraft(draft);
238
- this.metrics?.increment("oversized_event_count");
239
- this.diagnostics.record({
240
- code: "event_oversize",
241
- event_fingerprint: this.diagnostics.eventFingerprint(canonicalJsonStringify(draft.event)),
242
- });
243
- }
244
- oversized += 1;
245
- cursor += 1;
246
- continue;
247
- }
248
- const selected = remaining.slice(0, count);
249
- const record = createPending({
203
+ return draft;
204
+ }
205
+ claimBatch(input) {
206
+ const held = this.pendingByBatchId.get(input.batchId);
207
+ if (held)
208
+ return { record: held, minted: false };
209
+ const drafts = input.eventKeys.flatMap((eventKey) => {
210
+ const draft = this.drafts.find((item) => item.eventKeyHash === eventKey);
211
+ return draft ? [draft] : [];
212
+ });
213
+ if (drafts.length !== input.eventKeys.length)
214
+ return null;
215
+ const record = createPending({
216
+ projectHash: this.projectHash,
217
+ metadata: input.createMetadata(),
218
+ drafts,
219
+ ordinal: this.nextOrdinal,
220
+ });
221
+ if (!this.writeRecord(pendingRecordKey(this.prefix, record.batchId), record))
222
+ return null;
223
+ this.nextOrdinal += 1;
224
+ this.pending.push(record);
225
+ this.pendingByBatchId.set(input.batchId, record);
226
+ for (const draft of drafts) {
227
+ this.removeRecord(draftRecordKey(this.prefix, draft.eventKeyHash));
228
+ }
229
+ this.drafts = this.drafts.filter((draft) => !drafts.includes(draft));
230
+ return { record, minted: true };
231
+ }
232
+ releaseBatch(batchId) {
233
+ const record = this.pendingByBatchId.get(batchId);
234
+ if (!record)
235
+ return;
236
+ this.pendingByBatchId.delete(batchId);
237
+ if (!this.removeClaimedDraftRecords(record))
238
+ return;
239
+ if (!this.removeRecord(pendingRecordKey(this.prefix, record.batchId)))
240
+ return;
241
+ this.pending = this.pending.filter((item) => item !== record);
242
+ }
243
+ reopenBatch(batchId) {
244
+ const record = this.pendingByBatchId.get(batchId);
245
+ if (!record)
246
+ return;
247
+ this.pendingByBatchId.delete(batchId);
248
+ this.pending = this.pending.filter((item) => item !== record);
249
+ this.removeRecord(pendingRecordKey(this.prefix, record.batchId));
250
+ for (const stored of record.events) {
251
+ const draft = createDraft({
252
+ event: stored.event,
253
+ permit: {
254
+ generation: record.collectionGeneration,
255
+ permittedAtStart: stored.permittedAtStart,
256
+ },
250
257
  projectHash: this.projectHash,
251
- metadata,
252
- drafts: selected,
253
- ordinal: this.nextOrdinal,
258
+ createdAt: nowIso(),
254
259
  });
255
- const key = pendingRecordKey(this.prefix, record.batchId);
256
- if (!this.writeRecord(key, record)) {
260
+ if (!draft)
261
+ continue;
262
+ this.drafts.push(draft);
263
+ if (!this.writeRecord(draftRecordKey(this.prefix, draft.eventKeyHash), draft)) {
257
264
  this.memoryOnly = true;
258
265
  this.warnDurableUnavailable();
259
- break;
260
- }
261
- this.pending.push(record);
262
- for (const draft of selected) {
263
- this.removeRecord(draftRecordKey(this.prefix, draft.eventKeyHash));
264
266
  }
265
- this.drafts = this.drafts.filter((draft) => !selected.includes(draft));
266
- targetOrdinal = record.ordinal;
267
- this.nextOrdinal += 1;
268
- cursor += count;
269
- }
270
- return { targetOrdinal, oversized };
271
- }
272
- headThrough(targetOrdinal) {
273
- const record = this.pending
274
- .sort((left, right) => left.ordinal - right.ordinal)
275
- .find((item) => item.ordinal <= targetOrdinal);
276
- if (!record)
277
- return null;
278
- return toHeadBatch(record, pendingRecordKey(this.prefix, record.batchId));
279
- }
280
- removeHead(expected) {
281
- const record = this.pending.find((item) => item.ordinal === expected.ordinal &&
282
- item.batchId === recordBatchId(expected));
283
- if (!record || !this.permitsBatch(expected))
284
- return false;
285
- const key = pendingRecordKey(this.prefix, record.batchId);
286
- if (record.kind === "pending" ||
287
- record.nextOrdinal === record.children.length - 1) {
288
- if (!this.removeClaimedDraftRecords(record))
289
- return false;
290
- if (!this.removeRecord(key))
291
- return false;
292
- this.pending = this.pending.filter((item) => item !== record);
293
- return true;
294
267
  }
295
- const progressed = withChecksum({
296
- ...withoutChecksum(record),
297
- nextOrdinal: record.nextOrdinal + 1,
298
- });
299
- if (!this.writeRecord(key, progressed))
300
- return false;
301
- this.pending = this.pending.map((item) => item === record ? progressed : item);
302
- return true;
303
- }
304
- retainHead(expected) {
305
- return (this.permitsBatch(expected) &&
306
- this.headThrough(expected.ordinal)?.recordKey === expected.recordKey);
307
268
  }
308
- splitHead(expected, createMetadata) {
309
- const record = this.pending.find((item) => item.ordinal === expected.ordinal &&
310
- item.batchId === recordBatchId(expected));
311
- if (!record)
312
- return false;
313
- const plan = splitPendingRecord(record, createMetadata);
314
- if (!plan)
315
- return false;
316
- const key = pendingRecordKey(this.prefix, record.batchId);
317
- if (!this.writeRecord(key, plan))
318
- return false;
319
- this.pending = this.pending.map((item) => (item === record ? plan : item));
320
- this.diagnostics.record({
321
- code: "batch_split",
322
- batch_fingerprint: expected.diagnosticCanonicalBytes
323
- ? this.diagnostics.batchFingerprint(expected.diagnosticCanonicalBytes)
324
- : undefined,
325
- });
326
- return true;
269
+ releaseEvents(eventKeys) {
270
+ for (const eventKey of eventKeys) {
271
+ this.removeRecord(draftRecordKey(this.prefix, eventKey));
272
+ }
273
+ this.drafts = this.drafts.filter((draft) => !eventKeys.includes(draft.eventKeyHash));
274
+ }
275
+ restorable() {
276
+ return {
277
+ batches: this.pending
278
+ .filter((record) => record.collectionGeneration === this.generation)
279
+ .map((record) => ({
280
+ ordinal: record.ordinal,
281
+ storedBatchId: record.batchId,
282
+ events: record.events.map((event) => ({
283
+ event_key: event.eventKeyHash,
284
+ byte_length: sentByteLength(event.event),
285
+ diagnostic_canonical_bytes: canonicalJsonStringify(event.event),
286
+ })),
287
+ })),
288
+ drafts: this.drafts.filter((draft) => draft.collectionGeneration === this.generation),
289
+ };
290
+ }
291
+ bindRestoredBatch(storedBatchId, batchId) {
292
+ const record = this.pending.find((item) => item.batchId === storedBatchId);
293
+ if (record)
294
+ this.pendingByBatchId.set(batchId, record);
327
295
  }
328
296
  clear() {
329
297
  let removed = true;
@@ -355,12 +323,6 @@ export class BrowserOutbox {
355
323
  pendingEventCount() {
356
324
  return outboxEventCount(this.drafts, this.pending);
357
325
  }
358
- pendingBytes() {
359
- return browserEventsByteLength([
360
- ...this.drafts.map((item) => item.event),
361
- ...this.pending.flatMap((item) => item.events.map((event) => event.event)),
362
- ]);
363
- }
364
326
  async withDeliveryLock(operation, options = {}) {
365
327
  const locks = readLocks();
366
328
  if (!locks) {
@@ -387,23 +349,6 @@ export class BrowserOutbox {
387
349
  }
388
350
  });
389
351
  }
390
- permitsBatch(batch) {
391
- return batch.events.every((event) => this.permits(event.permit));
392
- }
393
- resolvePermit(permit) {
394
- if (!permit.permittedAtStart || this.consent === "denied")
395
- return null;
396
- if (permit.generation === UNANCHORED_COLLECTION_GENERATION) {
397
- if (!this.consentAnchorEstablished)
398
- return null;
399
- return Object.freeze({
400
- generation: this.generation,
401
- permittedAtStart: true,
402
- captureOrdinal: permit.captureOrdinal,
403
- });
404
- }
405
- return this.permits(permit) ? permit : null;
406
- }
407
352
  initializeConsentForDelivery() {
408
353
  if (this.consentStateUnavailable) {
409
354
  this.consent = "denied";
@@ -434,20 +379,6 @@ export class BrowserOutbox {
434
379
  }
435
380
  this.restoreOutbox();
436
381
  }
437
- enforceCapacity() {
438
- while (this.pendingEventCount() > this.maxEvents ||
439
- this.pendingBytes() > this.maxBytes) {
440
- const dropped = this.drafts.shift();
441
- if (!dropped)
442
- return;
443
- this.removeRecord(draftRecordKey(this.prefix, dropped.eventKeyHash));
444
- this.metrics?.increment("dropped_count");
445
- this.diagnostics.record({
446
- code: "queue_overflow",
447
- event_fingerprint: this.diagnostics.eventFingerprint(canonicalJsonStringify(dropped.event)),
448
- });
449
- }
450
- }
451
382
  purgeAll() {
452
383
  const count = this.pendingEventCount();
453
384
  let removed = this.clear();
@@ -649,7 +580,7 @@ export class BrowserOutbox {
649
580
  const draft = existingDraft ??
650
581
  createDraft({
651
582
  event,
652
- permit: this.capturePermit(),
583
+ permit: { generation: this.generation, permittedAtStart: true },
653
584
  projectHash: this.projectHash,
654
585
  createdAt: nowIso(),
655
586
  origin: "legacy_v1",
@@ -770,12 +701,6 @@ export class BrowserOutbox {
770
701
  return false;
771
702
  }
772
703
  }
773
- removeDraft(draft) {
774
- if (!this.removeRecord(draftRecordKey(this.prefix, draft.eventKeyHash)))
775
- return false;
776
- this.drafts = this.drafts.filter((item) => item !== draft);
777
- return true;
778
- }
779
704
  removeClaimedDraftRecords(record) {
780
705
  let removed = true;
781
706
  for (const eventKeyHash of record.eventKeyHashes) {
@@ -1,15 +1,13 @@
1
1
  import type { InternalMetricsStore } from "../internal/metrics.js";
2
- import { type BrowserSourceEvent } from "./source-event.js";
3
2
  import { type IngestRetryStrategy } from "./delivery-response.js";
4
3
  import type { DiagnosticStore } from "./diagnostics.js";
5
- import type { IngestUsageGovernorFeedback } from "../provider/types.js";
4
+ import type { TransportAbortCause, TransportOutcome, TransportRequest } from "./sdk-core-delivery.js";
5
+ import { type IngestEndpointDescription } from "./sdk-core-wasm.js";
6
+ import { type BrowserSourceEvent } from "./source-event.js";
6
7
  export declare const CLUEBASE_SDK_REQUEST_HEADER = "x-cluebase-sdk-request";
7
8
  export declare const CLUEBASE_SDK_VERSION_HEADER = "x-cluebase-sdk-version";
8
9
  export declare const CLUEBASE_SOURCE_SCHEMA_VERSION_HEADER = "x-cluebase-source-schema-version";
9
10
  export declare const CLUEBASE_BROWSER_TOKEN_HEADER = "x-cluebase-browser-token";
10
- export declare const CANONICAL_BROWSER_INGEST_PATH = "/api/v1/ingest/browser";
11
- export declare const CANONICAL_BROWSER_TOKEN_PATH = "/api/v1/ingest/browser-tokens";
12
- export declare const resolveCanonicalIngestEndpoint: (endpoint: string) => string;
13
11
  export type IngestClientOptions = {
14
12
  endpoint: string;
15
13
  projectKey: string;
@@ -18,27 +16,14 @@ export type IngestClientOptions = {
18
16
  schemaVersion: number;
19
17
  metrics?: InternalMetricsStore;
20
18
  diagnostics?: DiagnosticStore;
19
+ onEndpointsResolved?: (endpoints: IngestEndpointDescription) => void;
21
20
  };
22
- export declare const resolveBrowserTokenEndpoint: (endpoint: string) => string;
23
- export type SendEventsOptions = {
24
- keepalive?: boolean;
25
- useBeacon?: boolean;
26
- signal?: AbortSignal;
27
- requireCachedBrowserToken?: boolean;
28
- maxPayloadBytes?: number;
29
- metadata?: BatchEnvelopeMetadata;
30
- deadlineAt?: number;
31
- };
32
- export type SendEventsResult = {
33
- ok: boolean;
34
- status: number | null;
35
- attempts: number;
36
- governor: IngestUsageGovernorFeedback | null;
37
- retryStrategy: IngestRetryStrategy | null;
38
- observationIngestBatchId?: string;
39
- partial?: boolean;
40
- droppedEventCount?: number;
41
- reason?: string | null;
21
+ export type DeliveryTokenResult = {
22
+ readonly ok: true;
23
+ readonly token: string;
24
+ } | {
25
+ readonly ok: false;
26
+ readonly retryStrategy?: IngestRetryStrategy;
42
27
  };
43
28
  export type BatchEnvelopeMetadata = {
44
29
  batch_id: string;
@@ -47,30 +32,35 @@ export type BatchEnvelopeMetadata = {
47
32
  };
48
33
  export type { IngestRetryStrategy } from "./delivery-response.js";
49
34
  export declare class IngestClient {
50
- private readonly endpoint;
51
- private readonly browserTokenEndpoint;
35
+ private readonly configuredEndpoint;
36
+ private describedEndpoint;
37
+ private describePromise;
52
38
  private readonly projectKey;
53
- private readonly sourceIdentifier;
54
39
  private readonly producerId;
55
40
  private readonly sdkType;
56
41
  private readonly sdkVersion;
57
42
  private readonly schemaVersion;
58
43
  private readonly metrics;
59
44
  private readonly diagnostics;
45
+ private readonly onEndpointsResolved;
60
46
  private cachedToken;
61
47
  private pendingTokenRequest;
48
+ private inFlight;
62
49
  constructor(options: IngestClientOptions);
63
- send(events: BrowserSourceEvent[], options?: SendEventsOptions): Promise<SendEventsResult>;
50
+ private endpoints;
51
+ knownEndpoints(): IngestEndpointDescription | null;
52
+ perform(request: TransportRequest): Promise<TransportOutcome>;
53
+ abortAttempt(cause: TransportAbortCause): void;
64
54
  measurePayloadBytes(events: BrowserSourceEvent[], metadata?: BatchEnvelopeMetadata): number;
65
- private stringifyPayload;
66
- private withSourceEvidence;
55
+ stringifyPayload(events: BrowserSourceEvent[], metadata: BatchEnvelopeMetadata): string;
67
56
  createBatchEnvelopeMetadata(): BatchEnvelopeMetadata;
57
+ diagnosticCanonicalPayload(payload: string): string;
58
+ ensureDeliveryToken(options?: {
59
+ readonly requireCachedToken?: boolean;
60
+ readonly signal?: AbortSignal;
61
+ }): Promise<DeliveryTokenResult>;
68
62
  hasUsableBrowserToken(nowMs?: number): boolean;
69
63
  warmupBrowserToken(signal?: AbortSignal): Promise<boolean>;
70
- private failedSend;
71
- private recordDecision;
72
- private postBatch;
73
- private createId;
74
64
  private getUsableCachedBrowserToken;
75
65
  private ensureBrowserToken;
76
66
  private safeEnsureBrowserToken;