@cloudhal/core-contracts 0.3.4 → 0.3.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudhal/core-contracts",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Cloudhal domain contracts: JSON Schema source of truth plus generated TypeScript types",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://cloudhal.dev",
@@ -1,132 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://cloudhal.dev/schemas/v1/analytics-beacon.schema.json",
4
- "title": "AnalyticsBeacon",
5
- "description": "What a site's first-party analytics script sends to POST /__cloudhal/e (RFC-0006): JSON as text/plain, at most 2 KB. Everything in it is untrusted. The server keeps a beacon only after the same-origin, bot and rate checks, normalises the path and resolves it to a published route, reduces the referrer to a host, normalises UTM values, and derives everything else (node, country, device, visitor) itself. The script never sends an identifier, a cookie or a full URL.",
6
- "oneOf": [
7
- {
8
- "type": "object",
9
- "title": "AnalyticsPageviewBeacon",
10
- "description": "Sent once per page view, when the page is first visible (after prerendering, and again on a back/forward cache restore).",
11
- "additionalProperties": false,
12
- "required": [
13
- "schemaVersion",
14
- "kind",
15
- "path"
16
- ],
17
- "properties": {
18
- "schemaVersion": {
19
- "$ref": "#/$defs/SchemaVersion"
20
- },
21
- "kind": {
22
- "type": "string",
23
- "enum": [
24
- "pageview"
25
- ]
26
- },
27
- "path": {
28
- "$ref": "#/$defs/BeaconPath"
29
- },
30
- "referrer": {
31
- "type": "string",
32
- "description": "The host of document.referrer only (the script drops scheme, path and query); empty or absent for direct visits.",
33
- "maxLength": 253
34
- },
35
- "utmSource": {
36
- "$ref": "#/$defs/BeaconUtm"
37
- },
38
- "utmMedium": {
39
- "$ref": "#/$defs/BeaconUtm"
40
- },
41
- "utmCampaign": {
42
- "$ref": "#/$defs/BeaconUtm"
43
- },
44
- "navType": {
45
- "type": "string",
46
- "enum": [
47
- "navigate",
48
- "reload",
49
- "back_forward",
50
- "prerender",
51
- "restore"
52
- ]
53
- }
54
- }
55
- },
56
- {
57
- "type": "object",
58
- "title": "AnalyticsVitalsBeacon",
59
- "description": "Sent once, when a sampled page view is hidden, with the Core Web Vitals measured so far.",
60
- "additionalProperties": false,
61
- "required": [
62
- "schemaVersion",
63
- "kind",
64
- "path",
65
- "sampleOneIn"
66
- ],
67
- "properties": {
68
- "schemaVersion": {
69
- "$ref": "#/$defs/SchemaVersion"
70
- },
71
- "kind": {
72
- "type": "string",
73
- "enum": [
74
- "vitals"
75
- ]
76
- },
77
- "path": {
78
- "$ref": "#/$defs/BeaconPath"
79
- },
80
- "lcp": {
81
- "$ref": "#/$defs/BeaconMillis"
82
- },
83
- "inp": {
84
- "$ref": "#/$defs/BeaconMillis"
85
- },
86
- "cls": {
87
- "type": "number",
88
- "minimum": 0,
89
- "maximum": 100
90
- },
91
- "ttfb": {
92
- "$ref": "#/$defs/BeaconMillis"
93
- },
94
- "fcp": {
95
- "$ref": "#/$defs/BeaconMillis"
96
- },
97
- "sampleOneIn": {
98
- "type": "integer",
99
- "description": "The vitals sampling the script was served with (one page view in N); the server checks it against the site's setting.",
100
- "minimum": 1,
101
- "maximum": 1000
102
- }
103
- }
104
- }
105
- ],
106
- "$defs": {
107
- "BeaconMillis": {
108
- "type": "number",
109
- "minimum": 0,
110
- "maximum": 600000
111
- },
112
- "BeaconPath": {
113
- "type": "string",
114
- "description": "location.pathname as the browser reports it (no query string, no fragment).",
115
- "pattern": "^/[^?#\\s]*$",
116
- "maxLength": 1024
117
- },
118
- "BeaconUtm": {
119
- "type": "string",
120
- "description": "A raw utm_* value from the page URL; the server lower-cases it and drops it unless it fits the stored alphabet.",
121
- "minLength": 1,
122
- "maxLength": 128
123
- },
124
- "SchemaVersion": {
125
- "type": "integer",
126
- "description": "Version of this contract. Readers reject unknown versions; migrations move documents forward one version at a time.",
127
- "enum": [
128
- 1
129
- ]
130
- }
131
- }
132
- }
@@ -1,411 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://cloudhal.dev/schemas/v1/analytics-event.schema.json",
4
- "title": "AnalyticsEvent",
5
- "description": "One site analytics event as stored (RFC-0006): a page view or a Core Web Vitals sample reported by the site's first-party script, or a response the site Worker rendered itself (cache miss, redirect, 404, 410, 5xx). Written by the site Worker after it validated and enriched a beacon. The named fields are the columns of the local/self-host SQLite store; each one documents its fixed slot in a Workers Analytics Engine data point (index1 = siteId, blob1 = kind, blob2 = schemaVersion). Slots never move and new fields are only appended. Never carries an IP address, a user agent, a full referrer URL, a query string or a cookie.",
6
- "oneOf": [
7
- {
8
- "type": "object",
9
- "title": "AnalyticsPageviewEvent",
10
- "description": "A published page, article or archive was shown to a visitor (the site's script ran).",
11
- "additionalProperties": false,
12
- "required": [
13
- "schemaVersion",
14
- "kind",
15
- "siteId",
16
- "timestamp",
17
- "path",
18
- "nodeId",
19
- "nodeKind",
20
- "channel",
21
- "entrance",
22
- "device",
23
- "browser",
24
- "os",
25
- "navType"
26
- ],
27
- "properties": {
28
- "schemaVersion": {
29
- "$ref": "#/$defs/SchemaVersion"
30
- },
31
- "kind": {
32
- "type": "string",
33
- "enum": [
34
- "pageview"
35
- ]
36
- },
37
- "siteId": {
38
- "$ref": "#/$defs/Id",
39
- "description": "WAE index1."
40
- },
41
- "timestamp": {
42
- "$ref": "#/$defs/Timestamp"
43
- },
44
- "path": {
45
- "$ref": "#/$defs/Path",
46
- "description": "WAE blob3. The published route the view resolved to; never a query string."
47
- },
48
- "nodeId": {
49
- "$ref": "#/$defs/Id",
50
- "description": "WAE blob4. The page, entry or term the server resolved the path to, so stats survive slug changes."
51
- },
52
- "nodeKind": {
53
- "$ref": "#/$defs/AnalyticsNodeKind"
54
- },
55
- "refHost": {
56
- "$ref": "#/$defs/AnalyticsHostname"
57
- },
58
- "channel": {
59
- "$ref": "#/$defs/AnalyticsChannel"
60
- },
61
- "utmSource": {
62
- "$ref": "#/$defs/AnalyticsUtmValue",
63
- "description": "WAE blob8."
64
- },
65
- "utmMedium": {
66
- "$ref": "#/$defs/AnalyticsUtmValue",
67
- "description": "WAE blob9."
68
- },
69
- "utmCampaign": {
70
- "$ref": "#/$defs/AnalyticsUtmValue",
71
- "description": "WAE blob10."
72
- },
73
- "country": {
74
- "$ref": "#/$defs/AnalyticsCountry"
75
- },
76
- "device": {
77
- "$ref": "#/$defs/AnalyticsDevice"
78
- },
79
- "browser": {
80
- "$ref": "#/$defs/AnalyticsBrowser"
81
- },
82
- "os": {
83
- "$ref": "#/$defs/AnalyticsOs"
84
- },
85
- "visitor": {
86
- "$ref": "#/$defs/AnalyticsVisitorHash"
87
- },
88
- "navType": {
89
- "$ref": "#/$defs/AnalyticsNavType"
90
- },
91
- "locale": {
92
- "$ref": "#/$defs/Locale",
93
- "description": "WAE blob17. Locale of the resolved node, not the visitor's Accept-Language."
94
- },
95
- "entrance": {
96
- "type": "boolean",
97
- "description": "WAE double1 (1 or 0). The view starts a visit: the referrer is empty or another site, and the navigation is not a reload, back/forward or restore."
98
- },
99
- "privacySignal": {
100
- "type": "boolean",
101
- "description": "WAE double10 (1 or 0). The beacon request carried Global Privacy Control (Sec-GPC: 1) or Do Not Track (DNT: 1), so no visitor hash was formed. Only this flag is kept, never which signal or any header. Absent means no signal (and on events written before the field existed)."
102
- }
103
- }
104
- },
105
- {
106
- "type": "object",
107
- "title": "AnalyticsVitalsEvent",
108
- "description": "Core Web Vitals of one sampled page view, measured by the site's own script and sent when the page is hidden. Code checks that at least one metric is present (the schema subset has no cross-property rules).",
109
- "additionalProperties": false,
110
- "required": [
111
- "schemaVersion",
112
- "kind",
113
- "siteId",
114
- "timestamp",
115
- "path",
116
- "nodeId",
117
- "nodeKind",
118
- "device",
119
- "sampleOneIn"
120
- ],
121
- "properties": {
122
- "schemaVersion": {
123
- "$ref": "#/$defs/SchemaVersion"
124
- },
125
- "kind": {
126
- "type": "string",
127
- "enum": [
128
- "vitals"
129
- ]
130
- },
131
- "siteId": {
132
- "$ref": "#/$defs/Id",
133
- "description": "WAE index1."
134
- },
135
- "timestamp": {
136
- "$ref": "#/$defs/Timestamp"
137
- },
138
- "path": {
139
- "$ref": "#/$defs/Path",
140
- "description": "WAE blob3."
141
- },
142
- "nodeId": {
143
- "$ref": "#/$defs/Id",
144
- "description": "WAE blob4."
145
- },
146
- "nodeKind": {
147
- "$ref": "#/$defs/AnalyticsNodeKind"
148
- },
149
- "country": {
150
- "$ref": "#/$defs/AnalyticsCountry"
151
- },
152
- "device": {
153
- "$ref": "#/$defs/AnalyticsDevice"
154
- },
155
- "browser": {
156
- "$ref": "#/$defs/AnalyticsBrowser"
157
- },
158
- "lcp": {
159
- "$ref": "#/$defs/AnalyticsMillis",
160
- "description": "WAE double3. Largest Contentful Paint."
161
- },
162
- "inp": {
163
- "$ref": "#/$defs/AnalyticsMillis",
164
- "description": "WAE double4. Interaction to Next Paint."
165
- },
166
- "cls": {
167
- "type": "number",
168
- "description": "WAE double5, stored multiplied by 1000. Cumulative Layout Shift (unitless).",
169
- "minimum": 0,
170
- "maximum": 100
171
- },
172
- "ttfb": {
173
- "$ref": "#/$defs/AnalyticsMillis",
174
- "description": "WAE double6. Time to First Byte."
175
- },
176
- "fcp": {
177
- "$ref": "#/$defs/AnalyticsMillis",
178
- "description": "WAE double7. First Contentful Paint."
179
- },
180
- "sampleOneIn": {
181
- "$ref": "#/$defs/AnalyticsSampleOneIn"
182
- }
183
- }
184
- },
185
- {
186
- "type": "object",
187
- "title": "AnalyticsRenderEvent",
188
- "description": "The site Worker answered a request itself (a cache miss, redirect, 404, 410 or error). Cache hits never run the Worker, so these are not page views. The requested path is visitor-controlled text and is always shown as such.",
189
- "additionalProperties": false,
190
- "required": [
191
- "schemaVersion",
192
- "kind",
193
- "siteId",
194
- "timestamp",
195
- "path",
196
- "status",
197
- "device"
198
- ],
199
- "properties": {
200
- "schemaVersion": {
201
- "$ref": "#/$defs/SchemaVersion"
202
- },
203
- "kind": {
204
- "type": "string",
205
- "enum": [
206
- "render"
207
- ]
208
- },
209
- "siteId": {
210
- "$ref": "#/$defs/Id",
211
- "description": "WAE index1."
212
- },
213
- "timestamp": {
214
- "$ref": "#/$defs/Timestamp"
215
- },
216
- "path": {
217
- "$ref": "#/$defs/AnalyticsRequestPath"
218
- },
219
- "status": {
220
- "type": "integer",
221
- "description": "WAE double2. HTTP status the Worker answered with.",
222
- "minimum": 100,
223
- "maximum": 599
224
- },
225
- "nodeId": {
226
- "$ref": "#/$defs/Id",
227
- "description": "WAE blob4. The node rendered or redirected from, when the path resolved to one."
228
- },
229
- "nodeKind": {
230
- "$ref": "#/$defs/AnalyticsNodeKind"
231
- },
232
- "redirectTo": {
233
- "type": "string",
234
- "description": "WAE blob19. Target of a 301, 302 or 308: a site path or an https URL, without query string.",
235
- "pattern": "^(?:/|https://)[!-~]*$",
236
- "maxLength": 512
237
- },
238
- "refHost": {
239
- "$ref": "#/$defs/AnalyticsHostname"
240
- },
241
- "refPath": {
242
- "$ref": "#/$defs/Path",
243
- "description": "WAE blob20. Same-site referrers only: the page that linked here, which finds broken internal links."
244
- },
245
- "country": {
246
- "$ref": "#/$defs/AnalyticsCountry"
247
- },
248
- "device": {
249
- "$ref": "#/$defs/AnalyticsDevice"
250
- },
251
- "crawler": {
252
- "$ref": "#/$defs/AnalyticsCrawlerName"
253
- },
254
- "renderMs": {
255
- "$ref": "#/$defs/AnalyticsMillis",
256
- "description": "WAE double8. Time the Worker spent answering."
257
- },
258
- "sampleOneIn": {
259
- "$ref": "#/$defs/AnalyticsSampleOneIn"
260
- }
261
- }
262
- }
263
- ],
264
- "$defs": {
265
- "AnalyticsBrowser": {
266
- "type": "string",
267
- "description": "WAE blob13. Browser family, without version.",
268
- "enum": [
269
- "chrome",
270
- "edge",
271
- "firefox",
272
- "safari",
273
- "samsung",
274
- "opera",
275
- "other"
276
- ]
277
- },
278
- "AnalyticsChannel": {
279
- "type": "string",
280
- "description": "WAE blob7. Where the view came from, classified by the server from the referrer host and utm_medium; internal = another page of this site.",
281
- "enum": [
282
- "direct",
283
- "internal",
284
- "search",
285
- "social",
286
- "ai",
287
- "email",
288
- "paid",
289
- "referral"
290
- ]
291
- },
292
- "AnalyticsCountry": {
293
- "type": "string",
294
- "description": "WAE blob11. ISO 3166-1 alpha-2 country from Cloudflare's request.cf.country (XX unknown, T1 Tor). Never a city or region.",
295
- "pattern": "^[A-Z][A-Z0-9]$"
296
- },
297
- "AnalyticsCrawlerName": {
298
- "type": "string",
299
- "description": "WAE blob18. A known crawler identified from the user agent (e.g. googlebot, gptbot, claudebot, perplexitybot). The list and each crawler's class (search, AI, social, monitor) live in code.",
300
- "pattern": "^[a-z0-9][a-z0-9-]{0,31}$"
301
- },
302
- "AnalyticsDevice": {
303
- "type": "string",
304
- "description": "WAE blob12. Device class derived from the user agent and client hints, neither of which is stored.",
305
- "enum": [
306
- "desktop",
307
- "mobile",
308
- "tablet",
309
- "bot",
310
- "unknown"
311
- ]
312
- },
313
- "AnalyticsHostname": {
314
- "type": "string",
315
- "description": "WAE blob6. Host of an external referrer: lower case, without www., port, path or query.",
316
- "pattern": "^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$",
317
- "maxLength": 253
318
- },
319
- "AnalyticsMillis": {
320
- "type": "integer",
321
- "description": "Whole milliseconds (the server rounds), capped at ten minutes.",
322
- "minimum": 0,
323
- "maximum": 600000
324
- },
325
- "AnalyticsNavType": {
326
- "type": "string",
327
- "description": "WAE blob16. How the page was reached; restore = back/forward cache.",
328
- "enum": [
329
- "navigate",
330
- "reload",
331
- "back_forward",
332
- "prerender",
333
- "restore"
334
- ]
335
- },
336
- "AnalyticsNodeKind": {
337
- "type": "string",
338
- "description": "WAE blob5. The kind of node the path resolved to.",
339
- "enum": [
340
- "page",
341
- "entry",
342
- "archive"
343
- ]
344
- },
345
- "AnalyticsOs": {
346
- "type": "string",
347
- "description": "WAE blob14. Operating system family, without version.",
348
- "enum": [
349
- "windows",
350
- "macos",
351
- "ios",
352
- "android",
353
- "linux",
354
- "chromeos",
355
- "other"
356
- ]
357
- },
358
- "AnalyticsRequestPath": {
359
- "type": "string",
360
- "description": "WAE blob3. The requested path as received: percent-encoded printable ASCII, without query string or fragment, cut to 256 characters.",
361
- "pattern": "^/[!-~]*$",
362
- "maxLength": 256
363
- },
364
- "AnalyticsSampleOneIn": {
365
- "type": "integer",
366
- "description": "WAE double9. One in this many events of this kind was recorded (vitals sampling; render events under a flood); 1 = every event. Counts weight each event by this number. An integer, so a rate never suffers rounding.",
367
- "minimum": 1,
368
- "maximum": 1000
369
- },
370
- "AnalyticsUtmValue": {
371
- "type": "string",
372
- "description": "A normalised UTM value: lower case, a small alphabet, at most 64 characters. Values that do not fit are dropped, never stored as free text.",
373
- "pattern": "^[a-z0-9][a-z0-9._+-]{0,63}$"
374
- },
375
- "AnalyticsVisitorHash": {
376
- "type": "string",
377
- "description": "WAE blob15. Present only when the site owner turned on unique visitors and the request carried no GPC or DNT signal: the first 64 bits of SHA-256(dailySalt ‖ siteId ‖ ip ‖ userAgent) in hex. The salt is random, lives for one UTC day and is then deleted, so the hash can neither be recomputed nor linked across days.",
378
- "pattern": "^[0-9a-f]{16}$"
379
- },
380
- "Id": {
381
- "type": "string",
382
- "description": "Prefixed, URL-safe identifier, e.g. site_01HZX8K3Q9. The prefix names the entity kind; agents and the MCP server pass these as opaque handles.",
383
- "pattern": "^[a-z]+_[A-Za-z0-9]{6,32}$",
384
- "minLength": 8,
385
- "maxLength": 48
386
- },
387
- "Locale": {
388
- "type": "string",
389
- "description": "BCP 47 language tag, e.g. en, tr, en-US.",
390
- "pattern": "^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$"
391
- },
392
- "Path": {
393
- "type": "string",
394
- "description": "Absolute URL path of a route the site owns: starts with '/', lower-case slug segments, no trailing slash except root.",
395
- "pattern": "^/(?:[a-z0-9]+(?:-[a-z0-9]+)*(?:/[a-z0-9]+(?:-[a-z0-9]+)*)*)?$",
396
- "maxLength": 1024
397
- },
398
- "SchemaVersion": {
399
- "type": "integer",
400
- "description": "Version of this contract. Readers reject unknown versions; migrations move documents forward one version at a time.",
401
- "enum": [
402
- 1
403
- ]
404
- },
405
- "Timestamp": {
406
- "type": "string",
407
- "description": "RFC 3339 / ISO 8601 instant in UTC.",
408
- "format": "date-time"
409
- }
410
- }
411
- }