@syntrologie/runtime-sdk 2.17.0 → 2.19.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/context/schema.d.ts +14 -14
- package/dist/index.js +2041 -1657
- package/dist/index.js.map +4 -4
- package/dist/observability/healthReporter.d.ts +51 -0
- package/dist/observability/index.d.ts +5 -0
- package/dist/observability/otlpEmitter.d.ts +39 -0
- package/dist/observability/sdkScriptUrl.d.ts +16 -0
- package/dist/observability/types.d.ts +79 -0
- package/dist/observability/webVitalsAdapter.d.ts +22 -0
- package/dist/smart-canvas.esm.js +156 -156
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +5964 -5355
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +156 -156
- package/dist/smart-canvas.min.js.map +4 -4
- package/dist/token.d.ts +7 -0
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { CounterSignal, HealthReporterConfig, HistogramSignal, ReporterRuntimeBinding } from './types';
|
|
2
|
+
export declare class HealthReporter {
|
|
3
|
+
private readonly config;
|
|
4
|
+
private readonly resource;
|
|
5
|
+
private readonly flushIntervalMs;
|
|
6
|
+
private readonly counters;
|
|
7
|
+
private readonly histograms;
|
|
8
|
+
private windowStartMs;
|
|
9
|
+
private timer;
|
|
10
|
+
private pagehideHandler;
|
|
11
|
+
private runtime;
|
|
12
|
+
/** Cleanup function for adapters that registered side effects (e.g. the
|
|
13
|
+
* web-vitals long-task observer). Called from `stop()` so SPA re-init
|
|
14
|
+
* via `initHealthReporter` doesn't accumulate observers. */
|
|
15
|
+
private adapterCleanup;
|
|
16
|
+
constructor(config: HealthReporterConfig);
|
|
17
|
+
/**
|
|
18
|
+
* Bind runtime-derived attribute resolvers. Called after the canvas/telemetry
|
|
19
|
+
* are fully initialized. Must never throw — resolvers are wrapped in
|
|
20
|
+
* null-safe access at flush time.
|
|
21
|
+
*/
|
|
22
|
+
bindRuntime(binding: ReporterRuntimeBinding): void;
|
|
23
|
+
/**
|
|
24
|
+
* Register a cleanup function to run on `stop()`. Used by adapters
|
|
25
|
+
* (e.g. webVitalsAdapter) that need to release per-bind resources
|
|
26
|
+
* like PerformanceObservers. Replaces any prior cleanup — only one
|
|
27
|
+
* adapter cleanup is tracked.
|
|
28
|
+
*/
|
|
29
|
+
attachAdapterCleanup(cleanup: () => void): void;
|
|
30
|
+
increment(signal: CounterSignal, by?: number): void;
|
|
31
|
+
/**
|
|
32
|
+
* @internal — exposed for test inspection only. Mid-window state is intentionally
|
|
33
|
+
* unstable; consumers should subscribe to flush payloads instead.
|
|
34
|
+
*/
|
|
35
|
+
snapshotCounters(): Partial<Record<CounterSignal, number>>;
|
|
36
|
+
recordHistogram(signal: HistogramSignal, valueMs: number): void;
|
|
37
|
+
/**
|
|
38
|
+
* @internal — exposed for test inspection only. Mid-window state is intentionally
|
|
39
|
+
* unstable; consumers should subscribe to flush payloads instead.
|
|
40
|
+
*/
|
|
41
|
+
snapshotHistograms(): Partial<Record<HistogramSignal, {
|
|
42
|
+
count: number;
|
|
43
|
+
p50: number;
|
|
44
|
+
p95: number;
|
|
45
|
+
}>>;
|
|
46
|
+
flush(): Promise<void>;
|
|
47
|
+
start(): void;
|
|
48
|
+
stop(): void;
|
|
49
|
+
}
|
|
50
|
+
export declare function initHealthReporter(config: HealthReporterConfig): HealthReporter;
|
|
51
|
+
export declare function getHealthReporter(): HealthReporter | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { getHealthReporter, HealthReporter, initHealthReporter } from './healthReporter';
|
|
2
|
+
export { createOtlpEmitter } from './otlpEmitter';
|
|
3
|
+
export { getSdkScriptUrl, getSdkScriptUrlPrefix } from './sdkScriptUrl';
|
|
4
|
+
export type { CounterSignal, FlushPayload, HealthReporterConfig, HistogramSignal, ReporterResource, } from './types';
|
|
5
|
+
export { bindWebVitals } from './webVitalsAdapter';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { FlushPayload } from './types';
|
|
2
|
+
interface AnyValue {
|
|
3
|
+
stringValue?: string;
|
|
4
|
+
intValue?: number;
|
|
5
|
+
doubleValue?: number;
|
|
6
|
+
}
|
|
7
|
+
interface KV {
|
|
8
|
+
key: string;
|
|
9
|
+
value: AnyValue;
|
|
10
|
+
}
|
|
11
|
+
interface OtlpEnvelope {
|
|
12
|
+
resourceLogs: Array<{
|
|
13
|
+
resource: {
|
|
14
|
+
attributes: KV[];
|
|
15
|
+
};
|
|
16
|
+
scopeLogs: Array<{
|
|
17
|
+
scope: {
|
|
18
|
+
name: string;
|
|
19
|
+
};
|
|
20
|
+
logRecords: Array<{
|
|
21
|
+
timeUnixNano: string;
|
|
22
|
+
observedTimeUnixNano: string;
|
|
23
|
+
severityText: 'INFO';
|
|
24
|
+
body: AnyValue;
|
|
25
|
+
attributes: KV[];
|
|
26
|
+
}>;
|
|
27
|
+
}>;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @internal — exposed for unit testing only. Production code should use createOtlpEmitter.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildOtlpPayload(flush: FlushPayload): OtlpEnvelope;
|
|
34
|
+
export interface OtlpEmitterConfig {
|
|
35
|
+
endpoint: string;
|
|
36
|
+
fetchImpl?: typeof fetch;
|
|
37
|
+
}
|
|
38
|
+
export declare function createOtlpEmitter(cfg: OtlpEmitterConfig): (p: FlushPayload) => Promise<void>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The full URL of the SDK script, captured at module load. Returns
|
|
3
|
+
* `undefined` when the SDK is bundled into the host app (no separate
|
|
4
|
+
* `<script>` tag) or when running outside a browser.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getSdkScriptUrl(): string | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Directory prefix of the SDK script URL — useful for matching attribution
|
|
9
|
+
* entries from `PerformanceLongTaskTiming` against the SDK bundle and any
|
|
10
|
+
* sibling chunks (source maps, lazy-loaded adaptives) served from the same
|
|
11
|
+
* directory.
|
|
12
|
+
*
|
|
13
|
+
* Example: `https://cdn.syntrologie.com/runtime-sdk/v2/canary/smart-canvas.min.js`
|
|
14
|
+
* → `https://cdn.syntrologie.com/runtime-sdk/v2/canary/`
|
|
15
|
+
*/
|
|
16
|
+
export declare function getSdkScriptUrlPrefix(): string | undefined;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Names of signals the SDK emits. Add new entries as the taxonomy grows.
|
|
3
|
+
* Counter signals are unbounded integers; histogram signals are millisecond floats.
|
|
4
|
+
*/
|
|
5
|
+
export type CounterSignal = 'bootstrap_ok' | 'bootstrap_errors' | 'flag_fetch_count' | 'flag_fetch_errors' | 'longtasks_self_count'
|
|
6
|
+
/** Cumulative blocking time (ms) from long tasks attributed to the SDK
|
|
7
|
+
* script. Counter rather than histogram so HogQL sum() across windows
|
|
8
|
+
* gives the total — which is what alerts/dashboards actually want. */
|
|
9
|
+
| 'longtasks_self_blocking_ms';
|
|
10
|
+
/**
|
|
11
|
+
* Histogram signals. Web vitals are field-RUM measurements from the customer's
|
|
12
|
+
* browser, not synthetic Lighthouse audits — same metrics Lighthouse reports
|
|
13
|
+
* as "Core Web Vitals from CrUX," but measured live.
|
|
14
|
+
*
|
|
15
|
+
* - lcp_ms — Largest Contentful Paint
|
|
16
|
+
* - inp_ms — Interaction to Next Paint
|
|
17
|
+
* - cls_score — Cumulative Layout Shift (unitless 0..1+)
|
|
18
|
+
* - fcp_ms — First Contentful Paint
|
|
19
|
+
* - ttfb_ms — Time to First Byte
|
|
20
|
+
*/
|
|
21
|
+
export type HistogramSignal = 'flag_fetch_latency_ms' | 'lcp_ms' | 'inp_ms' | 'cls_score' | 'fcp_ms' | 'ttfb_ms';
|
|
22
|
+
/**
|
|
23
|
+
* Resource attributes for the OTLP payload. The static fields are set at
|
|
24
|
+
* reporter init; the dynamic fields are resolved at flush time via runtime
|
|
25
|
+
* binding (see HealthReporter.bindRuntime).
|
|
26
|
+
*/
|
|
27
|
+
export interface ReporterResource {
|
|
28
|
+
serviceName: 'syntro-runtime-sdk';
|
|
29
|
+
serviceVersion: string;
|
|
30
|
+
/** Customer's PostHog project SDK key. Identifies which PostHog project
|
|
31
|
+
* this telemetry corresponds to. The exporter joins on this. */
|
|
32
|
+
posthogKey: string;
|
|
33
|
+
/** Page origin where the SDK booted (e.g. https://customer.com). */
|
|
34
|
+
hostOrigin: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Runtime-derived attributes resolved at flush time. The HealthReporter
|
|
38
|
+
* binds resolvers via bindRuntime() once the canvas/telemetry are ready.
|
|
39
|
+
* Before bindRuntime is called, defaults apply.
|
|
40
|
+
*/
|
|
41
|
+
export interface ReporterRuntimeBinding {
|
|
42
|
+
/** PostHog session ID. Returns empty string before telemetry is ready. */
|
|
43
|
+
getSessionId(): string;
|
|
44
|
+
/** Surface context snapshot. Returns null before context is ready. */
|
|
45
|
+
getSurface(): {
|
|
46
|
+
type: 'web' | 'telegram' | 'mcp-app';
|
|
47
|
+
host: string;
|
|
48
|
+
device: 'mobile' | 'tablet' | 'desktop';
|
|
49
|
+
mode: 'agent' | 'mobile' | 'desktop';
|
|
50
|
+
} | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* In-memory aggregate produced at flush time. Resource is the snapshot
|
|
54
|
+
* of static + runtime-bound fields at flush moment.
|
|
55
|
+
*/
|
|
56
|
+
export interface FlushPayload {
|
|
57
|
+
resource: ReporterResource & {
|
|
58
|
+
sessionId: string;
|
|
59
|
+
surfaceType: 'web' | 'telegram' | 'mcp-app' | 'unknown';
|
|
60
|
+
surfaceHost: string;
|
|
61
|
+
surfaceDevice: 'mobile' | 'tablet' | 'desktop' | 'unknown';
|
|
62
|
+
surfaceMode: 'agent' | 'mobile' | 'desktop' | 'unknown';
|
|
63
|
+
};
|
|
64
|
+
windowSeconds: number;
|
|
65
|
+
windowStartUnixMs: number;
|
|
66
|
+
counters: Partial<Record<CounterSignal, number>>;
|
|
67
|
+
/** Histograms expose count, p50, p95 — raw samples are NOT shipped. */
|
|
68
|
+
histograms: Partial<Record<HistogramSignal, {
|
|
69
|
+
count: number;
|
|
70
|
+
p50: number;
|
|
71
|
+
p95: number;
|
|
72
|
+
}>>;
|
|
73
|
+
}
|
|
74
|
+
/** Configuration for the reporter singleton. */
|
|
75
|
+
export interface HealthReporterConfig {
|
|
76
|
+
resource: ReporterResource;
|
|
77
|
+
flushIntervalMs?: number;
|
|
78
|
+
emit: (payload: FlushPayload) => Promise<void>;
|
|
79
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HealthReporter } from './healthReporter';
|
|
2
|
+
/**
|
|
3
|
+
* Bind the web-vitals callbacks to the given HealthReporter. Each metric
|
|
4
|
+
* fires once per session per metric (with possible BFCache reactivations).
|
|
5
|
+
*
|
|
6
|
+
* Idempotent across `Syntro.init()` re-calls: web-vitals subscriptions are
|
|
7
|
+
* registered once per page; later binds re-route to the most recent
|
|
8
|
+
* reporter via a window-scoped pointer. Long-task observers are per-bind
|
|
9
|
+
* and disposed via the returned cleanup function.
|
|
10
|
+
*
|
|
11
|
+
* Long-task tracking is opt-in via `attributedScriptUrlPrefix`: when the
|
|
12
|
+
* browser exposes long-task attribution and the offending script's URL
|
|
13
|
+
* starts with this prefix, the long task is counted toward the SDK's own
|
|
14
|
+
* blocking time. Pass the SDK script URL prefix (typically the CDN
|
|
15
|
+
* directory the bundle was loaded from).
|
|
16
|
+
*
|
|
17
|
+
* Safe to call in non-browser environments — returns a no-op cleanup
|
|
18
|
+
* function when `window` is unavailable.
|
|
19
|
+
*/
|
|
20
|
+
export declare function bindWebVitals(reporter: HealthReporter, options?: {
|
|
21
|
+
attributedScriptUrlPrefix?: string;
|
|
22
|
+
}): () => void;
|