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,176 +0,0 @@
1
- "use strict";
2
- /**
3
- * AvoEncryption — React Native ECIES encryption using @noble/ciphers.
4
- *
5
- * CRITICAL: React Native's Hermes runtime does NOT have crypto.subtle.
6
- * This module uses @noble/ciphers/aes gcm() for AES-GCM instead — fully synchronous.
7
- * Ephemeral key generation and ECDH use @noble/curves/p256.
8
- *
9
- * Wire format (MUST match all SDKs):
10
- * [0x00][65-byte ephemeral pubkey (uncompressed)][16-byte IV][16-byte auth tag][ciphertext]
11
- * → base64
12
- *
13
- * Algorithm:
14
- * 1. Generate ephemeral P-256 key pair
15
- * 2. ECDH: ephemeral private key + recipient public key → shared secret (X-coordinate)
16
- * 3. KDF: SHA-256(shared secret) → 32-byte AES key
17
- * 4. AES-256-GCM encrypt with random 16-byte IV
18
- * 5. Serialize: version(1) + ephemeralPubKey(65) + IV(16) + authTag(16) + ciphertext
19
- * 6. Base64 encode
20
- */
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.shouldEncrypt = shouldEncrypt;
23
- exports.encryptValue = encryptValue;
24
- exports.encryptEventProperties = encryptEventProperties;
25
- var p256_1 = require("@noble/curves/p256");
26
- var aes_1 = require("@noble/ciphers/aes");
27
- var sha256_1 = require("@noble/hashes/sha256");
28
- var webcrypto_1 = require("@noble/ciphers/webcrypto");
29
- /**
30
- * Converts a hex string to a Uint8Array.
31
- * Strips optional 0x/0X prefix (matching Android SDK behavior).
32
- */
33
- function hexToBytes(hex) {
34
- if (hex.startsWith("0x") || hex.startsWith("0X")) {
35
- hex = hex.substring(2);
36
- }
37
- var bytes = new Uint8Array(hex.length / 2);
38
- for (var i = 0; i < hex.length; i += 2) {
39
- bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
40
- }
41
- return bytes;
42
- }
43
- /**
44
- * Determines whether encryption should be performed.
45
- *
46
- * Truth table:
47
- * dev + key → true
48
- * staging + key → true
49
- * prod + key → false
50
- * dev + null → false
51
- * dev + empty → false
52
- */
53
- function shouldEncrypt(env, publicEncryptionKey) {
54
- if (env === "prod")
55
- return false;
56
- if (publicEncryptionKey === null ||
57
- publicEncryptionKey === undefined ||
58
- publicEncryptionKey.trim().length === 0) {
59
- return false;
60
- }
61
- return true;
62
- }
63
- /**
64
- * Encrypts a value using ECIES (P-256 ECDH + AES-256-GCM).
65
- * Fully synchronous — no async/await.
66
- *
67
- * @param value - The plaintext string to encrypt (already JSON-stringified by caller if needed)
68
- * @param publicKeyHex - The recipient's P-256 public key as a hex string (uncompressed, 04...)
69
- * @returns Base64-encoded ciphertext in Avo ECIES wire format
70
- */
71
- function encryptValue(value, publicKeyHex) {
72
- // Fail fast with a helpful message when running in React Native without the polyfill.
73
- // Node.js and browsers provide crypto natively; only Hermes (RN) lacks it.
74
- if (!process.env.BROWSER &&
75
- typeof navigator !== "undefined" && navigator.product === "ReactNative" &&
76
- (typeof globalThis.crypto === "undefined" || typeof globalThis.crypto.getRandomValues !== "function")) {
77
- throw new Error("crypto.getRandomValues is not available. " +
78
- "If you are using React Native, add 'react-native-get-random-values' to your project " +
79
- "and import it at the top of your entry file (index.js) before any other imports: " +
80
- "import 'react-native-get-random-values';");
81
- }
82
- // 1. Parse recipient public key from hex
83
- var recipientPublicKeyBytes = hexToBytes(publicKeyHex);
84
- // 2. Generate ephemeral P-256 key pair
85
- var ephemeralPrivateKeyBytes = p256_1.p256.utils.randomPrivateKey();
86
- var ephemeralPublicKeyBytes = p256_1.p256.getPublicKey(ephemeralPrivateKeyBytes, false // uncompressed = 65 bytes (0x04 + 32-byte X + 32-byte Y)
87
- );
88
- // 3. ECDH: compute shared secret
89
- // getSharedSecret returns the full point; extract X-coordinate (last 32 bytes)
90
- var sharedSecretPoint = p256_1.p256.getSharedSecret(ephemeralPrivateKeyBytes, recipientPublicKeyBytes);
91
- var sharedSecret = sharedSecretPoint.slice(-32);
92
- // 4. KDF: SHA-256(sharedSecret) → 32-byte AES key
93
- var aesKey = (0, sha256_1.sha256)(sharedSecret);
94
- // 5. Generate random 16-byte IV
95
- var iv = (0, webcrypto_1.randomBytes)(16);
96
- // 6. AES-256-GCM encrypt
97
- var plaintext = new TextEncoder().encode(value);
98
- var aes = (0, aes_1.gcm)(aesKey, iv);
99
- var ciphertextWithTag = aes.encrypt(plaintext);
100
- // @noble/ciphers gcm() returns ciphertext + authTag concatenated
101
- // Split the LAST 16 bytes as the auth tag
102
- var authTagLength = 16;
103
- var ciphertextLength = ciphertextWithTag.length - authTagLength;
104
- var ciphertext = ciphertextWithTag.slice(0, ciphertextLength);
105
- var authTag = ciphertextWithTag.slice(ciphertextLength);
106
- // 7. Serialize: [Version 0x00 (1B)] + [EphemeralPubKey (65B)] + [IV (16B)] + [AuthTag (16B)] + [Ciphertext]
107
- var resultLength = 1 + ephemeralPublicKeyBytes.length + 16 + 16 + ciphertext.length;
108
- var result = new Uint8Array(resultLength);
109
- var offset = 0;
110
- result[0] = 0x00; // Version byte
111
- offset += 1;
112
- result.set(ephemeralPublicKeyBytes, offset);
113
- offset += ephemeralPublicKeyBytes.length;
114
- result.set(iv, offset);
115
- offset += 16;
116
- result.set(authTag, offset);
117
- offset += 16;
118
- result.set(ciphertext, offset);
119
- // 8. Base64 encode (platform-safe: avoids Buffer which is unavailable in Hermes/React Native)
120
- var binary = "";
121
- for (var i = 0; i < result.length; i++) {
122
- binary += String.fromCharCode(result[i]);
123
- }
124
- return btoa(binary);
125
- }
126
- /**
127
- * Encrypts event property values for transmission.
128
- *
129
- * Rules:
130
- * - List-type properties are omitted entirely
131
- * - On encryption failure: console.warn, omit the property, continue
132
- * - Returns new array with encryptedPropertyValue set (propertyType/propertyName preserved)
133
- */
134
- function encryptEventProperties(properties, eventProps, publicKeyHex) {
135
- var result = [];
136
- var encryptionFailed = false;
137
- for (var _i = 0, properties_1 = properties; _i < properties_1.length; _i++) {
138
- var prop = properties_1[_i];
139
- // Omit list-type properties entirely
140
- if (prop.propertyType === "list") {
141
- continue;
142
- }
143
- // If encryption already failed for this batch, skip remaining properties
144
- // to avoid spamming the console with the same error
145
- if (encryptionFailed) {
146
- continue;
147
- }
148
- try {
149
- var value = eventProps[prop.propertyName];
150
- var jsonValue = JSON.stringify(value === undefined ? null : value);
151
- var encrypted = encryptValue(jsonValue, publicKeyHex);
152
- var entry = {
153
- propertyName: prop.propertyName,
154
- propertyType: prop.propertyType,
155
- encryptedPropertyValue: encrypted,
156
- };
157
- // Preserve children if present
158
- if (prop.children !== undefined) {
159
- entry.children = prop.children;
160
- }
161
- // Preserve validation fields if present
162
- if (prop.failedEventIds !== undefined) {
163
- entry.failedEventIds = prop.failedEventIds;
164
- }
165
- if (prop.passedEventIds !== undefined) {
166
- entry.passedEventIds = prop.passedEventIds;
167
- }
168
- result.push(entry);
169
- }
170
- catch (e) {
171
- encryptionFailed = true;
172
- console.warn("[Avo Inspector] Encryption failed: ".concat(e instanceof Error ? e.message : String(e), ". Remaining event properties will be omitted from the encrypted payload."));
173
- }
174
- }
175
- return result;
176
- }
@@ -1,435 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
- function verb(n) { return function (v) { return step([n, v]); }; }
15
- function step(op) {
16
- if (f) throw new TypeError("Generator is already executing.");
17
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
- if (y = 0, t) op = [op[0] & 2, t.value];
20
- switch (op[0]) {
21
- case 0: case 1: t = op; break;
22
- case 4: _.label++; return { value: op[1], done: false };
23
- case 5: _.label++; y = op[1]; op = [0]; continue;
24
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
- default:
26
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
- if (t[2]) _.ops.pop();
31
- _.trys.pop(); continue;
32
- }
33
- op = body.call(thisArg, _);
34
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
- }
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.AvoInspector = void 0;
40
- var AvoInspectorEnv_1 = require("./AvoInspectorEnv");
41
- var AvoSchemaParser_1 = require("./AvoSchemaParser");
42
- var AvoBatcher_1 = require("./AvoBatcher");
43
- var AvoNetworkCallsHandler_1 = require("./AvoNetworkCallsHandler");
44
- var AvoStorage_1 = require("./AvoStorage");
45
- var AvoDeduplicator_1 = require("./AvoDeduplicator");
46
- var AvoStreamId_1 = require("./AvoStreamId");
47
- var AvoEventSpecCache_1 = require("./eventSpec/AvoEventSpecCache");
48
- var AvoEventSpecFetcher_1 = require("./eventSpec/AvoEventSpecFetcher");
49
- var EventValidator_1 = require("./eventSpec/EventValidator");
50
- var utils_1 = require("./utils");
51
- var libVersion = require("../package.json").version;
52
- var AvoInspector = /** @class */ (function () {
53
- function AvoInspector(options) {
54
- var _this = this;
55
- this.currentBranchId = null;
56
- // the constructor does aggressive null/undefined checking because same code paths will be accessible from JS
57
- if ((0, utils_1.isValueEmpty)(options.env)) {
58
- this.environment = AvoInspectorEnv_1.AvoInspectorEnv.Dev;
59
- console.warn("[Avo Inspector] No environment provided. Defaulting to dev.");
60
- }
61
- else if (Object.values(AvoInspectorEnv_1.AvoInspectorEnv).indexOf(options.env) === -1) {
62
- this.environment = AvoInspectorEnv_1.AvoInspectorEnv.Dev;
63
- console.warn("[Avo Inspector] Unsupported environment provided. Defaulting to dev. Supported environments - Dev, Staging, Prod.");
64
- }
65
- else {
66
- this.environment = options.env;
67
- }
68
- if ((0, utils_1.isValueEmpty)(options.apiKey)) {
69
- throw new Error("[Avo Inspector] No API key provided. Inspector can't operate without API key.");
70
- }
71
- else {
72
- this.apiKey = options.apiKey;
73
- }
74
- if ((0, utils_1.isValueEmpty)(options.version)) {
75
- 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.");
76
- }
77
- else {
78
- this.version = options.version;
79
- }
80
- if (options.publicEncryptionKey) {
81
- this.publicEncryptionKey = options.publicEncryptionKey;
82
- }
83
- if (this.environment === AvoInspectorEnv_1.AvoInspectorEnv.Dev) {
84
- AvoInspector._batchSize = 1;
85
- AvoInspector._shouldLog = true;
86
- }
87
- else {
88
- AvoInspector._batchSize = 30;
89
- AvoInspector._batchFlushSeconds = 30;
90
- AvoInspector._shouldLog = false;
91
- }
92
- try {
93
- AvoInspector.avoStorage = new AvoStorage_1.AvoStorage(AvoInspector._shouldLog);
94
- }
95
- catch (e) {
96
- console.error("[Avo Inspector] Failed to initialize storage. " +
97
- "If you are using React Native, make sure @react-native-async-storage/async-storage is installed.", e);
98
- }
99
- var avoNetworkCallsHandler = new AvoNetworkCallsHandler_1.AvoNetworkCallsHandler(this.apiKey, this.environment.toString(), options.appName || "", this.version, libVersion, this.publicEncryptionKey);
100
- this.avoBatcher = new AvoBatcher_1.AvoBatcher(avoNetworkCallsHandler);
101
- this.avoDeduplicator = new AvoDeduplicator_1.AvoDeduplicator();
102
- // Initialize event spec validation infrastructure for dev/staging
103
- if (this.environment !== AvoInspectorEnv_1.AvoInspectorEnv.Prod) {
104
- try {
105
- this.eventSpecCache = new AvoEventSpecCache_1.EventSpecCache(AvoInspector._shouldLog);
106
- this.eventSpecFetcher = new AvoEventSpecFetcher_1.AvoEventSpecFetcher(5000, AvoInspector._shouldLog, this.environment);
107
- if (AvoInspector._shouldLog) {
108
- console.log("[Avo Inspector] Event spec fetching and validation enabled");
109
- }
110
- }
111
- catch (e) {
112
- console.error("[Avo Inspector] Failed to initialize event spec validation.", e);
113
- }
114
- }
115
- // Fire-and-forget: eagerly initialize the anonymous ID and capture streamId
116
- AvoStreamId_1.AvoStreamId.initialize().then(function (id) {
117
- _this.streamId = id;
118
- }).catch(function (e) {
119
- console.error("Avo Inspector: failed to initialize anonymous ID.", e);
120
- });
121
- }
122
- Object.defineProperty(AvoInspector, "batchSize", {
123
- get: function () {
124
- return this._batchSize;
125
- },
126
- set: function (newSize) {
127
- if (newSize < 1) {
128
- this._batchSize = 1;
129
- }
130
- else {
131
- this._batchSize = newSize;
132
- }
133
- },
134
- enumerable: false,
135
- configurable: true
136
- });
137
- Object.defineProperty(AvoInspector, "batchFlushSeconds", {
138
- get: function () {
139
- return this._batchFlushSeconds;
140
- },
141
- enumerable: false,
142
- configurable: true
143
- });
144
- Object.defineProperty(AvoInspector, "shouldLog", {
145
- get: function () {
146
- return this._shouldLog;
147
- },
148
- set: function (enable) {
149
- this._shouldLog = enable;
150
- },
151
- enumerable: false,
152
- configurable: true
153
- });
154
- AvoInspector.prototype.trackSchemaFromEvent = function (eventName, eventProperties) {
155
- return __awaiter(this, void 0, void 0, function () {
156
- var eventSchema, validationResult, schemaWithValidation, e_1;
157
- return __generator(this, function (_a) {
158
- switch (_a.label) {
159
- case 0:
160
- _a.trys.push([0, 4, , 5]);
161
- if (!this.avoDeduplicator.shouldRegisterEvent(eventName, eventProperties, false)) return [3 /*break*/, 2];
162
- if (AvoInspector.shouldLog) {
163
- console.log("Avo Inspector: supplied event " +
164
- eventName +
165
- " with params " +
166
- JSON.stringify(eventProperties));
167
- }
168
- eventSchema = this.extractSchema(eventProperties, false);
169
- return [4 /*yield*/, this.fetchAndValidateEvent(eventName, eventProperties)];
170
- case 1:
171
- validationResult = _a.sent();
172
- if (validationResult) {
173
- schemaWithValidation = this.mergeValidationResults(eventSchema, validationResult);
174
- // Send validated events immediately, bypassing the batcher
175
- this.sendEventWithValidation(eventName, schemaWithValidation, null, null, validationResult, eventProperties);
176
- }
177
- else {
178
- this.trackSchemaInternal(eventName, eventSchema, null, null, eventProperties);
179
- }
180
- return [2 /*return*/, eventSchema];
181
- case 2:
182
- if (AvoInspector.shouldLog) {
183
- console.log("Avo Inspector: Deduplicated event: " + eventName);
184
- }
185
- return [2 /*return*/, []];
186
- case 3: return [3 /*break*/, 5];
187
- case 4:
188
- e_1 = _a.sent();
189
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e_1);
190
- return [2 /*return*/, []];
191
- case 5: return [2 /*return*/];
192
- }
193
- });
194
- });
195
- };
196
- AvoInspector.prototype._avoFunctionTrackSchemaFromEvent = function (eventName, eventProperties, eventId, eventHash) {
197
- return __awaiter(this, void 0, void 0, function () {
198
- var eventSchema, validationResult, schemaWithValidation, e_2;
199
- return __generator(this, function (_a) {
200
- switch (_a.label) {
201
- case 0:
202
- _a.trys.push([0, 4, , 5]);
203
- if (!this.avoDeduplicator.shouldRegisterEvent(eventName, eventProperties, true)) return [3 /*break*/, 2];
204
- if (AvoInspector.shouldLog) {
205
- console.log("Avo Inspector: supplied event " +
206
- eventName +
207
- " with params " +
208
- JSON.stringify(eventProperties));
209
- }
210
- eventSchema = this.extractSchema(eventProperties, false);
211
- return [4 /*yield*/, this.fetchAndValidateEvent(eventName, eventProperties)];
212
- case 1:
213
- validationResult = _a.sent();
214
- if (validationResult) {
215
- schemaWithValidation = this.mergeValidationResults(eventSchema, validationResult);
216
- // Send validated events immediately, bypassing the batcher
217
- this.sendEventWithValidation(eventName, schemaWithValidation, eventId, eventHash, validationResult, eventProperties);
218
- }
219
- else {
220
- this.trackSchemaInternal(eventName, eventSchema, eventId, eventHash, eventProperties);
221
- }
222
- return [2 /*return*/, eventSchema];
223
- case 2:
224
- if (AvoInspector.shouldLog) {
225
- console.log("Avo Inspector: Deduplicated event: " + eventName);
226
- }
227
- return [2 /*return*/, []];
228
- case 3: return [3 /*break*/, 5];
229
- case 4:
230
- e_2 = _a.sent();
231
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e_2);
232
- return [2 /*return*/, []];
233
- case 5: return [2 /*return*/];
234
- }
235
- });
236
- });
237
- };
238
- AvoInspector.prototype.trackSchema = function (eventName, eventSchema) {
239
- try {
240
- if (this.avoDeduplicator.shouldRegisterSchemaFromManually(eventName, eventSchema)) {
241
- if (AvoInspector.shouldLog) {
242
- console.log("Avo Inspector: supplied event " +
243
- eventName +
244
- " with schema " +
245
- JSON.stringify(eventSchema));
246
- }
247
- this.trackSchemaInternal(eventName, eventSchema, null, null);
248
- }
249
- else {
250
- if (AvoInspector.shouldLog) {
251
- console.log("Avo Inspector: Deduplicated event: " + eventName);
252
- }
253
- }
254
- }
255
- catch (e) {
256
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e);
257
- }
258
- };
259
- AvoInspector.prototype.trackSchemaInternal = function (eventName, eventSchema, eventId, eventHash, eventProperties) {
260
- try {
261
- this.avoBatcher.handleTrackSchema(eventName, eventSchema, eventId, eventHash, eventProperties);
262
- }
263
- catch (e) {
264
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e);
265
- }
266
- };
267
- AvoInspector.prototype.enableLogging = function (enable) {
268
- AvoInspector._shouldLog = enable;
269
- };
270
- AvoInspector.prototype.extractSchema = function (eventProperties, shouldLogIfEnabled) {
271
- if (shouldLogIfEnabled === void 0) { shouldLogIfEnabled = true; }
272
- try {
273
- if (this.avoDeduplicator.hasSeenEventParams(eventProperties, true)) {
274
- if (shouldLogIfEnabled && AvoInspector.shouldLog) {
275
- console.warn("Avo Inspector: WARNING! You are trying to extract schema shape that was just reported by your Avo functions. " +
276
- "This is an indicator of duplicate inspector reporting. " +
277
- "Please reach out to support@avo.app for advice if you are not sure how to handle this.");
278
- }
279
- }
280
- if (AvoInspector.shouldLog) {
281
- console.log("Avo Inspector: extracting schema from " +
282
- JSON.stringify(eventProperties));
283
- }
284
- return AvoSchemaParser_1.AvoSchemaParser.extractSchema(eventProperties);
285
- }
286
- catch (e) {
287
- console.error("Avo Inspector: something went wrong. Please report to support@avo.app.", e);
288
- return [];
289
- }
290
- };
291
- AvoInspector.prototype.setBatchSize = function (newBatchSize) {
292
- AvoInspector._batchSize = newBatchSize;
293
- };
294
- AvoInspector.prototype.setBatchFlushSeconds = function (newBatchFlushSeconds) {
295
- AvoInspector._batchFlushSeconds = newBatchFlushSeconds;
296
- };
297
- /**
298
- * Handles branch change detection and cache storage for a fetched event spec.
299
- */
300
- AvoInspector.prototype.handleBranchChangeAndCache = function (specResponse, eventName) {
301
- var _a;
302
- var newBranchId = specResponse.metadata.branchId;
303
- if (this.currentBranchId !== null && this.currentBranchId !== newBranchId) {
304
- if (AvoInspector.shouldLog) {
305
- console.log("[Avo Inspector] Branch changed from ".concat(this.currentBranchId, " to ").concat(newBranchId, ". Flushing cache."));
306
- }
307
- (_a = this.eventSpecCache) === null || _a === void 0 ? void 0 : _a.clear();
308
- }
309
- this.currentBranchId = newBranchId;
310
- if (this.eventSpecCache && this.streamId) {
311
- this.eventSpecCache.set(this.apiKey, this.streamId, eventName, specResponse);
312
- }
313
- };
314
- /**
315
- * Fetches event spec and validates the event against it.
316
- * Returns ValidationResult if spec is available, null otherwise.
317
- * Only runs in dev/staging environments.
318
- */
319
- AvoInspector.prototype.fetchAndValidateEvent = function (eventName, eventProperties) {
320
- return __awaiter(this, void 0, void 0, function () {
321
- var specResponse, fetched, validationResult, error_1;
322
- return __generator(this, function (_a) {
323
- switch (_a.label) {
324
- case 0:
325
- // Only fetch specs in dev/staging environments (NOT in production)
326
- if (this.environment === AvoInspectorEnv_1.AvoInspectorEnv.Prod) {
327
- return [2 /*return*/, null];
328
- }
329
- // Only fetch if we have the required infrastructure
330
- if (!this.eventSpecCache || !this.eventSpecFetcher || !this.streamId) {
331
- return [2 /*return*/, null];
332
- }
333
- _a.label = 1;
334
- case 1:
335
- _a.trys.push([1, 6, , 7]);
336
- specResponse = this.eventSpecCache.get(this.apiKey, this.streamId, eventName);
337
- if (!(specResponse === undefined)) return [3 /*break*/, 3];
338
- return [4 /*yield*/, this.eventSpecFetcher.fetch({
339
- apiKey: this.apiKey,
340
- streamId: this.streamId,
341
- eventName: eventName
342
- })];
343
- case 2:
344
- fetched = _a.sent();
345
- if (fetched) {
346
- this.handleBranchChangeAndCache(fetched, eventName);
347
- specResponse = fetched;
348
- }
349
- else {
350
- // Cache null response to prevent re-fetching
351
- this.eventSpecCache.set(this.apiKey, this.streamId, eventName, null);
352
- specResponse = null;
353
- }
354
- _a.label = 3;
355
- case 3:
356
- if (!specResponse) return [3 /*break*/, 5];
357
- return [4 /*yield*/, (0, EventValidator_1.validateEvent)(eventProperties, specResponse)];
358
- case 4:
359
- validationResult = _a.sent();
360
- return [2 /*return*/, validationResult];
361
- case 5: return [2 /*return*/, null];
362
- case 6:
363
- error_1 = _a.sent();
364
- if (AvoInspector.shouldLog) {
365
- console.error("[Avo Inspector] Error validating event ".concat(eventName, ":"), error_1);
366
- }
367
- return [2 /*return*/, null];
368
- case 7: return [2 /*return*/];
369
- }
370
- });
371
- });
372
- };
373
- /**
374
- * Merges validation results into the event schema.
375
- * Adds failedEventIds or passedEventIds to each property based on validation.
376
- */
377
- AvoInspector.prototype.mergeValidationResults = function (eventSchema, validationResult) {
378
- var _this = this;
379
- return eventSchema.map(function (prop) {
380
- var propValidation = validationResult.propertyResults[prop.propertyName];
381
- return _this.mergePropertyValidation(prop, propValidation);
382
- });
383
- };
384
- /**
385
- * Merges validation result into a single property, recursively handling children.
386
- */
387
- AvoInspector.prototype.mergePropertyValidation = function (prop, propValidation) {
388
- var _this = this;
389
- var result = {
390
- propertyName: prop.propertyName,
391
- propertyType: prop.propertyType
392
- };
393
- // Recursively merge validation results into children
394
- if (prop.children && Array.isArray(prop.children)) {
395
- result.children = prop.children.map(function (child) {
396
- var _a;
397
- if (typeof child === 'string') {
398
- return child;
399
- }
400
- if (child && typeof child === 'object' && child.propertyName) {
401
- var childValidation = (_a = propValidation === null || propValidation === void 0 ? void 0 : propValidation.children) === null || _a === void 0 ? void 0 : _a[child.propertyName];
402
- return _this.mergePropertyValidation(child, childValidation);
403
- }
404
- return child;
405
- });
406
- }
407
- // Add validation result for this property
408
- if (propValidation) {
409
- if (propValidation.failedEventIds) {
410
- result.failedEventIds = propValidation.failedEventIds;
411
- }
412
- if (propValidation.passedEventIds) {
413
- result.passedEventIds = propValidation.passedEventIds;
414
- }
415
- }
416
- return result;
417
- };
418
- /**
419
- * Sends a validated event immediately, bypassing the batcher.
420
- * Matches Android SDK's sendEventWithValidation behavior.
421
- */
422
- AvoInspector.prototype.sendEventWithValidation = function (eventName, eventSchema, eventId, eventHash, validationResult, eventProperties) {
423
- var networkHandler = this.avoBatcher.networkCallsHandler;
424
- networkHandler.bodyForEventSchemaCall(eventName, eventSchema, eventId, eventHash, eventProperties, validationResult.metadata).then(function (eventBody) {
425
- networkHandler.reportValidatedEvent(eventBody);
426
- }).catch(function (e) {
427
- console.error("Avo Inspector: failed to send validated event.", e);
428
- });
429
- };
430
- AvoInspector._batchSize = 30;
431
- AvoInspector._batchFlushSeconds = 30;
432
- AvoInspector._shouldLog = false;
433
- return AvoInspector;
434
- }());
435
- exports.AvoInspector = AvoInspector;