@telemetry-tracker/core 1.4.0 → 1.5.0
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/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +75 -33
- package/dist/to-reportable-error.d.ts +3 -0
- package/dist/to-reportable-error.d.ts.map +1 -0
- package/dist/to-reportable-error.js +30 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SDK_VERSION } from "./version.js";
|
|
2
2
|
export { SDK_VERSION };
|
|
3
|
+
export { toReportableError } from "./to-reportable-error.js";
|
|
3
4
|
export { scrubPiiText, scrubPiiRecord } from "./pii-scrub.js";
|
|
4
5
|
export { WEB_VITAL_EVENT_NAME, installWebVitals, rateWebVital, buildWebVitalProperties, setWebVitalsCaptureEnabled, isWebVitalsCaptureEnabled, type WebVitalEventProperties, type WebVitalMetricName, type WebVitalRating, } from "./web-vitals.js";
|
|
5
6
|
export declare function getAnonymousId(): string;
|
|
@@ -49,10 +50,9 @@ declare function resolveClientPiiScrub(cfg: TelemetryConfig | null): {
|
|
|
49
50
|
/** @internal exported for tests */
|
|
50
51
|
export { resolveClientPiiScrub };
|
|
51
52
|
export declare function trackEvent(name: string, properties?: Record<string, unknown>): void;
|
|
52
|
-
export declare function trackError(error:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}, context?: Record<string, unknown>): void;
|
|
53
|
+
export declare function trackError(error: unknown, context?: Record<string, unknown>): void;
|
|
54
|
+
/** Send an error and resolve after the ingest request settles. Fatal handlers await this. */
|
|
55
|
+
export declare function ingestError(error: unknown, context?: Record<string, unknown>): Promise<void>;
|
|
56
56
|
export declare function screen(name: string): void;
|
|
57
57
|
export declare function getUserId(): string | null;
|
|
58
58
|
export declare function getConfigOrNull(): TelemetryConfig | null;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAC;AAyCzB,wBAAgB,cAAc,IAAI,MAAM,CAkBvC;AAED,MAAM,MAAM,uBAAuB,GAC/B,OAAO,GACP;IACE,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEN,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CACpC,CAAC;AA0HF,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,kEAAkE;AAClE,wBAAgB,UAAU,IAAI,IAAI,CAOjC;AA4CD,wBAAgB,IAAI,CAAC,CAAC,EAAE,eAAe,GAAG,IAAI,CAwB7C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,IAAI,CAS/B;AAQD,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CASzE;AAYD,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO/F;AA6ED,iBAAS,qBAAqB,CAC5B,GAAG,EAAE,eAAe,GAAG,IAAI,GAC1B;IAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAahC;AAED,mCAAmC;AACnC,OAAO,EAAE,qBAAqB,EAAE,CAAC;AAWjC,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,IAAI,CAsBN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAEN;AAED,6FAA6F;AAC7F,wBAAgB,WAAW,CACzB,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEzC;AAED,wBAAgB,SAAS,IAAI,MAAM,GAAG,IAAI,CAEzC;AAED,wBAAgB,eAAe,IAAI,eAAe,GAAG,IAAI,CAExD"}
|
package/dist/index.js
CHANGED
|
@@ -2,21 +2,43 @@ import { readDeviceContext } from "./device-context.js";
|
|
|
2
2
|
import { installWebVitals, setWebVitalsCaptureEnabled, WEB_VITAL_EVENT_NAME, } from "./web-vitals.js";
|
|
3
3
|
import { scrubPiiRecord, scrubPiiText } from "./pii-scrub.js";
|
|
4
4
|
import { SDK_VERSION } from "./version.js";
|
|
5
|
+
import { toReportableError } from "./to-reportable-error.js";
|
|
5
6
|
export { SDK_VERSION };
|
|
7
|
+
export { toReportableError } from "./to-reportable-error.js";
|
|
6
8
|
export { scrubPiiText, scrubPiiRecord } from "./pii-scrub.js";
|
|
7
9
|
export { WEB_VITAL_EVENT_NAME, installWebVitals, rateWebVital, buildWebVitalProperties, setWebVitalsCaptureEnabled, isWebVitalsCaptureEnabled, } from "./web-vitals.js";
|
|
8
|
-
const REPORTED = Symbol.for("telemetry.reported");
|
|
9
10
|
const ANON_STORAGE_KEY = "tacko_telemetry_anon_id";
|
|
11
|
+
/** In-flight ingest promises so a later fatal flush can await trackError(e); throw e. */
|
|
12
|
+
const inFlightIngest = new WeakMap();
|
|
13
|
+
/** Completed error reports — WeakSet so we never mutate frozen/sealed Error objects. */
|
|
14
|
+
const reportedErrors = new WeakSet();
|
|
10
15
|
let anonymousId = null;
|
|
16
|
+
let fallbackIdSeq = 0;
|
|
17
|
+
function bytesToUuid(bytes) {
|
|
18
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
19
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
20
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
21
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
22
|
+
}
|
|
23
|
+
/** Prefer Web Crypto; fall back for Node/RN hosts without a global crypto polyfill. */
|
|
11
24
|
function generateUUID() {
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
const webCrypto = typeof globalThis !== "undefined" ? globalThis.crypto : undefined;
|
|
26
|
+
if (webCrypto && typeof webCrypto.randomUUID === "function") {
|
|
27
|
+
return webCrypto.randomUUID();
|
|
14
28
|
}
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
return
|
|
19
|
-
}
|
|
29
|
+
if (webCrypto && typeof webCrypto.getRandomValues === "function") {
|
|
30
|
+
const bytes = new Uint8Array(16);
|
|
31
|
+
webCrypto.getRandomValues(bytes);
|
|
32
|
+
return bytesToUuid(bytes);
|
|
33
|
+
}
|
|
34
|
+
// Constrained runtimes: unique analytics IDs without Math.random (CodeQL insecure-randomness).
|
|
35
|
+
const bytes = new Uint8Array(16);
|
|
36
|
+
let n = (Date.now() ^ (++fallbackIdSeq * 0x9e3779b9)) >>> 0;
|
|
37
|
+
for (let i = 0; i < 16; i++) {
|
|
38
|
+
n = (Math.imul(n, 1664525) + 1013904223) >>> 0;
|
|
39
|
+
bytes[i] = n & 0xff;
|
|
40
|
+
}
|
|
41
|
+
return bytesToUuid(bytes);
|
|
20
42
|
}
|
|
21
43
|
export function getAnonymousId() {
|
|
22
44
|
if (anonymousId)
|
|
@@ -390,33 +412,53 @@ export function trackEvent(name, properties) {
|
|
|
390
412
|
}
|
|
391
413
|
}
|
|
392
414
|
export function trackError(error, context) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if (
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
415
|
+
void ingestError(error, context);
|
|
416
|
+
}
|
|
417
|
+
/** Send an error and resolve after the ingest request settles. Fatal handlers await this. */
|
|
418
|
+
export function ingestError(error, context) {
|
|
419
|
+
try {
|
|
420
|
+
const cfg = getConfigOrNull();
|
|
421
|
+
if (!cfg)
|
|
422
|
+
return Promise.resolve();
|
|
423
|
+
const err = toReportableError(error);
|
|
424
|
+
const existing = inFlightIngest.get(err);
|
|
425
|
+
if (existing)
|
|
426
|
+
return existing;
|
|
427
|
+
if (reportedErrors.has(err)) {
|
|
428
|
+
return Promise.resolve();
|
|
429
|
+
}
|
|
430
|
+
let message = err.message;
|
|
431
|
+
let stack = err.stack;
|
|
432
|
+
let scrubbedContext = context ?? undefined;
|
|
433
|
+
const scrubOpts = resolveClientPiiScrub(cfg);
|
|
434
|
+
if (scrubOpts) {
|
|
435
|
+
message = scrubPiiText(message);
|
|
436
|
+
if (stack != null)
|
|
437
|
+
stack = scrubPiiText(stack);
|
|
438
|
+
if (scrubbedContext != null) {
|
|
439
|
+
scrubbedContext = scrubPiiRecord(scrubbedContext, scrubOpts);
|
|
440
|
+
}
|
|
409
441
|
}
|
|
442
|
+
// Non-mutating dedupe — safe for Object.freeze / seal / preventExtensions.
|
|
443
|
+
reportedErrors.add(err);
|
|
444
|
+
const pending = send("/ingest/error", {
|
|
445
|
+
message,
|
|
446
|
+
stack: stack ?? undefined,
|
|
447
|
+
context: scrubbedContext,
|
|
448
|
+
user_id: userId ?? undefined,
|
|
449
|
+
session_id: sessionId ?? undefined,
|
|
450
|
+
})
|
|
451
|
+
.catch(() => { })
|
|
452
|
+
.finally(() => {
|
|
453
|
+
inFlightIngest.delete(err);
|
|
454
|
+
});
|
|
455
|
+
inFlightIngest.set(err, pending);
|
|
456
|
+
return pending;
|
|
457
|
+
}
|
|
458
|
+
catch {
|
|
459
|
+
// Never let telemetry-internal failures escape into the caller's crash path.
|
|
460
|
+
return Promise.resolve();
|
|
410
461
|
}
|
|
411
|
-
if (err instanceof Error)
|
|
412
|
-
err[REPORTED] = true;
|
|
413
|
-
send("/ingest/error", {
|
|
414
|
-
message,
|
|
415
|
-
stack: stack ?? undefined,
|
|
416
|
-
context: scrubbedContext,
|
|
417
|
-
user_id: userId ?? undefined,
|
|
418
|
-
session_id: sessionId ?? undefined,
|
|
419
|
-
}).catch(() => { });
|
|
420
462
|
}
|
|
421
463
|
export function screen(name) {
|
|
422
464
|
trackEvent("$screen", { name });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-reportable-error.d.ts","sourceRoot":"","sources":["../src/to-reportable-error.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAuBvD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Normalize any thrown/rejected value into a reportable Error. */
|
|
2
|
+
export function toReportableError(value) {
|
|
3
|
+
if (value instanceof Error)
|
|
4
|
+
return value;
|
|
5
|
+
if (value === null)
|
|
6
|
+
return new Error("null");
|
|
7
|
+
if (value === undefined)
|
|
8
|
+
return new Error("undefined");
|
|
9
|
+
if (typeof value === "string")
|
|
10
|
+
return new Error(value);
|
|
11
|
+
if (typeof value === "number" ||
|
|
12
|
+
typeof value === "boolean" ||
|
|
13
|
+
typeof value === "bigint") {
|
|
14
|
+
return new Error(String(value));
|
|
15
|
+
}
|
|
16
|
+
if (typeof value === "symbol")
|
|
17
|
+
return new Error(value.toString());
|
|
18
|
+
if (typeof value === "object") {
|
|
19
|
+
try {
|
|
20
|
+
const json = JSON.stringify(value);
|
|
21
|
+
if (typeof json === "string")
|
|
22
|
+
return new Error(json);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// circular / non-serializable
|
|
26
|
+
}
|
|
27
|
+
return new Error(Object.prototype.toString.call(value));
|
|
28
|
+
}
|
|
29
|
+
return new Error(String(value));
|
|
30
|
+
}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Injected at build time from package.json. Do not edit manually. */
|
|
2
|
-
export const SDK_VERSION = "1.
|
|
2
|
+
export const SDK_VERSION = "1.5.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telemetry-tracker/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Lightweight telemetry client: events, errors, sessions. Framework-agnostic core.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"web-vitals": "^4.2.4"
|
|
36
36
|
},
|
|
37
|
+
"gitHead": "886d9f8e0b92a78471f27b87365fc40ba7043ce1",
|
|
37
38
|
"scripts": {
|
|
38
39
|
"build": "node scripts/inject-version.cjs && rm -rf dist && tsc",
|
|
39
40
|
"dev": "tsc --watch",
|