stitchkit 0.116.0 → 0.118.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/agent-runtime/run-acquisition.d.ts +9 -2
  3. package/dist/agent-runtime/run-acquisition.d.ts.map +1 -1
  4. package/dist/agent-runtime/run-execution.d.ts +3 -0
  5. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  6. package/dist/agent-runtime/run-failure.d.ts +4 -1
  7. package/dist/agent-runtime/run-failure.d.ts.map +1 -1
  8. package/dist/agent-runtime/run-store-retry.d.ts +8 -0
  9. package/dist/agent-runtime/run-store-retry.d.ts.map +1 -0
  10. package/dist/agent-runtime/run-terminal.d.ts.map +1 -1
  11. package/dist/agent-runtime/run-unacquired.d.ts +19 -0
  12. package/dist/agent-runtime/run-unacquired.d.ts.map +1 -0
  13. package/dist/agent-runtime/store-conformance.d.ts +8 -0
  14. package/dist/agent-runtime/store-conformance.d.ts.map +1 -1
  15. package/dist/agent-runtime/store-driver-contract.d.ts +5 -0
  16. package/dist/agent-runtime/store-driver-contract.d.ts.map +1 -1
  17. package/dist/agent-runtime/terminal-commit.d.ts +34 -4
  18. package/dist/agent-runtime/terminal-commit.d.ts.map +1 -1
  19. package/dist/entrypoints/agent-runtime/harness.js +2 -2
  20. package/dist/entrypoints/agent-runtime/sqlite/bun.js +3 -3
  21. package/dist/entrypoints/agent-runtime/sqlite/node.js +3 -3
  22. package/dist/entrypoints/agent-runtime/testing.js +22 -4
  23. package/dist/entrypoints/agent-runtime.d.ts +1 -1
  24. package/dist/entrypoints/agent-runtime.d.ts.map +1 -1
  25. package/dist/entrypoints/agent-runtime.js +13 -11
  26. package/dist/entrypoints/application/diagnostic-journal.js +1 -1
  27. package/dist/entrypoints/application/directory-inbox.js +3 -3
  28. package/dist/entrypoints/cli/publish.js +2 -2
  29. package/dist/entrypoints/files.js +2 -2
  30. package/dist/entrypoints/primitives.js +51 -154
  31. package/dist/entrypoints/server.js +6 -6
  32. package/dist/entrypoints/telegram.d.ts +1 -1
  33. package/dist/entrypoints/telegram.d.ts.map +1 -1
  34. package/dist/entrypoints/telegram.js +352 -137
  35. package/dist/entrypoints/tracking/contract.d.ts +11 -0
  36. package/dist/entrypoints/tracking/contract.d.ts.map +1 -0
  37. package/dist/entrypoints/tracking/contract.js +162 -0
  38. package/dist/entrypoints/tracking/performance.d.ts +8 -0
  39. package/dist/entrypoints/tracking/performance.d.ts.map +1 -0
  40. package/dist/entrypoints/tracking/performance.js +181 -0
  41. package/dist/entrypoints/tracking/server.d.ts +1 -0
  42. package/dist/entrypoints/tracking/server.d.ts.map +1 -1
  43. package/dist/entrypoints/tracking/server.js +40 -12
  44. package/dist/entrypoints/tracking.d.ts +4 -3
  45. package/dist/entrypoints/tracking.d.ts.map +1 -1
  46. package/dist/entrypoints/tracking.js +43 -143
  47. package/dist/entrypoints/xlsx.d.ts +4 -0
  48. package/dist/entrypoints/xlsx.d.ts.map +1 -0
  49. package/dist/entrypoints/xlsx.js +406 -0
  50. package/dist/{index-fa435yq2.js → index-073nw9qr.js} +8 -8
  51. package/dist/index-1f40z584.js +7 -0
  52. package/dist/{index-fdk4r4r6.js → index-75ns2ybj.js} +1 -1
  53. package/dist/{index-jq2ky8fw.js → index-cycp3r3e.js} +124 -181
  54. package/dist/{index-4g6qmgdx.js → index-ghtpfz4z.js} +9 -9
  55. package/dist/{index-n3v695sb.js → index-hdjmdwsj.js} +277 -96
  56. package/dist/{index-zqkz4af9.js → index-nqxrm176.js} +1 -1
  57. package/dist/index-qezhmp51.js +242 -0
  58. package/dist/index-vv1sch8a.js +94 -0
  59. package/dist/{index-fggxgbrk.js → index-xx1j310k.js} +165 -102
  60. package/dist/internal/exclusive-lock.d.ts.map +1 -1
  61. package/dist/primitives/decimal.d.ts +10 -0
  62. package/dist/primitives/decimal.d.ts.map +1 -1
  63. package/dist/primitives/index.d.ts +3 -1
  64. package/dist/primitives/index.d.ts.map +1 -1
  65. package/dist/primitives/money.d.ts +20 -0
  66. package/dist/primitives/money.d.ts.map +1 -1
  67. package/dist/primitives/quantity.d.ts.map +1 -1
  68. package/dist/primitives/rounding.d.ts +40 -0
  69. package/dist/primitives/rounding.d.ts.map +1 -0
  70. package/dist/telegram/budget-transformer.d.ts +2 -2
  71. package/dist/telegram/not-dispatched.d.ts +2 -2
  72. package/dist/telegram/not-dispatched.d.ts.map +1 -1
  73. package/dist/telegram/outbound-budget.d.ts +53 -16
  74. package/dist/telegram/outbound-budget.d.ts.map +1 -1
  75. package/dist/telegram/outbound-cost.d.ts +5 -0
  76. package/dist/telegram/outbound-cost.d.ts.map +1 -0
  77. package/dist/telegram/outbound-pauses.d.ts +17 -0
  78. package/dist/telegram/outbound-pauses.d.ts.map +1 -0
  79. package/dist/telegram/outbound-queue.d.ts +17 -0
  80. package/dist/telegram/outbound-queue.d.ts.map +1 -0
  81. package/dist/telegram/update-intake-work.d.ts +20 -1
  82. package/dist/telegram/update-intake-work.d.ts.map +1 -1
  83. package/dist/telegram/update-intake.d.ts +12 -3
  84. package/dist/telegram/update-intake.d.ts.map +1 -1
  85. package/dist/telegram/update-store-check.d.ts +1 -1
  86. package/dist/telegram/update-store-check.d.ts.map +1 -1
  87. package/dist/telegram/update-store-postgres.d.ts.map +1 -1
  88. package/dist/telegram/update-store-sqlite.d.ts.map +1 -1
  89. package/dist/telegram/update-store.d.ts +5 -1
  90. package/dist/telegram/update-store.d.ts.map +1 -1
  91. package/dist/tracking/attribution.d.ts +1 -1
  92. package/dist/tracking/attribution.d.ts.map +1 -1
  93. package/dist/tracking/client-visit.d.ts +3 -1
  94. package/dist/tracking/client-visit.d.ts.map +1 -1
  95. package/dist/tracking/client.d.ts.map +1 -1
  96. package/dist/tracking/performance/collector.d.ts +61 -0
  97. package/dist/tracking/performance/collector.d.ts.map +1 -0
  98. package/dist/tracking/performance/schema.d.ts +45 -0
  99. package/dist/tracking/performance/schema.d.ts.map +1 -0
  100. package/dist/tracking/performance/summary.d.ts +12 -0
  101. package/dist/tracking/performance/summary.d.ts.map +1 -0
  102. package/dist/tracking/privacy.d.ts +5 -0
  103. package/dist/tracking/privacy.d.ts.map +1 -0
  104. package/dist/tracking/server/telemetry-health.d.ts +31 -0
  105. package/dist/tracking/server/telemetry-health.d.ts.map +1 -0
  106. package/dist/xlsx/cells.d.ts +17 -0
  107. package/dist/xlsx/cells.d.ts.map +1 -0
  108. package/dist/xlsx/render.d.ts +11 -0
  109. package/dist/xlsx/render.d.ts.map +1 -0
  110. package/dist/xlsx/schema.d.ts +119 -0
  111. package/dist/xlsx/schema.d.ts.map +1 -0
  112. package/dist/xlsx/zip.d.ts +13 -0
  113. package/dist/xlsx/zip.d.ts.map +1 -0
  114. package/llms/agent-runtime.2.txt +40 -16
  115. package/llms/agent-runtime.3.txt +17 -0
  116. package/llms/agent-runtime.txt +4 -1
  117. package/llms/primitives.txt +21 -0
  118. package/llms/stitchkit.txt +9 -6
  119. package/llms/telegram.txt +46 -15
  120. package/llms/tracking-contract.txt +32 -0
  121. package/llms/tracking-performance.txt +21 -0
  122. package/llms/tracking-server.txt +1 -0
  123. package/llms/tracking.txt +75 -12
  124. package/llms/{upgrading-0.105.0-0.116.0.txt → upgrading-0.105.0-0.118.0.txt} +73 -3
  125. package/llms/upgrading.txt +1 -1
  126. package/llms/xlsx.txt +107 -0
  127. package/llms-full.txt +392 -34
  128. package/llms.txt +11 -7
  129. package/package.json +27 -9
  130. package/dist/{index-z3d6smer.js → index-tdpmfks8.js} +5 -5
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `stitchkit/tracking/contract` — the wire shapes of tracking: the contract
3
+ * factory, the event and visit schemas, and the performance sample with its
4
+ * trust threshold. It brings `zod`, so it belongs to the server and to a shared
5
+ * contract, and browser code that sends events does not import it. → ADR 0280.
6
+ */
7
+ export { createTrackingContract, type TrackingContractConfig, type TrackingContractEndpoints, } from '../../tracking/contract.js';
8
+ export { type PerformanceSample, PerformanceSampleSchema, type PerformanceVitals, PerformanceVitalsSchema, } from '../../tracking/performance/schema.js';
9
+ export { type PerformanceMetricSummary, summarizePerformanceMetric, } from '../../tracking/performance/summary.js';
10
+ export { type AttributionData, AttributionDataSchema, createTrackingSchemas, DEFAULT_BUILD_ID_PATTERN, type TrackEventsRequest, type TrackEventsResponse, TrackEventsResponseSchema, type TrackingDisposition, TrackingDispositionSchema, type TrackingDispositionStatus, TrackingDispositionStatusSchema, type TrackingEventEnvelope, type TrackingEventShape, type TrackingOutboxState, TrackingOutboxStateSchema, type TrackingSchemas, type TrackingSchemasConfig, type UtmData, UtmDataSchema, type VisitBootstrapResponse, VisitBootstrapResponseSchema, type VisitEntryContext, type VisitEntryContextShape, } from '../../tracking/schemas.js';
11
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/tracking/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,uBAAuB,GACxB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,KAAK,wBAAwB,EAC7B,0BAA0B,GAC3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,KAAK,eAAe,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,aAAa,EACb,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,162 @@
1
+ import"../../index-m38ej7e5.js";
2
+ import {
3
+ defineContract2
4
+ } from "../../index-d9hq291n.js";
5
+
6
+ // src/tracking/schemas.ts
7
+ import { z } from "zod";
8
+ var UtmDataSchema = z.object({
9
+ source: z.string().max(200).optional(),
10
+ medium: z.string().max(200).optional(),
11
+ campaign: z.string().max(200).optional(),
12
+ content: z.string().max(200).optional(),
13
+ term: z.string().max(200).optional()
14
+ });
15
+ var AttributionDataSchema = z.object({
16
+ utm: UtmDataSchema.optional(),
17
+ referrer: z.string().optional(),
18
+ landingPage: z.string().optional()
19
+ });
20
+ var DEFAULT_BUILD_ID_PATTERN = /^(dev|[a-f0-9]{7,40})$/;
21
+ var TrackingDispositionStatusSchema = z.enum([
22
+ "accepted",
23
+ "duplicate",
24
+ "identity-invalid",
25
+ "excluded-bot"
26
+ ]);
27
+ var TrackingDispositionSchema = z.object({
28
+ eventId: z.uuid(),
29
+ status: TrackingDispositionStatusSchema
30
+ });
31
+ var TrackEventsResponseSchema = z.object({
32
+ accepted: z.number().int().nonnegative(),
33
+ dispositions: z.array(TrackingDispositionSchema)
34
+ });
35
+ var VisitBootstrapResponseSchema = z.object({
36
+ visitId: z.uuid(),
37
+ expiresAt: z.iso.datetime()
38
+ });
39
+ var TrackingOutboxStateSchema = z.enum(["available", "unavailable"]);
40
+ function trackingEventShape(eventTypes) {
41
+ return {
42
+ eventId: z.uuid(),
43
+ visitId: z.uuid(),
44
+ browserStreamId: z.uuid(),
45
+ browserSequence: z.number().int().nonnegative(),
46
+ type: z.enum(eventTypes),
47
+ page: z.string().max(2000),
48
+ metadata: z.record(z.string(), z.unknown()).optional(),
49
+ clientTimestamp: z.number()
50
+ };
51
+ }
52
+ function visitEntryContextShape(buildIdPattern) {
53
+ return {
54
+ browserStreamId: z.uuid(),
55
+ previousVisitId: z.uuid().optional(),
56
+ origin: z.url().max(500),
57
+ landingPath: z.string().startsWith("/").max(300).regex(/^[^?#]*$/),
58
+ referrer: z.url().max(2000).optional(),
59
+ utm: UtmDataSchema.optional(),
60
+ displayMode: z.enum(["browser", "standalone"]),
61
+ screenWidth: z.number().int().positive().max(20000),
62
+ screenHeight: z.number().int().positive().max(20000),
63
+ buildId: z.string().regex(buildIdPattern),
64
+ outboxState: TrackingOutboxStateSchema,
65
+ outboxQueued: z.number().int().nonnegative().max(1000),
66
+ outboxDropped: z.number().int().nonnegative()
67
+ };
68
+ }
69
+ function createTrackingSchemas(config) {
70
+ const base = z.object(trackingEventShape(config.eventTypes));
71
+ const event = config.eventExtras ? base.extend(config.eventExtras.shape) : base;
72
+ const buildIdPattern = config.buildIdPattern ?? DEFAULT_BUILD_ID_PATTERN;
73
+ const maxEvents = config.maxEventsPerBatch ?? 50;
74
+ return {
75
+ event,
76
+ request: z.object({
77
+ buildId: z.string().regex(buildIdPattern),
78
+ events: z.array(event).min(1).max(maxEvents),
79
+ utm: UtmDataSchema.optional()
80
+ }),
81
+ response: TrackEventsResponseSchema,
82
+ disposition: TrackingDispositionSchema,
83
+ entry: z.object(visitEntryContextShape(buildIdPattern)),
84
+ bootstrap: VisitBootstrapResponseSchema
85
+ };
86
+ }
87
+
88
+ // src/tracking/contract.ts
89
+ function createTrackingContract(config) {
90
+ const schemas = createTrackingSchemas(config);
91
+ return defineContract2({ prefix: config.prefix ?? "tracking", scope: config.scope }, {
92
+ bootstrap: {
93
+ method: "POST",
94
+ path: "/visit",
95
+ expose: ["HTTP"],
96
+ desc: "Issue or renew a browser visit lease",
97
+ input: schemas.entry,
98
+ output: schemas.bootstrap
99
+ },
100
+ track: {
101
+ method: "POST",
102
+ path: "/events",
103
+ expose: ["HTTP"],
104
+ desc: "Batch track browser events",
105
+ input: schemas.request,
106
+ output: schemas.response,
107
+ safelistedBody: true,
108
+ maxJsonBodyBytes: config.maxJsonBodyBytes ?? 256 * 1024
109
+ }
110
+ });
111
+ }
112
+ // src/tracking/performance/schema.ts
113
+ import { z as z2 } from "zod";
114
+ var BoundedMsSchema = z2.number().nonnegative().max(3600000).nullable();
115
+ var PerformanceVitalsSchema = z2.object({
116
+ lcpMs: BoundedMsSchema,
117
+ inpMs: BoundedMsSchema,
118
+ fcpMs: BoundedMsSchema,
119
+ ttfbMs: BoundedMsSchema,
120
+ cls: z2.number().nonnegative().max(100).nullable()
121
+ });
122
+ var PerformanceSampleSchema = z2.object({
123
+ schemaVersion: z2.literal(1),
124
+ id: z2.string().min(1).max(64),
125
+ kind: z2.enum(["early", "final"]),
126
+ route: z2.string().min(1).max(2000),
127
+ buildId: z2.string().min(1).max(64),
128
+ visitId: z2.string().min(1).max(128).nullable(),
129
+ deviceClass: z2.enum(["mobile", "desktop"]),
130
+ navigationType: z2.string().min(1).max(32).nullable(),
131
+ vitals: PerformanceVitalsSchema,
132
+ capturedAt: z2.number().int().nonnegative()
133
+ });
134
+ // src/tracking/performance/summary.ts
135
+ var DEFAULT_MIN_SAMPLES = 100;
136
+ function percentile(ascending, rank) {
137
+ return ascending[Math.ceil(ascending.length * rank) - 1] ?? null;
138
+ }
139
+ function summarizePerformanceMetric(values, options = {}) {
140
+ const present = values.filter((value) => value !== null).sort((left, right) => left - right);
141
+ const trusted = present.length >= (options.minSamples ?? DEFAULT_MIN_SAMPLES);
142
+ return {
143
+ samples: present.length,
144
+ p75: percentile(present, 0.75),
145
+ p95: trusted ? percentile(present, 0.95) : null
146
+ };
147
+ }
148
+ export {
149
+ AttributionDataSchema,
150
+ DEFAULT_BUILD_ID_PATTERN,
151
+ PerformanceSampleSchema,
152
+ PerformanceVitalsSchema,
153
+ TrackEventsResponseSchema,
154
+ TrackingDispositionSchema,
155
+ TrackingDispositionStatusSchema,
156
+ TrackingOutboxStateSchema,
157
+ UtmDataSchema,
158
+ VisitBootstrapResponseSchema,
159
+ createTrackingContract,
160
+ createTrackingSchemas,
161
+ summarizePerformanceMetric
162
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * `stitchkit/tracking/performance` — Web Vitals from real visitors, collected
3
+ * after the page has loaded. The sample's schema and the report's trust threshold
4
+ * are `stitchkit/tracking/contract`; tables and reports stay the application's.
5
+ * Importing this needs the optional peer `web-vitals`. → ADR 0280.
6
+ */
7
+ export { createPerformanceCollector, isLabUserAgent, type PerformanceCollector, type PerformanceCollectorConfig, type PerformanceHost, type VitalsLibrary, type VitalsMetric, type VitalsObserver, } from '../../tracking/performance/collector.js';
8
+ //# sourceMappingURL=performance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/tracking/performance.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,sCAAsC,CAAC"}
@@ -0,0 +1,181 @@
1
+ import {
2
+ DEFAULT_BOT_USER_AGENT_PATTERN2
3
+ } from "../../index-1f40z584.js";
4
+ import {
5
+ sendUnloadBeacon2,
6
+ redactTrackingText2
7
+ } from "../../index-vv1sch8a.js";
8
+
9
+ // src/tracking/performance/collector.ts
10
+ var DEFAULT_EARLY_DELAY_MS = 5000;
11
+ var IDLE_TIMEOUT_MS = 2000;
12
+ var PENDING_KEY = "stitchkit:performance:pending";
13
+ var MAX_PENDING = 20;
14
+ var MAX_MS = 3600000;
15
+ var MAX_CLS = 100;
16
+ var RESTORED_NAVIGATIONS = new Set(["back-forward-cache", "restore"]);
17
+ var LAB_AGENT = /lighthouse|gtmetrix/i;
18
+ function isLabUserAgent(userAgent) {
19
+ return LAB_AGENT.test(userAgent) || DEFAULT_BOT_USER_AGENT_PATTERN2.test(userAgent);
20
+ }
21
+ var INACTIVE = { stop: () => {
22
+ return;
23
+ } };
24
+ var running;
25
+ function sessionStore() {
26
+ try {
27
+ return typeof sessionStorage === "undefined" ? undefined : sessionStorage;
28
+ } catch {
29
+ return;
30
+ }
31
+ }
32
+ function loadId() {
33
+ const bytes = crypto.getRandomValues(new Uint8Array(16));
34
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
35
+ }
36
+ function browserHost() {
37
+ const agent = Reflect.get(navigator, "userAgentData");
38
+ const mobile = agent === undefined ? undefined : Reflect.get(Object(agent), "mobile");
39
+ return {
40
+ userAgent: navigator.userAgent,
41
+ automated: navigator.webdriver === true,
42
+ mobile: typeof mobile === "boolean" ? mobile : /Mobi|Android/i.test(navigator.userAgent),
43
+ now: () => Date.now(),
44
+ route: () => location.pathname,
45
+ afterLoad(work) {
46
+ const idle = () => {
47
+ if (typeof requestIdleCallback === "function") {
48
+ requestIdleCallback(work, { timeout: IDLE_TIMEOUT_MS });
49
+ } else {
50
+ setTimeout(work, 0);
51
+ }
52
+ };
53
+ if (document.readyState === "complete")
54
+ idle();
55
+ else
56
+ addEventListener("load", idle, { once: true });
57
+ },
58
+ onHidden(work) {
59
+ document.addEventListener("visibilitychange", () => {
60
+ if (document.visibilityState === "hidden")
61
+ work();
62
+ });
63
+ addEventListener("pagehide", work);
64
+ },
65
+ after: (delayMs, work) => void setTimeout(work, delayMs),
66
+ beacon: (url, body) => sendUnloadBeacon2(url, body),
67
+ storage: sessionStore()
68
+ };
69
+ }
70
+ function readPending(host) {
71
+ try {
72
+ const stored = JSON.parse(host.storage?.getItem(PENDING_KEY) ?? "[]");
73
+ if (!Array.isArray(stored))
74
+ return [];
75
+ return stored.filter((entry) => typeof entry === "string");
76
+ } catch {
77
+ return [];
78
+ }
79
+ }
80
+ function writePending(host, pending) {
81
+ try {
82
+ if (pending.length === 0)
83
+ host.storage?.removeItem(PENDING_KEY);
84
+ else
85
+ host.storage?.setItem(PENDING_KEY, JSON.stringify(pending.slice(-MAX_PENDING)));
86
+ } catch {}
87
+ }
88
+ function samePage(body, id) {
89
+ return body.includes(`"id":"${id}"`);
90
+ }
91
+ function createPerformanceCollector(config) {
92
+ if (running)
93
+ return running;
94
+ if (config.host === undefined && typeof document === "undefined")
95
+ return INACTIVE;
96
+ const host = config.host ?? browserHost();
97
+ if (host.automated || isLabUserAgent(host.userAgent))
98
+ return INACTIVE;
99
+ const route = redactTrackingText2(host.route());
100
+ const id = loadId();
101
+ const vitals = {
102
+ lcpMs: null,
103
+ inpMs: null,
104
+ fcpMs: null,
105
+ ttfbMs: null,
106
+ cls: null
107
+ };
108
+ let navigationType = null;
109
+ let stopped = false;
110
+ let finalSent = false;
111
+ let lastSent;
112
+ const send = (kind) => {
113
+ if (stopped || Object.values(vitals).every((value) => value === null))
114
+ return;
115
+ const measured = `${kind}:${JSON.stringify(vitals)}`;
116
+ if (measured === lastSent || kind === "early" && finalSent)
117
+ return;
118
+ if (kind === "final")
119
+ finalSent = true;
120
+ const sample = {
121
+ schemaVersion: 1,
122
+ id,
123
+ kind,
124
+ route,
125
+ buildId: config.buildId,
126
+ visitId: config.visitId?.() ?? null,
127
+ deviceClass: host.mobile ? "mobile" : "desktop",
128
+ navigationType,
129
+ vitals: { ...vitals },
130
+ capturedAt: host.now()
131
+ };
132
+ const body = JSON.stringify(sample);
133
+ lastSent = measured;
134
+ if (host.beacon(config.url, body))
135
+ return;
136
+ const others = readPending(host).filter((pending) => !samePage(pending, id));
137
+ writePending(host, [...others, body]);
138
+ };
139
+ const replayPending = () => {
140
+ writePending(host, readPending(host).filter((body) => !host.beacon(config.url, body)));
141
+ };
142
+ const observe = (library) => {
143
+ const record = (field, limit, metric) => {
144
+ if (metric.navigationType && RESTORED_NAVIGATIONS.has(metric.navigationType))
145
+ return;
146
+ vitals[field] = Math.min(limit, Math.max(0, metric.value));
147
+ navigationType ??= metric.navigationType ?? null;
148
+ };
149
+ const options = { reportAllChanges: true };
150
+ library.onLCP((metric) => record("lcpMs", MAX_MS, metric), options);
151
+ library.onINP((metric) => record("inpMs", MAX_MS, metric), options);
152
+ library.onCLS((metric) => record("cls", MAX_CLS, metric), options);
153
+ library.onFCP((metric) => record("fcpMs", MAX_MS, metric), options);
154
+ library.onTTFB((metric) => record("ttfbMs", MAX_MS, metric), options);
155
+ };
156
+ host.onHidden(() => send("final"));
157
+ host.afterLoad(() => {
158
+ if (stopped)
159
+ return;
160
+ replayPending();
161
+ const load = config.loadVitals ?? (() => import("web-vitals"));
162
+ load().then((library) => {
163
+ observe(library);
164
+ host.after(config.earlyDelayMs ?? DEFAULT_EARLY_DELAY_MS, () => send("early"));
165
+ }, () => {
166
+ return;
167
+ });
168
+ });
169
+ const collector = {
170
+ stop() {
171
+ stopped = true;
172
+ running = undefined;
173
+ }
174
+ };
175
+ running = collector;
176
+ return collector;
177
+ }
178
+ export {
179
+ createPerformanceCollector,
180
+ isLabUserAgent
181
+ };
@@ -11,5 +11,6 @@ export { DEFAULT_BOT_USER_AGENT_PATTERN, isBotUserAgent } from '../../tracking/s
11
11
  export { type DispositionEvent, type DispositionInput, type DispositionResult, dispositionTrackingBatch, type KnownVisit, } from '../../tracking/server/disposition.js';
12
12
  export { hashTrackingEvent } from '../../tracking/server/hash.js';
13
13
  export { createPresenceRegistry, type PresenceEntry, type PresenceRegistry, } from '../../tracking/server/presence.js';
14
+ export { type TrackingOutboxReport, type TrackingTelemetryHealth, trackingTelemetryHealth, } from '../../tracking/server/telemetry-health.js';
14
15
  export { type ActiveVisit, type FindActiveVisitQuery, type IssuedVisitLease, type IssueVisitLeaseOptions, issueVisitLease, type TrackingVisitStore, type VisitActor, type VisitOutboxHealth, type VisitOwnership, } from '../../tracking/server/visit-lease.js';
15
16
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/tracking/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,gBAAgB,GACjB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,8BAA8B,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,wBAAwB,EACxB,KAAK,UAAU,GAChB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EACL,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/tracking/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,gBAAgB,GACjB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,8BAA8B,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,wBAAwB,EACxB,KAAK,UAAU,GAChB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EACL,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,uBAAuB,GACxB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,mCAAmC,CAAC"}
@@ -1,3 +1,8 @@
1
+ import {
2
+ DEFAULT_BOT_USER_AGENT_PATTERN2,
3
+ isBotUserAgent2
4
+ } from "../../index-1f40z584.js";
5
+
1
6
  // src/tracking/server/active-interval.ts
2
7
  var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3
8
  function activeIntervalOf(event, serverNow, {
@@ -23,11 +28,6 @@ function activeIntervalOf(event, serverNow, {
23
28
  endedAt: serverNow
24
29
  };
25
30
  }
26
- // src/tracking/server/bot.ts
27
- var DEFAULT_BOT_USER_AGENT_PATTERN = /bot|crawl|spider|slurp|mediapartners|facebookexternalhit|bingpreview|yandex|baidu|duckduckbot|uptimerobot|pingdom|gtmetrix|pagespeed|lighthouse|headlesschrome/i;
28
- function isBotUserAgent(userAgent, pattern = DEFAULT_BOT_USER_AGENT_PATTERN) {
29
- return userAgent ? pattern.test(userAgent) : false;
30
- }
31
31
  // src/tracking/server/hash.ts
32
32
  import { createHash } from "node:crypto";
33
33
  function hashTrackingEvent(event) {
@@ -41,9 +41,9 @@ function dispositionTrackingBatch({
41
41
  existing,
42
42
  actorOwnerId,
43
43
  userAgent,
44
- botPattern = DEFAULT_BOT_USER_AGENT_PATTERN
44
+ botPattern = DEFAULT_BOT_USER_AGENT_PATTERN2
45
45
  }) {
46
- if (isBotUserAgent(userAgent, botPattern)) {
46
+ if (isBotUserAgent2(userAgent, botPattern)) {
47
47
  return {
48
48
  accepted: [],
49
49
  dispositions: events.map((event) => ({
@@ -115,20 +115,47 @@ function createPresenceRegistry(options = {}) {
115
115
  clear: () => active.clear()
116
116
  };
117
117
  }
118
+ // src/tracking/server/telemetry-health.ts
119
+ function trackingTelemetryHealth(reports, baselines = new Map) {
120
+ const latest = new Map;
121
+ const queued = new Map;
122
+ for (const report of reports) {
123
+ queued.set(report.stream, report.queued);
124
+ if (report.state !== "available")
125
+ continue;
126
+ latest.set(report.stream, Math.max(latest.get(report.stream) ?? 0, report.dropped));
127
+ }
128
+ let dropped = 0;
129
+ for (const [stream, reported] of latest) {
130
+ dropped += Math.max(0, reported - (baselines.get(stream) ?? 0));
131
+ }
132
+ const count = (state) => reports.filter((report) => report.state === state).length;
133
+ const unavailable = count("unavailable");
134
+ const unknown = count("unknown");
135
+ const degraded = dropped > 0 || unavailable > 0;
136
+ return {
137
+ status: reports.length === 0 ? "unknown" : degraded ? "degraded" : unknown > 0 ? "unknown" : "ok",
138
+ observedVisits: reports.length - unknown,
139
+ unknownVisits: unknown,
140
+ unavailable,
141
+ queued: [...queued.values()].reduce((sum, count) => sum + count, 0),
142
+ dropped
143
+ };
144
+ }
118
145
  // src/tracking/server/visit-lease.ts
119
146
  async function issueVisitLease(store, actor, entry, {
120
147
  ownership,
121
148
  idleMs = 30 * 60 * 1000,
122
149
  now = () => new Date,
123
150
  randomUUID = () => crypto.randomUUID(),
124
- botPattern = DEFAULT_BOT_USER_AGENT_PATTERN
151
+ botPattern = DEFAULT_BOT_USER_AGENT_PATTERN2
125
152
  }) {
126
153
  if (ownership === "adopting" && !store.adopt) {
127
154
  throw new Error("issueVisitLease: ownership 'adopting' requires store.adopt");
128
155
  }
129
156
  const at = now();
130
157
  const expiresAt = new Date(at.getTime() + idleMs).toISOString();
131
- if (isBotUserAgent(actor.userAgent, botPattern)) {
158
+ if (isBotUserAgent2(actor.userAgent, botPattern)) {
132
159
  return { visitId: randomUUID(), expiresAt, outcome: "bot", adopted: null };
133
160
  }
134
161
  const health = {
@@ -163,11 +190,12 @@ async function issueVisitLease(store, actor, entry, {
163
190
  });
164
191
  }
165
192
  export {
166
- DEFAULT_BOT_USER_AGENT_PATTERN,
193
+ DEFAULT_BOT_USER_AGENT_PATTERN2 as DEFAULT_BOT_USER_AGENT_PATTERN,
167
194
  activeIntervalOf,
168
195
  createPresenceRegistry,
169
196
  dispositionTrackingBatch,
170
197
  hashTrackingEvent,
171
- isBotUserAgent,
172
- issueVisitLease
198
+ isBotUserAgent2 as isBotUserAgent,
199
+ issueVisitLease,
200
+ trackingTelemetryHealth
173
201
  };
@@ -4,20 +4,21 @@
4
4
  * with one bounded retry, the page-leave beacon that actually arrives, visible
5
5
  * time, scroll milestones, declarative clicks, attribution, and the client
6
6
  * that composes them. No React, no DOM at import time, no event vocabulary of
7
- * its own. The server half is `stitchkit/tracking/server`. → ADR 0166.
7
+ * its own, and no `zod`: this runs on every page. The wire shapes are
8
+ * `stitchkit/tracking/contract`, the server half `stitchkit/tracking/server`.
9
+ * → ADR 0166, ADR 0280.
8
10
  */
9
11
  export { type AttributionStorage, parseReferrer, parseUtmFromSearch, type ReferrerRule, type ResolveAttributionInput, type ResolvedAttribution, resolveAttribution, } from '../tracking/attribution.js';
10
12
  export { sendUnloadBeacon } from '../tracking/beacon.js';
11
13
  export { type ClickTarget, type ResolveTrackedClickOptions, resolveTrackedClick, type TrackedClick, type TrackedClickAttributes, } from '../tracking/clicks.js';
12
14
  export { type BuiltinTrackingEventTypes, CONVENTIONAL_TRACKING_EVENT_TYPES, createTrackingClient, type EventsWithMetadata, type EventsWithoutMetadata, type TrackFn, type TrackingClient, type TrackingClientConfig, } from '../tracking/client.js';
13
- export { createTrackingContract, type TrackingContractConfig, type TrackingContractEndpoints, } from '../tracking/contract.js';
14
15
  export { deliverTrackingBatch, type TrackingDeliveryOptions, type TrackingDeliveryOutcome, } from '../tracking/delivery.js';
15
16
  export { browserTrackingHost, type TrackingHost, type TrackingPageContext, } from '../tracking/host.js';
16
17
  export { createOncePerPage, type OncePerPage } from '../tracking/once-per-page.js';
17
18
  export { createTrackingOutbox, type TrackingOutbox, type TrackingOutboxEvents, type TrackingOutboxHealth, type TrackingOutboxMeta, type TrackingOutboxOptions, type TrackingOutboxRecord, type TrackingOutboxStorage, type TrackingQueuedEvent, } from '../tracking/outbox.js';
18
19
  export { indexedDbOutboxStorage } from '../tracking/outbox-storage-indexeddb.js';
19
20
  export { memoryOutboxStorage } from '../tracking/outbox-storage-memory.js';
20
- export { type AttributionData, AttributionDataSchema, createTrackingSchemas, DEFAULT_BUILD_ID_PATTERN, type TrackEventsRequest, type TrackEventsResponse, TrackEventsResponseSchema, type TrackingDisposition, TrackingDispositionSchema, type TrackingDispositionStatus, TrackingDispositionStatusSchema, type TrackingEventEnvelope, type TrackingEventShape, type TrackingOutboxState, TrackingOutboxStateSchema, type TrackingSchemas, type TrackingSchemasConfig, type UtmData, UtmDataSchema, type VisitBootstrapResponse, VisitBootstrapResponseSchema, type VisitEntryContext, type VisitEntryContextShape, } from '../tracking/schemas.js';
21
+ export { redactTrackingText, redactTrackingValue } from '../tracking/privacy.js';
21
22
  export { createScrollMilestones, type ScrollMilestones, scrollDepthPercent, } from '../tracking/scroll.js';
22
23
  export { createSequenceReserve, type SequenceReserve, type SequenceReserveOptions, } from '../tracking/sequence-reserve.js';
23
24
  export { createVisibleTimeMeter, type VisibleHeartbeat, type VisibleInterval, type VisibleTimeMeter, type VisibleTimeMeterOptions, } from '../tracking/visible-time.js';
@@ -1 +1 @@
1
- {"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../../src/entrypoints/tracking.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,KAAK,kBAAkB,EACvB,aAAa,EACb,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,0BAA0B,EAC/B,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,yBAAyB,EAC9B,iCAAiC,EACjC,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,oBAAoB,EACpB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EACL,KAAK,eAAe,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,aAAa,EACb,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../../src/entrypoints/tracking.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,KAAK,kBAAkB,EACvB,aAAa,EACb,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,0BAA0B,EAC/B,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,yBAAyB,EAC9B,iCAAiC,EACjC,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,0BAA0B,CAAC"}