avo-inspector 3.2.0 → 3.2.3

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 (84) hide show
  1. package/README.md +10 -0
  2. package/dist/AvoBatcher.d.ts +9 -3
  3. package/dist/AvoInspector.d.ts +4 -0
  4. package/dist/AvoNetworkCallsHandler.d.ts +80 -5
  5. package/dist/__tests__/UnboundPublicMethods_test.d.ts +1 -0
  6. package/dist/__tests__/constants.d.ts +2 -1
  7. package/dist/__tests__/helpers/internalGateway.d.ts +23 -0
  8. package/dist/eventSpec/AvoEventSpecCache.d.ts +7 -4
  9. package/dist/eventSpec/AvoEventSpecFetchTypes.d.ts +12 -1
  10. package/dist/eventSpec/AvoEventSpecFetcher.d.ts +6 -1
  11. package/dist/index.js +1 -1
  12. package/dist/lite/AvoBatcherLite.d.ts +9 -3
  13. package/dist/lite/AvoBatcherLite.js +46 -7
  14. package/dist/lite/AvoInspectorLite.d.ts +2 -0
  15. package/dist/lite/AvoInspectorLite.js +95 -15
  16. package/dist/lite/AvoNetworkCallsHandlerLite.d.ts +79 -5
  17. package/dist/lite/AvoNetworkCallsHandlerLite.js +300 -20
  18. package/package.json +10 -1
  19. package/dist/AvoBatcher.js +0 -87
  20. package/dist/AvoDeduplicator.js +0 -142
  21. package/dist/AvoEncryption.js +0 -176
  22. package/dist/AvoInspector.js +0 -435
  23. package/dist/AvoNetworkCallsHandler.js +0 -229
  24. package/dist/AvoSchemaParser.js +0 -95
  25. package/dist/AvoStreamId.js +0 -82
  26. package/dist/__mocks__/xhr.js +0 -14
  27. package/dist/__mocks__/xhrError.js +0 -14
  28. package/dist/__tests__/AvoEncryption.js +0 -272
  29. package/dist/__tests__/AvoEncryptionIntegration.js +0 -191
  30. package/dist/__tests__/AvoEventSpecFetcher.js +0 -377
  31. package/dist/__tests__/AvoInspector.js +0 -335
  32. package/dist/__tests__/Batcher.js +0 -214
  33. package/dist/__tests__/BatcherPublic.js +0 -139
  34. package/dist/__tests__/Deduplicator.js +0 -190
  35. package/dist/__tests__/EventSpecCache.js +0 -143
  36. package/dist/__tests__/EventValidator.js +0 -543
  37. package/dist/__tests__/InstallationId.js +0 -60
  38. package/dist/__tests__/NetworkCallsHandler.js +0 -222
  39. package/dist/__tests__/NetworkCallsHandlerModelA.js +0 -206
  40. package/dist/__tests__/Parsing.js +0 -115
  41. package/dist/__tests__/Sessions.d.ts +0 -1
  42. package/dist/__tests__/Sessions.js +0 -10
  43. package/dist/__tests__/Storage.d.ts +0 -1
  44. package/dist/__tests__/Storage.js +0 -173
  45. package/dist/__tests__/StreamId.d.ts +0 -1
  46. package/dist/__tests__/StreamId.js +0 -153
  47. package/dist/__tests__/constants.js +0 -48
  48. package/dist/esm/AvoBatcher.js +0 -75
  49. package/dist/esm/AvoDeduplicator.js +0 -137
  50. package/dist/esm/AvoEncryption.js +0 -277
  51. package/dist/esm/AvoGuid.js +0 -9
  52. package/dist/esm/AvoInspector.js +0 -470
  53. package/dist/esm/AvoInspectorEnv.js +0 -5
  54. package/dist/esm/AvoNetworkCallsHandler.js +0 -181
  55. package/dist/esm/AvoSchemaParser.js +0 -128
  56. package/dist/esm/AvoStorage.js +0 -176
  57. package/dist/esm/AvoStreamId.js +0 -140
  58. package/dist/esm/eventSpec/AvoEventSpecCache.js +0 -165
  59. package/dist/esm/eventSpec/AvoEventSpecFetchTypes.js +0 -6
  60. package/dist/esm/eventSpec/AvoEventSpecFetcher.js +0 -203
  61. package/dist/esm/eventSpec/EventValidator.js +0 -687
  62. package/dist/esm/eventSpec/index.js +0 -4
  63. package/dist/esm/index.js +0 -3
  64. package/dist/esm/utils.js +0 -38
  65. package/dist/esm/version.js +0 -2
  66. package/dist/eventSpec/AvoEventSpecCache.js +0 -181
  67. package/dist/eventSpec/AvoEventSpecFetcher.js +0 -290
  68. package/dist/eventSpec/EventValidator.js +0 -846
  69. package/dist/eventSpec/index.js +0 -20
  70. package/dist/version.d.ts +0 -1
  71. package/dist/version.js +0 -5
  72. /package/dist/__tests__/{AvoEncryption.d.ts → ApiKeyHeaderInjection_test.d.ts} +0 -0
  73. /package/dist/__tests__/{AvoEncryptionIntegration.d.ts → BrowserBootstrap_test.d.ts} +0 -0
  74. /package/dist/__tests__/{AvoEventSpecFetcher.d.ts → EventSpecGatewayCoordinates_test.d.ts} +0 -0
  75. /package/dist/__tests__/{AvoInspector.d.ts → InFlightQueueGaps_test.d.ts} +0 -0
  76. /package/dist/__tests__/{Batcher.d.ts → InFlightQueue_test.d.ts} +0 -0
  77. /package/dist/__tests__/{BatcherPublic.d.ts → NetworkCallsHandlerLite_test.d.ts} +0 -0
  78. /package/dist/__tests__/{Deduplicator.d.ts → PublicSurface_test.d.ts} +0 -0
  79. /package/dist/__tests__/{EventSpecCache.d.ts → TrackOptionsIntegration_test.d.ts} +0 -0
  80. /package/dist/__tests__/{EventValidator.d.ts → TrackOptionsTransport_test.d.ts} +0 -0
  81. /package/dist/__tests__/{InstallationId.d.ts → TrackingHeaders_test.d.ts} +0 -0
  82. /package/dist/__tests__/{NetworkCallsHandler.d.ts → V1WireBaseline_test.d.ts} +0 -0
  83. /package/dist/__tests__/{NetworkCallsHandlerModelA.d.ts → V2QueuedAttribution_test.d.ts} +0 -0
  84. /package/dist/__tests__/{Parsing.d.ts → V2StopSending_test.d.ts} +0 -0
@@ -1,470 +0,0 @@
1
- import { AvoInspectorEnv } from "./AvoInspectorEnv";
2
- import { AvoSchemaParser } from "./AvoSchemaParser";
3
- import { AvoBatcher } from "./AvoBatcher";
4
- import { AvoNetworkCallsHandler } from "./AvoNetworkCallsHandler";
5
- import { AvoStorage } from "./AvoStorage";
6
- import { AvoDeduplicator } from "./AvoDeduplicator";
7
- import { AvoStreamId } from "./AvoStreamId";
8
- import { isValueEmpty } from "./utils";
9
- import { LIB_VERSION } from "./version";
10
- const libVersion = LIB_VERSION;
11
- export class AvoInspector {
12
- static get batchSize() {
13
- return this._batchSize;
14
- }
15
- static set batchSize(newSize) {
16
- if (newSize < 1) {
17
- this._batchSize = 1;
18
- }
19
- else {
20
- this._batchSize = newSize;
21
- }
22
- }
23
- static get batchFlushSeconds() {
24
- return this._batchFlushSeconds;
25
- }
26
- static get shouldLog() {
27
- return this._shouldLog;
28
- }
29
- static set shouldLog(enable) {
30
- this._shouldLog = enable;
31
- }
32
- static get networkTimeout() {
33
- return this._networkTimeout;
34
- }
35
- static set networkTimeout(timeout) {
36
- this._networkTimeout = timeout;
37
- }
38
- constructor(options) {
39
- this.currentBranchId = null;
40
- // the constructor does aggressive null/undefined checking because same code paths will be accessible from JS
41
- if (isValueEmpty(options.env)) {
42
- this.environment = AvoInspectorEnv.Dev;
43
- console.warn("[Avo Inspector] No environment provided. Defaulting to dev.");
44
- }
45
- else if (!Object.values(AvoInspectorEnv).includes(options.env)) {
46
- this.environment = AvoInspectorEnv.Dev;
47
- console.warn("[Avo Inspector] Unsupported environment provided. Defaulting to dev. Supported environments - Dev, Staging, Prod.");
48
- }
49
- else {
50
- this.environment = options.env;
51
- }
52
- if (isValueEmpty(options.apiKey)) {
53
- throw new Error("[Avo Inspector] No API key provided. Inspector can't operate without API key.");
54
- }
55
- else {
56
- this.apiKey = options.apiKey;
57
- }
58
- if (isValueEmpty(options.version)) {
59
- throw new Error("[Avo Inspector] No version provided. Many features of Inspector rely on versioning. Please provide comparable string version, i.e. integer or semantic.");
60
- }
61
- else {
62
- this.version = options.version;
63
- }
64
- if (this.environment === AvoInspectorEnv.Dev) {
65
- AvoInspector._batchSize = 1;
66
- AvoInspector._shouldLog = true;
67
- }
68
- else {
69
- AvoInspector._batchSize = 30;
70
- AvoInspector._batchFlushSeconds = 30;
71
- AvoInspector._shouldLog = false;
72
- }
73
- AvoInspector.avoStorage = new AvoStorage(AvoInspector._shouldLog, options.suffix != null ? options.suffix : "");
74
- this.publicEncryptionKey = options.publicEncryptionKey;
75
- this.avoNetworkCallsHandler = new AvoNetworkCallsHandler(this.apiKey, this.environment.toString(), options.appName || "", this.version, libVersion, this.publicEncryptionKey);
76
- this.avoBatcher = new AvoBatcher(this.avoNetworkCallsHandler);
77
- this.avoDeduplicator = new AvoDeduplicator();
78
- this.streamId = AvoStreamId.streamId;
79
- // Enable event spec fetching if streamId is present (note: "unknown" is truthy and will trigger initEventSpecModules; see streamId edge case in spec)
80
- if (this.streamId && this.environment !== AvoInspectorEnv.Prod) {
81
- this._eventSpecReady = this.initEventSpecModules();
82
- }
83
- }
84
- async initEventSpecModules() {
85
- // ORDERING CONSTRAINT: All instance field assignments (this.eventSpecCache,
86
- // this.eventSpecFetcher, this._validateEvent) MUST occur inside the try block,
87
- // before the finally block clears this._eventSpecReady. The finally block sets
88
- // this._eventSpecReady = undefined to signal completion. Concurrent callers that
89
- // await this._eventSpecReady (via ensureEventSpecReady) will resume after the
90
- // finally block executes. If any field assignment were moved to or after the
91
- // finally block, those concurrent callers would find fields unpopulated, creating
92
- // a race condition where they incorrectly proceed as if no event spec is available.
93
- try {
94
- const [{ EventSpecCache }, { AvoEventSpecFetcher }, { validateEvent }] = await Promise.all([
95
- import("./eventSpec/AvoEventSpecCache"),
96
- import("./eventSpec/AvoEventSpecFetcher"),
97
- import("./eventSpec/EventValidator")
98
- ]);
99
- this.eventSpecCache = new EventSpecCache(AvoInspector._shouldLog);
100
- this.eventSpecFetcher = new AvoEventSpecFetcher(AvoInspector._networkTimeout, AvoInspector._shouldLog, this.environment);
101
- this._validateEvent = validateEvent;
102
- if (AvoInspector._shouldLog) {
103
- console.log("[Avo Inspector] Event spec fetching and validation enabled");
104
- if (this.publicEncryptionKey) {
105
- console.log("[Avo Inspector] Property value encryption enabled");
106
- }
107
- }
108
- }
109
- catch (error) {
110
- if (AvoInspector._shouldLog) {
111
- console.error("[Avo Inspector] Failed to load event spec modules:", error);
112
- }
113
- }
114
- finally {
115
- this._eventSpecReady = undefined;
116
- }
117
- }
118
- async ensureEventSpecReady() {
119
- if (this.environment === AvoInspectorEnv.Prod)
120
- return null;
121
- if (this._eventSpecReady)
122
- await this._eventSpecReady;
123
- if (!this.eventSpecCache || !this.eventSpecFetcher || !this.streamId || !this._validateEvent)
124
- return null;
125
- return {
126
- cache: this.eventSpecCache,
127
- fetcher: this.eventSpecFetcher,
128
- validate: this._validateEvent,
129
- streamId: this.streamId,
130
- };
131
- }
132
- async trackSchemaFromEvent(eventName, eventProperties) {
133
- try {
134
- if (this.avoDeduplicator.shouldRegisterEvent(eventName, eventProperties, false)) {
135
- if (AvoInspector.shouldLog) {
136
- console.log("Avo Inspector: supplied event " +
137
- eventName +
138
- " with params " +
139
- JSON.stringify(eventProperties));
140
- }
141
- const eventSchema = await this.extractSchema(eventProperties, false);
142
- // Fetch and validate event spec (sync blocking)
143
- const validationResult = await this.fetchAndValidateEvent(eventName, eventProperties);
144
- if (validationResult) {
145
- // Spec available: merge validation results into schema and send immediately
146
- const schemaWithValidation = this.mergeValidationResults(eventSchema, validationResult);
147
- this.sendEventWithValidation(eventName, schemaWithValidation, null, null, validationResult);
148
- }
149
- else {
150
- // No spec: fall back to batched flow
151
- this.trackSchemaInternal(eventName, eventSchema, null, null);
152
- }
153
- return eventSchema;
154
- }
155
- else {
156
- if (AvoInspector.shouldLog) {
157
- console.log("Avo Inspector: Deduplicated event: " + eventName);
158
- }
159
- return [];
160
- }
161
- }
162
- catch (e) {
163
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e);
164
- return [];
165
- }
166
- }
167
- async _avoFunctionTrackSchemaFromEvent(eventName, eventProperties, eventId, eventHash) {
168
- try {
169
- if (this.avoDeduplicator.shouldRegisterEvent(eventName, eventProperties, true)) {
170
- if (AvoInspector.shouldLog) {
171
- console.log("Avo Inspector: supplied event " +
172
- eventName +
173
- " with params " +
174
- JSON.stringify(eventProperties));
175
- }
176
- const eventSchema = await this.extractSchema(eventProperties, false);
177
- // Fetch and validate event spec (sync blocking)
178
- const validationResult = await this.fetchAndValidateEvent(eventName, eventProperties);
179
- if (validationResult) {
180
- // Spec available: merge validation results into schema and send immediately
181
- const schemaWithValidation = this.mergeValidationResults(eventSchema, validationResult);
182
- this.sendEventWithValidation(eventName, schemaWithValidation, eventId, eventHash, validationResult);
183
- }
184
- else {
185
- // No spec: fall back to batched flow
186
- this.trackSchemaInternal(eventName, eventSchema, eventId, eventHash);
187
- }
188
- return eventSchema;
189
- }
190
- else {
191
- if (AvoInspector.shouldLog) {
192
- console.log("Avo Inspector: Deduplicated event: " + eventName);
193
- }
194
- return [];
195
- }
196
- }
197
- catch (e) {
198
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e);
199
- return [];
200
- }
201
- }
202
- async trackSchema(eventName, eventSchema) {
203
- try {
204
- if (await this.avoDeduplicator.shouldRegisterSchemaFromManually(eventName, eventSchema)) {
205
- if (AvoInspector.shouldLog) {
206
- console.log("Avo Inspector: supplied event " +
207
- eventName +
208
- " with schema " +
209
- JSON.stringify(eventSchema));
210
- }
211
- // For trackSchema we don't have raw properties, so we can't validate
212
- // Just fetch/cache spec for future use and use batched flow
213
- await this.fetchEventSpecIfNeeded(eventName);
214
- this.trackSchemaInternal(eventName, eventSchema, null, null);
215
- }
216
- else {
217
- if (AvoInspector.shouldLog) {
218
- console.log("Avo Inspector: Deduplicated event: " + eventName);
219
- }
220
- }
221
- }
222
- catch (e) {
223
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e);
224
- }
225
- }
226
- trackSchemaInternal(eventName, eventSchema, eventId, eventHash) {
227
- try {
228
- this.avoBatcher.handleTrackSchema(eventName, eventSchema, eventId, eventHash);
229
- }
230
- catch (e) {
231
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e);
232
- }
233
- }
234
- enableLogging(enable) {
235
- AvoInspector._shouldLog = enable;
236
- }
237
- async extractSchema(eventProperties, shouldLogIfEnabled = true) {
238
- try {
239
- if (this.avoDeduplicator.hasSeenEventParams(eventProperties, true)) {
240
- if (shouldLogIfEnabled && AvoInspector.shouldLog) {
241
- console.warn("Avo Inspector: WARNING! You are trying to extract schema shape that was just reported by your Avo Codegen. " +
242
- "This is an indicator of duplicate inspector reporting. " +
243
- "Please reach out to support@avo.app for advice if you are not sure how to handle this.");
244
- }
245
- }
246
- if (AvoInspector.shouldLog) {
247
- console.log("Avo Inspector: extracting schema from " +
248
- JSON.stringify(eventProperties));
249
- }
250
- return await AvoSchemaParser.extractSchema(eventProperties, this.publicEncryptionKey, this.environment);
251
- }
252
- catch (e) {
253
- console.error("Avo Inspector: something went wrong in extractSchema. Please report to support@avo.app.", e);
254
- return [];
255
- }
256
- }
257
- setBatchSize(newBatchSize) {
258
- AvoInspector._batchSize = newBatchSize;
259
- }
260
- setBatchFlushSeconds(newBatchFlushSeconds) {
261
- AvoInspector._batchFlushSeconds = newBatchFlushSeconds;
262
- }
263
- /**
264
- * Handles branch change detection and cache storage for a fetched event spec.
265
- * This logic is shared between fetchEventSpecIfNeeded and fetchAndValidateEvent.
266
- */
267
- handleBranchChangeAndCache(specResponse, eventName) {
268
- // Check for branch change
269
- const newBranchId = specResponse.metadata.branchId;
270
- if (this.currentBranchId !== null && this.currentBranchId !== newBranchId) {
271
- if (AvoInspector.shouldLog) {
272
- console.log(`[Avo Inspector] Branch changed from ${this.currentBranchId} to ${newBranchId}. Flushing cache.`);
273
- }
274
- this.eventSpecCache?.clear();
275
- }
276
- this.currentBranchId = newBranchId;
277
- // Store in cache
278
- if (this.eventSpecCache && this.streamId) {
279
- this.eventSpecCache.set(this.apiKey, this.streamId, eventName, specResponse);
280
- }
281
- }
282
- /**
283
- * Fetches the event spec if spec fetching is enabled.
284
- * Used by trackSchema when we don't have raw properties to validate.
285
- *
286
- * Note: EventSpec fetching only happens in dev/staging environments.
287
- */
288
- async fetchEventSpecIfNeeded(eventName) {
289
- const spec = await this.ensureEventSpecReady();
290
- if (!spec)
291
- return;
292
- try {
293
- // Check cache first (includes cached empty responses)
294
- if (spec.cache.contains(this.apiKey, spec.streamId, eventName)) {
295
- const cached = spec.cache.get(this.apiKey, spec.streamId, eventName);
296
- if (!cached) {
297
- // Cached empty response — no spec exists for this event
298
- if (AvoInspector.shouldLog) {
299
- console.log(`[Avo Inspector] Cache hit (empty) for event: ${eventName}. Sending without validation.`);
300
- }
301
- }
302
- return;
303
- }
304
- // Cache miss - fetch from API (blocking)
305
- const specResponse = await spec.fetcher.fetch({
306
- apiKey: this.apiKey,
307
- streamId: spec.streamId,
308
- eventName
309
- });
310
- if (specResponse) {
311
- this.handleBranchChangeAndCache(specResponse, eventName);
312
- }
313
- else {
314
- // Cache the empty response so we don't re-fetch
315
- spec.cache.set(this.apiKey, spec.streamId, eventName, null);
316
- if (AvoInspector.shouldLog) {
317
- console.log(`[Avo Inspector] Event spec fetch returned null for event: ${eventName}. Cached empty response.`);
318
- }
319
- }
320
- }
321
- catch (error) {
322
- // Graceful degradation - log but don't fail
323
- if (AvoInspector.shouldLog) {
324
- console.error(`[Avo Inspector] Error fetching event spec for ${eventName}:`, error);
325
- }
326
- }
327
- }
328
- /**
329
- * Fetches event spec and validates the event against it.
330
- * Returns ValidationResult if spec is available, null otherwise.
331
- *
332
- * Note: EventSpec fetching and validation only happens in dev/staging environments.
333
- */
334
- async fetchAndValidateEvent(eventName, eventProperties) {
335
- const spec = await this.ensureEventSpecReady();
336
- if (!spec)
337
- return null;
338
- try {
339
- // Check cache first (includes cached empty responses)
340
- if (spec.cache.contains(this.apiKey, spec.streamId, eventName)) {
341
- const cached = spec.cache.get(this.apiKey, spec.streamId, eventName);
342
- if (cached) {
343
- if (AvoInspector.shouldLog) {
344
- console.log(`[Avo Inspector] Cache hit for event: ${eventName}`);
345
- }
346
- return spec.validate(eventProperties, cached);
347
- }
348
- else {
349
- // Cached empty response — no spec exists for this event
350
- if (AvoInspector.shouldLog) {
351
- console.log(`[Avo Inspector] Cache hit (empty) for event: ${eventName}. Sending without validation.`);
352
- }
353
- return null;
354
- }
355
- }
356
- // Cache miss - fetch from API (blocking)
357
- const specResponse = await spec.fetcher.fetch({
358
- apiKey: this.apiKey,
359
- streamId: spec.streamId,
360
- eventName
361
- });
362
- if (specResponse) {
363
- this.handleBranchChangeAndCache(specResponse, eventName);
364
- return spec.validate(eventProperties, specResponse);
365
- }
366
- else {
367
- // Cache the empty response so we don't re-fetch
368
- spec.cache.set(this.apiKey, spec.streamId, eventName, null);
369
- if (AvoInspector.shouldLog) {
370
- console.log(`[Avo Inspector] Event spec fetch returned null for event: ${eventName}. Cached empty response.`);
371
- }
372
- return null;
373
- }
374
- }
375
- catch (error) {
376
- // Graceful degradation - log but don't fail
377
- if (AvoInspector.shouldLog) {
378
- console.error(`[Avo Inspector] Error validating event ${eventName}:`, error);
379
- }
380
- return null;
381
- }
382
- }
383
- /**
384
- * Merges validation results into the event schema.
385
- * Adds failedEventIds or passedEventIds to each property based on validation.
386
- * Recursively merges validation results for nested children.
387
- */
388
- mergeValidationResults(eventSchema, validationResult) {
389
- return eventSchema.map((prop) => {
390
- const propValidation = validationResult.propertyResults[prop.propertyName];
391
- return this.mergePropertyValidation(prop, propValidation);
392
- });
393
- }
394
- /**
395
- * Merges validation result into a single property, recursively handling children.
396
- */
397
- mergePropertyValidation(prop, propValidation) {
398
- const result = {
399
- propertyName: prop.propertyName,
400
- propertyType: prop.propertyType
401
- };
402
- if (prop.encryptedPropertyValue) {
403
- result.encryptedPropertyValue = prop.encryptedPropertyValue;
404
- }
405
- // Recursively merge validation results into children
406
- if (prop.children && Array.isArray(prop.children)) {
407
- result.children = prop.children.map((child) => {
408
- // Children can be strings (for array types) or objects (for nested properties)
409
- if (typeof child === 'string') {
410
- return child;
411
- }
412
- if (child && typeof child === 'object' && child.propertyName) {
413
- // Get nested validation result for this child
414
- const childValidation = propValidation?.children?.[child.propertyName];
415
- return this.mergePropertyValidation(child, childValidation);
416
- }
417
- return child;
418
- });
419
- }
420
- // Add validation result for this property
421
- if (propValidation) {
422
- if (propValidation.failedEventIds) {
423
- result.failedEventIds = propValidation.failedEventIds;
424
- }
425
- if (propValidation.passedEventIds) {
426
- result.passedEventIds = propValidation.passedEventIds;
427
- }
428
- }
429
- return result;
430
- }
431
- /**
432
- * Sends an event immediately with validation data (bypasses batching).
433
- * Logs validation info if shouldLog is true.
434
- */
435
- sendEventWithValidation(eventName, eventSchema, eventId, eventHash, validationResult) {
436
- // Log validation info if shouldLog is enabled
437
- if (AvoInspector.shouldLog) {
438
- const hasFailures = eventSchema.some((p) => p.failedEventIds && p.failedEventIds.length > 0);
439
- if (hasFailures) {
440
- console.log(`[Avo Inspector] Validation failures for event "${eventName}":`, eventSchema
441
- .filter((p) => p.failedEventIds && p.failedEventIds.length > 0)
442
- .map((p) => ({
443
- property: p.propertyName,
444
- failedEventIds: p.failedEventIds
445
- })));
446
- }
447
- }
448
- // Create the event body with validation data
449
- const eventBody = this.avoNetworkCallsHandler.bodyForEventSchemaCall(eventName, eventSchema, eventId, eventHash, validationResult.metadata ?? undefined, validationResult.metadata?.branchId);
450
- // Send immediately (bypass batching)
451
- this.avoNetworkCallsHandler.callInspectorImmediately(eventBody, (error) => {
452
- if (error) {
453
- if (AvoInspector.shouldLog) {
454
- console.error(`[Avo Inspector] Failed to send event "${eventName}" with validation:`, error);
455
- }
456
- // Fallback: add to batch on failure (without validation data)
457
- this.avoBatcher.handleTrackSchema(eventName, eventSchema, eventId, eventHash);
458
- }
459
- else {
460
- if (AvoInspector.shouldLog) {
461
- console.log(`[Avo Inspector] Event "${eventName}" sent successfully with validation`);
462
- }
463
- }
464
- });
465
- }
466
- }
467
- AvoInspector._batchSize = 30;
468
- AvoInspector._batchFlushSeconds = 30;
469
- AvoInspector._shouldLog = false;
470
- AvoInspector._networkTimeout = 2000;
@@ -1,5 +0,0 @@
1
- export const AvoInspectorEnv = {
2
- Prod: "prod",
3
- Dev: "dev",
4
- Staging: "staging"
5
- };
@@ -1,181 +0,0 @@
1
- import AvoGuid from "./AvoGuid";
2
- import { AvoInspector } from "./AvoInspector";
3
- import { AvoStreamId } from "./AvoStreamId";
4
- export class AvoNetworkCallsHandler {
5
- constructor(apiKey, envName, appName, appVersion, libVersion, publicEncryptionKey) {
6
- this.samplingRate = 1.0;
7
- this.sending = false;
8
- this.apiKey = apiKey;
9
- this.envName = envName;
10
- this.appName = appName;
11
- this.appVersion = appVersion;
12
- this.libVersion = libVersion;
13
- this.publicEncryptionKey = publicEncryptionKey;
14
- }
15
- callInspectorWithBatchBody(inEvents, onCompleted) {
16
- if (this.sending) {
17
- onCompleted(new Error("Batch sending cancelled because another batch sending is in progress. Your events will be sent with next batch."));
18
- return;
19
- }
20
- const events = inEvents.filter((x) => x != null);
21
- this.fixStreamIds(events);
22
- if (events.length === 0) {
23
- return;
24
- }
25
- if (this.shouldDropBySampling()) {
26
- if (AvoInspector.shouldLog) {
27
- console.log("Avo Inspector: last event schema dropped due to sampling rate.");
28
- }
29
- return;
30
- }
31
- if (AvoInspector.shouldLog) {
32
- console.log("Avo Inspector: events", events);
33
- events.forEach((event) => {
34
- if (event.type === "sessionStarted") {
35
- console.log("Avo Inspector: sending session started event.");
36
- }
37
- else if (event.type === "event") {
38
- console.log("Avo Inspector: sending event " +
39
- event.eventName +
40
- " with schema " +
41
- JSON.stringify(event.eventProperties));
42
- }
43
- });
44
- }
45
- this.sending = true;
46
- this.callInspectorApi(events, (error) => {
47
- this.sending = false;
48
- onCompleted(error);
49
- });
50
- }
51
- fixStreamIds(events) {
52
- let knownStreamId = null;
53
- events.forEach(function (event) {
54
- if (event.streamId !== null &&
55
- event.streamId !== undefined &&
56
- event.streamId !== "unknown") {
57
- knownStreamId = event.streamId;
58
- }
59
- });
60
- events.forEach(function (event) {
61
- if (event.streamId === "unknown") {
62
- if (knownStreamId != null) {
63
- event.streamId = knownStreamId;
64
- }
65
- else {
66
- event.streamId = AvoStreamId.streamId;
67
- }
68
- }
69
- });
70
- }
71
- bodyForSessionStartedCall() {
72
- const sessionBody = this.createBaseCallBody();
73
- sessionBody.type = "sessionStarted";
74
- return sessionBody;
75
- }
76
- bodyForEventSchemaCall(eventName, eventProperties, eventId, eventHash, eventSpecMetadata, validatedBranchId) {
77
- const eventSchemaBody = this.createBaseCallBody();
78
- eventSchemaBody.type = "event";
79
- eventSchemaBody.eventName = eventName;
80
- eventSchemaBody.eventProperties = eventProperties;
81
- if (eventId != null) {
82
- eventSchemaBody.avoFunction = true;
83
- eventSchemaBody.eventId = eventId;
84
- eventSchemaBody.eventHash = eventHash;
85
- }
86
- else {
87
- eventSchemaBody.avoFunction = false;
88
- eventSchemaBody.eventId = null;
89
- eventSchemaBody.eventHash = null;
90
- }
91
- // Set metadata on base body if provided
92
- if (eventSpecMetadata) {
93
- eventSchemaBody.eventSpecMetadata = eventSpecMetadata;
94
- }
95
- // Set validated branch ID if value validation was performed
96
- if (validatedBranchId) {
97
- eventSchemaBody.validatedBranchId = validatedBranchId;
98
- }
99
- return eventSchemaBody;
100
- }
101
- createBaseCallBody() {
102
- const body = {
103
- apiKey: this.apiKey,
104
- appName: this.appName,
105
- appVersion: this.appVersion,
106
- libVersion: this.libVersion,
107
- env: this.envName,
108
- libPlatform: "web",
109
- messageId: AvoGuid.newGuid(),
110
- trackingId: "",
111
- createdAt: new Date().toISOString(),
112
- sessionId: "",
113
- streamId: AvoStreamId.streamId,
114
- samplingRate: this.samplingRate
115
- };
116
- if (this.publicEncryptionKey) {
117
- body.publicEncryptionKey = this.publicEncryptionKey;
118
- }
119
- return body;
120
- }
121
- /**
122
- * Calls Inspector API immediately with a single event (bypasses batching).
123
- * Used when event spec validation is available.
124
- * Note: Does not drop due to sampling - validated events are always sent.
125
- */
126
- callInspectorImmediately(eventBody, onCompleted) {
127
- // Fix stream ID if needed
128
- if (eventBody.streamId === "unknown") {
129
- eventBody.streamId = AvoStreamId.streamId;
130
- }
131
- if (AvoInspector.shouldLog) {
132
- console.log("Avo Inspector: calling inspector immediately (with validation)", eventBody.eventName);
133
- console.log("Avo Inspector: event body", eventBody);
134
- }
135
- this.callInspectorApi([eventBody], onCompleted);
136
- }
137
- /**
138
- * Check if event should be dropped based on sampling rate.
139
- */
140
- shouldDropBySampling() {
141
- return Math.random() > this.samplingRate;
142
- }
143
- /**
144
- * Core Inspector API call logic shared by batch and immediate calls.
145
- */
146
- callInspectorApi(events, onCompleted) {
147
- const xmlhttp = new XMLHttpRequest();
148
- xmlhttp.open("POST", AvoNetworkCallsHandler.trackingEndpoint, true);
149
- xmlhttp.setRequestHeader("Content-Type", "text/plain");
150
- xmlhttp.timeout = AvoInspector.networkTimeout;
151
- xmlhttp.send(JSON.stringify(events));
152
- xmlhttp.onload = () => {
153
- if (xmlhttp.status !== 200) {
154
- onCompleted(new Error(`Error ${xmlhttp.status}: ${xmlhttp.statusText}`));
155
- }
156
- else {
157
- let response;
158
- try {
159
- response = JSON.parse(xmlhttp.response);
160
- }
161
- catch (e) {
162
- onCompleted(new Error(`Failed to parse response: ${e instanceof Error ? e.message : String(e)}`));
163
- return;
164
- }
165
- if (response != null &&
166
- typeof response.samplingRate === "number" &&
167
- !isNaN(response.samplingRate)) {
168
- this.samplingRate = response.samplingRate;
169
- }
170
- onCompleted(null);
171
- }
172
- };
173
- xmlhttp.onerror = () => {
174
- onCompleted(new Error("Request failed"));
175
- };
176
- xmlhttp.ontimeout = () => {
177
- onCompleted(new Error("Request timed out"));
178
- };
179
- }
180
- }
181
- AvoNetworkCallsHandler.trackingEndpoint = "https://api.avo.app/inspector/v1/track";