stitchkit 0.116.0 → 0.117.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 +42 -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 +196 -76
- 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/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 +32 -12
- 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.117.0.txt} +50 -3
- package/llms/upgrading.txt +1 -1
- package/llms/xlsx.txt +107 -0
- package/llms-full.txt +355 -31
- package/llms.txt +11 -7
- package/package.json +27 -9
- package/dist/{index-z3d6smer.js → index-tdpmfks8.js} +5 -5
package/llms/tracking.txt
CHANGED
|
@@ -33,7 +33,7 @@ Both entrypoints are **evolving**.
|
|
|
33
33
|
## Contract
|
|
34
34
|
|
|
35
35
|
```ts
|
|
36
|
-
import { createTrackingContract } from 'stitchkit/tracking'
|
|
36
|
+
import { createTrackingContract } from 'stitchkit/tracking/contract'
|
|
37
37
|
|
|
38
38
|
export const tracking = createTrackingContract({
|
|
39
39
|
scope: 'public',
|
|
@@ -232,6 +232,76 @@ has an identity. A bot gets a lease that no store holds, so its events are
|
|
|
232
232
|
`createPresenceRegistry` is who is here now, in this process: touch it from
|
|
233
233
|
`track`, read it for a live feed. It is honestly empty after a restart.
|
|
234
234
|
|
|
235
|
+
## Real-visitor speed
|
|
236
|
+
|
|
237
|
+
`stitchkit/tracking/performance` collects Web Vitals from the people who use the site. Install the
|
|
238
|
+
optional peer `web-vitals` and call it once on the page:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import { createPerformanceCollector } from 'stitchkit/tracking/performance'
|
|
242
|
+
|
|
243
|
+
createPerformanceCollector({
|
|
244
|
+
buildId: BUILD_ID,
|
|
245
|
+
url: '/api/tracking/performance',
|
|
246
|
+
visitId: () => client.visitId(),
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The library is fetched as its own chunk after `load`, when the browser is idle, so the measurement costs
|
|
251
|
+
the page nothing it is measuring. Each load posts an `early` sample five seconds later and a `final` one
|
|
252
|
+
as the page goes, both with `sendBeacon` and the same `id`: keep the later one. The body is a string, so
|
|
253
|
+
the endpoint declares `safelistedBody: true`. A sample that could not leave waits in session storage for the
|
|
254
|
+
next page, up to 20 of them, and of one load only the newest.
|
|
255
|
+
|
|
256
|
+
A browser under automation sends nothing, and neither does an agent that admits to being Lighthouse,
|
|
257
|
+
headless Chrome, GTmetrix or a crawler. Lighthouse with its default settings imitates an ordinary browser, so a
|
|
258
|
+
local run with `webdriver` off cannot be told from a visitor.
|
|
259
|
+
|
|
260
|
+
One load is one document: a client-side navigation stays under the route the page opened on, and whatever
|
|
261
|
+
`web-vitals` reports after a back-forward restore is left out, because it would replace the load's numbers
|
|
262
|
+
with a restore's. A second call on a page returns the running collector.
|
|
263
|
+
|
|
264
|
+
A sample carries the route, the build, `mobile` or `desktop`, and the five metrics. **A metric that did not
|
|
265
|
+
arrive is `null`, never zero**: most visits have no INP at all, and a zero would pull every average down.
|
|
266
|
+
|
|
267
|
+
Parse a sample on your own endpoint and store it in your own table:
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
import { redactTrackingText } from 'stitchkit/tracking'
|
|
271
|
+
import { PerformanceSampleSchema, summarizePerformanceMetric } from 'stitchkit/tracking/contract'
|
|
272
|
+
|
|
273
|
+
const sample = PerformanceSampleSchema.parse(await request.json())
|
|
274
|
+
await samples.upsert({ ...sample, route: redactTrackingText(sample.route) })
|
|
275
|
+
|
|
276
|
+
const lcp = summarizePerformanceMetric(rows.map((row) => row.vitals.lcpMs))
|
|
277
|
+
// { samples: 42, p75: 1840, p95: null } — a p95 needs 100 samples
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The report is yours: which routes matter and what is slow are the application's words.
|
|
281
|
+
|
|
282
|
+
## Privacy
|
|
283
|
+
|
|
284
|
+
`redactTrackingText` masks passwords, sign-in credentials, API keys, bearer tokens and signed Telegram launch
|
|
285
|
+
data in a URL or free text, and leaves paths and campaign parameters byte for byte. Text past 16 KiB is cut
|
|
286
|
+
first, because the endpoint is open to anyone. `code` and `hash` count only beside the
|
|
287
|
+
`state` or `auth_date` that makes them credentials, so a promo code stays. `redactTrackingValue` applies the
|
|
288
|
+
same rule through a value of any shape. The client applies it to the landing path, the referrer and the
|
|
289
|
+
campaign tags before sending or storing them. Apply it again on your ingest: anyone can post to that endpoint without running the client.
|
|
290
|
+
|
|
291
|
+
## Is tracking losing events?
|
|
292
|
+
|
|
293
|
+
`trackingTelemetryHealth(reports, baselines)` reads the outbox figures of a visit's bootstrap
|
|
294
|
+
(`browserStreamId` as `stream`, `outboxState`, `outboxQueued`, `outboxDropped`) and answers `ok`, `degraded` or
|
|
295
|
+
`unknown`. An application running without an outbox reports `unavailable` and reads as `degraded`. A browser repeats its lifetime `dropped` with
|
|
296
|
+
every visit, so pass what each stream reported before the window as `baselines`, and only the growth counts.
|
|
297
|
+
|
|
298
|
+
## Bundle weight
|
|
299
|
+
|
|
300
|
+
`stitchkit/tracking` has no `zod` in its graph: `createTrackingClient` with `indexedDbOutboxStorage` is under
|
|
301
|
+
8 KB gzip, a test holds that, and the build refuses a published file that reaches `zod`. The schemas live in
|
|
302
|
+
`stitchkit/tracking/contract` for the server and a shared contract. Importing that in code a browser loads
|
|
303
|
+
brings `zod` back, so keep a shared contract out of the storefront's client bundle.
|
|
304
|
+
|
|
235
305
|
## Not here
|
|
236
306
|
|
|
237
307
|
GeoIP, event labels, funnels, reports, the analytics page, Socket.IO push into
|
|
@@ -246,8 +316,9 @@ looks different even though their mechanics are now one.
|
|
|
246
316
|
|
|
247
317
|
Browser-safe visitor-tracking mechanics, with no event vocabulary of their own
|
|
248
318
|
and no React. The React wrapper (a provider and a hook, ~40 lines) is the
|
|
249
|
-
application's — it owns the router and the session.
|
|
250
|
-
`stitchkit/tracking/
|
|
319
|
+
application's — it owns the router and the session. It imports no `zod`: the wire
|
|
320
|
+
shapes are `stitchkit/tracking/contract`, the server half is
|
|
321
|
+
`stitchkit/tracking/server`. → ADR 0166, ADR 0280 — [guide](../guide/tracking.md)
|
|
251
322
|
|
|
252
323
|
| Export | Kind | Summary |
|
|
253
324
|
|--------|------|---------|
|
|
@@ -256,15 +327,6 @@ application's — it owns the router and the session. The server half is
|
|
|
256
327
|
| `TrackFn` / `EventsWithMetadata` / `EventsWithoutMetadata` | _type_ | `track(type)` / `track(type, metadata)` typed by the application's metadata map, and the two halves of that map |
|
|
257
328
|
| `BuiltinTrackingEventTypes` / `CONVENTIONAL_TRACKING_EVENT_TYPES` | _type_ / const | the application's names for the events the client emits itself; the conventional `PAGE_VIEW` … `INTERACTION` set |
|
|
258
329
|
| `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 |
|
|
259
|
-
| `createTrackingContract` / `TrackingContractConfig` / `TrackingContractEndpoints` | function / _type_ | `bootstrap` (`POST /visit`) and `track` (`POST /events`, `safelistedBody`) from the application's event types, scope and optional extras |
|
|
260
|
-
| `createTrackingSchemas` / `TrackingSchemas` / `TrackingSchemasConfig` | function / _type_ | every schema of one surface — `event`, `request`, `response`, `disposition`, `entry`, `bootstrap` — from `eventTypes`, optional `eventExtras`, `buildIdPattern`, `maxEventsPerBatch` |
|
|
261
|
-
| `TrackingEventEnvelope` / `TrackingEventShape` | _type_ | `eventId`, `visitId`, `browserStreamId`, `browserSequence`, `type`, `page`, `metadata`, `clientTimestamp` |
|
|
262
|
-
| `TrackEventsRequest` / `TrackEventsResponse` / `TrackEventsResponseSchema` | _type_ / schema | a batch (`buildId`, `events`, `utm`) and its answer (`accepted`, `dispositions`) |
|
|
263
|
-
| `TrackingDisposition` / `TrackingDispositionSchema` / `TrackingDispositionStatus` / `TrackingDispositionStatusSchema` | _type_ / schema | `accepted` / `duplicate` / `identity-invalid` / `excluded-bot` — every one terminal |
|
|
264
|
-
| `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 |
|
|
265
|
-
| `TrackingOutboxState` / `TrackingOutboxStateSchema` | _type_ / schema | `available` / `unavailable` |
|
|
266
|
-
| `UtmData` / `UtmDataSchema` / `AttributionData` / `AttributionDataSchema` | _type_ / schema | campaign tags and a touch (UTM, referrer, landing page) |
|
|
267
|
-
| `DEFAULT_BUILD_ID_PATTERN` | const | `dev` or a git SHA |
|
|
268
330
|
| `createTrackingOutbox` / `TrackingOutbox` / `TrackingOutboxOptions` / `TrackingOutboxHealth` | function / _type_ | the tab-shared outbox: `streamId`, `reserveSequences`, `enqueue`, `acquireLease` / `releaseLease` (short, released on leave), `readBatch`, `acknowledge`, `health`; bounded by count and age |
|
|
269
331
|
| `TrackingOutboxStorage` / `TrackingOutboxMeta` / `TrackingOutboxEvents` / `TrackingOutboxRecord` / `TrackingQueuedEvent` | _type_ | one atomic, all-or-nothing `transact` over a key/value store and an event store (`readonly` for pure reads) — the contract an adapter implements |
|
|
270
332
|
| `indexedDbOutboxStorage` / `memoryOutboxStorage` | function | the IndexedDB adapter (one `readwrite` transaction per `transact`) and the in-memory one for tests and degraded mode |
|
|
@@ -276,6 +338,7 @@ application's — it owns the router and the session. The server half is
|
|
|
276
338
|
| `createOncePerPage` / `OncePerPage` | function / _type_ | one fact per key per page within a window — the guard a twice-mounted component cannot keep itself |
|
|
277
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 |
|
|
278
340
|
| `parseUtmFromSearch` / `parseReferrer` | function | the two parsers `resolveAttribution` is built from |
|
|
341
|
+
| `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 |
|
|
279
342
|
| `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 |
|
|
280
343
|
|
|
281
344
|
---
|
|
@@ -1,14 +1,61 @@
|
|
|
1
|
-
# Upgrading 0.105.0 → 0.
|
|
1
|
+
# Upgrading 0.105.0 → 0.117.0 — stitchkit docs slice
|
|
2
2
|
|
|
3
3
|
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
4
|
> `llms.txt` in this package.
|
|
5
5
|
|
|
6
|
-
Contains: Guide: Upgrading, 0.105.0 → 0.
|
|
6
|
+
Contains: Guide: Upgrading, 0.105.0 → 0.117.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.105.0 → 0.
|
|
9
|
+
# Guide: Upgrading, 0.105.0 → 0.117.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.117.0
|
|
13
|
+
|
|
14
|
+
### telegram-chat-pause
|
|
15
|
+
|
|
16
|
+
**Who must act:** code that relied on a 429 to one chat to stop the token's other chats. A bot that
|
|
17
|
+
only sends needs no change: its other chats stop waiting.
|
|
18
|
+
|
|
19
|
+
`run` pauses the `chat_id` of a refused send; the token pauses when `tokenPauseChats` chats are refused
|
|
20
|
+
inside `tokenPauseWindowMs`, or when the call has no chat
|
|
21
|
+
([ADR 0278](../decisions/0278-a-telegram-429-holds-the-chat-that-got-it.md)). A second budget kept under a
|
|
22
|
+
derived key to isolate one group is no longer needed: remove it. Where one refusal must still stop everything,
|
|
23
|
+
say so:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
// before
|
|
27
|
+
await api.sendMessage(chatId, text)
|
|
28
|
+
// after
|
|
29
|
+
await api.sendMessage(chatId, text).catch((error) => {
|
|
30
|
+
budget.pauseAfter(error)
|
|
31
|
+
throw error
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The catch belongs at the `Api` call, where grammY has turned a returned refusal into a thrown one. A raw
|
|
36
|
+
`budget.run` around a client transformer's `send` gets that refusal as a value.
|
|
37
|
+
|
|
38
|
+
Search pattern: `budget.run`, and budgets created under a key derived from the token.
|
|
39
|
+
|
|
40
|
+
### tracking-contract-entry
|
|
41
|
+
|
|
42
|
+
**Who must act:** code that imports `createTrackingContract` or a tracking schema or wire type from
|
|
43
|
+
`stitchkit/tracking`. Code that only uses the browser client needs no change.
|
|
44
|
+
|
|
45
|
+
The wire shapes moved to `stitchkit/tracking/contract`, so a page that sends events no longer carries `zod`
|
|
46
|
+
([ADR 0280](../decisions/0280-real-visitor-speed-is-collected-after-the-page.md)):
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// before
|
|
50
|
+
import { createTrackingContract, createTrackingSchemas } from 'stitchkit/tracking'
|
|
51
|
+
// after
|
|
52
|
+
import { createTrackingContract, createTrackingSchemas } from 'stitchkit/tracking/contract'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Search pattern: imports from `stitchkit/tracking` naming `createTrackingContract`, `createTrackingSchemas`,
|
|
56
|
+
`UtmData`, `AttributionData`, `TrackingEventEnvelope`, `TrackingDisposition`, `TrackEvents*`, `VisitEntryContext`,
|
|
57
|
+
`VisitBootstrapResponse`, `TrackingOutboxState` or `DEFAULT_BUILD_ID_PATTERN`.
|
|
58
|
+
|
|
12
59
|
## Released migration: 0.116.0
|
|
13
60
|
|
|
14
61
|
### send-only-telegram-pause
|
package/llms/upgrading.txt
CHANGED
|
@@ -11,7 +11,7 @@ Contains: Guide: Upgrading, general (docs/guide/upgrading.md)
|
|
|
11
11
|
|
|
12
12
|
Load this slice, then every range slice between your installed version and the target:
|
|
13
13
|
|
|
14
|
-
- 0.105.0 → 0.
|
|
14
|
+
- 0.105.0 → 0.117.0: `llms/upgrading-0.105.0-0.117.0.txt`
|
|
15
15
|
- 0.84.0 → 0.104.0: `llms/upgrading-0.84.0-0.104.0.txt`
|
|
16
16
|
- 0.63.0 → 0.83.0: `llms/upgrading-0.63.0-0.83.0.txt`
|
|
17
17
|
- 0.44.0 → 0.62.0: `llms/upgrading-0.44.0-0.62.0.txt`
|
package/llms/xlsx.txt
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# stitchkit/xlsx — 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: Guide: XLSX (docs/guide/xlsx.md) · API reference: `stitchkit/xlsx` (docs/api/reference.md)
|
|
7
|
+
|
|
8
|
+
==============================================================================
|
|
9
|
+
# Guide: XLSX (docs/guide/xlsx.md)
|
|
10
|
+
==============================================================================
|
|
11
|
+
|
|
12
|
+
# XLSX
|
|
13
|
+
|
|
14
|
+
`stitchkit/xlsx` turns rows into a workbook. It is evolving, it needs nothing beyond the `zod` the package
|
|
15
|
+
already requires, and it runs wherever
|
|
16
|
+
`CompressionStream` does: Bun, Node and a browser.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { defineMoney } from 'stitchkit/primitives'
|
|
20
|
+
import { renderXlsx, XLSX_MEDIA_TYPE } from 'stitchkit/xlsx'
|
|
21
|
+
|
|
22
|
+
const rub = defineMoney('RUB')
|
|
23
|
+
|
|
24
|
+
const bytes = await renderXlsx({
|
|
25
|
+
sheets: [
|
|
26
|
+
{
|
|
27
|
+
name: 'Orders',
|
|
28
|
+
columns: [
|
|
29
|
+
{ key: 'title', header: 'Title', type: 'text' },
|
|
30
|
+
{ key: 'count', header: 'Count', type: 'number', format: '0.00' },
|
|
31
|
+
{ key: 'day', header: 'Day', type: 'date' },
|
|
32
|
+
{ key: 'at', header: 'Created', type: 'datetime', timeZone: 'Asia/Bangkok' },
|
|
33
|
+
{ key: 'total', header: 'Total', type: 'money', currency: 'RUB', scale: 2 },
|
|
34
|
+
{ key: 'paid', header: 'Paid', type: 'boolean' },
|
|
35
|
+
],
|
|
36
|
+
rows: [
|
|
37
|
+
{
|
|
38
|
+
title: 'First order',
|
|
39
|
+
count: '2.5',
|
|
40
|
+
day: '2026-11-03',
|
|
41
|
+
at: new Date(),
|
|
42
|
+
total: rub.create('504182'),
|
|
43
|
+
paid: true,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return new Response(bytes, {
|
|
51
|
+
headers: {
|
|
52
|
+
'content-type': XLSX_MEDIA_TYPE,
|
|
53
|
+
'content-disposition': `attachment; filename*=UTF-8''${encodeURIComponent('Übersicht.xlsx')}`,
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
A missing or `null` value leaves the cell empty. The first row holds the headers, stays frozen and carries a
|
|
59
|
+
filter. The same input produces the same bytes on one runtime; Bun and Node compress differently.
|
|
60
|
+
|
|
61
|
+
## Column types
|
|
62
|
+
|
|
63
|
+
| `type` | Cell value | In the file |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `text` | string | text, whatever it looks like: `007` keeps its zeros |
|
|
66
|
+
| `number` | number, bigint or decimal string | a number, with an optional Excel `format` |
|
|
67
|
+
| `date` | `YYYY-MM-DD` | a date serial; a calendar date has no time zone to get wrong |
|
|
68
|
+
| `datetime` | `Date` or ISO instant with an offset | the wall clock of the column's `timeZone` to the second, since a cell stores no zone |
|
|
69
|
+
| `money` | `Money` in the column's `currency` | a number with `scale` places and the currency in its format |
|
|
70
|
+
| `boolean` | boolean | a boolean |
|
|
71
|
+
|
|
72
|
+
## What it refuses
|
|
73
|
+
|
|
74
|
+
A value of the wrong type throws `XlsxCellError` naming the cell, such as `sheet "Orders" B2: expected a
|
|
75
|
+
number or a decimal string`, instead of landing as a wrong cell.
|
|
76
|
+
|
|
77
|
+
Excel keeps numbers as doubles, so 15 significant digits are what survives. A decimal string or `Money` with
|
|
78
|
+
more refuses rather than turning into a different amount. Keep such a value in a `text` column if it must
|
|
79
|
+
stay exact and needs no arithmetic. Dates before 1900-03-01 refuse too: Excel counts a leap day that never
|
|
80
|
+
happened, so its serials before it are off by one.
|
|
81
|
+
|
|
82
|
+
A wall clock cannot tell the two hours of a daylight-saving change apart: 05:30Z and 06:30Z on a New York
|
|
83
|
+
autumn night are the same cell. Use `UTC` for a column whose order must survive that hour.
|
|
84
|
+
|
|
85
|
+
## Text is never a formula
|
|
86
|
+
|
|
87
|
+
Cells are written as inline strings, so `=HYPERLINK("x")` from a user's input is text a reader shows,
|
|
88
|
+
and the file has no formula element at all. A cell that starts with `=`, `+`, `-` or `@` also carries Excel's
|
|
89
|
+
quote prefix, so it stays text when a person edits that cell.
|
|
90
|
+
|
|
91
|
+
## Limits
|
|
92
|
+
|
|
93
|
+
Everything is built in memory, up to Excel's own 1 048 576 rows per sheet. There is no reading, no
|
|
94
|
+
charts, no merged cells and no streaming: an application that needs them takes a library.
|
|
95
|
+
|
|
96
|
+
==============================================================================
|
|
97
|
+
# API reference: `stitchkit/xlsx` (docs/api/reference.md)
|
|
98
|
+
==============================================================================
|
|
99
|
+
|
|
100
|
+
## `stitchkit/xlsx`
|
|
101
|
+
|
|
102
|
+
| Export | Kind | Summary |
|
|
103
|
+
|--------|------|---------|
|
|
104
|
+
| `renderXlsx` | function | a workbook from rows and typed columns as XLSX bytes; deterministic, no formula in the file |
|
|
105
|
+
| `XLSX_MEDIA_TYPE` | constant | the media type for `defineExportOperation` and a download response |
|
|
106
|
+
| `XlsxCellError` | class | a value of the wrong type, or one Excel cannot hold exactly, with the cell's address |
|
|
107
|
+
| `XlsxWorkbookSchema` / `XlsxWorkbook` / `XlsxSheetSchema` / `XlsxColumnSchema` / `XlsxColumn` | schemas / _types_ | the workbook, its sheets and the six column types |
|