node-avo-inspector 1.2.0-alpha.1 → 2.0.0-beta.1
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/CHANGELOG.md +46 -0
- package/README.md +268 -4
- package/package.json +17 -1
- package/.claude/scheduled_tasks.lock +0 -1
- package/.claude/settings.local.json +0 -11
- package/.claude/worktrees/release-1.1.1/LICENSE +0 -21
- package/.claude/worktrees/release-1.1.1/README.md +0 -69
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-js/index.js +0 -30
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-js/package.json +0 -15
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-js/yarn.lock +0 -6
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-ts/dist/index.js +0 -34
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-ts/index.ts +0 -30
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-ts/package.json +0 -18
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-ts/tsconfig.json +0 -15
- package/.claude/worktrees/release-1.1.1/examples/node-inspector-ts/yarn.lock +0 -11
- package/.claude/worktrees/release-1.1.1/package-lock.json +0 -4039
- package/.claude/worktrees/release-1.1.1/package.json +0 -48
- package/.claude/worktrees/release-1.1.1/reason/AvoInspector.rei +0 -11
- package/.claude/worktrees/release-1.1.1/reason/NodeAvoInspector.re +0 -27
- package/.claude/worktrees/release-1.1.1/src/AvoDeduplicator.ts +0 -146
- package/.claude/worktrees/release-1.1.1/src/AvoEncryption.ts +0 -90
- package/.claude/worktrees/release-1.1.1/src/AvoGuid.ts +0 -9
- package/.claude/worktrees/release-1.1.1/src/AvoInspector.ts +0 -383
- package/.claude/worktrees/release-1.1.1/src/AvoInspectorEnv.ts +0 -8
- package/.claude/worktrees/release-1.1.1/src/AvoNetworkCallsHandler.ts +0 -267
- package/.claude/worktrees/release-1.1.1/src/AvoSchemaParser.ts +0 -115
- package/.claude/worktrees/release-1.1.1/src/AvoStreamId.ts +0 -16
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestAvoEncryption.ts +0 -515
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestAvoEventSpecCache.ts +0 -242
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestAvoEventSpecFetcher.ts +0 -241
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestAvoInspector.ts +0 -360
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestAvoStreamId.ts +0 -72
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestDeduplicator.ts +0 -191
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestEventValidator.ts +0 -231
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestNetworkCallsHandler.ts +0 -179
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestNetworkCallsHandlerPublic.ts +0 -208
- package/.claude/worktrees/release-1.1.1/src/__tests__/TestParsing.ts +0 -153
- package/.claude/worktrees/release-1.1.1/src/__tests__/constants.ts +0 -63
- package/.claude/worktrees/release-1.1.1/src/eventSpec/AvoEventSpecCache.ts +0 -109
- package/.claude/worktrees/release-1.1.1/src/eventSpec/AvoEventSpecFetchTypes.ts +0 -47
- package/.claude/worktrees/release-1.1.1/src/eventSpec/AvoEventSpecFetcher.ts +0 -106
- package/.claude/worktrees/release-1.1.1/src/eventSpec/EventValidator.ts +0 -74
- package/.claude/worktrees/release-1.1.1/src/index.ts +0 -2
- package/.claude/worktrees/release-1.1.1/src/utils.ts +0 -49
- package/.claude/worktrees/release-1.1.1/tsconfig.json +0 -13
- package/.claude/worktrees/release-1.1.1/yarn.lock +0 -2310
- package/.github/workflows/claude.yml +0 -55
- package/dist/__tests__/TestAvoEncryption.d.ts +0 -1
- package/dist/__tests__/TestAvoEncryption.js +0 -288
- package/dist/__tests__/TestAvoEventSpecCache.d.ts +0 -1
- package/dist/__tests__/TestAvoEventSpecCache.js +0 -194
- package/dist/__tests__/TestAvoEventSpecFetcher.d.ts +0 -1
- package/dist/__tests__/TestAvoEventSpecFetcher.js +0 -219
- package/dist/__tests__/TestAvoInspector.d.ts +0 -1
- package/dist/__tests__/TestAvoInspector.js +0 -291
- package/dist/__tests__/TestAvoStreamId.d.ts +0 -1
- package/dist/__tests__/TestAvoStreamId.js +0 -55
- package/dist/__tests__/TestDeduplicator.d.ts +0 -1
- package/dist/__tests__/TestDeduplicator.js +0 -102
- package/dist/__tests__/TestEventValidator.d.ts +0 -1
- package/dist/__tests__/TestEventValidator.js +0 -196
- package/dist/__tests__/TestNetworkCallsHandler.d.ts +0 -1
- package/dist/__tests__/TestNetworkCallsHandler.js +0 -86
- package/dist/__tests__/TestNetworkCallsHandlerPublic.d.ts +0 -1
- package/dist/__tests__/TestNetworkCallsHandlerPublic.js +0 -160
- package/dist/__tests__/TestParsing.d.ts +0 -1
- package/dist/__tests__/TestParsing.js +0 -128
- package/dist/__tests__/constants.d.ts +0 -42
- package/dist/__tests__/constants.js +0 -53
- package/examples/node-inspector-js/index.js +0 -30
- package/examples/node-inspector-js/package.json +0 -15
- package/examples/node-inspector-js/yarn.lock +0 -6
- package/examples/node-inspector-ts/dist/index.js +0 -34
- package/examples/node-inspector-ts/index.ts +0 -30
- package/examples/node-inspector-ts/package.json +0 -18
- package/examples/node-inspector-ts/tsconfig.json +0 -15
- package/examples/node-inspector-ts/yarn.lock +0 -11
- package/reason/AvoInspector.rei +0 -11
- package/reason/NodeAvoInspector.re +0 -27
- package/src/AvoDeduplicator.ts +0 -150
- package/src/AvoEncryption.ts +0 -90
- package/src/AvoGuid.ts +0 -9
- package/src/AvoInspector.ts +0 -498
- package/src/AvoInspectorEnv.ts +0 -8
- package/src/AvoNetworkCallsHandler.ts +0 -340
- package/src/AvoSchemaParser.ts +0 -115
- package/src/AvoStreamId.ts +0 -16
- package/src/__tests__/TestAvoEncryption.ts +0 -515
- package/src/__tests__/TestAvoEventSpecCache.ts +0 -242
- package/src/__tests__/TestAvoEventSpecFetcher.ts +0 -279
- package/src/__tests__/TestAvoInspector.ts +0 -376
- package/src/__tests__/TestAvoStreamId.ts +0 -72
- package/src/__tests__/TestDeduplicator.ts +0 -191
- package/src/__tests__/TestEventValidator.ts +0 -231
- package/src/__tests__/TestNetworkCallsHandler.ts +0 -181
- package/src/__tests__/TestNetworkCallsHandlerPublic.ts +0 -208
- package/src/__tests__/TestParsing.ts +0 -153
- package/src/__tests__/constants.ts +0 -63
- package/src/eventSpec/AvoEventSpecCache.ts +0 -119
- package/src/eventSpec/AvoEventSpecFetchTypes.ts +0 -47
- package/src/eventSpec/AvoEventSpecFetcher.ts +0 -186
- package/src/eventSpec/EventValidator.ts +0 -74
- package/src/index.ts +0 -2
- package/src/utils.ts +0 -49
- package/tsconfig.json +0 -13
package/src/AvoInspector.ts
DELETED
|
@@ -1,498 +0,0 @@
|
|
|
1
|
-
import { AvoInspectorEnv, AvoInspectorEnvValueType } from "./AvoInspectorEnv";
|
|
2
|
-
import { AvoSchemaParser } from "./AvoSchemaParser";
|
|
3
|
-
import { AvoNetworkCallsHandler } from "./AvoNetworkCallsHandler";
|
|
4
|
-
import { AvoDeduplicator } from "./AvoDeduplicator";
|
|
5
|
-
import { AvoStreamId } from "./AvoStreamId";
|
|
6
|
-
import { AvoEventSpecFetcher } from "./eventSpec/AvoEventSpecFetcher";
|
|
7
|
-
import { AvoEventSpecCache } from "./eventSpec/AvoEventSpecCache";
|
|
8
|
-
import { EventValidator } from "./eventSpec/EventValidator";
|
|
9
|
-
import { EventSpecResponse } from "./eventSpec/AvoEventSpecFetchTypes";
|
|
10
|
-
|
|
11
|
-
import { isValueEmpty } from "./utils";
|
|
12
|
-
|
|
13
|
-
const libVersion = require("../package.json").version;
|
|
14
|
-
|
|
15
|
-
export class AvoInspector {
|
|
16
|
-
environment: AvoInspectorEnvValueType;
|
|
17
|
-
avoNetworkCallsHandler: AvoNetworkCallsHandler;
|
|
18
|
-
avoDeduplicator: AvoDeduplicator;
|
|
19
|
-
apiKey: string;
|
|
20
|
-
version: string;
|
|
21
|
-
private publicEncryptionKey?: string;
|
|
22
|
-
|
|
23
|
-
private eventSpecFetcher: AvoEventSpecFetcher | null = null;
|
|
24
|
-
private eventSpecCache: AvoEventSpecCache | null = null;
|
|
25
|
-
private eventValidator: EventValidator | null = null;
|
|
26
|
-
private generatedAnonymousId: string = "";
|
|
27
|
-
|
|
28
|
-
// Keep the Node process alive while there are pending inspector operations.
|
|
29
|
-
// Without this, short-lived processes (e.g. CLIs) can exit before async
|
|
30
|
-
// sends complete, since the caller typically doesn't await the inspector promise.
|
|
31
|
-
private pendingCount = 0;
|
|
32
|
-
private keepAliveTimer: ReturnType<typeof setInterval> | null = null;
|
|
33
|
-
|
|
34
|
-
private trackPending(promise: Promise<any>): void {
|
|
35
|
-
this.pendingCount++;
|
|
36
|
-
if (this.keepAliveTimer === null) {
|
|
37
|
-
this.keepAliveTimer = setInterval(() => {}, 60_000);
|
|
38
|
-
}
|
|
39
|
-
const done = () => {
|
|
40
|
-
this.pendingCount--;
|
|
41
|
-
if (this.pendingCount === 0 && this.keepAliveTimer !== null) {
|
|
42
|
-
clearInterval(this.keepAliveTimer);
|
|
43
|
-
this.keepAliveTimer = null;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
promise.then(done, done);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private static _shouldLog = false;
|
|
50
|
-
static get shouldLog() {
|
|
51
|
-
return this._shouldLog;
|
|
52
|
-
}
|
|
53
|
-
static set shouldLog(enable) {
|
|
54
|
-
this._shouldLog = enable;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
constructor(options: {
|
|
58
|
-
apiKey: string;
|
|
59
|
-
env: AvoInspectorEnvValueType;
|
|
60
|
-
version: string;
|
|
61
|
-
appName?: string;
|
|
62
|
-
publicEncryptionKey?: string;
|
|
63
|
-
}) {
|
|
64
|
-
// the constructor does aggressive null/undefined checking because same code paths will be accessible from JS
|
|
65
|
-
if (isValueEmpty(options.env)) {
|
|
66
|
-
this.environment = AvoInspectorEnv.Dev;
|
|
67
|
-
console.warn(
|
|
68
|
-
"[Avo Inspector] No environment provided. Defaulting to dev."
|
|
69
|
-
);
|
|
70
|
-
} else if (Object.values(AvoInspectorEnv).indexOf(options.env) === -1) {
|
|
71
|
-
this.environment = AvoInspectorEnv.Dev;
|
|
72
|
-
console.warn(
|
|
73
|
-
"[Avo Inspector] Unsupported environment provided. Defaulting to dev. Supported environments - Dev, Staging, Prod."
|
|
74
|
-
);
|
|
75
|
-
} else {
|
|
76
|
-
this.environment = options.env;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (isValueEmpty(options.apiKey)) {
|
|
80
|
-
throw new Error(
|
|
81
|
-
"[Avo Inspector] No API key provided. Inspector can't operate without API key."
|
|
82
|
-
);
|
|
83
|
-
} else {
|
|
84
|
-
this.apiKey = options.apiKey;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (isValueEmpty(options.version)) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
"[Avo Inspector] No version provided. Many features of Inspector rely on versioning. Please provide comparable string version, i.e. integer or semantic."
|
|
90
|
-
);
|
|
91
|
-
} else {
|
|
92
|
-
this.version = options.version;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
this.publicEncryptionKey = options.publicEncryptionKey;
|
|
96
|
-
|
|
97
|
-
if (
|
|
98
|
-
this.publicEncryptionKey &&
|
|
99
|
-
this.environment !== AvoInspectorEnv.Prod
|
|
100
|
-
) {
|
|
101
|
-
const hexPattern = /^[0-9a-fA-F]+$/;
|
|
102
|
-
const len = this.publicEncryptionKey.length;
|
|
103
|
-
// Accept both compressed (66 hex chars, prefix 02/03) and uncompressed (130 hex chars, prefix 04) P-256 keys
|
|
104
|
-
const isValidLength = len === 66 || len === 130;
|
|
105
|
-
if (!hexPattern.test(this.publicEncryptionKey) || !isValidLength) {
|
|
106
|
-
console.warn(
|
|
107
|
-
"[Avo Inspector] Warning: publicEncryptionKey does not look like a valid P-256 public key (expected 66 or 130 hex characters). Encryption may fail."
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (this.environment === AvoInspectorEnv.Dev) {
|
|
113
|
-
AvoInspector._shouldLog = true;
|
|
114
|
-
} else {
|
|
115
|
-
AvoInspector._shouldLog = false;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
this.avoNetworkCallsHandler = new AvoNetworkCallsHandler(
|
|
119
|
-
this.apiKey,
|
|
120
|
-
this.environment.toString(),
|
|
121
|
-
options.appName || "",
|
|
122
|
-
this.version,
|
|
123
|
-
libVersion,
|
|
124
|
-
this.publicEncryptionKey
|
|
125
|
-
);
|
|
126
|
-
this.avoDeduplicator = new AvoDeduplicator();
|
|
127
|
-
|
|
128
|
-
// Initialize event spec validation for dev/staging only
|
|
129
|
-
if (this.environment !== AvoInspectorEnv.Prod) {
|
|
130
|
-
this.eventSpecFetcher = new AvoEventSpecFetcher(this.apiKey);
|
|
131
|
-
this.eventSpecCache = new AvoEventSpecCache();
|
|
132
|
-
this.eventValidator = new EventValidator();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
trackSchemaFromEvent(
|
|
137
|
-
eventName: string,
|
|
138
|
-
eventProperties: { [propName: string]: any },
|
|
139
|
-
streamId?: string
|
|
140
|
-
): Promise<
|
|
141
|
-
Array<{
|
|
142
|
-
propertyName: string;
|
|
143
|
-
propertyType: string;
|
|
144
|
-
children?: any;
|
|
145
|
-
}>
|
|
146
|
-
> {
|
|
147
|
-
try {
|
|
148
|
-
const avoStreamId = new AvoStreamId(streamId);
|
|
149
|
-
const anonymousId = avoStreamId.streamId || this.generatedAnonymousId;
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
this.avoDeduplicator.shouldRegisterEvent(
|
|
153
|
-
eventName,
|
|
154
|
-
eventProperties,
|
|
155
|
-
false,
|
|
156
|
-
anonymousId
|
|
157
|
-
)
|
|
158
|
-
) {
|
|
159
|
-
if (AvoInspector.shouldLog) {
|
|
160
|
-
console.log(
|
|
161
|
-
"Avo Inspector: Supplied event " +
|
|
162
|
-
eventName +
|
|
163
|
-
" with params \n" +
|
|
164
|
-
JSON.stringify(eventProperties)
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
let eventSchema = this.extractSchema(eventProperties, false);
|
|
168
|
-
|
|
169
|
-
return this.sendEventWithOptionalValidation(
|
|
170
|
-
eventName,
|
|
171
|
-
eventSchema,
|
|
172
|
-
null,
|
|
173
|
-
null,
|
|
174
|
-
anonymousId,
|
|
175
|
-
eventProperties
|
|
176
|
-
).then(() => {
|
|
177
|
-
return eventSchema;
|
|
178
|
-
});
|
|
179
|
-
} else {
|
|
180
|
-
if (AvoInspector.shouldLog) {
|
|
181
|
-
console.log("Avo Inspector: Deduplicated event " + eventName);
|
|
182
|
-
}
|
|
183
|
-
return Promise.resolve([]);
|
|
184
|
-
}
|
|
185
|
-
} catch (e) {
|
|
186
|
-
console.error(
|
|
187
|
-
"Avo Inspector: something went wrong. Please report to support@avo.app.",
|
|
188
|
-
e
|
|
189
|
-
);
|
|
190
|
-
return Promise.reject(
|
|
191
|
-
"Avo Inspector: something went wrong. Please report to support@avo.app."
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
_avoFunctionTrackSchemaFromEvent(
|
|
197
|
-
eventName: string,
|
|
198
|
-
eventProperties: { [propName: string]: any },
|
|
199
|
-
eventId: string,
|
|
200
|
-
eventHash: string,
|
|
201
|
-
streamId?: string
|
|
202
|
-
): Promise<
|
|
203
|
-
Array<{
|
|
204
|
-
propertyName: string;
|
|
205
|
-
propertyType: string;
|
|
206
|
-
children?: any;
|
|
207
|
-
}>
|
|
208
|
-
> {
|
|
209
|
-
try {
|
|
210
|
-
const anonymousId = (streamId && streamId.length > 0) ? streamId : this.generatedAnonymousId;
|
|
211
|
-
|
|
212
|
-
if (
|
|
213
|
-
this.avoDeduplicator.shouldRegisterEvent(
|
|
214
|
-
eventName,
|
|
215
|
-
eventProperties,
|
|
216
|
-
true,
|
|
217
|
-
anonymousId
|
|
218
|
-
)
|
|
219
|
-
) {
|
|
220
|
-
if (AvoInspector.shouldLog) {
|
|
221
|
-
console.log(
|
|
222
|
-
"Avo Inspector: Supplied event " +
|
|
223
|
-
eventName +
|
|
224
|
-
" with params \n" +
|
|
225
|
-
JSON.stringify(eventProperties)
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
let eventSchema = this.extractSchema(eventProperties, false);
|
|
229
|
-
|
|
230
|
-
return this.sendEventWithOptionalValidation(
|
|
231
|
-
eventName,
|
|
232
|
-
eventSchema,
|
|
233
|
-
eventId,
|
|
234
|
-
eventHash,
|
|
235
|
-
anonymousId,
|
|
236
|
-
eventProperties
|
|
237
|
-
).then(() => {
|
|
238
|
-
return eventSchema;
|
|
239
|
-
});
|
|
240
|
-
} else {
|
|
241
|
-
if (AvoInspector.shouldLog) {
|
|
242
|
-
console.log("Avo Inspector: Deduplicated event " + eventName);
|
|
243
|
-
}
|
|
244
|
-
return Promise.resolve([]);
|
|
245
|
-
}
|
|
246
|
-
} catch (e) {
|
|
247
|
-
console.error(
|
|
248
|
-
"Avo Inspector: something went wrong. Please report to support@avo.app.",
|
|
249
|
-
e
|
|
250
|
-
);
|
|
251
|
-
return Promise.reject(
|
|
252
|
-
"Avo Inspector: something went wrong. Please report to support@avo.app."
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Try to fetch event spec and validate, then send a single event call.
|
|
259
|
-
* If validation succeeds, sends a validated event (with results merged in).
|
|
260
|
-
* If unavailable, sends a plain event.
|
|
261
|
-
*
|
|
262
|
-
* Uses trackPending() to keep the Node process alive until the work completes,
|
|
263
|
-
* so short-lived processes (CLIs) don't exit before the send finishes — even
|
|
264
|
-
* when the caller doesn't await the returned promise.
|
|
265
|
-
*/
|
|
266
|
-
private sendEventWithOptionalValidation(
|
|
267
|
-
eventName: string,
|
|
268
|
-
eventSchema: Array<{
|
|
269
|
-
propertyName: string;
|
|
270
|
-
propertyType: string;
|
|
271
|
-
children?: any;
|
|
272
|
-
}>,
|
|
273
|
-
eventId: string | null,
|
|
274
|
-
eventHash: string | null,
|
|
275
|
-
anonymousId: string,
|
|
276
|
-
rawEventProperties?: { [propName: string]: any }
|
|
277
|
-
): Promise<void> {
|
|
278
|
-
const work = this.doSendEventWithOptionalValidation(
|
|
279
|
-
eventName, eventSchema, eventId, eventHash, anonymousId, rawEventProperties
|
|
280
|
-
);
|
|
281
|
-
this.trackPending(work);
|
|
282
|
-
return work;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
private async doSendEventWithOptionalValidation(
|
|
286
|
-
eventName: string,
|
|
287
|
-
eventSchema: Array<{
|
|
288
|
-
propertyName: string;
|
|
289
|
-
propertyType: string;
|
|
290
|
-
children?: any;
|
|
291
|
-
}>,
|
|
292
|
-
eventId: string | null,
|
|
293
|
-
eventHash: string | null,
|
|
294
|
-
anonymousId: string,
|
|
295
|
-
rawEventProperties?: { [propName: string]: any }
|
|
296
|
-
): Promise<void> {
|
|
297
|
-
const validationResult = await this.fetchAndValidate(eventName, eventSchema, anonymousId, rawEventProperties, eventId);
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
let body;
|
|
301
|
-
if (validationResult) {
|
|
302
|
-
if (AvoInspector.shouldLog) {
|
|
303
|
-
console.log("Avo Inspector: Sending validated event " + eventName);
|
|
304
|
-
}
|
|
305
|
-
const eventProps = this.avoNetworkCallsHandler.buildEventProperties(eventSchema, rawEventProperties);
|
|
306
|
-
body = this.avoNetworkCallsHandler.bodyForValidatedEventSchemaCall(
|
|
307
|
-
anonymousId,
|
|
308
|
-
eventName,
|
|
309
|
-
eventProps,
|
|
310
|
-
eventId,
|
|
311
|
-
eventHash,
|
|
312
|
-
validationResult.metadata,
|
|
313
|
-
validationResult.propertyResults
|
|
314
|
-
);
|
|
315
|
-
} else {
|
|
316
|
-
body = this.avoNetworkCallsHandler.bodyForEventSchemaCall(
|
|
317
|
-
anonymousId,
|
|
318
|
-
eventName,
|
|
319
|
-
eventSchema,
|
|
320
|
-
eventId,
|
|
321
|
-
eventHash,
|
|
322
|
-
rawEventProperties
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
await this.avoNetworkCallsHandler.callInspectorWithBatchBody([body]);
|
|
327
|
-
|
|
328
|
-
if (AvoInspector.shouldLog) {
|
|
329
|
-
const schemaString = eventSchema.map(p => '\t"' + p.propertyName + '": "' + p.propertyType + '"').join(";\n");
|
|
330
|
-
console.log("Avo Inspector: Saved event " + eventName + " with schema {\n" + schemaString + "\n}");
|
|
331
|
-
}
|
|
332
|
-
} catch (err) {
|
|
333
|
-
console.error("Avo Inspector: schema sending failed: " + err + ".");
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
enableLogging(enable: boolean) {
|
|
338
|
-
AvoInspector._shouldLog = enable;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
extractSchema(
|
|
342
|
-
eventProperties: {
|
|
343
|
-
[propName: string]: any;
|
|
344
|
-
},
|
|
345
|
-
shouldLogIfEnabled = true
|
|
346
|
-
): Array<{
|
|
347
|
-
propertyName: string;
|
|
348
|
-
propertyType: string;
|
|
349
|
-
children?: any;
|
|
350
|
-
}> {
|
|
351
|
-
try {
|
|
352
|
-
if (this.avoDeduplicator.hasSeenEventParams(eventProperties, true)) {
|
|
353
|
-
if (shouldLogIfEnabled && AvoInspector.shouldLog) {
|
|
354
|
-
console.warn(
|
|
355
|
-
"Avo Inspector: WARNING! You are trying to extract schema shape that was just reported by your Codegen. " +
|
|
356
|
-
"This is an indicator of duplicate inspector reporting. " +
|
|
357
|
-
"Please reach out to support@avo.app for advice if you are not sure how to handle this."
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (AvoInspector.shouldLog) {
|
|
363
|
-
console.log(
|
|
364
|
-
"Avo Inspector: extracting schema from " +
|
|
365
|
-
JSON.stringify(eventProperties)
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const schema = AvoSchemaParser.extractSchema(eventProperties);
|
|
370
|
-
|
|
371
|
-
if (AvoInspector.shouldLog) {
|
|
372
|
-
const schemaString = schema.map(p => '\t"' + p.propertyName + '": "' + p.propertyType + '"').join(";\n");
|
|
373
|
-
console.log("Avo Inspector: Parsed schema {\n" + schemaString + "\n}");
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return schema;
|
|
377
|
-
} catch (e) {
|
|
378
|
-
console.error(
|
|
379
|
-
"Avo Inspector: something went wrong. Please report to support@avo.app.",
|
|
380
|
-
e
|
|
381
|
-
);
|
|
382
|
-
return [];
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Fetch event spec and validate. Returns validation results + metadata if
|
|
388
|
-
* validation succeeds, or null if unavailable (prod, no spec, fetch error).
|
|
389
|
-
*/
|
|
390
|
-
private async fetchAndValidate(
|
|
391
|
-
eventName: string,
|
|
392
|
-
eventSchema: Array<{
|
|
393
|
-
propertyName: string;
|
|
394
|
-
propertyType: string;
|
|
395
|
-
children?: any;
|
|
396
|
-
}>,
|
|
397
|
-
anonymousId: string,
|
|
398
|
-
rawEventProperties?: { [propName: string]: any },
|
|
399
|
-
eventId?: string | null
|
|
400
|
-
): Promise<{ metadata: import("./eventSpec/AvoEventSpecFetchTypes").EventSpecMetadata; propertyResults: import("./eventSpec/AvoEventSpecFetchTypes").PropertyValidationResult[] } | null> {
|
|
401
|
-
if (!this.eventSpecFetcher || !this.eventSpecCache || !this.eventValidator) {
|
|
402
|
-
if (AvoInspector.shouldLog) {
|
|
403
|
-
console.log("Avo Inspector: Skipping event spec validation for event: " + eventName
|
|
404
|
-
+ " (fetcher=" + (this.eventSpecFetcher != null)
|
|
405
|
-
+ ", cache=" + (this.eventSpecCache != null)
|
|
406
|
-
+ ", env=" + this.environment + ")");
|
|
407
|
-
}
|
|
408
|
-
return null;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
const cacheKey = AvoEventSpecCache.makeKey(this.apiKey, anonymousId, eventName);
|
|
412
|
-
const cache = this.eventSpecCache;
|
|
413
|
-
const validator = this.eventValidator;
|
|
414
|
-
|
|
415
|
-
const doValidate = (specResponse: EventSpecResponse) => {
|
|
416
|
-
if (specResponse.eventSpec === null) {
|
|
417
|
-
if (AvoInspector.shouldLog) {
|
|
418
|
-
console.log("Avo Inspector: Event spec fetch returned null for event: " + eventName + ". Sending without validation.");
|
|
419
|
-
}
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const eventProperties = eventSchema.map((prop) => ({
|
|
424
|
-
propertyName: prop.propertyName,
|
|
425
|
-
propertyType: prop.propertyType,
|
|
426
|
-
...(rawEventProperties && rawEventProperties[prop.propertyName] !== undefined
|
|
427
|
-
? { propertyValue: String(rawEventProperties[prop.propertyName]) }
|
|
428
|
-
: {}),
|
|
429
|
-
}));
|
|
430
|
-
|
|
431
|
-
if (AvoInspector.shouldLog) {
|
|
432
|
-
console.log("Avo Inspector: Validating event: " + eventName
|
|
433
|
-
+ " with " + eventProperties.length + " properties"
|
|
434
|
-
+ " against " + specResponse.eventSpec.properties.length + " spec properties");
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const validationId = eventId || eventName;
|
|
438
|
-
const results = validator.validate(
|
|
439
|
-
specResponse.eventSpec,
|
|
440
|
-
eventProperties,
|
|
441
|
-
validationId
|
|
442
|
-
);
|
|
443
|
-
|
|
444
|
-
if (AvoInspector.shouldLog) {
|
|
445
|
-
console.log("Avo Inspector: Validation complete for event: " + eventName
|
|
446
|
-
+ " with " + results.length + " property results");
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
return { metadata: specResponse.metadata, propertyResults: results };
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
// Check cache first
|
|
453
|
-
const cached = cache.get(cacheKey);
|
|
454
|
-
if (cached !== undefined) {
|
|
455
|
-
if (AvoInspector.shouldLog) {
|
|
456
|
-
console.log("Avo Inspector: Event spec cache hit for event: " + eventName);
|
|
457
|
-
}
|
|
458
|
-
return doValidate(cached);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Cache miss — fetch spec (process stays alive via trackPending)
|
|
462
|
-
if (AvoInspector.shouldLog) {
|
|
463
|
-
console.log("Avo Inspector: Event spec cache miss for event: " + eventName + ". Fetching before sending.");
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const fetcher = this.eventSpecFetcher;
|
|
467
|
-
return new Promise((resolve) => {
|
|
468
|
-
fetcher.fetch(eventName, anonymousId, (result) => {
|
|
469
|
-
if (result !== null) {
|
|
470
|
-
cache.set(cacheKey, result);
|
|
471
|
-
resolve(doValidate(result));
|
|
472
|
-
} else {
|
|
473
|
-
if (AvoInspector.shouldLog) {
|
|
474
|
-
console.log("Avo Inspector: Event spec fetch returned null for event: " + eventName + ". Cached empty response. Sending without validation.");
|
|
475
|
-
}
|
|
476
|
-
resolve(null);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
destroy(): void {
|
|
483
|
-
if (this.eventSpecFetcher) {
|
|
484
|
-
this.eventSpecFetcher.destroy();
|
|
485
|
-
this.eventSpecFetcher = null;
|
|
486
|
-
}
|
|
487
|
-
if (this.eventSpecCache) {
|
|
488
|
-
this.eventSpecCache.flush();
|
|
489
|
-
this.eventSpecCache = null;
|
|
490
|
-
}
|
|
491
|
-
this.eventValidator = null;
|
|
492
|
-
if (this.keepAliveTimer !== null) {
|
|
493
|
-
clearInterval(this.keepAliveTimer);
|
|
494
|
-
this.keepAliveTimer = null;
|
|
495
|
-
}
|
|
496
|
-
this.pendingCount = 0;
|
|
497
|
-
}
|
|
498
|
-
}
|
package/src/AvoInspectorEnv.ts
DELETED