stitchkit 0.118.0 → 0.119.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 (151) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/dist/browser/http.d.ts.map +1 -1
  3. package/dist/contract/client-types.d.ts +6 -3
  4. package/dist/contract/client-types.d.ts.map +1 -1
  5. package/dist/contract/define-validation.d.ts.map +1 -1
  6. package/dist/contract/define.d.ts +18 -12
  7. package/dist/contract/define.d.ts.map +1 -1
  8. package/dist/contract/endpoint-capabilities.d.ts +28 -0
  9. package/dist/contract/endpoint-capabilities.d.ts.map +1 -0
  10. package/dist/contract/factory.d.ts +49 -19
  11. package/dist/contract/factory.d.ts.map +1 -1
  12. package/dist/contract/tool-view.d.ts +1 -1
  13. package/dist/contract/tool-view.d.ts.map +1 -1
  14. package/dist/contract/transports.d.ts +5 -0
  15. package/dist/contract/transports.d.ts.map +1 -0
  16. package/dist/entrypoints/agent-runtime/coding-tools.js +6 -5
  17. package/dist/entrypoints/agent-runtime/harness.js +6 -5
  18. package/dist/entrypoints/agent-runtime/sandbox.js +6 -5
  19. package/dist/entrypoints/agent-runtime/sqlite/bun.js +9 -8
  20. package/dist/entrypoints/agent-runtime/sqlite/node.js +9 -8
  21. package/dist/entrypoints/agent-runtime/testing.js +9 -8
  22. package/dist/entrypoints/agent-runtime.js +14 -13
  23. package/dist/entrypoints/application/diagnostic-journal.js +3 -3
  24. package/dist/entrypoints/application/directory-inbox.js +4 -4
  25. package/dist/entrypoints/application/opentelemetry.js +1 -1
  26. package/dist/entrypoints/application.js +5 -5
  27. package/dist/entrypoints/cli/publish.js +4 -4
  28. package/dist/entrypoints/cli.js +8 -7
  29. package/dist/entrypoints/contract.d.ts +1 -1
  30. package/dist/entrypoints/contract.d.ts.map +1 -1
  31. package/dist/entrypoints/contract.js +6 -4
  32. package/dist/entrypoints/files.js +3 -3
  33. package/dist/entrypoints/geo/contract.d.ts +7 -0
  34. package/dist/entrypoints/geo/contract.d.ts.map +1 -0
  35. package/dist/entrypoints/geo/contract.js +6 -0
  36. package/dist/entrypoints/geo.js +60 -23
  37. package/dist/entrypoints/http.js +2 -2
  38. package/dist/entrypoints/index.js +8 -6
  39. package/dist/entrypoints/live.js +1 -1
  40. package/dist/entrypoints/node.js +7 -6
  41. package/dist/entrypoints/primitives.js +1 -1
  42. package/dist/entrypoints/process/owner-loss.js +1 -1
  43. package/dist/entrypoints/process.js +3 -3
  44. package/dist/entrypoints/react.js +1 -1
  45. package/dist/entrypoints/remote.js +4 -3
  46. package/dist/entrypoints/server.d.ts +1 -1
  47. package/dist/entrypoints/server.d.ts.map +1 -1
  48. package/dist/entrypoints/server.js +42 -27
  49. package/dist/entrypoints/telegram.js +2 -2
  50. package/dist/entrypoints/testing.js +7 -6
  51. package/dist/entrypoints/tools/connections.js +3 -2
  52. package/dist/entrypoints/tools/contract.js +1 -1
  53. package/dist/entrypoints/tools/invoker.js +5 -4
  54. package/dist/entrypoints/tools/mcp.js +7 -6
  55. package/dist/entrypoints/tools.js +17 -15
  56. package/dist/entrypoints/tracking/contract.js +5 -3
  57. package/dist/entrypoints/tracking/performance.js +3 -3
  58. package/dist/entrypoints/tracking.d.ts +1 -1
  59. package/dist/entrypoints/tracking.d.ts.map +1 -1
  60. package/dist/entrypoints/tracking.js +63 -83
  61. package/dist/entrypoints/xlsx.js +1 -1
  62. package/dist/geo/index.d.ts +2 -1
  63. package/dist/geo/index.d.ts.map +1 -1
  64. package/dist/geo/record.d.ts +8 -0
  65. package/dist/geo/record.d.ts.map +1 -0
  66. package/dist/geo/resolver.d.ts +1 -3
  67. package/dist/geo/resolver.d.ts.map +1 -1
  68. package/dist/geo/schema.d.ts +44 -0
  69. package/dist/geo/schema.d.ts.map +1 -0
  70. package/dist/geo/types.d.ts +2 -13
  71. package/dist/geo/types.d.ts.map +1 -1
  72. package/dist/{index-n5sv4z0w.js → index-1k18qzqa.js} +13 -15
  73. package/dist/{index-tsngj2b5.js → index-2dfvv1jg.js} +206 -206
  74. package/dist/{index-d9hq291n.js → index-4jpykzvw.js} +70 -81
  75. package/dist/{index-ghtpfz4z.js → index-57gqaq8b.js} +2 -2
  76. package/dist/index-69t14s4a.js +39 -0
  77. package/dist/{index-6p3frkv5.js → index-6a69xzrx.js} +4 -4
  78. package/dist/{index-dky0dcmf.js → index-72r9k0av.js} +6 -2
  79. package/dist/{index-vv1sch8a.js → index-8vzh5wpv.js} +13 -8
  80. package/dist/{index-xx1j310k.js → index-8yxgcyt6.js} +171 -169
  81. package/dist/{index-p6apg0jg.js → index-9frf01t9.js} +16 -9
  82. package/dist/{index-q0th8q0z.js → index-9mjrnqxs.js} +1 -3
  83. package/dist/{index-ega3yz4c.js → index-aqwg2dm5.js} +1 -1
  84. package/dist/{index-073nw9qr.js → index-ba7are04.js} +524 -522
  85. package/dist/{index-095ya5hm.js → index-bbvc59gw.js} +13 -11
  86. package/dist/{index-txg1npmg.js → index-cyxp8rbf.js} +1 -1
  87. package/dist/index-d3xdyjt6.js +38 -0
  88. package/dist/{index-n8z3rvzw.js → index-f4njz9j0.js} +3 -5
  89. package/dist/{index-90p34rts.js → index-fcqj44mb.js} +3 -1
  90. package/dist/{index-86nbfysb.js → index-ff39f9dr.js} +3 -3
  91. package/dist/{index-75ns2ybj.js → index-fqd4yqwd.js} +1 -1
  92. package/dist/{index-nqxrm176.js → index-g444vfz2.js} +1 -1
  93. package/dist/{index-vwhrnp67.js → index-kz9734jc.js} +3 -3
  94. package/dist/{index-dr3t5n1v.js → index-nn9qvkww.js} +46 -46
  95. package/dist/{index-qezhmp51.js → index-nz06qw5a.js} +3 -1
  96. package/dist/{index-1bx1xv1k.js → index-pfvde2fz.js} +5 -2
  97. package/dist/{index-s80awwsw.js → index-qch1vcaa.js} +3 -1
  98. package/dist/{index-cycp3r3e.js → index-rxcgp4b9.js} +2 -2
  99. package/dist/{index-w7jq3fz9.js → index-s0qjs6ee.js} +1198 -1196
  100. package/dist/{index-p0rf7sq9.js → index-s20s2mad.js} +209 -209
  101. package/dist/{index-v6vb5qx8.js → index-s3yxw6kt.js} +1 -1
  102. package/dist/{index-cqmqyjax.js → index-sa99p98w.js} +1 -1
  103. package/dist/{index-0gxvns6s.js → index-sba3e6m4.js} +1 -0
  104. package/dist/{index-f24bdt13.js → index-v1swr26p.js} +3 -1
  105. package/dist/{index-rhzkndr5.js → index-x4p3kw1p.js} +533 -530
  106. package/dist/{index-hdjmdwsj.js → index-x8d9fdeg.js} +513 -507
  107. package/dist/{index-htxh46ej.js → index-ycqhyars.js} +2 -2
  108. package/dist/{index-9bwcthxw.js → index-yj6saztf.js} +31 -13
  109. package/dist/{index-tdpmfks8.js → index-ynrf908v.js} +1 -1
  110. package/dist/{index-f6m4c545.js → index-zrdcmg6j.js} +4 -6
  111. package/dist/process/bun-child.d.ts +3 -2
  112. package/dist/process/bun-child.d.ts.map +1 -1
  113. package/dist/server/contract-method.d.ts.map +1 -1
  114. package/dist/server/file.d.ts +12 -6
  115. package/dist/server/file.d.ts.map +1 -1
  116. package/dist/tools/internal/surface-projector.d.ts.map +1 -1
  117. package/dist/tools/operations/async-operation-canonical-types.d.ts +1 -1
  118. package/dist/tracking/attribution.d.ts +21 -25
  119. package/dist/tracking/attribution.d.ts.map +1 -1
  120. package/dist/tracking/client-visit.d.ts +5 -7
  121. package/dist/tracking/client-visit.d.ts.map +1 -1
  122. package/dist/tracking/client.d.ts +2 -2
  123. package/dist/tracking/client.d.ts.map +1 -1
  124. package/dist/tracking/contract.d.ts +1 -1
  125. package/dist/tracking/host.d.ts +0 -1
  126. package/dist/tracking/host.d.ts.map +1 -1
  127. package/dist/tracking/privacy.d.ts +6 -0
  128. package/dist/tracking/privacy.d.ts.map +1 -1
  129. package/dist/tracking/schemas.d.ts +2 -2
  130. package/dist/tracking/schemas.d.ts.map +1 -1
  131. package/llms/contract.txt +46 -24
  132. package/llms/geo-contract.txt +23 -0
  133. package/llms/geo.txt +40 -4
  134. package/llms/server.2.txt +19 -6
  135. package/llms/server.5.txt +2 -1
  136. package/llms/stitchkit.txt +4 -3
  137. package/llms/testing.txt +3 -3
  138. package/llms/tools.2.txt +2 -2
  139. package/llms/tools.3.txt +1 -1
  140. package/llms/tracking-contract.txt +1 -1
  141. package/llms/tracking.txt +27 -5
  142. package/llms/{upgrading-0.105.0-0.118.0.txt → upgrading-0.106.0-0.119.0.txt} +121 -410
  143. package/llms/upgrading-0.37.0-0.53.0.txt +969 -0
  144. package/llms/{upgrading-0.44.0-0.62.0.txt → upgrading-0.55.0-0.68.0.txt} +509 -528
  145. package/llms/{upgrading-0.63.0-0.83.0.txt → upgrading-0.69.0-0.95.0.txt} +506 -509
  146. package/llms/{upgrading-0.84.0-0.104.0.txt → upgrading-0.96.0-0.105.0.txt} +410 -506
  147. package/llms/upgrading.txt +5 -5
  148. package/llms-full.txt +271 -48
  149. package/llms.txt +11 -10
  150. package/package.json +23 -19
  151. package/llms/upgrading-0.37.0-0.44.0.txt +0 -444
@@ -0,0 +1,23 @@
1
+ # stitchkit/geo/contract — stitchkit docs slice
2
+
3
+ > Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
4
+ > `llms.txt` in this package.
5
+
6
+ Contains: API reference: `stitchkit/geo/contract` (docs/api/reference.md)
7
+
8
+ Also read:
9
+ - see `llms/geo.txt` for the GeoIP guide
10
+
11
+ ==============================================================================
12
+ # API reference: `stitchkit/geo/contract` (docs/api/reference.md)
13
+ ==============================================================================
14
+
15
+ ## `stitchkit/geo/contract`
16
+
17
+ The place snapshot's schema, browser-safe, for a shared contract. Brings `zod`.
18
+
19
+ | Export | Kind | Summary |
20
+ |--------|------|---------|
21
+ | `GeoAttributionSchema` / `GeoAttribution` | schema / _type_ | the strict readonly Zod owner of the snapshot `stitchkit/geo` resolves — [guide](../guide/geo.md#lookups) |
22
+
23
+ ---
package/llms/geo.txt CHANGED
@@ -70,7 +70,45 @@ const attribution = await geo.resolve(requestIp);
70
70
  `resolve` returns `null` for invalid, loopback, private, link-local and otherwise
71
71
  non-public addresses without querying the reader. A database miss or lookup
72
72
  failure also returns `null`; `onError` receives operational failures. A result
73
- may include country, region, city, postal, coordinates, timezone and ASN fields.
73
+ is a sparse `GeoAttribution`: absent facts have no own property, not `null` or
74
+ an own `undefined` value. City and ASN can be present independently. The default
75
+ mapper preserves the complete City + ASN place snapshot:
76
+
77
+ | Fields | Meaning |
78
+ |--------|---------|
79
+ | `continentCode`, `continentName`, `continentGeonameId` | continent code, English name and GeoNames identifier |
80
+ | `countryCode`, `countryName`, `countryGeonameId` | the country the database locates the address in; absent when the record locates none |
81
+ | `registeredCountryCode`, `registeredCountryName`, `registeredCountryGeonameId` | the country the address block is registered to, a separate fact |
82
+ | `regionCode`, `regionName`, `regionGeonameId` | first subdivision |
83
+ | `city`, `cityGeonameId`, `postalCode` | city and postal facts; no city is required |
84
+ | `latitude`, `longitude`, `timezone`, `accuracyRadiusKm` | coordinates, timezone and accuracy radius in kilometres; zero is a value |
85
+ | `autonomousSystemNumber`, `autonomousSystemOrganization` | finite autonomous system number and organisation |
86
+ | `localizedNames` | every available language under optional `continent`, `country`, `registeredCountry`, `region` and `city` dictionaries |
87
+
88
+ No locale is synthesised: without English names, localized dictionaries make a
89
+ meaningful result, but `countryName`, `regionName` or `city` stays absent. The
90
+ located country is never inferred from the registered one — an application that
91
+ wants a country for every address chooses `countryCode ?? registeredCountryCode`
92
+ itself, knowing which fact it used. Empty localized groups are omitted. Each field
93
+ is validated on its own by the schema: text is nonempty, GeoNames identifiers and
94
+ `accuracyRadiusKm` are nonnegative safe integers, latitude and longitude are in
95
+ range. A malformed field is omitted without erasing the other valid facts. Unknown
96
+ vendor fields are not projected.
97
+
98
+ A snapshot carries every language the database has: with the eight GeoLite2
99
+ languages in all five groups it is 1–1.5 KB of JSON. An application that stores
100
+ one per visit and needs fewer languages maps the result to its own shape.
101
+
102
+ `GeoAttributionSchema` is the strict, readonly Zod owner of the DTO. It lives in
103
+ the browser-safe `stitchkit/geo/contract`, so a shared contract validates a stored
104
+ or transported snapshot without the server-only resolver. Every field is optional
105
+ and readonly; use `.unwrap()` before composing the underlying object schema. The
106
+ mapper copies localized dictionaries, so later reader mutations do not change a
107
+ snapshot. An empty or unrecognised record returns `null`.
108
+
109
+ An explicit `map` callback receives the raw reader result and owns its
110
+ answer. The resolver does not apply `GeoAttributionSchema` after a custom mapper,
111
+ strip its application fields or replace its returned object.
74
112
 
75
113
  When a reload succeeds, new lookups move to the new generation immediately.
76
114
  The previous reader closes only after its in-flight lookups finish.
@@ -100,6 +138,4 @@ adapter is used.
100
138
  | `createGeoIpResolver` / `GeoIpResolver` / `GeoIpResolverOptions` / `GeoIpSnapshot` | function / _type_ | public-IP lookup over one stable reader generation; unavailable start, last-known-good degraded reload and cleanup are explicit states |
101
139
  | `createMaxMindGeoIpLoader` / `MaxMindGeoIpLoaderOptions` / `MaxMindGeoIpPaths` | function / _type_ | lazy optional-peer City+ASN loader with stable before/after file revision checks |
102
140
  | `GeoIpReader` / `GeoIpReaderLoader` | _type_ | peer-neutral reader/generation seam for adapters and tests |
103
- | `GeoAttribution` / `mapGeoIpRecord` | _type_ / function | generic optional place and autonomous-system projection; application-specific fields remain outside |
104
-
105
- ---
141
+ | `GeoAttribution` / `mapGeoIpRecord` | _type_ / function | strict readonly sparse City + ASN snapshot: continent, located and registered country as separate facts, GeoNames IDs, first region/city/postal, coordinates/timezone, `accuracyRadiusKm`, autonomous system and all source languages in five `localizedNames` groups; each malformed field is omitted on its own; custom resolver mappers remain app-owned — [guide](../guide/geo.md#lookups) |
package/llms/server.2.txt CHANGED
@@ -97,11 +97,24 @@ contract route does.
97
97
 
98
98
  ### Serving files & Range requests
99
99
 
100
- `staticRoute` is basic on purpose — it reads the whole file into memory and has
101
- no `Range` or conditional support; put a CDN in front, or use it for small web
102
- assets. To serve **media** (video / audio / large downloads) that a browser must
103
- seek and cache, use **`serveFile`** (Bun) — it streams the requested byte range
104
- and speaks the conditional-request half of RFC 7233 / 9110:
100
+ `staticRoute(prefix, dir, { cacheControl })` serves a directory: it checks
101
+ containment, then answers the file through `serveFile`, so a static image or
102
+ video carries `ETag`, `Last-Modified` and `Accept-Ranges`, revalidates to `304`
103
+ and seeks with `206`. `cacheControl` sets `Cache-Control` on every answer; by
104
+ default none is sent.
105
+
106
+ ```ts
107
+ import { createServer, staticRoute } from 'stitchkit/server'
108
+
109
+ createServer({
110
+ rawRoutes: [staticRoute('/static', './public', { cacheControl: 'public, max-age=3600' })],
111
+ })
112
+ ```
113
+
114
+ The route answers `GET`. To serve a file chosen by your own logic — through a
115
+ contract, with `HEAD`, a download name or a custom type — call **`serveFile`**
116
+ directly. It runs on Bun and Node, streams the requested byte range and speaks
117
+ the conditional-request half of RFC 7233 / 9110:
105
118
 
106
119
  ```ts
107
120
  import { defineContract } from 'stitchkit/contract'
@@ -151,7 +164,7 @@ emit none.
151
164
  `serveFile` takes an explicit `path` and trusts it — **the caller owns
152
165
  containment**. For a URL-derived path use `staticRoute` (which enforces it) or
153
166
  `isWithinDir` first. The byte-range parser is exported on its own as
154
- `parseByteRange(header, size)` for direct use and testing. → ADR 0023.
167
+ `parseByteRange(header, size)` for direct use and testing. → ADR 0023, ADR 0281.
155
168
 
156
169
  ## Server primitives
157
170
 
package/llms/server.5.txt CHANGED
@@ -47,7 +47,8 @@ Also re-exports the error helpers from `stitchkit/contract`.
47
47
  | `KeyedServices` | _type_ | registry result: the mount-ordered `ServiceDef[]` carrying the same services under `.byKey` |
48
48
  | `RegistryHandlers` | _type_ | exact backend handler registry inferred from a contract registry |
49
49
  | `ExactRegistryHandlers` | _type_ | fail-first handler shape that rejects extra registry and endpoint keys |
50
- | `staticRoute` | function | a raw route that serves a directory |
50
+ | `staticRoute` | function | a raw route that serves a contained directory through `serveFile` (`Range` / `304` / validators) |
51
+ | `StaticRouteOptions` | _type_ | `{ cacheControl }` — what `staticRoute` adds to every file it serves |
51
52
  | `serveFile` | function | serve a file with `Range` / `304` / `HEAD` — [guide](../guide/server.md#serving-files--range-requests) |
52
53
  | `parseByteRange` | function | parse a single `Range` header → range / `unsatisfiable` / `null` |
53
54
  | `isWithinDir` | function | path containment — `(root, resolvedTarget) => boolean`; call it before `serveFile` on any URL-derived path |
@@ -86,16 +86,17 @@ own, recorded as an ADR.
86
86
  | `stitchkit/release` | browser **and** server | evolving | a page follows the release it was built for — `createReleaseMarker` on the server, `createReleaseWatcher` in the browser, the `X-Build-Id` header and a socket event between them |
87
87
  | `stitchkit/voice` | browser **and** server | evolving | the mechanics of a live voice reply — `SentenceCutter`, `speakableText`, a `SpeechQueue` that synthesises ahead and stops on interruption, the conversation phases |
88
88
  | `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
89
+ | `stitchkit/geo/contract` | browser **and** server | evolving | the place snapshot schema, for a shared contract that stores or sends `GeoAttribution`; brings `zod` |
89
90
  | `stitchkit/xlsx` | browser **and** server | evolving | a workbook from rows and typed columns, with no dependency; text never runs as a formula |
90
91
  | `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
91
92
  | `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
92
- | `stitchkit/observability` | server | stable<br>_redefined in 2 of the 63 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
93
+ | `stitchkit/observability` | server | stable<br>_redefined in 2 of the 64 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
93
94
  | `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, the managed-resource conformance kit and manual time for schedules and retries |
94
95
  | `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
95
96
  | `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
96
97
  | `stitchkit/react/keyboard` | browser | evolving | which part of a screen gets a key — ordered layers, one Escape per level, list zones with real focus; see [keyboard guide](keyboard.md) |
97
98
  | `stitchkit/react/keyboard/testing` | server (Bun or Node) | evolving | the keyboard layers and zones without a DOM — fakes for the window, elements and key events beside the two engines, to test the order of layers, `scope`/`inert` and the edges of a zone in milliseconds |
98
- | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 25 of the 63 minors since 0.56.2, most recently 0.115.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
99
+ | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 25 of the 64 minors since 0.56.2, most recently 0.115.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
99
100
  | `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
100
101
  | `stitchkit/agent-runtime/testing` | tests on Bun or Node | evolving | credential-free replay, scripted provider faults, deterministic race controls and the agent-store conformance kit |
101
102
  | `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
@@ -107,7 +108,7 @@ own, recorded as an ADR.
107
108
  | `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
108
109
  | `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
109
110
  | `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
110
- | `stitchkit/application` | browser + server | evolving<br>_redefined in 14 of the 63 minors since 0.56.2, most recently 0.110.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
111
+ | `stitchkit/application` | browser + server | evolving<br>_redefined in 14 of the 64 minors since 0.56.2, most recently 0.110.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
111
112
  | `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
112
113
  | `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
113
114
  | `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
package/llms/testing.txt CHANGED
@@ -608,9 +608,9 @@ Notes for a Node host:
608
608
  - **Socket.IO** attaches to the Node HTTP server via `serveNode({ socket })`, and
609
609
  on Node the default transport is `['websocket']` — set the client to match
610
610
  (`transports: ['websocket']`). See [realtime](./realtime.md).
611
- - **Bun-only helpers** do not run on Node: `serveFile` (uses `Bun.file`) and the
612
- raw WebSocket lane. `staticRoute` is runtime-neutral (`node:fs`) and works on
613
- both, but in production prefer a CDN / the static front-end below.
611
+ - **Bun-only helpers** do not run on Node: the raw WebSocket lane. `serveFile`
612
+ and `staticRoute` work on both — on Node the body is a `node:fs` read stream —
613
+ but in production prefer a CDN / the static front-end below.
614
614
 
615
615
  ### Production checklist
616
616
 
package/llms/tools.2.txt CHANGED
@@ -154,8 +154,8 @@ export const users = defineContract({ prefix: 'users' }, {
154
154
  reshapes values inside the full schema. With `output` alone it is a slice, and
155
155
  the full result must fit that schema — `withToolView` refuses the endpoint at
156
156
  compile time when it does not.
157
- - **Exposure.** A view needs a tool transport. With `createContractFactory({
158
- toolExposure: 'explicit' })` an endpoint without `expose` is HTTP-only, so an
157
+ - **Exposure.** A view needs a tool transport. With `createContractFactory<Scope>().configure({
158
+ toolExposure: { default: ['HTTP'] } })` an endpoint without `expose` is HTTP-only, so an
159
159
  endpoint with a view names its tool transports in `expose`.
160
160
  - **What it refuses.** `defineContract` rejects a view on an endpoint with no
161
161
  tool transport or no full `output`, on a raw, `rawBody`, multipart,
package/llms/tools.3.txt CHANGED
@@ -163,7 +163,7 @@ runtime-tool runner, plus deliberate raw MCP adapters over the same mechanics.
163
163
  | `AsyncOperationOutputCapability` | _type_ | optional result/artifact schema plus handler |
164
164
  | `RuntimeAsyncOperationConfig` | _type_ | runtime-only descriptor configuration |
165
165
  | `RuntimeAsyncOperation` | _type_ | inferred generated definitions and schemas |
166
- | `AsyncOperationContractConfig` | _type_ | canonical contract config where start returns the operation id; optional `expose` names the transports per capability, because this contract is built inside the framework and never passes through a consumer's `toolExposure: 'explicit'` factory |
166
+ | `AsyncOperationContractConfig` | _type_ | canonical contract config where start returns the operation id; optional `expose` names the transports per capability, because this contract is built inside the framework and never passes through a consumer's configured factory |
167
167
  | `AsyncOperationContractWithStartOutputConfig` | _type_ | canonical contract config with an application start envelope and typed id extractor |
168
168
  | `DefinedAsyncOperationContract` | _type_ | generated contract, capability keys, schemas and parsed adapters |
169
169
  | `ContractAsyncOperationConfig` | _type_ | literal contract method binding and handlers |
@@ -22,7 +22,7 @@ browser code that only sends events does not import it. → ADR 0280
22
22
  | `createTrackingContract` / `TrackingContractConfig` / `TrackingContractEndpoints` | function / _type_ | `bootstrap` (`POST /visit`) and `track` (`POST /events`, `safelistedBody`) from the application's event types, scope and optional extras |
23
23
  | `createTrackingSchemas` / `TrackingSchemas` / `TrackingSchemasConfig` | function / _type_ | every schema of one surface — `event`, `request`, `response`, `disposition`, `entry`, `bootstrap` — from `eventTypes`, optional `eventExtras`, `buildIdPattern`, `maxEventsPerBatch` |
24
24
  | `TrackingEventEnvelope` / `TrackingEventShape` | _type_ | `eventId`, `visitId`, `browserStreamId`, `browserSequence`, `type`, `page`, `metadata`, `clientTimestamp` |
25
- | `TrackEventsRequest` / `TrackEventsResponse` / `TrackEventsResponseSchema` | _type_ / schema | a batch (`buildId`, `events`, `utm`) and its answer (`accepted`, `dispositions`) |
25
+ | `TrackEventsRequest` / `TrackEventsResponse` / `TrackEventsResponseSchema` | _type_ / schema | a batch (`buildId`, `events`; attribution travels with the visit bootstrap) and its answer (`accepted`, `dispositions`) |
26
26
  | `TrackingDisposition` / `TrackingDispositionSchema` / `TrackingDispositionStatus` / `TrackingDispositionStatusSchema` | _type_ / schema | `accepted` / `duplicate` / `identity-invalid` / `excluded-bot` — every one terminal |
27
27
  | `VisitEntryContext` / `VisitEntryContextShape` / `VisitBootstrapResponse` / `VisitBootstrapResponseSchema` | _type_ / schema | what a browser reports to open a visit (lineage, landing, referrer, UTM, display, screen, `buildId`, outbox health) and the lease it gets back |
28
28
  | `TrackingOutboxState` / `TrackingOutboxStateSchema` | _type_ / schema | `available` / `unavailable` |
package/llms/tracking.txt CHANGED
@@ -27,7 +27,7 @@ Both entrypoints are **evolving**.
27
27
  | the event envelope, the batch, the dispositions, the visit entry and lease schemas | the event **types**, their metadata, their labels |
28
28
  | the tab-shared outbox with reserved sequences and a short flush lease | which storage adapter (IndexedDB in a tab) |
29
29
  | the page-leave beacon that arrives, and its queued insurance copy | the session, the router, the React provider |
30
- | visible time, scroll milestones, `data-track` clicks, UTM first/current touch | the referrer → source map, the attribute names |
30
+ | visible time, scroll milestones, `data-track` clicks, raw first/current touch | channel classification, click-marker names, the attribute names |
31
31
  | `dispositionTrackingBatch`, `issueVisitLease`, `activeIntervalOf`, presence | the tables, the transaction, adoption, geo, reports |
32
32
 
33
33
  ## Contract
@@ -74,7 +74,7 @@ const client = createTrackingClient<BrowserEvents>({
74
74
  deliver: (batch) => api.tracking.track(batch), // or a socket first, HTTP as the fallback
75
75
  unloadUrl: urls.tracking.track(),
76
76
  outbox: createTrackingOutbox(indexedDbOutboxStorage('my-app-tracking')),
77
- referrerMap: [{ pattern: /t\.me|telegram\.org/, source: 'telegram', medium: 'social' }],
77
+ clickIdParams: ['gclid', 'gbraid', 'wbraid', 'msclkid', 'yclid', 'ttclid', 'fbclid'],
78
78
  isAction: isInteractionAction,
79
79
  onVisit: (visitId) => rum.setVisit(visitId),
80
80
  })
@@ -87,6 +87,28 @@ client.track('ITEM_VIEW', { itemId, itemTitle })
87
87
  client.track('SIGN_OUT')
88
88
  ```
89
89
 
90
+ Attribution carries observations, not a channel verdict. `utm` contains only the current URL's
91
+ `utm_*` parameters, retaining case and whitespace up to 200 characters per field; tags without
92
+ `utm_source` are valid. Parameter names are case-sensitive (`UTM_SOURCE` is not a tag), a repeated
93
+ tag keeps its first value, and a whitespace-only value is kept as the fact it is. `referrer` carries
94
+ the referring URL with credentials masked. Neither an external referrer nor a click marker creates
95
+ campaign tags. Classify the channel on your server.
96
+
97
+ Attribution belongs to the visit: the bootstrap entry carries it, and an event batch carries events
98
+ only. Join events to their visit on the server to attribute them.
99
+
100
+ `clickIdParams` is the application's ordered list of query-parameter names to recognise. There is no
101
+ built-in list: the first configured name with a nonempty value becomes `clickId` in the touch and
102
+ bootstrap entry. Only the name is retained, never the click ID's value: a referrer from your own site
103
+ repeats the landing query, so the value of every configured marker in a referrer is masked too. An empty
104
+ list collects none; names must contain 1–200 characters, and `createTrackingClient` refuses a list that
105
+ does not. Bootstrap collects these facts even if browser storage is unavailable.
106
+
107
+ `client.attribution()` returns `firstTouch` and `currentTouch`. The first is persisted for 90 days
108
+ by default; the current is this capture's raw context, so an untagged page does not inherit an earlier
109
+ campaign. The server owns any policy for retaining the last non-direct channel. Stored first-touch
110
+ records carry a format version; unversioned attribution is discarded because its tags may be inferred.
111
+
90
112
  Two knobs match the client to your schema: `batchSize` is the contract's
91
113
  `maxEventsPerBatch` (a larger batch is a `400` the outbox can never retire),
92
114
  and `decorate` adds your `eventExtras` — a locale, an area, or the identity a
@@ -323,7 +345,7 @@ shapes are `stitchkit/tracking/contract`, the server half is
323
345
  | Export | Kind | Summary |
324
346
  |--------|------|---------|
325
347
  | `createTrackingClient` | function | the client: visit lease and renewal, pending queue, synchronous identity from reserved sequences, outbox and flush lease, delivery, the string-body page-leave beacon plus a queued copy, visible time, scroll milestones, declarative clicks, heartbeats |
326
- | `TrackingClient` / `TrackingClientConfig` | _type_ | `track` / `onNavigate` / `start` / `visitId` / `browserStreamId` / `attribution`, and the host, `buildId`, `builtin` names, `bootstrap`, `deliver`, optional `decorate` (your `eventExtras` on every minted event), `unload` / `unloadUrl`, `outbox`, `onUnauthorized`, `onVisit`, `onFailure`, `isAction`, `referrerMap`, `clickAttributes`, `hrefPolicy` (`path-only` by default; `full` retains click query/fragment before `decorate`), `scrollMilestones`, `batchSize`, periods and limits |
348
+ | `TrackingClient` / `TrackingClientConfig` | _type_ | `track` / `onNavigate` / `start` / `visitId` / `browserStreamId` / `attribution`, and the host, `buildId`, `builtin` names, `bootstrap`, `deliver`, optional `decorate` (your `eventExtras` on every minted event), `unload` / `unloadUrl`, `outbox`, `onUnauthorized`, `onVisit`, `onFailure`, `isAction`, `clickIdParams` (ordered application-defined marker names; no values retained), `clickAttributes`, `hrefPolicy` (`path-only` by default; `full` retains click query/fragment before `decorate`), `scrollMilestones`, `batchSize`, periods and limits |
327
349
  | `TrackFn` / `EventsWithMetadata` / `EventsWithoutMetadata` | _type_ | `track(type)` / `track(type, metadata)` typed by the application's metadata map, and the two halves of that map |
328
350
  | `BuiltinTrackingEventTypes` / `CONVENTIONAL_TRACKING_EVENT_TYPES` | _type_ / const | the application's names for the events the client emits itself; the conventional `PAGE_VIEW` … `INTERACTION` set |
329
351
  | `browserTrackingHost` / `TrackingHost` / `TrackingPageContext` | function / _type_ | everything the client takes from a browser tab behind one interface — page context, visibility, scroll depth, events, intervals, clocks, storage — so a test or a non-tab host can supply its own |
@@ -336,8 +358,8 @@ shapes are `stitchkit/tracking/contract`, the server half is
336
358
  | `createVisibleTimeMeter` / `VisibleTimeMeter` / `VisibleInterval` / `VisibleHeartbeat` / `VisibleTimeMeterOptions` | function / _type_ | additive visible time — `checkpoint` / `cut` / `heartbeat`, each interval with its own id; a hidden heartbeat carries no interval |
337
359
  | `scrollDepthPercent` / `createScrollMilestones` / `ScrollMilestones` | function / _type_ | depth as a percentage of the scrollable range; milestones fired once each per page |
338
360
  | `createOncePerPage` / `OncePerPage` | function / _type_ | one fact per key per page within a window — the guard a twice-mounted component cannot keep itself |
339
- | `resolveAttribution` / `ResolveAttributionInput` / `ResolvedAttribution` / `AttributionStorage` / `ReferrerRule` | function / _type_ | first-touch once, current-touch on every new UTM; the referrer → source/medium map is the application's, there is no built-in list |
340
- | `parseUtmFromSearch` / `parseReferrer` | function | the two parsers `resolveAttribution` is built from |
361
+ | `resolveAttribution` / `ResolveAttributionInput` / `ResolvedAttribution` / `AttributionStorage` | function / _type_ | persisted first-touch with TTL, raw current-touch on each capture; actual UTM, referrer and optional `clickId` name from `clickIdParams`; `storage: null` collects without persistence; no channel inference |
362
+ | `parseUtmFromSearch` | function | reads only `utm_*`, preserving case and whitespace up to 200 characters per field; any tag is sufficient, no source required |
341
363
  | `redactTrackingText` / `redactTrackingValue` | functions | mask passwords, sign-in credentials and signed launch data in text or a value of any shape; the key stays, and navigation and campaign parameters are untouched |
342
364
  | `resolveTrackedClick` / `ResolveTrackedClickOptions` / `TrackedClick` / `TrackedClickAttributes` / `ClickTarget` | function / _type_ | `data-track` → click, `data-track-action` → interaction, a link to another origin → outbound; attribute names configurable; `hrefPolicy: 'full'` retains query/fragment (default `path-only` omits them), URL credentials excluded; `leavesPage` says which path to send on |
343
365