stitchkit 0.106.1 → 0.108.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 +151 -0
- package/README.md +2 -0
- package/darwin-native.cjs +17 -4
- package/dist/agent-runtime/deferred-tool-types.d.ts +6 -27
- package/dist/agent-runtime/deferred-tool-types.d.ts.map +1 -1
- package/dist/browser/stream.d.ts +38 -12
- package/dist/browser/stream.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/browser.js +2 -3
- package/dist/entrypoints/agent-runtime/coding-tools.js +6 -8
- package/dist/entrypoints/agent-runtime/harness.js +7 -11
- package/dist/entrypoints/agent-runtime/realtime.js +2 -3
- package/dist/entrypoints/agent-runtime/sandbox.js +6 -8
- package/dist/entrypoints/agent-runtime.d.ts +2 -1
- package/dist/entrypoints/agent-runtime.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime.js +20 -23
- package/dist/entrypoints/application/diagnostic-journal.js +3 -3
- package/dist/entrypoints/application/directory-inbox.js +8 -9
- package/dist/entrypoints/application/grammy.js +3 -3
- package/dist/entrypoints/application.js +7 -8
- package/dist/entrypoints/bin/upgrade-cli.d.ts +32 -0
- package/dist/entrypoints/bin/upgrade-cli.d.ts.map +1 -1
- package/dist/entrypoints/bin/upgrade-cli.js +451 -8
- package/dist/entrypoints/cli/publish.js +10 -11
- package/dist/entrypoints/cli.js +12 -16
- package/dist/entrypoints/contract.js +1 -1
- package/dist/entrypoints/files/packaging.d.ts +3 -1
- package/dist/entrypoints/files/packaging.d.ts.map +1 -1
- package/dist/entrypoints/files/packaging.js +171 -55
- package/dist/entrypoints/files.js +16 -16
- package/dist/entrypoints/index.d.ts +1 -1
- package/dist/entrypoints/index.d.ts.map +1 -1
- package/dist/entrypoints/index.js +47 -41
- package/dist/entrypoints/node.js +27 -29
- package/dist/entrypoints/observability.js +10 -12
- package/dist/entrypoints/process.js +2 -2
- package/dist/entrypoints/react.js +3 -4
- package/dist/entrypoints/remote.js +8 -9
- package/dist/entrypoints/server.js +48 -51
- package/dist/entrypoints/telegram/html.js +3 -3
- package/dist/entrypoints/telegram/screens.js +6 -6
- package/dist/entrypoints/telegram.d.ts +2 -0
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +344 -11
- package/dist/entrypoints/testing.d.ts +1 -0
- package/dist/entrypoints/testing.d.ts.map +1 -1
- package/dist/entrypoints/testing.js +138 -11
- package/dist/entrypoints/tools/connections.js +11 -11
- package/dist/entrypoints/tools/invoker.js +5 -9
- package/dist/entrypoints/tools/mcp.js +8 -14
- package/dist/entrypoints/tools.js +19 -25
- package/dist/entrypoints/tracking.js +3 -3
- package/dist/files/native-artifact.d.ts +14 -0
- package/dist/files/native-artifact.d.ts.map +1 -0
- package/dist/files/native-packaging-layout.d.ts +11 -2
- package/dist/files/native-packaging-layout.d.ts.map +1 -1
- package/dist/files/native-packaging-plugin.d.ts +53 -0
- package/dist/files/native-packaging-plugin.d.ts.map +1 -0
- package/dist/files/native-packaging.d.ts +44 -43
- package/dist/files/native-packaging.d.ts.map +1 -1
- package/dist/{index-v5ee8ath.js → index-1h2zv8rx.js} +10 -40
- package/dist/index-2kbysk9s.js +42 -0
- package/dist/{index-wbhdzxar.js → index-2s6fpehp.js} +5 -5
- package/dist/{index-ksfagmyz.js → index-4qh90tyw.js} +8 -8
- package/dist/{index-yvfk3y36.js → index-636mggad.js} +4 -3
- package/dist/{index-f199nfq5.js → index-6y9t2fwz.js} +7 -7
- package/dist/{index-w8etpm8j.js → index-9j2atjte.js} +1 -1
- package/dist/index-a5qr2rj6.js +26 -0
- package/dist/{index-azx12jgv.js → index-bh2ht9y5.js} +13 -7
- package/dist/{index-pz3y6b6g.js → index-cx2nh595.js} +3 -3
- package/dist/{index-2k91mewf.js → index-dm2fv45z.js} +9 -9
- package/dist/{index-9bskshe3.js → index-dwf0gymy.js} +10 -10
- package/dist/{index-qaqbdm7s.js → index-h7qms8f9.js} +8 -8
- package/dist/{index-drs41arz.js → index-ktjmgq9p.js} +1 -1
- package/dist/{index-916yh4e2.js → index-mep4sb48.js} +14 -14
- package/dist/{index-wdy68sh6.js → index-njs9gvrh.js} +17 -17
- package/dist/{index-1ptj98e0.js → index-nx49x0tw.js} +2 -2
- package/dist/{index-1pwwan01.js → index-p5kx5vqd.js} +214 -59
- package/dist/{index-sj28htvf.js → index-pvh3z03x.js} +1 -1
- package/dist/{index-r393tnfp.js → index-q6crhe1n.js} +4 -4
- package/dist/{index-dsnjzb62.js → index-t2bsd0hm.js} +1 -1
- package/dist/{index-4vsby8n8.js → index-w9mqgnz9.js} +1 -1
- package/dist/{index-z23rfxhj.js → index-xmgjtkvr.js} +1 -1
- package/dist/{index-e05cjgtf.js → index-xvj9h8yh.js} +28 -1
- package/dist/{index-gr5g3xfw.js → index-yz8x0hbx.js} +1 -1
- package/dist/{index-gxm9rc97.js → index-zrtrjkbf.js} +1 -1
- package/dist/internal/bounded-lines.d.ts +46 -2
- package/dist/internal/bounded-lines.d.ts.map +1 -1
- package/dist/internal/darwin-binding-error.d.ts +9 -1
- package/dist/internal/darwin-binding-error.d.ts.map +1 -1
- package/dist/internal/darwin-binding.d.ts.map +1 -1
- package/dist/internal/process-identity.d.ts.map +1 -1
- package/dist/internal/until-aborted.d.ts +9 -0
- package/dist/internal/until-aborted.d.ts.map +1 -0
- package/dist/internal/upgrade-affects.d.ts +58 -0
- package/dist/internal/upgrade-affects.d.ts.map +1 -0
- package/dist/internal/upgrade-plan.d.ts +20 -0
- package/dist/internal/upgrade-plan.d.ts.map +1 -1
- package/dist/internal/upgrade-usage.d.ts +61 -0
- package/dist/internal/upgrade-usage.d.ts.map +1 -0
- package/dist/telegram/bot-api.d.ts +10 -4
- package/dist/telegram/bot-api.d.ts.map +1 -1
- package/dist/telegram/broadcast.d.ts +2 -1
- package/dist/telegram/broadcast.d.ts.map +1 -1
- package/dist/telegram/not-dispatched.d.ts +26 -0
- package/dist/telegram/not-dispatched.d.ts.map +1 -0
- package/dist/telegram/operator-channel.d.ts +2 -1
- package/dist/telegram/operator-channel.d.ts.map +1 -1
- package/dist/telegram/send-failure.d.ts +4 -3
- package/dist/telegram/send-failure.d.ts.map +1 -1
- package/dist/telegram/transport-connect.d.ts +38 -0
- package/dist/telegram/transport-connect.d.ts.map +1 -0
- package/dist/telegram/transport.d.ts +43 -0
- package/dist/telegram/transport.d.ts.map +1 -0
- package/dist/telegram/webhook.d.ts +2 -1
- package/dist/telegram/webhook.d.ts.map +1 -1
- package/dist/testing/manual-clock.d.ts +82 -0
- package/dist/testing/manual-clock.d.ts.map +1 -0
- package/dist/tools/internal/surface-projector.d.ts +0 -7
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools/runtime-tool-declaration.d.ts +11 -0
- package/dist/tools/runtime-tool-declaration.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts +2 -3
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/llms/files-packaging.txt +13 -6
- package/llms/process.txt +71 -15
- package/llms/stitchkit.2.txt +211 -628
- package/llms/stitchkit.txt +635 -10
- package/llms/telegram.txt +36 -3
- package/llms/testing.txt +47 -0
- package/llms/{upgrading-0.96.0-0.106.0.txt → upgrading-0.100.0-0.108.0.txt} +112 -144
- package/llms/{upgrading-0.37.0-0.53.0.txt → upgrading-0.37.0-0.58.0.txt} +209 -3
- package/llms/{upgrading-0.55.0-0.68.0.txt → upgrading-0.59.0-0.71.0.txt} +149 -209
- package/llms/{upgrading-0.69.0-0.95.0.txt → upgrading-0.72.0-0.99.0.txt} +137 -149
- package/llms/upgrading.txt +36 -4
- package/llms-full.txt +360 -39
- package/llms.txt +10 -10
- package/package.json +2 -1
- package/llms/stitchkit.3.txt +0 -177
- package/dist/{index-cazts87s.js → index-07dcf2yn.js} +3 -3
- package/dist/{index-n1nszyk0.js → index-7jvwrjqa.js} +3 -3
- package/dist/{index-cmzvhhtd.js → index-85qve8mq.js} +3 -3
- package/dist/{index-rpzewktb.js → index-fynr93w4.js} +3 -3
- package/dist/{index-37asdw3a.js → index-k7qdkh3n.js} +3 -3
- package/dist/{index-x7w1z6pf.js → index-q4hjtyye.js} +4 -4
- package/dist/{index-7n68nmc6.js → index-y3nemndz.js} +3 -3
- package/dist/{index-12zsej7b.js → index-y70v24cw.js} +3 -3
- package/dist/{index-pzb63z66.js → index-ykdcnq1f.js} +3 -3
package/llms/upgrading.txt
CHANGED
|
@@ -11,10 +11,10 @@ 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.
|
|
15
|
-
- 0.
|
|
16
|
-
- 0.
|
|
17
|
-
- 0.37.0 → 0.
|
|
14
|
+
- 0.100.0 → 0.108.0: `llms/upgrading-0.100.0-0.108.0.txt`
|
|
15
|
+
- 0.72.0 → 0.99.0: `llms/upgrading-0.72.0-0.99.0.txt`
|
|
16
|
+
- 0.59.0 → 0.71.0: `llms/upgrading-0.59.0-0.71.0.txt`
|
|
17
|
+
- 0.37.0 → 0.58.0: `llms/upgrading-0.37.0-0.58.0.txt`
|
|
18
18
|
|
|
19
19
|
# Upgrading stitchkit
|
|
20
20
|
|
|
@@ -41,6 +41,38 @@ of the range if you want a different one.
|
|
|
41
41
|
So upgrading is: read the `### ⚠️ Breaking changes` of every version *above* your
|
|
42
42
|
current one *up to* your target, and apply each snippet.
|
|
43
43
|
|
|
44
|
+
### Does an item touch your project?
|
|
45
|
+
|
|
46
|
+
Every breaking item since 0.104.0 carries one machine line, `**Affects:**`, naming what it changes
|
|
47
|
+
in a form that is read without guessing from prose:
|
|
48
|
+
|
|
49
|
+
```md
|
|
50
|
+
**Affects:** `stitchkit/files/packaging` createNativePackaging(delivery: 'embedded')
|
|
51
|
+
**Affects:** `stitchkit/contract`, `stitchkit/server` AppError; `stitchkit` ApiError
|
|
52
|
+
**Affects:** `stitchkit/process` behaviour
|
|
53
|
+
**Affects:** `stitchkit/agent-runtime/harness-tools` *
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Targets are separated by `; `. Each starts with one or more backticked entrypoints, then lists the
|
|
57
|
+
exports it changes (an optional parenthesised qualifier names the option or member), or says
|
|
58
|
+
`behaviour` for a change of semantics no import name reveals, or `*` for every import of a removed
|
|
59
|
+
entrypoint. `stitchkit upgrade` reads your project's imports (`--cwd`, default `.`; TypeScript, JavaScript,
|
|
60
|
+
Vue and Svelte files; not `node_modules`, and not a `dist`, `build`, `out` or `coverage` folder
|
|
61
|
+
beside a `package.json`, which is build output) and gives each item one verdict:
|
|
62
|
+
|
|
63
|
+
- **affects this project** — with every `path:line` that imports a named export, or a namespace;
|
|
64
|
+
- **not used here** — nothing imported matches;
|
|
65
|
+
- **behavioural — check by hand** — with the files that import the entrypoint;
|
|
66
|
+
- **not declared — check by hand** — an item from before the line existed, with the files that
|
|
67
|
+
import the entrypoints it leads with.
|
|
68
|
+
|
|
69
|
+
`--json` prints the same verdicts per item for a CI step. The scan reads static `import` and
|
|
70
|
+
`export … from` declarations, bare imports and `import()` / `require()` of a literal specifier; a
|
|
71
|
+
specifier built at run time is invisible to it, and so is a file of another kind (`.astro`,
|
|
72
|
+
`.mdx`). A directory or file the process may not read is
|
|
73
|
+
listed under **Not scanned** (`unscanned` in `--json`) instead of ending the plan: the verdicts do
|
|
74
|
+
not cover it.
|
|
75
|
+
|
|
44
76
|
## What your range does, and does not, do for you
|
|
45
77
|
|
|
46
78
|
A caret range (`"stitchkit": "^0.71.0"`) is a real gate: it resolves `< 0.72.0`,
|
package/llms-full.txt
CHANGED
|
@@ -62,9 +62,9 @@ own, recorded as an ADR.
|
|
|
62
62
|
| `stitchkit/cli/publish` | build and release tooling (Bun or Node, POSIX) | evolving | `publishCli` — commit a verified CLI distribution and move its public manifest last; see [CLI guide](cli.md#publishing-a-complete-version) |
|
|
63
63
|
| `stitchkit/remote` | browser **and** server | stable | peer-free `implementRemote` for thin HTTP proxy processes |
|
|
64
64
|
| `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture and process-group cancellation |
|
|
65
|
-
| `stitchkit/files/packaging` | build time (Bun or Node) | evolving | installed native asset graph, integrity
|
|
65
|
+
| `stitchkit/files/packaging` | build time (Bun or Node) | evolving | installed native asset graph, integrity, Bun packaging plugin and the artifact loader check; no runtime install policy |
|
|
66
66
|
| `stitchkit/files` | server (Bun or Node) | stable | peer-free managed local-file boundary |
|
|
67
|
-
| `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification, send-failure classification, resumable broadcasts, the operator channel with dedupe, local Bot API files, webhook ownership and durable webhook update intake |
|
|
67
|
+
| `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification, send-failure classification, resumable broadcasts, the operator channel with dedupe, a Bot API transport that separates a request that never left from an unknown outcome, local Bot API files, webhook ownership and durable webhook update intake |
|
|
68
68
|
| `stitchkit/telegram/html` | browser and server | evolving | Telegram's HTML as a tree — clean any markup to what Telegram accepts, cut long text into valid parts by what the reader sees, check markup before it is sent |
|
|
69
69
|
| `stitchkit/telegram/screens` | server (Bun or Node) | evolving | a bot's menus as declared screens over grammY — typed paths, actions and input, message reconciliation, state in any `StorageAdapter`, a test chat |
|
|
70
70
|
| `stitchkit/tracking` | browser **and** server | evolving | visitor-tracking mechanics — `createTrackingClient`, the tab-shared outbox, the page-leave beacon, attribution, the contract factory; no event vocabulary, no React |
|
|
@@ -74,12 +74,12 @@ own, recorded as an ADR.
|
|
|
74
74
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
75
75
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
76
76
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
77
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
78
|
-
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler,
|
|
77
|
+
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the 53 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
78
|
+
| `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 |
|
|
79
79
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
80
80
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
81
81
|
| `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) |
|
|
82
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 23 of the
|
|
82
|
+
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 23 of the 53 minors since 0.56.2, most recently 0.105.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
|
|
83
83
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
84
84
|
| `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 |
|
|
85
85
|
| `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
|
|
@@ -91,7 +91,7 @@ own, recorded as an ADR.
|
|
|
91
91
|
| `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
|
|
92
92
|
| `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
|
|
93
93
|
| `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
|
|
94
|
-
| `stitchkit/application` | browser + server | evolving<br>_redefined in 13 of the
|
|
94
|
+
| `stitchkit/application` | browser + server | evolving<br>_redefined in 13 of the 53 minors since 0.56.2, most recently 0.105.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
|
|
95
95
|
| `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
|
|
96
96
|
| `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
|
|
97
97
|
| `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
|
|
@@ -3403,6 +3403,47 @@ Set `finalLine: 'require-newline'` when the final newline is part of the
|
|
|
3403
3403
|
protocol's truncation proof. The default `allow` continues to accept one valid
|
|
3404
3404
|
final JSON document without a newline.
|
|
3405
3405
|
|
|
3406
|
+
### Any byte source
|
|
3407
|
+
|
|
3408
|
+
`parseNDJSON` (and `parseSSE`) read more than a `Response`: a `ReadableStream<Uint8Array>`
|
|
3409
|
+
(a fetch body, a Bun child's `stdout`) or any `AsyncIterable<Uint8Array>` (a Node child's
|
|
3410
|
+
`stdout`). `signal` stops reading and cancels or returns the source:
|
|
3411
|
+
|
|
3412
|
+
```ts
|
|
3413
|
+
import { parseNDJSON } from 'stitchkit'
|
|
3414
|
+
|
|
3415
|
+
const child = Bun.spawn(['worker'], { stdout: 'pipe' })
|
|
3416
|
+
for await (const progress of parseNDJSON(child.stdout, {
|
|
3417
|
+
maxLineBytes: 64 * 1024,
|
|
3418
|
+
finalLine: 'require-newline',
|
|
3419
|
+
})) report(progress)
|
|
3420
|
+
```
|
|
3421
|
+
|
|
3422
|
+
A source that hands over bytes through a callback — a `Bun.listen` or `Bun.connect` socket's
|
|
3423
|
+
`data` handler — uses `createNDJSONDecoder`, the same reader driven by pushes:
|
|
3424
|
+
|
|
3425
|
+
```ts
|
|
3426
|
+
import { createNDJSONDecoder } from 'stitchkit'
|
|
3427
|
+
|
|
3428
|
+
const decoder = createNDJSONDecoder<ControlRequest>({ maxLineBytes: 16 * 1024 })
|
|
3429
|
+
Bun.listen({
|
|
3430
|
+
unix: socketPath,
|
|
3431
|
+
socket: {
|
|
3432
|
+
data(socket, bytes) {
|
|
3433
|
+
for (const request of decoder.push(bytes)) handle(socket, request)
|
|
3434
|
+
},
|
|
3435
|
+
},
|
|
3436
|
+
})
|
|
3437
|
+
```
|
|
3438
|
+
|
|
3439
|
+
Use one decoder per connection. Lines are split in bytes and decoded only once complete, so a
|
|
3440
|
+
character split across chunks is never torn. A line that crosses `maxLineBytes` throws
|
|
3441
|
+
`StreamLineLimitError` (`limitBytes`, `lineBytes`) at the chunk that crossed it: the reader
|
|
3442
|
+
retains at most the limit, however long the line. With `finalLine: 'require-newline'`, a source
|
|
3443
|
+
that ends inside a line throws `StreamTruncatedLineError` (`lineBytes`) instead of yielding the
|
|
3444
|
+
fragment as a value — the right policy for a socket or a child process, where a missing newline
|
|
3445
|
+
means the writer died. Both errors extend the `RangeError` / `SyntaxError` they replace.
|
|
3446
|
+
|
|
3406
3447
|
## Resumable streams
|
|
3407
3448
|
|
|
3408
3449
|
A stream that survives a dropped connection needs four things beyond opening it:
|
|
@@ -8585,23 +8626,55 @@ version: carry their reachable relative `.d.ts` closure, rather than emitting re
|
|
|
8585
8626
|
instead emit declarations for only that DTO contract. Keep the library's manifest at runtime
|
|
8586
8627
|
`dependencies: {}` and `peerDependencies: { zod: ... }` when that is its declared promise.
|
|
8587
8628
|
|
|
8588
|
-
The packaged Darwin loader
|
|
8589
|
-
never follows it: bundling `stitchkit/server`,
|
|
8590
|
-
the same single JS file on every operating
|
|
8591
|
-
`bun build --outfile` works
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
plugin of the next section; it is the only way
|
|
8629
|
+
The packaged Darwin loader computes its addon path at run time from its own file
|
|
8630
|
+
(`module.filename`), so a bundler never follows it: bundling `stitchkit/server`,
|
|
8631
|
+
`stitchkit/files` or `stitchkit/process` yields the same single JS file on every operating
|
|
8632
|
+
system, with no `.node` output, `bun build --outfile` works, and no path of the build machine
|
|
8633
|
+
becomes a literal of the artifact. A bundle has no installed package beside it, so without the
|
|
8634
|
+
packaging plugin it never loads the addon: the first call that needs it reports the Darwin backend
|
|
8635
|
+
`unavailable` with stage `packaging`, and the message names `createNativePackaging`. An artifact
|
|
8636
|
+
that must carry the Darwin addon uses the packaging plugin of the next section; it is the only way
|
|
8637
|
+
a static loader enters a bundle.
|
|
8638
|
+
|
|
8639
|
+
Only these calls load the addon, and only on macOS: process identity (`observeProcessInstance`
|
|
8640
|
+
and `probeProcessOwner`), every exclusive lock (`withExclusiveLock` and what is built on it, such
|
|
8641
|
+
as the file state store and the diagnostic journal) and the contained file operations of the Agent
|
|
8642
|
+
coding tools. Without the addon a lock still works, but it cannot record or check its owner's
|
|
8643
|
+
identity, so a lock held by a crashed owner is not reclaimed. The managed file boundary
|
|
8644
|
+
(`createManagedFileBoundary` and the transfer tools built on it), atomic writes and the chunk
|
|
8645
|
+
spool never load it, on any operating system. The package is free of import side effects
|
|
8646
|
+
(`sideEffects: false`), so a bundle that imports only those parts carries no Darwin loader at all.
|
|
8647
|
+
|
|
8648
|
+
Check an artifact by its loader, never by whether it holds `.node` bytes: Bun can copy the addon
|
|
8649
|
+
into a compiled executable even without the plugin, and the unpackaged loader does not use it.
|
|
8650
|
+
`inspectNativeArtifact(bytes)` from `stitchkit/files/packaging` reads the marker every generated
|
|
8651
|
+
loader carries and answers `packaged` (the plugin's static loader is inside), `unpackaged` (the
|
|
8652
|
+
default loader is inside, and every call above refuses on macOS) or `no-loader` (nothing in the
|
|
8653
|
+
artifact loads the addon). It reads both latin1 and UTF-16LE, because Bun stores source text with
|
|
8654
|
+
non-ASCII characters as UTF-16, and it does not mistake the `STITCHKIT_NATIVE_NOT_PACKAGED` error
|
|
8655
|
+
code, which every bundle with a lock carries, for a loader. Artifacts built by 0.107.0 or earlier
|
|
8656
|
+
carry no marker and read `no-loader`.
|
|
8657
|
+
|
|
8658
|
+
```ts
|
|
8659
|
+
import { inspectNativeArtifact } from 'stitchkit/files/packaging'
|
|
8660
|
+
|
|
8661
|
+
const loader = inspectNativeArtifact(await Bun.file('dist/cli').bytes())
|
|
8662
|
+
if (loader === 'unpackaged') throw new Error('dist/cli was built without native packaging')
|
|
8663
|
+
```
|
|
8596
8664
|
|
|
8597
8665
|
```sh
|
|
8598
8666
|
bun build src/native.ts --target=bun --minify --outfile=dist/native.js
|
|
8599
8667
|
```
|
|
8600
8668
|
|
|
8669
|
+
That plain build serves Linux and the parts that never load the addon. A library whose consumers
|
|
8670
|
+
take locks or read process identity on macOS builds each native entry with the companion plugin of
|
|
8671
|
+
the next section (one entry per build, `naming.entry` equal to `entryPath`) and ships the addon it
|
|
8672
|
+
writes beside the entries.
|
|
8673
|
+
|
|
8601
8674
|
Qualify the complete output outside its build tree and installed dependency graph. Test process
|
|
8602
8675
|
identity, live-owner refusal, dead-owner recovery and contained file operations in artifacts built
|
|
8603
8676
|
with the packaging plugin, and check that an unpackaged build reports the backend `unavailable`
|
|
8604
|
-
rather than certifying a dead owner. Bun and Node package imports retain the same
|
|
8677
|
+
with stage `packaging` rather than certifying a dead owner. Bun and Node package imports retain the same
|
|
8605
8678
|
lazy loader; importing a portable leaf does not load a Darwin addon on another OS. Test
|
|
8606
8679
|
declarations too, and check that importing an unbundled Stitchkit leaf fails in a deliberately
|
|
8607
8680
|
isolated library distribution. A separate schema-only entry must not import the native entry.
|
|
@@ -8609,7 +8682,9 @@ isolated library distribution. A separate schema-only entry must not import the
|
|
|
8609
8682
|
If the Darwin backend cannot load, `observeProcessInstance` still returns `unavailable`.
|
|
8610
8683
|
Its backend `Error` preserves the original `cause`; JSON serialization carries only the stable
|
|
8611
8684
|
`DARWIN_BACKEND_UNAVAILABLE` code, architecture, safe message and failure stage
|
|
8612
|
-
(`architecture`, `resolve`, `load` or `surface`), plus a recognized native error code
|
|
8685
|
+
(`architecture`, `packaging`, `resolve`, `load` or `surface`), plus a recognized native error code
|
|
8686
|
+
when present: `packaging` is a bundle built without the packaging plugin, with native code
|
|
8687
|
+
`STITCHKIT_NATIVE_NOT_PACKAGED`.
|
|
8613
8688
|
It excludes stack, paths and nested cause. This backend diagnosis does not reclassify kernel
|
|
8614
8689
|
failures or turn unavailable identity into proof that an owner is dead. If a runtime provides
|
|
8615
8690
|
no recognized native error code, the stage stays `load`; the loader never infers errno from text.
|
|
@@ -8656,7 +8731,7 @@ for (const asset of native.assets) {
|
|
|
8656
8731
|
}
|
|
8657
8732
|
```
|
|
8658
8733
|
|
|
8659
|
-
`entryPath` and `assetPath` are relative paths inside the application's output root, without
|
|
8734
|
+
In companion delivery, `entryPath` and `assetPath` are relative paths inside the application's output root, without
|
|
8660
8735
|
absolute paths, traversal or overlapping file/directory paths. `assetPath` may contain `[hash]`,
|
|
8661
8736
|
which becomes the first 16 hex digits of that addon's published SHA256: the digest is known before
|
|
8662
8737
|
the build, so `addons/darwin-arm64-[hash].node` gives two installed versions of the package
|
|
@@ -8665,6 +8740,11 @@ addon path accepts. `entryPath` is fixed, without
|
|
|
8665
8740
|
Bun naming templates such as `[dir]` or `[name]`. Companion JS builds require one entry, no splitting,
|
|
8666
8741
|
and `naming.entry` exactly matching `entryPath`; the plugin rejects a mismatching layout.
|
|
8667
8742
|
Choose any application layout; the framework does not prescribe an app directory or installer.
|
|
8743
|
+
The plugin packages the loader of the installation it was created from. A build whose entry
|
|
8744
|
+
imports another `stitchkit` installation — another version, or the same version under another
|
|
8745
|
+
path, as when a build tool carries its own copy — fails with an error naming both versions and
|
|
8746
|
+
roots: that installation's loader would refuse the addon at run time, so the artifact is never
|
|
8747
|
+
written. Call `createNativePackaging` from the `stitchkit` the entry imports.
|
|
8668
8748
|
Keep every bundler output and write `asset.bytes`; never read the addon from `node_modules` a
|
|
8669
8749
|
second time. An installed addon whose size or SHA256 differs from the published manifest refuses
|
|
8670
8750
|
with `mismatch` / `NATIVE_ASSET_DIGEST_MISMATCH`, so a file substituted after installation never
|
|
@@ -8695,10 +8775,27 @@ process primitives without loading Darwin assets. Qualify the exact same JS byte
|
|
|
8695
8775
|
Darwin arm64 and x64 machines, with both companions preserved through archive delivery.
|
|
8696
8776
|
Build-machine architecture and cross-build success cannot establish universal native support.
|
|
8697
8777
|
|
|
8698
|
-
For a standalone executable use `delivery: 'embedded'` and
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8778
|
+
For a standalone executable use `delivery: 'embedded'` and its plugin in `Bun.build` with
|
|
8779
|
+
`compile`. An executable carries the addon inside itself, so this form names no `entryPath` or
|
|
8780
|
+
`assetPath`; passing one is a type error and a schema refusal, never silently ignored:
|
|
8781
|
+
|
|
8782
|
+
```ts
|
|
8783
|
+
const native = createNativePackaging({
|
|
8784
|
+
platform: 'darwin', architecture: 'arm64', delivery: 'embedded',
|
|
8785
|
+
})
|
|
8786
|
+
if (native.state !== 'ready') throw new Error(native.code)
|
|
8787
|
+
const result = await Bun.build({
|
|
8788
|
+
entrypoints: ['src/cli.ts'], minify: true,
|
|
8789
|
+
compile: { target: 'bun-darwin-arm64', outfile: 'dist/cli' },
|
|
8790
|
+
plugins: [native.plugin],
|
|
8791
|
+
})
|
|
8792
|
+
if (!result.success) throw new AggregateError(result.logs, 'Build failed')
|
|
8793
|
+
```
|
|
8794
|
+
|
|
8795
|
+
Bun embeds the selected addon from the verified bytes the plugin holds, not from a second read of
|
|
8796
|
+
the file, and the executable loads it from `/$bunfs/root/darwin-arm64-<hash>.node`. Its `assets`
|
|
8797
|
+
(`NativePackagingEmbeddedAsset`: `bytes`, `size`, `sha256`) identify those bytes and their
|
|
8798
|
+
published digest for qualification; there is nothing to write beside the executable.
|
|
8702
8799
|
Cross-builds must select the requested architecture explicitly; the artifact must run on that target.
|
|
8703
8800
|
The installed package must contain that target's addon. No automatic fallback/downgrade occurs.
|
|
8704
8801
|
|
|
@@ -13880,6 +13977,50 @@ The suite in `packages/core/tests` is the working reference for testing each
|
|
|
13880
13977
|
piece. Its size changes with the public surface, so the guide does not pin a
|
|
13881
13978
|
count that can drift independently from the test runner.
|
|
13882
13979
|
|
|
13980
|
+
### Manual time for schedules and retries
|
|
13981
|
+
|
|
13982
|
+
`createManualClock()` from `stitchkit/testing` stands time still until the test moves it. It is
|
|
13983
|
+
the `clock` of `createManagedSchedule`, a durable sleep, a revision signal or bounded admission,
|
|
13984
|
+
and the `schedule` a retrier of your own takes:
|
|
13985
|
+
|
|
13986
|
+
```ts
|
|
13987
|
+
import { createManagedSchedule } from 'stitchkit/application'
|
|
13988
|
+
import { createManualClock } from 'stitchkit/testing'
|
|
13989
|
+
|
|
13990
|
+
const clock = createManualClock()
|
|
13991
|
+
const schedule = createManagedSchedule({ id: 'sweep', everyMs: 1_000, clock, run })
|
|
13992
|
+
// …start and activate it…
|
|
13993
|
+
await clock.advance(3_500) // runs at 1 s, 2 s and 3 s of manual time; the test takes milliseconds
|
|
13994
|
+
```
|
|
13995
|
+
|
|
13996
|
+
Only one `advance` (or `until`) runs at a time; a second one started before the first settled is
|
|
13997
|
+
refused, because two interleaved moves would run time backwards.
|
|
13998
|
+
|
|
13999
|
+
Due timers fire in deadline order, ties in scheduling order. After each firing the clock yields
|
|
14000
|
+
real event-loop turns, not just microtasks: a continuation that arms the next retry after an
|
|
14001
|
+
already-readable socket or another macrotask has armed it before the clock moves on, so
|
|
14002
|
+
`advance(10_000)` does not skip a retry armed at the fifth second. Real work of unknown length —
|
|
14003
|
+
a request to a fake server, a hash in the thread pool — outruns any number of turns; the test
|
|
14004
|
+
wraps the dependency it injects in a `hold`:
|
|
14005
|
+
|
|
14006
|
+
```ts
|
|
14007
|
+
const request = async (body) => {
|
|
14008
|
+
const held = clock.hold('upload to the fake server')
|
|
14009
|
+
try {
|
|
14010
|
+
return await fakeServer.send(body)
|
|
14011
|
+
} finally {
|
|
14012
|
+
held.release()
|
|
14013
|
+
}
|
|
14014
|
+
}
|
|
14015
|
+
```
|
|
14016
|
+
|
|
14017
|
+
Time does not move while a hold is open; past `holdLimitMs` of real time (default 5 s)
|
|
14018
|
+
`advance` fails with `ManualClockError` `MANUAL_CLOCK_HOLD_TIMEOUT`, naming every open hold. A
|
|
14019
|
+
held operation that waits for the clock itself — a request timing out on a deadline — `park`s
|
|
14020
|
+
its hold so the deadline can come. `until(done)` moves from deadline to deadline until `done()`
|
|
14021
|
+
holds and fails with `MANUAL_CLOCK_LIMIT` past `limitMs` of manual time; `pending()` counts the
|
|
14022
|
+
timers still waiting, so a timer leaked past `close()` shows as a number, not as a hang.
|
|
14023
|
+
|
|
13883
14024
|
### Managed-resource conformance
|
|
13884
14025
|
|
|
13885
14026
|
Consumer-owned resource adapters can run the framework's deterministic
|
|
@@ -14973,8 +15114,8 @@ and pacing/progress intervals must fit native timers. The optional
|
|
|
14973
15114
|
when the signal aborts if a custom sleeper ignores it. A send already in flight
|
|
14974
15115
|
finishes and is recorded before stopping.
|
|
14975
15116
|
|
|
14976
|
-
Without `classify`, known Bot API 429, unreachable-recipient, malformed-message
|
|
14977
|
-
|
|
15117
|
+
Without `classify`, known Bot API 429, unreachable-recipient, malformed-message,
|
|
15118
|
+
server-error and not-dispatched behavior remains. Unknown/no-status failures now halt as
|
|
14978
15119
|
uncertain, rather than being automatically retried. Existing custom `send`
|
|
14979
15120
|
implementations that relied on those retries must supply an explicit classifier
|
|
14980
15121
|
for proven pre-effect failures. `report.halt` now carries
|
|
@@ -14993,6 +15134,36 @@ The installed
|
|
|
14993
15134
|
fixture checks injected rate limits, ambiguity/no resend, wait budgets and abort
|
|
14994
15135
|
on Bun and Node without a client SDK.
|
|
14995
15136
|
|
|
15137
|
+
## A transport that knows whether a request left
|
|
15138
|
+
|
|
15139
|
+
`fetch` folds establishing the connection and waiting for the answer into one failure. From that
|
|
15140
|
+
failure nobody can say whether Telegram saw the message, so the senders above treat every network
|
|
15141
|
+
failure as unknown: a broadcast records the recipient `uncertain` and the operator channel drops
|
|
15142
|
+
the message rather than risk a duplicate. On a route that sometimes fails to connect at all, that
|
|
15143
|
+
loses messages that never left.
|
|
15144
|
+
|
|
15145
|
+
`createTelegramBotTransport()` connects first and writes the request only on an established
|
|
15146
|
+
connection. Every failure before the first byte is written is `TelegramNotDispatchedError`
|
|
15147
|
+
(`stage`: `lookup`, `connect` or `request`), and `classifyTelegramSendFailure` reads it as
|
|
15148
|
+
`not-dispatched` — `retryable`, with `evidence: 'transport'`. A broadcast retries it as
|
|
15149
|
+
`transient`; the operator channel sends it again. A failure after the request was written stays
|
|
15150
|
+
an outcome nobody can know.
|
|
15151
|
+
|
|
15152
|
+
```ts
|
|
15153
|
+
import { createTelegramBotTransport, telegramOperatorSender } from 'stitchkit/telegram'
|
|
15154
|
+
|
|
15155
|
+
const transport = createTelegramBotTransport()
|
|
15156
|
+
const send = telegramOperatorSender({ token: env.BOT_TOKEN, fetch: transport })
|
|
15157
|
+
```
|
|
15158
|
+
|
|
15159
|
+
Pass it as `fetch` to `callTelegramBotApi`, `telegramBroadcastSender`, `telegramOperatorSender`
|
|
15160
|
+
or the webhook calls. Addresses come in the system resolver's order with no family forced; the
|
|
15161
|
+
next address starts 250 ms later (Happy Eyeballs), and a round with no connection is repeated
|
|
15162
|
+
with new sockets inside `connectBudgetMs` (default 5 s, which also bounds the address lookup; each
|
|
15163
|
+
round waits `connectAttemptMs`, default 2 s). The answer must arrive within `responseTimeoutMs` (default 30 s) and fit
|
|
15164
|
+
`maxResponseBytes` (default 1 MiB). It speaks HTTP/1.1 over `https:`, and over `http:` for a
|
|
15165
|
+
local Bot API server, and it uses no proxy: where the network needs one, keep `fetch`.
|
|
15166
|
+
|
|
14996
15167
|
## Message markup
|
|
14997
15168
|
|
|
14998
15169
|
`stitchkit/telegram/html` is Telegram's HTML parse mode as a tree, with no peer
|
|
@@ -15580,6 +15751,94 @@ analytics policy belong to the application.
|
|
|
15580
15751
|
|
|
15581
15752
|
# Upgrading stitchkit
|
|
15582
15753
|
|
|
15754
|
+
## Released migration: 0.108.0
|
|
15755
|
+
|
|
15756
|
+
### a request that never left is its own send outcome
|
|
15757
|
+
|
|
15758
|
+
**Who must act:** code with an exhaustive `switch` or `Record` over `TelegramSendFailureReason` or
|
|
15759
|
+
over `TelegramSendFailure['evidence']` (`stitchkit/telegram`). Code that reads `retryable` and
|
|
15760
|
+
`recipientUnreachable` needs no change.
|
|
15761
|
+
|
|
15762
|
+
`classifyTelegramSendFailure` now returns `reason: 'not-dispatched'` with `evidence: 'transport'`
|
|
15763
|
+
for a `TelegramNotDispatchedError`: the request never left, so it is `retryable` and repeating it
|
|
15764
|
+
cannot duplicate a message
|
|
15765
|
+
([ADR 0253](../decisions/0253-a-telegram-request-that-never-left-is-safe-to-repeat.md)). Only
|
|
15766
|
+
`createTelegramBotTransport` throws that error; with the default `fetch` nothing changes at run time.
|
|
15767
|
+
|
|
15768
|
+
1. Add the reason and the evidence to every exhaustive mapping:
|
|
15769
|
+
|
|
15770
|
+
```ts
|
|
15771
|
+
// before
|
|
15772
|
+
const code: Record<TelegramSendFailureReason, string> = { /* … */ unknown: 'E_UNKNOWN' }
|
|
15773
|
+
// after
|
|
15774
|
+
const code: Record<TelegramSendFailureReason, string> = {
|
|
15775
|
+
/* … */ 'not-dispatched': 'E_NOT_SENT', unknown: 'E_UNKNOWN',
|
|
15776
|
+
}
|
|
15777
|
+
```
|
|
15778
|
+
|
|
15779
|
+
Search pattern: `TelegramSendFailureReason`, `TELEGRAM_SEND_FAILURE_REASONS` and `evidence ===`.
|
|
15780
|
+
2. Type-check: a `Record` or an exhaustive `switch` without the new members fails to compile.
|
|
15781
|
+
3. To use the distinction, pass `fetch: createTelegramBotTransport()` to the senders that need it
|
|
15782
|
+
(see the [Telegram guide](telegram.md#a-transport-that-knows-whether-a-request-left)).
|
|
15783
|
+
|
|
15784
|
+
### a packaging plugin packages only its own installation
|
|
15785
|
+
|
|
15786
|
+
**Who must act:** builds that call `createNativePackaging` (`stitchkit/files/packaging`) from a
|
|
15787
|
+
`stitchkit` installation other than the one the bundled entry imports — typically a build tool that
|
|
15788
|
+
carries its own copy. Builds whose entry and plugin come from one installation are unchanged.
|
|
15789
|
+
|
|
15790
|
+
Such a build used to succeed and ship the other installation's default Darwin loader, which refuses
|
|
15791
|
+
the addon on macOS at run time. It now fails, naming both versions and roots
|
|
15792
|
+
([ADR 0254](../decisions/0254-a-packaging-plugin-owns-one-loader-and-names-what-it-finds.md)).
|
|
15793
|
+
|
|
15794
|
+
1. Create the plugin from the `stitchkit` the entry resolves, not from the build tool's copy:
|
|
15795
|
+
|
|
15796
|
+
```ts
|
|
15797
|
+
// before: the build tool's own stitchkit
|
|
15798
|
+
import { createNativePackaging } from 'stitchkit/files/packaging'
|
|
15799
|
+
// after: resolved from the project that owns the entry
|
|
15800
|
+
const { createNativePackaging } = await import(
|
|
15801
|
+
Bun.resolveSync('stitchkit/files/packaging', projectRoot)
|
|
15802
|
+
)
|
|
15803
|
+
```
|
|
15804
|
+
|
|
15805
|
+
Search pattern: `createNativePackaging` in build tooling that is installed apart from the project.
|
|
15806
|
+
2. Check the artifact with `inspectNativeArtifact`: a correct build reads `packaged`. An artifact
|
|
15807
|
+
built by 0.107.0 or earlier carries no loader marker and reads `no-loader` whatever it holds, so
|
|
15808
|
+
rebuild before relying on the check; a test of `=== 'unpackaged'` alone passes such an artifact.
|
|
15809
|
+
|
|
15810
|
+
## Released migration: 0.107.0
|
|
15811
|
+
|
|
15812
|
+
### embedded native packaging names no paths
|
|
15813
|
+
|
|
15814
|
+
**Who must act:** builds that call `createNativePackaging` (`stitchkit/files/packaging`) with
|
|
15815
|
+
`delivery: 'embedded'`. Companion delivery is unchanged.
|
|
15816
|
+
|
|
15817
|
+
A standalone executable carries the Darwin addon inside itself, so the embedded form takes only
|
|
15818
|
+
`platform`, `architecture` and `delivery`. `entryPath` and `assetPath` were required before but
|
|
15819
|
+
changed nothing in the executable; passing them now is a type error and a schema refusal. The
|
|
15820
|
+
ready result names the embedded addon by `NativePackagingEmbeddedAsset` (`bytes`, `size`,
|
|
15821
|
+
`sha256`), without `outputPath`, since nothing is written beside the executable.
|
|
15822
|
+
|
|
15823
|
+
1. Drop the two paths from the embedded call:
|
|
15824
|
+
|
|
15825
|
+
```ts
|
|
15826
|
+
// before
|
|
15827
|
+
createNativePackaging({
|
|
15828
|
+
platform: 'darwin', architecture: 'arm64', delivery: 'embedded',
|
|
15829
|
+
entryPath: 'cli.js', assetPath: 'native/darwin-arm64.node',
|
|
15830
|
+
})
|
|
15831
|
+
// after
|
|
15832
|
+
createNativePackaging({ platform: 'darwin', architecture: 'arm64', delivery: 'embedded' })
|
|
15833
|
+
```
|
|
15834
|
+
|
|
15835
|
+
Search pattern: `delivery: 'embedded'`.
|
|
15836
|
+
2. Code that read `asset.outputPath` from an embedded result reads `bytes`, `size` and `sha256`
|
|
15837
|
+
only; an annotation `NativePackagingOptions` / `NativePackagingResult` on an embedded call
|
|
15838
|
+
becomes `NativePackagingEmbeddedOptions` / `NativePackagingEmbeddedResult`.
|
|
15839
|
+
3. Rebuild every artifact made without the plugin by 0.105.0–0.106.1: it carries the build
|
|
15840
|
+
machine's package path (see [Darwin native assets in JS distributions](#darwin-native-assets-in-js-distributions)).
|
|
15841
|
+
|
|
15583
15842
|
## Released migration: 0.106.0
|
|
15584
15843
|
|
|
15585
15844
|
### a stopped leader settles as stopped
|
|
@@ -16180,13 +16439,27 @@ Custom output layout uses the evolving build-only packaging contract in the
|
|
|
16180
16439
|
Three deliveries have different rules: an ordinary npm install retains the package's
|
|
16181
16440
|
native assets; a JS distribution must ship its complete output graph; a Bun compiled
|
|
16182
16441
|
executable embeds the matching addon and may still use `--outfile`. In 0.103.13–0.104.2 a plain
|
|
16183
|
-
`bun build` carries the addon without a plugin
|
|
16184
|
-
uses `createNativePackaging` (`delivery: 'companion'` for JS, `'embedded'` for a
|
|
16185
|
-
executable).
|
|
16186
|
-
|
|
16187
|
-
|
|
16188
|
-
|
|
16189
|
-
|
|
16442
|
+
`bun build` carries the addon without a plugin. Later releases load it from a bundle only when
|
|
16443
|
+
the build uses `createNativePackaging` (`delivery: 'companion'` for JS, `'embedded'` for a
|
|
16444
|
+
compiled executable). Without the plugin, Bun may still copy the addon's bytes into a compiled
|
|
16445
|
+
executable, but the loader never uses them, so their presence proves nothing.
|
|
16446
|
+
|
|
16447
|
+
What an unpackaged bundle does depends on the release:
|
|
16448
|
+
|
|
16449
|
+
- **0.105.0–0.106.1:** the bundle carries the absolute path of the package on the build machine,
|
|
16450
|
+
because the loader read `__dirname`. It looks for the addon there, so it works only on that
|
|
16451
|
+
machine, and the path itself leaks into a distributed artifact. Rebuild with a later release.
|
|
16452
|
+
- **0.107.0 and later:** no build path is in the artifact, and the first call that needs the
|
|
16453
|
+
addon reports the Darwin backend `unavailable` with stage `packaging`.
|
|
16454
|
+
|
|
16455
|
+
Only macOS is affected, and only process identity (`observeProcessInstance`,
|
|
16456
|
+
`probeProcessOwner`), exclusive locks and contained Agent file operations load the addon. The
|
|
16457
|
+
managed file boundary, atomic writes and the chunk spool never do. The
|
|
16458
|
+
[native IO guide](native-io.md#libraries-with-a-zod-only-runtime) is the canonical recipe and
|
|
16459
|
+
shows how to check an artifact by its loader without running it on a Mac. Check the resulting
|
|
16460
|
+
artifact offline outside the build tree and `node_modules`, including process identity,
|
|
16461
|
+
live-owner lock refusal, dead-owner recovery and contained IO. A missing or corrupt addon
|
|
16462
|
+
remains `unavailable`, never evidence that an owner died.
|
|
16190
16463
|
|
|
16191
16464
|
### CLI: repeated options are refused
|
|
16192
16465
|
|
|
@@ -16783,6 +17056,38 @@ of the range if you want a different one.
|
|
|
16783
17056
|
So upgrading is: read the `### ⚠️ Breaking changes` of every version *above* your
|
|
16784
17057
|
current one *up to* your target, and apply each snippet.
|
|
16785
17058
|
|
|
17059
|
+
### Does an item touch your project?
|
|
17060
|
+
|
|
17061
|
+
Every breaking item since 0.104.0 carries one machine line, `**Affects:**`, naming what it changes
|
|
17062
|
+
in a form that is read without guessing from prose:
|
|
17063
|
+
|
|
17064
|
+
```md
|
|
17065
|
+
**Affects:** `stitchkit/files/packaging` createNativePackaging(delivery: 'embedded')
|
|
17066
|
+
**Affects:** `stitchkit/contract`, `stitchkit/server` AppError; `stitchkit` ApiError
|
|
17067
|
+
**Affects:** `stitchkit/process` behaviour
|
|
17068
|
+
**Affects:** `stitchkit/agent-runtime/harness-tools` *
|
|
17069
|
+
```
|
|
17070
|
+
|
|
17071
|
+
Targets are separated by `; `. Each starts with one or more backticked entrypoints, then lists the
|
|
17072
|
+
exports it changes (an optional parenthesised qualifier names the option or member), or says
|
|
17073
|
+
`behaviour` for a change of semantics no import name reveals, or `*` for every import of a removed
|
|
17074
|
+
entrypoint. `stitchkit upgrade` reads your project's imports (`--cwd`, default `.`; TypeScript, JavaScript,
|
|
17075
|
+
Vue and Svelte files; not `node_modules`, and not a `dist`, `build`, `out` or `coverage` folder
|
|
17076
|
+
beside a `package.json`, which is build output) and gives each item one verdict:
|
|
17077
|
+
|
|
17078
|
+
- **affects this project** — with every `path:line` that imports a named export, or a namespace;
|
|
17079
|
+
- **not used here** — nothing imported matches;
|
|
17080
|
+
- **behavioural — check by hand** — with the files that import the entrypoint;
|
|
17081
|
+
- **not declared — check by hand** — an item from before the line existed, with the files that
|
|
17082
|
+
import the entrypoints it leads with.
|
|
17083
|
+
|
|
17084
|
+
`--json` prints the same verdicts per item for a CI step. The scan reads static `import` and
|
|
17085
|
+
`export … from` declarations, bare imports and `import()` / `require()` of a literal specifier; a
|
|
17086
|
+
specifier built at run time is invisible to it, and so is a file of another kind (`.astro`,
|
|
17087
|
+
`.mdx`). A directory or file the process may not read is
|
|
17088
|
+
listed under **Not scanned** (`unscanned` in `--json`) instead of ending the plan: the verdicts do
|
|
17089
|
+
not cover it.
|
|
17090
|
+
|
|
16786
17091
|
## Released migration: 0.88.0
|
|
16787
17092
|
|
|
16788
17093
|
Two mechanical edits, and only if your project builds these values rather than only reading them.
|
|
@@ -20270,8 +20575,11 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
20270
20575
|
| `LiveStateSource` / `LiveStateSourceOpenInput` / `LiveStateSourceOpenResult` | _types_ | host binding for one continuous snapshot/event boundary; transport retry and cursor semantics remain host-owned |
|
|
20271
20576
|
| `LiveStateControllerError` / `LiveStateSubscriberError` | _types_ | isolated observer failure payloads that do not change source or subscriber truth |
|
|
20272
20577
|
| `createRetainedTopics` | function | retained last-value store for sticky events — [guide](../guide/realtime.md#sticky-events) |
|
|
20273
|
-
| `parseSSE` | function | parse
|
|
20274
|
-
| `parseNDJSON` | function | parse bounded fatal-UTF-8 NDJSON; blank keep-alives are skipped
|
|
20578
|
+
| `parseSSE` | function | parse SSE from a `Response`, a web stream or an async byte iterable into an async generator — [guide](../guide/client.md#sse) |
|
|
20579
|
+
| `parseNDJSON` | function | parse bounded fatal-UTF-8 NDJSON from a `Response`, a `ReadableStream<Uint8Array>` or an `AsyncIterable<Uint8Array>` (a child's stdout); blank keep-alives are skipped, `finalLine: 'require-newline'` makes the delimiter mandatory and `signal` cancels the source — [guide](../guide/client.md#any-byte-source) |
|
|
20580
|
+
| `createNDJSONDecoder` / `NDJSONDecoder` | function / _type_ | the same bounded NDJSON reading driven by `push(chunk)` / `end()`, for a socket `data` callback |
|
|
20581
|
+
| `StreamByteSource` | _type_ | `Response \| ReadableStream<Uint8Array> \| AsyncIterable<Uint8Array>`, what the NDJSON and SSE readers accept |
|
|
20582
|
+
| `StreamLineLimitError` / `StreamTruncatedLineError` | class | a line past `maxLineBytes` (`limitBytes`, `lineBytes`; a `RangeError`) and a source ended inside a line under `require-newline` (`lineBytes`; a `SyntaxError`) |
|
|
20275
20583
|
| `resumableIterator` | function | re-open a long-lived stream from the last delivered cursor, with jittered backoff, a caller-owned terminal item and prompt abort — [guide](../guide/client.md#resumable-streams) |
|
|
20276
20584
|
| `createBackoff` | function | exponential backoff with subtractive jitter as a value: `next()` / `reset()` |
|
|
20277
20585
|
| `ContractStreamFrameSchema` / `ContractStreamFrame` | schema / _type_ | default on-the-wire `data` / safe `error` / `end` envelope of a contract-first stream |
|
|
@@ -22085,6 +22393,9 @@ handler pipeline without opening a TCP port.
|
|
|
22085
22393
|
|--------|------|---------|
|
|
22086
22394
|
| `createHandlerTestClient` | function | one contract client backed by an in-process `FetchHandler` |
|
|
22087
22395
|
| `createHandlerTestClients` | function | exact contract-registry batch form |
|
|
22396
|
+
| `createManualClock` / `ManualClock` | function / _type_ | manual time for schedules, retries and deadlines: `now`, `wallNow`, `schedule`, `advance(ms)` firing due timers in order with real event-loop yields between them, `until`, `pending` and `hold`; a `ManagedScheduleClock`, `DurabilityClock`, `RevisionSignalClock` and `BoundedAdmissionClock` — [guide](../guide/testing-and-deployment.md#manual-time-for-schedules-and-retries) |
|
|
22397
|
+
| `ManualClockOptions` / `ManualClockUntilOptions` / `ManualClockTimer` / `ManualClockHold` | _types_ | start and wall instants, event-loop turns per firing and the real-time hold limit; `until` step and manual limit; a cancellable timer; a hold that is released or parked |
|
|
22398
|
+
| `ManualClockError` / `ManualClockErrorCode` | class / _type_ | `MANUAL_CLOCK_HOLD_TIMEOUT` naming the open holds, or `MANUAL_CLOCK_LIMIT` when `until` runs out |
|
|
22088
22399
|
| `runManagedResourceConformance` | function | run the canonical deterministic lifecycle matrix against a fresh consumer-owned `ManagedResource` fixture; resolves `void` or throws `ManagedResourceConformanceError` with a stable scenario ID and normalized trace |
|
|
22089
22400
|
| `ManagedResourceConformanceScenarioIdSchema` / `ManagedResourceConformanceScenarioId` | schema / _type_ | stable clean, rollback, readiness/completion, activation, shutdown-race and forced-cleanup scenario vocabulary |
|
|
22090
22401
|
| `ManagedResourceConformanceScenarioSchema` / `ManagedResourceConformanceScenario` | schema / _type_ | discriminated scenario record including whether the controlled resource is required |
|
|
@@ -22194,7 +22505,10 @@ injected grammY bot. → ADR 0143, ADR 0201 — [guide](../guide/telegram.md)
|
|
|
22194
22505
|
| `TelegramInitDataRefusal` | _type_ | `missing-hash` / `signature-mismatch` / `malformed` / `expired` — an expired string is not a forged one |
|
|
22195
22506
|
| `classifyTelegramSendFailure` | function | name a refused Bot API send and separate "retry this send" from "stop addressing this recipient" |
|
|
22196
22507
|
| `TelegramSendFailure` | _type_ | reason, `status`, Telegram-stated `retryAfterSeconds`, `retryable`, `recipientUnreachable` and which evidence produced the answer |
|
|
22197
|
-
| `
|
|
22508
|
+
| `createTelegramBotTransport` / `TelegramBotTransportOptions` | function / _type_ | a `fetch` for the Bot API senders that connects before it writes, so a failure before the first byte is `TelegramNotDispatchedError`; connection attempt and budget, answer timeout and size, injectable resolver and socket factory — [guide](../guide/telegram.md#a-transport-that-knows-whether-a-request-left) |
|
|
22509
|
+
| `TelegramFetch` / `TelegramBotTransportOpen` / `TelegramBotTransportResolve` / `TelegramBotTransportSocket` | _types_ | the `(url, init) => Promise<Response>` the senders take; the transport's socket factory, resolver and the structural socket it needs (a Node `net.Socket` or `tls.TLSSocket` fits) |
|
|
22510
|
+
| `TelegramNotDispatchedError` / `TelegramNotDispatchedStage` | class / _type_ | a request that provably never left (`lookup`, `connect` or `request`), so repeating it cannot duplicate a message |
|
|
22511
|
+
| `TelegramSendFailureReason` / `TELEGRAM_SEND_FAILURE_REASONS` | _type_ / constant | `blocked-by-user` / `user-deactivated` / `chat-not-found` / `not-started` / `rate-limited` / `message-invalid` / `server-error` / `not-dispatched` / `unknown`, and the same as a list; a `Record<TelegramSendFailureReason, …>` over them fails to compile when a reason is added |
|
|
22198
22512
|
| `runTelegramBroadcast` | function | a resumable broadcast by `name` under a state `directory`: audience and journal durably recorded, pacing at `ratePerSecond` (25), exact retry delays within the finite declared budget, injected classifier, uncertain send outcomes never replayed, `dryRun`, one fenced runner per name |
|
|
22199
22513
|
| `TelegramBroadcastConfig` / `TelegramBroadcastSend` / `TelegramBroadcastReport` / `TelegramBroadcastRunOutcome` / `TelegramBroadcastOutcome` / `TelegramBroadcastRecipient` | _type_ | `name`, `directory`, `recipients()`, `send({ recipient, attempt })`, `maxAttempts`, `signal`, `onProgress`; counts `delivered` / `unreachable` / `failed` / `uncertain` / `pending` and `finished` / `stopped` / `halted` / `dry-run` |
|
|
22200
22514
|
| `TelegramBroadcastFailureSchema` / `TelegramBroadcastFailure` | schema / _type_ | injected `classify` answers retry-after/transient/permanent/ambiguous; exact provider delay is bounded by `maxRetryDelayMs` without shortening, unknown outcome remains uncertain and is never replayed |
|
|
@@ -22743,13 +23057,19 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
|
|
|
22743
23057
|
## `stitchkit/files/packaging`
|
|
22744
23058
|
|
|
22745
23059
|
`stitchkit/files/packaging` owns `createNativePackaging` and the types
|
|
22746
|
-
`NativePackagingOptions`, `NativePackagingAsset`, `NativePackagingPlugin`, `NativePackagingResult
|
|
23060
|
+
`NativePackagingOptions`, `NativePackagingAsset`, `NativePackagingPlugin`, `NativePackagingResult`,
|
|
23061
|
+
and for a standalone executable `NativePackagingEmbeddedOptions`, `NativePackagingEmbeddedAsset`,
|
|
23062
|
+
`NativePackagingEmbeddedResult`. `inspectNativeArtifact` classifies a built artifact's bytes by the
|
|
23063
|
+
loader it carries as a `NativeArtifactLoader`: `packaged`, `unpackaged` or `no-loader`. The plugin
|
|
23064
|
+
fails a build whose entry imports the default loader of another `stitchkit` installation, naming
|
|
23065
|
+
both versions and roots.
|
|
22747
23066
|
It resolves the installed package's target/version, reads each selected addon once and checks it
|
|
22748
23067
|
against the `size` and `sha256` published in the package's `native-assets.json` (`formatVersion: 2`,
|
|
22749
23068
|
written when Stitchkit is built). Call it once per build and reuse the result.
|
|
22750
|
-
`platform`, `architecture`, `delivery`, `entryPath` and `assetPath` are explicit
|
|
22751
|
-
|
|
22752
|
-
|
|
23069
|
+
`platform`, `architecture`, `delivery`, `entryPath` and `assetPath` are the explicit inputs of
|
|
23070
|
+
companion delivery; embedded delivery takes `platform`, one `architecture` and `delivery` only, and
|
|
23071
|
+
refuses a path. `assetPath` accepts one template, `[hash]`, replaced by the first 16 hex digits of
|
|
23072
|
+
the addon's published SHA256;
|
|
22753
23073
|
`platform` is the closed set `'darwin'`, and another name is a type error and a schema refusal.
|
|
22754
23074
|
The result is `ready` with verified assets and a structural Bun plugin, or `unsupported` /
|
|
22755
23075
|
`missing` / `mismatch` with the safe code `NATIVE_TARGET_UNSUPPORTED`, `NATIVE_ASSET_MISSING` or
|
|
@@ -22766,7 +23086,8 @@ and the published `size` and `sha256`.
|
|
|
22766
23086
|
Targets must be unique; entry and all asset paths must be disjoint. One lazy loader chooses only
|
|
22767
23087
|
the actual runtime architecture, with no fallback.
|
|
22768
23088
|
Companion mode places external addons relative to the emitted entry; embedded mode gives
|
|
22769
|
-
Bun compile the verified bytes of the matching addon
|
|
22770
|
-
|
|
23089
|
+
Bun compile the verified bytes of the matching addon, and its asset (`bytes`, `size`, `sha256`)
|
|
23090
|
+
has no `outputPath`, because nothing is written beside the executable. Keep companion JS builds
|
|
23091
|
+
without splitting, preserve every output, and write each asset's `bytes` to its `outputPath`.
|
|
22771
23092
|
This evolving entrypoint is a build dependency; runtime imports do not reach it.
|
|
22772
23093
|
The detailed recipe is in [native IO](../guide/native-io.md#public-native-packaging).
|