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.
- package/CHANGELOG.md +56 -0
- package/dist/agent-runtime/run-acquisition.d.ts +9 -2
- package/dist/agent-runtime/run-acquisition.d.ts.map +1 -1
- package/dist/agent-runtime/run-execution.d.ts +3 -0
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/run-failure.d.ts +4 -1
- package/dist/agent-runtime/run-failure.d.ts.map +1 -1
- package/dist/agent-runtime/run-store-retry.d.ts +8 -0
- package/dist/agent-runtime/run-store-retry.d.ts.map +1 -0
- package/dist/agent-runtime/run-terminal.d.ts.map +1 -1
- package/dist/agent-runtime/run-unacquired.d.ts +19 -0
- package/dist/agent-runtime/run-unacquired.d.ts.map +1 -0
- package/dist/agent-runtime/store-conformance.d.ts +8 -0
- package/dist/agent-runtime/store-conformance.d.ts.map +1 -1
- package/dist/agent-runtime/store-driver-contract.d.ts +5 -0
- package/dist/agent-runtime/store-driver-contract.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-commit.d.ts +34 -4
- package/dist/agent-runtime/terminal-commit.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/harness.js +2 -2
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +3 -3
- package/dist/entrypoints/agent-runtime/sqlite/node.js +3 -3
- package/dist/entrypoints/agent-runtime/testing.js +22 -4
- package/dist/entrypoints/agent-runtime.d.ts +1 -1
- package/dist/entrypoints/agent-runtime.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime.js +13 -11
- package/dist/entrypoints/application/diagnostic-journal.js +1 -1
- package/dist/entrypoints/application/directory-inbox.js +3 -3
- package/dist/entrypoints/cli/publish.js +2 -2
- package/dist/entrypoints/files.js +2 -2
- package/dist/entrypoints/primitives.js +51 -154
- package/dist/entrypoints/server.js +6 -6
- package/dist/entrypoints/telegram.d.ts +1 -1
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +352 -137
- package/dist/entrypoints/tracking/contract.d.ts +11 -0
- package/dist/entrypoints/tracking/contract.d.ts.map +1 -0
- package/dist/entrypoints/tracking/contract.js +162 -0
- package/dist/entrypoints/tracking/performance.d.ts +8 -0
- package/dist/entrypoints/tracking/performance.d.ts.map +1 -0
- package/dist/entrypoints/tracking/performance.js +181 -0
- package/dist/entrypoints/tracking/server.d.ts +1 -0
- package/dist/entrypoints/tracking/server.d.ts.map +1 -1
- package/dist/entrypoints/tracking/server.js +40 -12
- package/dist/entrypoints/tracking.d.ts +4 -3
- package/dist/entrypoints/tracking.d.ts.map +1 -1
- package/dist/entrypoints/tracking.js +43 -143
- package/dist/entrypoints/xlsx.d.ts +4 -0
- package/dist/entrypoints/xlsx.d.ts.map +1 -0
- package/dist/entrypoints/xlsx.js +406 -0
- package/dist/{index-fa435yq2.js → index-073nw9qr.js} +8 -8
- package/dist/index-1f40z584.js +7 -0
- package/dist/{index-fdk4r4r6.js → index-75ns2ybj.js} +1 -1
- package/dist/{index-jq2ky8fw.js → index-cycp3r3e.js} +124 -181
- package/dist/{index-4g6qmgdx.js → index-ghtpfz4z.js} +9 -9
- package/dist/{index-n3v695sb.js → index-hdjmdwsj.js} +277 -96
- package/dist/{index-zqkz4af9.js → index-nqxrm176.js} +1 -1
- package/dist/index-qezhmp51.js +242 -0
- package/dist/index-vv1sch8a.js +94 -0
- package/dist/{index-fggxgbrk.js → index-xx1j310k.js} +165 -102
- package/dist/internal/exclusive-lock.d.ts.map +1 -1
- package/dist/primitives/decimal.d.ts +10 -0
- package/dist/primitives/decimal.d.ts.map +1 -1
- package/dist/primitives/index.d.ts +3 -1
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/money.d.ts +20 -0
- package/dist/primitives/money.d.ts.map +1 -1
- package/dist/primitives/quantity.d.ts.map +1 -1
- package/dist/primitives/rounding.d.ts +40 -0
- package/dist/primitives/rounding.d.ts.map +1 -0
- package/dist/telegram/budget-transformer.d.ts +2 -2
- package/dist/telegram/not-dispatched.d.ts +2 -2
- package/dist/telegram/not-dispatched.d.ts.map +1 -1
- package/dist/telegram/outbound-budget.d.ts +53 -16
- package/dist/telegram/outbound-budget.d.ts.map +1 -1
- package/dist/telegram/outbound-cost.d.ts +5 -0
- package/dist/telegram/outbound-cost.d.ts.map +1 -0
- package/dist/telegram/outbound-pauses.d.ts +17 -0
- package/dist/telegram/outbound-pauses.d.ts.map +1 -0
- package/dist/telegram/outbound-queue.d.ts +17 -0
- package/dist/telegram/outbound-queue.d.ts.map +1 -0
- package/dist/telegram/update-intake-work.d.ts +20 -1
- package/dist/telegram/update-intake-work.d.ts.map +1 -1
- package/dist/telegram/update-intake.d.ts +12 -3
- package/dist/telegram/update-intake.d.ts.map +1 -1
- package/dist/telegram/update-store-check.d.ts +1 -1
- package/dist/telegram/update-store-check.d.ts.map +1 -1
- package/dist/telegram/update-store-postgres.d.ts.map +1 -1
- package/dist/telegram/update-store-sqlite.d.ts.map +1 -1
- package/dist/telegram/update-store.d.ts +5 -1
- package/dist/telegram/update-store.d.ts.map +1 -1
- package/dist/tracking/attribution.d.ts +1 -1
- package/dist/tracking/attribution.d.ts.map +1 -1
- package/dist/tracking/client-visit.d.ts +3 -1
- package/dist/tracking/client-visit.d.ts.map +1 -1
- package/dist/tracking/client.d.ts.map +1 -1
- package/dist/tracking/performance/collector.d.ts +61 -0
- package/dist/tracking/performance/collector.d.ts.map +1 -0
- package/dist/tracking/performance/schema.d.ts +45 -0
- package/dist/tracking/performance/schema.d.ts.map +1 -0
- package/dist/tracking/performance/summary.d.ts +12 -0
- package/dist/tracking/performance/summary.d.ts.map +1 -0
- package/dist/tracking/privacy.d.ts +5 -0
- package/dist/tracking/privacy.d.ts.map +1 -0
- package/dist/tracking/server/telemetry-health.d.ts +31 -0
- package/dist/tracking/server/telemetry-health.d.ts.map +1 -0
- package/dist/xlsx/cells.d.ts +17 -0
- package/dist/xlsx/cells.d.ts.map +1 -0
- package/dist/xlsx/render.d.ts +11 -0
- package/dist/xlsx/render.d.ts.map +1 -0
- package/dist/xlsx/schema.d.ts +119 -0
- package/dist/xlsx/schema.d.ts.map +1 -0
- package/dist/xlsx/zip.d.ts +13 -0
- package/dist/xlsx/zip.d.ts.map +1 -0
- package/llms/agent-runtime.2.txt +40 -16
- package/llms/agent-runtime.3.txt +17 -0
- package/llms/agent-runtime.txt +4 -1
- package/llms/primitives.txt +21 -0
- package/llms/stitchkit.txt +9 -6
- package/llms/telegram.txt +46 -15
- package/llms/tracking-contract.txt +32 -0
- package/llms/tracking-performance.txt +21 -0
- package/llms/tracking-server.txt +1 -0
- package/llms/tracking.txt +75 -12
- package/llms/{upgrading-0.105.0-0.116.0.txt → upgrading-0.105.0-0.118.0.txt} +73 -3
- package/llms/upgrading.txt +1 -1
- package/llms/xlsx.txt +107 -0
- package/llms-full.txt +392 -34
- package/llms.txt +11 -7
- package/package.json +27 -9
- 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 =
|
|
44
|
+
botPattern = DEFAULT_BOT_USER_AGENT_PATTERN2
|
|
45
45
|
}) {
|
|
46
|
-
if (
|
|
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 =
|
|
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 (
|
|
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
|
|
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 {
|
|
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
|
|
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"}
|