@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.
- package/README.md +21 -0
- package/dist/_generated/correlation-attribute-keys.d.ts +3 -0
- package/dist/_generated/correlation-attribute-keys.js +34 -0
- package/dist/_generated/diagnostic-codes.d.ts +4 -0
- package/dist/_generated/diagnostic-codes.js +48 -0
- package/dist/_generated/drop-reasons.d.ts +2 -0
- package/dist/_generated/drop-reasons.js +25 -0
- package/dist/_generated/{identity-pii-policy.d.ts → identity-pii-policy-text-contains.d.ts} +1 -1
- package/dist/_generated/{identity-pii-policy.js → identity-pii-policy-text-contains.js} +1 -1
- package/dist/_generated/identity-pii-policy-whole-value.d.ts +37 -0
- package/dist/_generated/identity-pii-policy-whole-value.js +106 -0
- package/dist/_generated/ingest-routes.d.ts +5 -0
- package/dist/_generated/ingest-routes.js +12 -0
- package/dist/_generated/otel-span-conversion.js +1 -9
- package/dist/context/browser-storage.js +1 -2
- package/dist/context/environment.js +5 -3
- package/dist/context/identity.js +5 -9
- package/dist/context/organization.d.ts +1 -1
- package/dist/context/organization.js +6 -8
- package/dist/context/session.js +6 -8
- package/dist/context/tab.js +8 -12
- package/dist/context/trace.js +4 -5
- package/dist/exporter/batch.d.ts +26 -27
- package/dist/exporter/batch.js +248 -294
- package/dist/exporter/browser-outbox-records.d.ts +8 -25
- package/dist/exporter/browser-outbox-records.js +21 -100
- package/dist/exporter/browser-outbox.d.ts +23 -25
- package/dist/exporter/browser-outbox.js +106 -181
- package/dist/exporter/client.d.ts +25 -35
- package/dist/exporter/client.js +107 -335
- package/dist/exporter/delivery-pipeline.d.ts +71 -0
- package/dist/exporter/delivery-pipeline.js +196 -0
- package/dist/exporter/delivery-response-contract.d.ts +1 -81
- package/dist/exporter/delivery-response-contract.js +0 -118
- package/dist/exporter/delivery-response.d.ts +9 -4
- package/dist/exporter/delivery-response.js +59 -122
- package/dist/exporter/diagnostics.d.ts +3 -2
- package/dist/exporter/diagnostics.js +5 -26
- package/dist/exporter/event-id.d.ts +1 -0
- package/dist/exporter/event-id.js +4 -3
- package/dist/exporter/frontend-resource.js +5 -4
- package/dist/exporter/observation-source-event-exporter.d.ts +2 -1
- package/dist/exporter/observation-source-event-exporter.js +7 -4
- package/dist/exporter/path-template.js +3 -1
- package/dist/exporter/raw-event-to-source-signal.js +4 -2
- package/dist/exporter/sanitize.d.ts +3 -2
- package/dist/exporter/sanitize.js +4 -3
- package/dist/exporter/sdk-core-delivery.d.ts +225 -0
- package/dist/exporter/sdk-core-delivery.js +97 -0
- package/dist/exporter/sdk-core-wasm.d.ts +11 -0
- package/dist/exporter/sdk-core-wasm.js +39 -0
- package/dist/exporter/source-event.d.ts +3 -0
- package/dist/exporter/source-event.js +17 -0
- package/dist/exporter/span-to-source-signal.d.ts +2 -2
- package/dist/exporter/span-to-source-signal.js +45 -125
- package/dist/index.d.ts +5 -4
- package/dist/index.js +18 -6
- package/dist/instrumentation/action.js +9 -8
- package/dist/instrumentation/dom.js +13 -21
- package/dist/instrumentation/drag.js +0 -3
- package/dist/instrumentation/error.js +3 -1
- package/dist/instrumentation/form.js +5 -6
- package/dist/instrumentation/input.js +4 -8
- package/dist/instrumentation/location.js +3 -1
- package/dist/instrumentation/network-request.js +1 -1
- package/dist/instrumentation/network-span-attributes.js +2 -2
- package/dist/instrumentation/network.d.ts +1 -1
- package/dist/instrumentation/network.js +24 -3
- package/dist/instrumentation/performance.js +1 -2
- package/dist/internal/internal-log.js +2 -1
- package/dist/provider/_version.d.ts +1 -1
- package/dist/provider/_version.js +1 -1
- package/dist/provider/config.js +16 -4
- package/dist/provider/constants.d.ts +1 -1
- package/dist/provider/constants.js +0 -2
- package/dist/provider/lifecycle-event-dedup.d.ts +7 -0
- package/dist/provider/lifecycle-event-dedup.js +31 -0
- package/dist/provider/sdk-event-pipeline.d.ts +3 -4
- package/dist/provider/sdk-event-pipeline.js +5 -17
- package/dist/provider/sdk-input-normalization.js +2 -2
- package/dist/provider/sdk-otel-pipeline.d.ts +2 -1
- package/dist/provider/sdk-otel-pipeline.js +7 -15
- package/dist/provider/sdk-runtime-surfaces.d.ts +17 -13
- package/dist/provider/sdk-runtime-surfaces.js +15 -13
- package/dist/provider/sdk.js +137 -48
- package/dist/provider/types.d.ts +18 -24
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.d.ts +44 -0
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.js +355 -0
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm +0 -0
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm.d.ts +11 -0
- package/dist/wasm/pkg-web/package.json +15 -0
- package/package.json +62 -53
- package/dist/provider/usage-governor.d.ts +0 -7
- 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 =
|
|
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
|
-
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
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({
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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:
|
|
182
|
+
permit: { generation: this.generation, permittedAtStart: true },
|
|
191
183
|
projectHash: this.projectHash,
|
|
192
184
|
createdAt: nowIso(),
|
|
193
185
|
});
|
|
194
186
|
if (!draft)
|
|
195
|
-
return
|
|
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
|
|
193
|
+
return draft;
|
|
202
194
|
}
|
|
203
195
|
this.diagnostics.record({ code: "outbox_key_collision" });
|
|
204
|
-
return
|
|
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
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
-
|
|
252
|
-
drafts: selected,
|
|
253
|
-
ordinal: this.nextOrdinal,
|
|
258
|
+
createdAt: nowIso(),
|
|
254
259
|
});
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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.
|
|
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 {
|
|
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
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
51
|
-
private
|
|
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
|
-
|
|
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
|
-
|
|
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;
|