node-avo-inspector 1.2.0 → 2.0.0-beta.2
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 +270 -4
- package/dist/AvoBatchQueue.d.ts +73 -0
- package/dist/AvoBatchQueue.js +239 -0
- package/dist/AvoDeduplicator.d.ts +15 -6
- package/dist/AvoDeduplicator.js +46 -24
- package/dist/AvoInspector.d.ts +136 -23
- package/dist/AvoInspector.js +777 -109
- package/dist/AvoInspectorVersion.d.ts +3 -0
- package/dist/AvoInspectorVersion.js +10 -0
- package/dist/AvoLog.d.ts +52 -0
- package/dist/AvoLog.js +246 -0
- package/dist/AvoNetworkCallsHandler.d.ts +55 -8
- package/dist/AvoNetworkCallsHandler.js +266 -92
- package/dist/AvoSchemaParser.d.ts +6 -0
- package/dist/AvoSchemaParser.js +138 -33
- package/dist/AvoStreamId.d.ts +2 -1
- package/dist/AvoStreamId.js +21 -2
- package/dist/eventSpec/AvoEventSpecCache.d.ts +28 -5
- package/dist/eventSpec/AvoEventSpecCache.js +66 -11
- package/dist/eventSpec/AvoEventSpecFetchTypes.d.ts +50 -18
- package/dist/eventSpec/AvoEventSpecFetcher.d.ts +29 -6
- package/dist/eventSpec/AvoEventSpecFetcher.js +279 -69
- package/dist/eventSpec/EventValidator.d.ts +16 -10
- package/dist/eventSpec/EventValidator.js +351 -38
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -1
- package/dist/utils.d.ts +29 -1
- package/dist/utils.js +86 -10
- package/package.json +18 -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
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LIB_PLATFORM = exports.SPEC_VERSION = exports.VERSION = void 0;
|
|
4
|
+
// SDK library version, sent on the wire as `libVersion`. Plain SemVer, no suffix.
|
|
5
|
+
// Update this constant (and package.json "version") on every release.
|
|
6
|
+
exports.VERSION = "2.0.0";
|
|
7
|
+
// Version of avohq/spec-first-inspector-server-sdk this SDK implements.
|
|
8
|
+
exports.SPEC_VERSION = "3.0.1";
|
|
9
|
+
// Sent as `libPlatform` on every event and as the `X-Avo-Client` request header.
|
|
10
|
+
exports.LIB_PLATFORM = "node";
|
package/dist/AvoLog.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** The event name sent for a track call whose event name is missing. */
|
|
2
|
+
export declare const MISSING_EVENT_NAME = "Missing Event Name";
|
|
3
|
+
export type DropReason = "queue full" | "send backlog full" | "internal error" | "unsent at exit" | "unconfirmed at exit";
|
|
4
|
+
export declare class AvoLog {
|
|
5
|
+
static now: () => number;
|
|
6
|
+
private static windows;
|
|
7
|
+
private static exitListenerArmed;
|
|
8
|
+
private static exiting;
|
|
9
|
+
/** Events dropped because the unsent buffer or the send backlog is full. */
|
|
10
|
+
static dropped(count: number, reason: DropReason): void;
|
|
11
|
+
/** A batch answered with an HTTP status other than 200. Only the status is logged. */
|
|
12
|
+
static rejected(status: number): void;
|
|
13
|
+
/** A batch that could not be sent (network error, timeout, header guard). */
|
|
14
|
+
static failed(error: unknown): void;
|
|
15
|
+
/**
|
|
16
|
+
* An internal error. Only its type is printed: the error may come from reading a property
|
|
17
|
+
* (a throwing getter or proxy), so its message or stack can carry a property value.
|
|
18
|
+
*/
|
|
19
|
+
static internal(error: unknown): void;
|
|
20
|
+
private static readonly errorTypes;
|
|
21
|
+
/** A track call without a usable event name, sent as MISSING_EVENT_NAME. */
|
|
22
|
+
static missingEventName(): void;
|
|
23
|
+
/** A streamId containing ':' (warned on every call before; now once per window). */
|
|
24
|
+
static streamIdColon(): void;
|
|
25
|
+
/**
|
|
26
|
+
* A tracked InspectorEvent with keys the SDK does not know (a typo such as `outputRef` or
|
|
27
|
+
* `eventname`). Only the key names are printed, JSON-quoted, at most
|
|
28
|
+
* MAX_LOGGED_OPTION_KEYS of them, each cut to MAX_LOGGED_OPTION_KEY_LENGTH characters;
|
|
29
|
+
* never a value.
|
|
30
|
+
*/
|
|
31
|
+
static unknownEventKeys(keys: string[], known: string[]): void;
|
|
32
|
+
/**
|
|
33
|
+
* trackSchemaFromEvent called with something other than an InspectorEvent object, such
|
|
34
|
+
* as a 1.x call with the event name first. Nothing about the argument is printed.
|
|
35
|
+
*/
|
|
36
|
+
static notAnInspectorEvent(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Prints every pending count and resets its key. With `onlyExpired` (flush()), only keys
|
|
39
|
+
* whose window has expired; destroy() and the exit drain print them all.
|
|
40
|
+
*/
|
|
41
|
+
static flushPending: (onlyExpired?: boolean) => void;
|
|
42
|
+
private static names;
|
|
43
|
+
private static noteNames;
|
|
44
|
+
private static takeNames;
|
|
45
|
+
private static occur;
|
|
46
|
+
private static seconds;
|
|
47
|
+
private static suffix;
|
|
48
|
+
private static updateExitListener;
|
|
49
|
+
private static onBeforeExit;
|
|
50
|
+
private static onExit;
|
|
51
|
+
private static write;
|
|
52
|
+
}
|
package/dist/AvoLog.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AvoLog = exports.MISSING_EVENT_NAME = exports.INTERNAL_ERROR_MESSAGE = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
// Lines about lost data and failed sends, written to stderr whatever the logging flag. Each
|
|
7
|
+
// kind (per drop reason, HTTP status or failure reason) prints at most one line per 10 s:
|
|
8
|
+
// the first occurrence prints at once, and later ones in the window are counted. A count is
|
|
9
|
+
// printed with the next occurrence after the window, by flush() once the window has expired,
|
|
10
|
+
// or by destroy() and the exit drain at once. "in the last Ns" is the real whole seconds
|
|
11
|
+
// since the window began (at least 1). There is no timer. While a count is pending, a
|
|
12
|
+
// "beforeExit" listener prints the expired ones (beforeExit also fires at every idle point of
|
|
13
|
+
// a script whose only pending work is the SDK's, so it is not treated as the exit), and an
|
|
14
|
+
// "exit" listener prints the rest, synchronously, when the process really exits.
|
|
15
|
+
const WINDOW_MS = 10000;
|
|
16
|
+
// How many names (unknown InspectorEvent keys, error types) a line prints, and how much of each key.
|
|
17
|
+
const MAX_LOGGED_OPTION_KEYS = 5;
|
|
18
|
+
const MAX_LOGGED_OPTION_KEY_LENGTH = 64;
|
|
19
|
+
// Imports only utils, which imports nothing: the jest setup loads this module before test
|
|
20
|
+
// files install their mocks, so it must not pull in the rest of the SDK.
|
|
21
|
+
/** @internal The track rejection reason and internal-error log text (SPEC §4.2 step 5). */
|
|
22
|
+
exports.INTERNAL_ERROR_MESSAGE = "Avo Inspector: something went wrong. Please report to support@avo.app.";
|
|
23
|
+
/** The event name sent for a track call whose event name is missing. */
|
|
24
|
+
exports.MISSING_EVENT_NAME = "Missing Event Name";
|
|
25
|
+
class AvoLog {
|
|
26
|
+
/** Events dropped because the unsent buffer or the send backlog is full. */
|
|
27
|
+
static dropped(count, reason) {
|
|
28
|
+
AvoLog.occur("dropped:" + reason, count, (total, _more, seconds) => {
|
|
29
|
+
AvoLog.write("warn", `Avo Inspector: dropped ${total} event(s) (${reason}) in the last ${seconds}s.`);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** A batch answered with an HTTP status other than 200. Only the status is logged. */
|
|
33
|
+
static rejected(status) {
|
|
34
|
+
AvoLog.occur("non200:" + status, 1, (total, _more, seconds) => {
|
|
35
|
+
AvoLog.write("warn", `Avo Inspector: ${total} batch(es) rejected with HTTP ${status} in the last ${seconds}s.`);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** A batch that could not be sent (network error, timeout, header guard). */
|
|
39
|
+
static failed(error) {
|
|
40
|
+
// The two fixed transport reasons print as is; anything else (an Error thrown while
|
|
41
|
+
// sending, any other value) prints only its type, so neither the line nor the limiter
|
|
42
|
+
// key ever depends on an error's message.
|
|
43
|
+
const reason = error === "Request failed" || error === "Request timed out"
|
|
44
|
+
? error
|
|
45
|
+
: "Request failed (" + AvoLog.errorType(error) + ")";
|
|
46
|
+
AvoLog.occur("failed:" + reason, 1, (_total, more, seconds) => {
|
|
47
|
+
AvoLog.write("error", "Avo Inspector: schema sending failed: " + reason + "." + AvoLog.suffix(more, seconds));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* An internal error. Only its type is printed: the error may come from reading a property
|
|
52
|
+
* (a throwing getter or proxy), so its message or stack can carry a property value.
|
|
53
|
+
*/
|
|
54
|
+
static internal(error) {
|
|
55
|
+
AvoLog.noteNames("internal", [AvoLog.errorType(error)]);
|
|
56
|
+
AvoLog.occur("internal", 1, (_total, more, seconds) => {
|
|
57
|
+
const types = AvoLog.takeNames("internal", (type) => type);
|
|
58
|
+
AvoLog.write("error", exports.INTERNAL_ERROR_MESSAGE + AvoLog.suffix(more, seconds) + " (" + types + ")");
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* @internal A fixed label for what was thrown, for any log line that reports a caught
|
|
63
|
+
* error; it never reads a field of the value. A proxy whose traps throw yields "unknown".
|
|
64
|
+
*/
|
|
65
|
+
static errorType(error) {
|
|
66
|
+
try {
|
|
67
|
+
for (const [type, label] of AvoLog.errorTypes) {
|
|
68
|
+
if (error instanceof type) {
|
|
69
|
+
return label;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return typeof error;
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
return "unknown";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** A track call without a usable event name, sent as MISSING_EVENT_NAME. */
|
|
79
|
+
static missingEventName() {
|
|
80
|
+
AvoLog.occur("missing-event-name", 1, (total, _more, seconds) => {
|
|
81
|
+
AvoLog.write("warn", `Avo Inspector: ${total} event(s) tracked without an event name in the last ${seconds}s, sent as "${exports.MISSING_EVENT_NAME}".`);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** A streamId containing ':' (warned on every call before; now once per window). */
|
|
85
|
+
static streamIdColon() {
|
|
86
|
+
AvoLog.occur("streamid-colon", 1, (_total, more, seconds) => {
|
|
87
|
+
AvoLog.write("warn", "[Avo Inspector] Warning: streamId contains ':' which is not supported" + AvoLog.suffix(more, seconds));
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* A tracked InspectorEvent with keys the SDK does not know (a typo such as `outputRef` or
|
|
92
|
+
* `eventname`). Only the key names are printed, JSON-quoted, at most
|
|
93
|
+
* MAX_LOGGED_OPTION_KEYS of them, each cut to MAX_LOGGED_OPTION_KEY_LENGTH characters;
|
|
94
|
+
* never a value.
|
|
95
|
+
*/
|
|
96
|
+
static unknownEventKeys(keys, known) {
|
|
97
|
+
AvoLog.noteNames("unknown-event-keys", keys.map((key) => (key.length > MAX_LOGGED_OPTION_KEY_LENGTH ? key.slice(0, MAX_LOGGED_OPTION_KEY_LENGTH) + "…" : key)));
|
|
98
|
+
AvoLog.occur("unknown-event-keys", 1, (_total, more, seconds) => {
|
|
99
|
+
const names = AvoLog.takeNames("unknown-event-keys", (key) => JSON.stringify(key));
|
|
100
|
+
AvoLog.write("warn", "[Avo Inspector] Warning: unknown InspectorEvent key(s) " + names + " ignored; the known keys are " +
|
|
101
|
+
known.join(", ") + AvoLog.suffix(more, seconds));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* trackSchemaFromEvent called with something other than an InspectorEvent object, such
|
|
106
|
+
* as a 1.x call with the event name first. Nothing about the argument is printed.
|
|
107
|
+
*/
|
|
108
|
+
static notAnInspectorEvent() {
|
|
109
|
+
AvoLog.occur("not-an-inspector-event", 1, (_total, more, seconds) => {
|
|
110
|
+
AvoLog.write("error", "[Avo Inspector] Error: since 2.0.0, trackSchemaFromEvent takes one InspectorEvent object; nothing was sent. " +
|
|
111
|
+
"Replace trackSchemaFromEvent(eventName, eventProperties) with trackSchemaFromEvent({ eventName, eventProperties })." +
|
|
112
|
+
AvoLog.suffix(more, seconds));
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
static noteNames(kind, names) {
|
|
116
|
+
const seen = AvoLog.names.get(kind) || [];
|
|
117
|
+
for (const name of names) {
|
|
118
|
+
if (seen.length > MAX_LOGGED_OPTION_KEYS) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
if (seen.indexOf(name) < 0) {
|
|
122
|
+
seen.push(name);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
AvoLog.names.set(kind, seen);
|
|
126
|
+
}
|
|
127
|
+
// The names noted for `kind`, formatted, joined and capped (", …" past the cap), and forgets
|
|
128
|
+
// them: the next line names only what is seen after this one.
|
|
129
|
+
static takeNames(kind, format) {
|
|
130
|
+
const seen = AvoLog.names.get(kind) || [];
|
|
131
|
+
AvoLog.names.delete(kind);
|
|
132
|
+
return seen.slice(0, MAX_LOGGED_OPTION_KEYS).map(format).join(", ") +
|
|
133
|
+
(seen.length > MAX_LOGGED_OPTION_KEYS ? ", …" : "");
|
|
134
|
+
}
|
|
135
|
+
/** @internal Test-only: forget every window. */
|
|
136
|
+
static _resetForTesting() {
|
|
137
|
+
AvoLog.windows.clear();
|
|
138
|
+
AvoLog.names.clear();
|
|
139
|
+
AvoLog.updateExitListener();
|
|
140
|
+
}
|
|
141
|
+
// Counts `amount` for `key`, or prints a line when the key's window is over (or new). The
|
|
142
|
+
// line reports this occurrence plus what the previous window counted, over the real time
|
|
143
|
+
// since that window began; with nothing counted it covers just this occurrence (1 s).
|
|
144
|
+
static occur(key, amount, print) {
|
|
145
|
+
const now = AvoLog.now();
|
|
146
|
+
const window = AvoLog.windows.get(key);
|
|
147
|
+
if (window && now - window.start < WINDOW_MS) {
|
|
148
|
+
window.suppressed += amount;
|
|
149
|
+
AvoLog.updateExitListener();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const previous = window ? window.suppressed : 0;
|
|
153
|
+
AvoLog.windows.set(key, { start: now, suppressed: 0, print });
|
|
154
|
+
print(amount + previous, previous, previous > 0 ? AvoLog.seconds(now - window.start) : 1);
|
|
155
|
+
AvoLog.updateExitListener();
|
|
156
|
+
}
|
|
157
|
+
static seconds(elapsedMs) {
|
|
158
|
+
return Math.max(1, Math.floor(elapsedMs / 1000));
|
|
159
|
+
}
|
|
160
|
+
static suffix(more, seconds) {
|
|
161
|
+
return more > 0 ? ` (${more} more in the last ${seconds}s)` : "";
|
|
162
|
+
}
|
|
163
|
+
// Armed only while some key has a pending count: it prints them at a natural exit. It
|
|
164
|
+
// schedules nothing, so it never keeps the process alive.
|
|
165
|
+
static updateExitListener() {
|
|
166
|
+
let pending = false;
|
|
167
|
+
AvoLog.windows.forEach((window) => {
|
|
168
|
+
pending = pending || window.suppressed > 0;
|
|
169
|
+
});
|
|
170
|
+
if (pending && !AvoLog.exitListenerArmed) {
|
|
171
|
+
process.on("beforeExit", AvoLog.onBeforeExit);
|
|
172
|
+
process.on("exit", AvoLog.onExit);
|
|
173
|
+
AvoLog.exitListenerArmed = true;
|
|
174
|
+
}
|
|
175
|
+
else if (!pending && AvoLog.exitListenerArmed) {
|
|
176
|
+
process.removeListener("beforeExit", AvoLog.onBeforeExit);
|
|
177
|
+
process.removeListener("exit", AvoLog.onExit);
|
|
178
|
+
AvoLog.exitListenerArmed = false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** @internal From now on lines are written synchronously: the process is exiting. */
|
|
182
|
+
static enterExit() {
|
|
183
|
+
AvoLog.exiting = true;
|
|
184
|
+
}
|
|
185
|
+
static write(level, line) {
|
|
186
|
+
if (!AvoLog.exiting) {
|
|
187
|
+
console[level](line);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
(0, fs_1.writeSync)(2, line + "\n");
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
// stderr is gone; nothing else to do as the process exits.
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
exports.AvoLog = AvoLog;
|
|
199
|
+
// Milliseconds from a monotonic clock; overridable in tests.
|
|
200
|
+
AvoLog.now = utils_1.monotonicNowMs;
|
|
201
|
+
AvoLog.windows = new Map();
|
|
202
|
+
AvoLog.exitListenerArmed = false;
|
|
203
|
+
// Set by the "exit" listener: from then on lines are written synchronously, because
|
|
204
|
+
// console writes to a pipe are asynchronous and would be lost as the process ends.
|
|
205
|
+
AvoLog.exiting = false;
|
|
206
|
+
// Built-in error classes, most specific first. Matched by prototype, never by reading the
|
|
207
|
+
// error's own `name`, which is writable and may be a getter.
|
|
208
|
+
AvoLog.errorTypes = [
|
|
209
|
+
[TypeError, "TypeError"],
|
|
210
|
+
[RangeError, "RangeError"],
|
|
211
|
+
[ReferenceError, "ReferenceError"],
|
|
212
|
+
[SyntaxError, "SyntaxError"],
|
|
213
|
+
[URIError, "URIError"],
|
|
214
|
+
[EvalError, "EvalError"],
|
|
215
|
+
[Error, "Error"],
|
|
216
|
+
];
|
|
217
|
+
/**
|
|
218
|
+
* Prints every pending count and resets its key. With `onlyExpired` (flush()), only keys
|
|
219
|
+
* whose window has expired; destroy() and the exit drain print them all.
|
|
220
|
+
*/
|
|
221
|
+
AvoLog.flushPending = (onlyExpired = false) => {
|
|
222
|
+
const now = AvoLog.now();
|
|
223
|
+
for (const [key, window] of Array.from(AvoLog.windows)) {
|
|
224
|
+
if (window.suppressed === 0 || (onlyExpired && now - window.start < WINDOW_MS)) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
AvoLog.windows.delete(key);
|
|
228
|
+
window.print(window.suppressed, window.suppressed, AvoLog.seconds(now - window.start));
|
|
229
|
+
}
|
|
230
|
+
AvoLog.updateExitListener();
|
|
231
|
+
};
|
|
232
|
+
// Distinct names (unknown keys, error types) a kind has seen since its last line, in order,
|
|
233
|
+
// for the line that reports them: a count line covers every occurrence it counts, so it
|
|
234
|
+
// names all of theirs, not only the first. At most MAX_LOGGED_OPTION_KEYS + 1 are kept, so
|
|
235
|
+
// the line can tell that more were seen.
|
|
236
|
+
AvoLog.names = new Map();
|
|
237
|
+
// Not the exit: the SDK's exit drain may resume the process. Only expired counts print,
|
|
238
|
+
// as in flush(), so idle points cannot break the rate limit.
|
|
239
|
+
AvoLog.onBeforeExit = () => {
|
|
240
|
+
AvoLog.flushPending(true);
|
|
241
|
+
};
|
|
242
|
+
// The real exit (natural, or process.exit()): print everything still pending.
|
|
243
|
+
AvoLog.onExit = () => {
|
|
244
|
+
AvoLog.enterExit();
|
|
245
|
+
AvoLog.flushPending();
|
|
246
|
+
};
|
|
@@ -2,18 +2,28 @@ import { EventSpecMetadata, PropertyValidationResult } from "./eventSpec/AvoEven
|
|
|
2
2
|
export interface BaseBody {
|
|
3
3
|
apiKey: string;
|
|
4
4
|
appName: string;
|
|
5
|
-
appVersion: string;
|
|
5
|
+
appVersion: string | null;
|
|
6
6
|
libVersion: string;
|
|
7
7
|
env: string;
|
|
8
8
|
libPlatform: "node";
|
|
9
9
|
messageId: string;
|
|
10
|
-
|
|
11
|
-
sessionId: string;
|
|
10
|
+
streamId: string;
|
|
12
11
|
anonymousId: string;
|
|
13
12
|
createdAt: string;
|
|
14
13
|
samplingRate: number;
|
|
15
14
|
publicEncryptionKey?: string;
|
|
16
15
|
}
|
|
16
|
+
export interface ResolvedGatewayFields {
|
|
17
|
+
appVersion: string | null;
|
|
18
|
+
outputReference?: string;
|
|
19
|
+
originHint?: string;
|
|
20
|
+
/** True when the caller supplied at least one non-blank gateway option. */
|
|
21
|
+
gatewayScoped: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface CallStamp {
|
|
24
|
+
createdAt: string;
|
|
25
|
+
samplingRate: number;
|
|
26
|
+
}
|
|
17
27
|
export interface EventPropertyEncrypted {
|
|
18
28
|
propertyName: string;
|
|
19
29
|
propertyType: string;
|
|
@@ -27,7 +37,6 @@ export interface EventPropertyPlain {
|
|
|
27
37
|
}
|
|
28
38
|
export interface EventPropertyValidation {
|
|
29
39
|
failedEventIds?: string[];
|
|
30
|
-
passedEventIds?: string[];
|
|
31
40
|
}
|
|
32
41
|
export type EventProperty = (EventPropertyEncrypted | EventPropertyPlain) & EventPropertyValidation;
|
|
33
42
|
export interface EventSchemaBody extends BaseBody {
|
|
@@ -37,7 +46,8 @@ export interface EventSchemaBody extends BaseBody {
|
|
|
37
46
|
avoFunction: boolean;
|
|
38
47
|
eventId: string | null;
|
|
39
48
|
eventHash: string | null;
|
|
40
|
-
|
|
49
|
+
outputReference?: string;
|
|
50
|
+
originHint?: string;
|
|
41
51
|
eventSpecMetadata?: EventSpecMetadata;
|
|
42
52
|
}
|
|
43
53
|
export type InspectorBody = EventSchemaBody;
|
|
@@ -49,16 +59,45 @@ export declare class AvoNetworkCallsHandler {
|
|
|
49
59
|
private libVersion;
|
|
50
60
|
private samplingRate;
|
|
51
61
|
private publicEncryptionKey?;
|
|
62
|
+
private inFlightRequests;
|
|
63
|
+
private aborted;
|
|
64
|
+
/** The valid mock-endpoint override in effect for this instance, read once, or null. */
|
|
65
|
+
readonly mockEndpoint: string | null;
|
|
52
66
|
private static trackingEndpoint;
|
|
67
|
+
private static mockEndpointEnvVar;
|
|
68
|
+
private static requestTimeoutMs;
|
|
69
|
+
private static gzipThresholdBytes;
|
|
53
70
|
constructor(apiKey: string, envName: string, appName: string, appVersion: string, libVersion: string, publicEncryptionKey?: string);
|
|
54
|
-
|
|
71
|
+
/**
|
|
72
|
+
* The test-only endpoint override. Fail-closed: a prod instance never honors it,
|
|
73
|
+
* whatever the surrounding process environment says. A value that is not an http(s)
|
|
74
|
+
* URL is ignored (with a one-time warning), so callers only ever see a valid URL.
|
|
75
|
+
*/
|
|
76
|
+
static mockEndpointFor(envName: string): string | null;
|
|
77
|
+
private static warnRedirect;
|
|
78
|
+
private static warnedMockEndpoint;
|
|
79
|
+
private static warnOnce;
|
|
80
|
+
/** The sampling rate last returned by the Inspector API (1 until a response sets it). */
|
|
81
|
+
getSamplingRate(): number;
|
|
82
|
+
/** Aborts every request still in flight (used by AvoInspector.destroy). */
|
|
83
|
+
abortInFlight(): void;
|
|
84
|
+
/**
|
|
85
|
+
* POSTs one batch. Resolves with the HTTP status code (the batch is never retried);
|
|
86
|
+
* rejects with "Request failed" / "Request timed out" on transport failures, or when
|
|
87
|
+
* a header value cannot be transmitted safely.
|
|
88
|
+
*/
|
|
89
|
+
callInspectorWithBatchBody(inEvents: Array<InspectorBody>): Promise<number | void>;
|
|
90
|
+
private static gzipAsync;
|
|
91
|
+
private post;
|
|
92
|
+
/** Builds the wire body for one event, encrypting property values when configured. */
|
|
55
93
|
bodyForEventSchemaCall(anonymousId: string, eventName: string, eventProperties: Array<{
|
|
56
94
|
propertyName: string;
|
|
57
95
|
propertyType: string;
|
|
58
96
|
children?: any;
|
|
59
97
|
}>, eventId: string | null, eventHash: string | null, rawEventProperties?: {
|
|
60
98
|
[propName: string]: any;
|
|
61
|
-
}): EventSchemaBody;
|
|
99
|
+
}, gatewayFields?: ResolvedGatewayFields, stamp?: CallStamp): EventSchemaBody;
|
|
100
|
+
/** Returns the event properties, with values encrypted when encryption applies. */
|
|
62
101
|
buildEventProperties(eventProperties: Array<{
|
|
63
102
|
propertyName: string;
|
|
64
103
|
propertyType: string;
|
|
@@ -66,7 +105,15 @@ export declare class AvoNetworkCallsHandler {
|
|
|
66
105
|
}>, rawEventProperties?: {
|
|
67
106
|
[propName: string]: any;
|
|
68
107
|
}): Array<EventProperty>;
|
|
69
|
-
|
|
108
|
+
/** Builds the wire body for one event, including its event-spec validation results. */
|
|
109
|
+
bodyForValidatedEventSchemaCall(anonymousId: string, eventName: string, eventProperties: Array<EventProperty>, eventId: string | null, eventHash: string | null, eventSpecMetadata: EventSpecMetadata, propertyResults: PropertyValidationResult[], gatewayFields?: ResolvedGatewayFields, stamp?: CallStamp): EventSchemaBody;
|
|
110
|
+
/**
|
|
111
|
+
* A property with its failed event IDs, and those of its object properties merged into its
|
|
112
|
+
* children. A list's children are its element schemas; each object element gets the
|
|
113
|
+
* results of the properties it has (a list of objects is validated across all its items).
|
|
114
|
+
*/
|
|
115
|
+
private static withValidation;
|
|
116
|
+
private static applyAvoFunctionFields;
|
|
70
117
|
private encryptProperties;
|
|
71
118
|
private createBaseCallBody;
|
|
72
119
|
}
|