stitchkit 0.98.2 → 0.100.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 +63 -0
- package/dist/agent-runtime/contained-darwin.d.ts +0 -17
- package/dist/agent-runtime/contained-darwin.d.ts.map +1 -1
- package/dist/agent-runtime/contained-write.d.ts.map +1 -1
- package/dist/agent-runtime/invocation-attempt.d.ts +22 -0
- package/dist/agent-runtime/invocation-attempt.d.ts.map +1 -0
- package/dist/agent-runtime/invocation-failure.d.ts +6 -0
- package/dist/agent-runtime/invocation-failure.d.ts.map +1 -0
- package/dist/agent-runtime/invocation-payload.d.ts +18 -0
- package/dist/agent-runtime/invocation-payload.d.ts.map +1 -0
- package/dist/agent-runtime/invocation-read.d.ts +131 -0
- package/dist/agent-runtime/invocation-read.d.ts.map +1 -0
- package/dist/agent-runtime/invocation-schema.d.ts +378 -0
- package/dist/agent-runtime/invocation-schema.d.ts.map +1 -0
- package/dist/agent-runtime/invocations.d.ts +46 -0
- package/dist/agent-runtime/invocations.d.ts.map +1 -0
- package/dist/agent-runtime/run-acquisition.d.ts.map +1 -1
- package/dist/agent-runtime/run-execution-state.d.ts +4 -2
- package/dist/agent-runtime/run-execution-state.d.ts.map +1 -1
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/run-failure.d.ts.map +1 -1
- package/dist/agent-runtime/run-model-attempts.d.ts.map +1 -1
- package/dist/agent-runtime/run-operation-lifecycle.d.ts +2 -2
- package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -1
- package/dist/agent-runtime/run-provider-ledger.d.ts +1 -0
- package/dist/agent-runtime/run-provider-ledger.d.ts.map +1 -1
- package/dist/agent-runtime/runtime.d.ts +11 -0
- package/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/agent-runtime/store-create.d.ts.map +1 -1
- package/dist/agent-runtime/store-event-once.d.ts +29 -0
- package/dist/agent-runtime/store-event-once.d.ts.map +1 -0
- package/dist/agent-runtime/store.d.ts +5 -0
- package/dist/agent-runtime/store.d.ts.map +1 -1
- package/dist/application/change-subscription.d.ts +36 -0
- package/dist/application/change-subscription.d.ts.map +1 -0
- package/dist/application/diagnostic-journal-contract.d.ts +3 -6
- package/dist/application/diagnostic-journal-contract.d.ts.map +1 -1
- package/dist/application/notification-delivery.d.ts +32 -0
- package/dist/application/notification-delivery.d.ts.map +1 -0
- package/dist/application/notification-outbox-state.d.ts +37 -0
- package/dist/application/notification-outbox-state.d.ts.map +1 -0
- package/dist/application/notification-outbox.d.ts +7 -1
- package/dist/application/notification-outbox.d.ts.map +1 -1
- package/dist/application/watch-hub-core.d.ts +10 -15
- package/dist/application/watch-hub-core.d.ts.map +1 -1
- package/dist/application/watch-hub.d.ts +10 -2
- package/dist/application/watch-hub.d.ts.map +1 -1
- package/dist/browser/session-credentials.d.ts +20 -0
- package/dist/browser/session-credentials.d.ts.map +1 -0
- package/dist/browser/session.d.ts +31 -0
- package/dist/browser/session.d.ts.map +1 -0
- package/dist/durability/events.d.ts +6 -0
- package/dist/durability/events.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/coding-tools.js +5 -4
- package/dist/entrypoints/agent-runtime/harness.js +8 -6
- package/dist/entrypoints/agent-runtime/sandbox.js +5 -4
- 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 +3 -3
- package/dist/entrypoints/agent-runtime.d.ts +3 -0
- package/dist/entrypoints/agent-runtime.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime.js +21 -10
- package/dist/entrypoints/application/diagnostic-journal.js +2 -1
- package/dist/entrypoints/application.d.ts +3 -1
- package/dist/entrypoints/application.d.ts.map +1 -1
- package/dist/entrypoints/application.js +629 -189
- package/dist/entrypoints/cli.js +6 -6
- package/dist/entrypoints/files.js +2 -1
- package/dist/entrypoints/index.d.ts +2 -0
- package/dist/entrypoints/index.d.ts.map +1 -1
- package/dist/entrypoints/index.js +172 -0
- package/dist/entrypoints/live.js +68 -13
- package/dist/entrypoints/react.d.ts +1 -1
- package/dist/entrypoints/react.d.ts.map +1 -1
- package/dist/entrypoints/react.js +59 -16
- package/dist/entrypoints/testing.js +1 -1
- package/dist/entrypoints/tools/connections.js +2 -2
- package/dist/entrypoints/tools/invoker.js +4 -4
- package/dist/entrypoints/tools.js +8 -8
- package/dist/{index-wsm5w4ee.js → index-0b1cnze2.js} +35 -3
- package/dist/{index-np4m8hd3.js → index-0r0fbk7z.js} +9 -7
- package/dist/{index-p9sh0xx4.js → index-5p2m7we1.js} +3 -3
- package/dist/{index-55hkhm67.js → index-8qt2m66q.js} +1 -1
- package/dist/{index-hmp4800j.js → index-9t3dffv2.js} +3 -3
- package/dist/{index-khtgb21r.js → index-bm5rx7n6.js} +2 -2
- package/dist/{index-gxrt5h6v.js → index-cyktc4bp.js} +3 -0
- package/dist/{index-xw3s75nj.js → index-d8m8zpd8.js} +1 -1
- package/dist/{index-px2gm2jp.js → index-fhwqwxe0.js} +17 -55
- package/dist/{index-het2he5g.js → index-gw8bmyaj.js} +5 -3
- package/dist/{index-8p52kd5p.js → index-js7gqrb1.js} +96 -14
- package/dist/{index-wt743f7f.js → index-k6gpggb9.js} +2 -1
- package/dist/index-q3pyb9n0.js +22 -0
- package/dist/{index-f1nb70ae.js → index-r066jx76.js} +4 -4
- package/dist/{index-sp1tzwnb.js → index-s84he4v7.js} +2 -2
- package/dist/{index-863ea9jb.js → index-sh3s86na.js} +3 -3
- package/dist/{index-nts4a2br.js → index-xwhjjw2x.js} +879 -280
- package/dist/{index-1m2thnq0.js → index-y9qn426m.js} +2 -2
- package/dist/index-zjjyynm3.js +42 -0
- package/dist/internal/coalesced-task.d.ts +15 -0
- package/dist/internal/coalesced-task.d.ts.map +1 -0
- package/dist/internal/darwin-binding.d.ts +19 -0
- package/dist/internal/darwin-binding.d.ts.map +1 -0
- package/dist/internal/exclusive-lock.d.ts +20 -7
- package/dist/internal/exclusive-lock.d.ts.map +1 -1
- package/dist/internal/mutation-queue.d.ts +4 -0
- package/dist/internal/mutation-queue.d.ts.map +1 -0
- package/dist/internal/process-identity.d.ts +1 -1
- package/dist/internal/process-identity.d.ts.map +1 -1
- package/dist/internal/process-instance.d.ts +26 -0
- package/dist/internal/process-instance.d.ts.map +1 -0
- package/dist/live/watch-client-state.d.ts +71 -0
- package/dist/live/watch-client-state.d.ts.map +1 -0
- package/dist/live/watch-client.d.ts +5 -1
- package/dist/live/watch-client.d.ts.map +1 -1
- package/dist/live/watch-contract.d.ts +12 -0
- package/dist/live/watch-contract.d.ts.map +1 -1
- package/dist/react/cache-bridge.d.ts +10 -0
- package/dist/react/cache-bridge.d.ts.map +1 -1
- package/dist/tools/schema/flatten-join.d.ts.map +1 -1
- package/llms/agent-runtime.2.txt +94 -0
- package/llms/agent-runtime.3.txt +24 -0
- package/llms/application.2.txt +68 -2
- package/llms/application.txt +32 -2
- package/llms/files.txt +1 -1
- package/llms/live.txt +7 -0
- package/llms/react.txt +8 -0
- package/llms/server.3.txt +35 -0
- package/llms/stitchkit.2.txt +41 -0
- package/llms/stitchkit.3.txt +22 -0
- package/llms/stitchkit.txt +3 -3
- package/llms/tools.txt +9 -8
- package/llms/upgrading-0.37.0.txt +176 -0
- package/llms/{upgrading-0.37.0-0.58.0.txt → upgrading-0.44.0-0.60.0.txt} +229 -169
- package/llms/{upgrading-0.59.0-0.71.0.txt → upgrading-0.61.0-0.73.0.txt} +122 -229
- package/llms/{upgrading-0.72.0-0.98.0.txt → upgrading-0.74.0-0.100.0.txt} +96 -122
- package/llms/upgrading.txt +4 -3
- package/llms-full.txt +431 -14
- package/llms.txt +11 -10
- package/native/darwin-arm64.node +0 -0
- package/native/darwin-x64.node +0 -0
- package/package.json +1 -1
- package/dist/agent-runtime/run-mutation-queue.d.ts +0 -21
- package/dist/agent-runtime/run-mutation-queue.d.ts.map +0 -1
package/llms/application.2.txt
CHANGED
|
@@ -5,7 +5,35 @@
|
|
|
5
5
|
|
|
6
6
|
Parts of this slice:
|
|
7
7
|
- `llms/application.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md)
|
|
8
|
-
- `llms/application.2.txt`: Guide: Application migration recipes (docs/guide/application-migration-recipes.md) · API reference: `stitchkit/application` (docs/api/reference.md)
|
|
8
|
+
- `llms/application.2.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md) · Guide: Application migration recipes (docs/guide/application-migration-recipes.md) · API reference: `stitchkit/application` (docs/api/reference.md)
|
|
9
|
+
|
|
10
|
+
==============================================================================
|
|
11
|
+
# Guide: Managed application kernel (docs/guide/application-kernel.md) (continued)
|
|
12
|
+
==============================================================================
|
|
13
|
+
|
|
14
|
+
## Multi-action notification delivery
|
|
15
|
+
|
|
16
|
+
Opt into `delivery: { version, actions, project }` on `createNotificationOutbox`.
|
|
17
|
+
The pure `actions(payload)` selector runs at enqueue; the versioned plan remains
|
|
18
|
+
fixed throughout retry. Each `send` receives its action and a stable idempotency
|
|
19
|
+
key; return a small JSON receipt such as a remote message or uploaded object ID.
|
|
20
|
+
`project(notification, receipts)` applies all confirmed results locally and must
|
|
21
|
+
be idempotent. Checkpoints and the final projection timestamp live in the existing
|
|
22
|
+
atomic StateStore; completed receipts retain them within retention/byte limits.
|
|
23
|
+
|
|
24
|
+
This supports, for example, text plus attachment delivery with a local timeline
|
|
25
|
+
projection, or upload plus publication with a local asset index. These are protocol
|
|
26
|
+
examples, not claims of deployed consumer adoption. A failure in projection does
|
|
27
|
+
not repeat confirmed sends. A crash after remote success but before receipt commit
|
|
28
|
+
is ambiguous: the provider must deduplicate the action key or reconcile its result.
|
|
29
|
+
A projection can also repeat if its completion checkpoint is lost.
|
|
30
|
+
|
|
31
|
+
A new executor version must explicitly migrate or terminally classify incompatible
|
|
32
|
+
queued plans. Existing `classify`/`onDropped` handles terminal items; a durable
|
|
33
|
+
quarantine is the application's responsibility. Whole-state file and memory stores
|
|
34
|
+
remain supported. Atomic enqueue with an unrelated business transaction is not
|
|
35
|
+
provided by this contract; retain the application's transactional adapter when that
|
|
36
|
+
boundary is required. Send and projection callbacks own their external deadlines.
|
|
9
37
|
|
|
10
38
|
==============================================================================
|
|
11
39
|
# Guide: Application migration recipes (docs/guide/application-migration-recipes.md)
|
|
@@ -386,7 +414,7 @@ cutovers are covered by the executable
|
|
|
386
414
|
| `DiagnosticJournalConfig` / `DiagnosticJournal` | _type_ | owner schema/path/limits/failure observer and the synchronous `submit`, bounded-wait `flush`/`close`, status handle |
|
|
387
415
|
| `DiagnosticJournalLimitsSchema` / `DiagnosticJournalLimits` | schema / _type_ | positive event, pending-item, pending-byte, file-byte and retained-file limits |
|
|
388
416
|
| `DiagnosticJournalLockPolicySchema` / `DiagnosticJournalLockPolicy` | schema / _type_ | `refuse` (default) or `reclaim-stale`, which reclaims only a lock whose recorded owner is provably gone |
|
|
389
|
-
| `readDiagnosticJournalLockDiagnosis` / `DiagnosticJournalLockDiagnosis` | function / _type_ | why a `reclaim-stale` acquisition refused —
|
|
417
|
+
| `readDiagnosticJournalLockDiagnosis` / `DiagnosticJournalLockDiagnosis` | function / _type_ | why a `reclaim-stale` acquisition refused — attribution, PID liveness and optional process `identity` evidence (`matched`, `different-boot`, `reused-pid`, `pid-gone`, `legacy`, `unavailable`) — read off the thrown `EEXIST` |
|
|
390
418
|
| `DiagnosticJournalSubmitResultSchema` / `DiagnosticJournalSubmitResult` | schema / _type_ | accepted epoch/sequence or explicit invalid, oversized, capacity, closed or failed refusal |
|
|
391
419
|
| `DiagnosticJournalStatusSchema` / `DiagnosticJournalStatus` | schema / _type_ | state, limits, exact admission/write/failure counters, pending ownership, rotations, partial tails and last safe sequences |
|
|
392
420
|
| `DiagnosticJournalFrameSchema` / `DiagnosticJournalFrame` | schema / _type_ | version-1 JSONL frame carrying process epoch, contiguous accepted sequence and schema-validated JSON event |
|
|
@@ -488,3 +516,41 @@ vocabulary with an event topic declared `mode: 'decision'`.
|
|
|
488
516
|
|
|
489
517
|
→ [ADR 0152](../decisions/0152-a-keyspace-is-memory-that-nothing-reaches-before-it-is-durable.md),
|
|
490
518
|
[ADR 0153](../decisions/0153-a-watched-read-is-one-read-per-question.md).
|
|
519
|
+
|
|
520
|
+
### Managed change subscriptions and scoped watches
|
|
521
|
+
|
|
522
|
+
`changeSubscriptionResource` (`stitchkit/application`) accepts
|
|
523
|
+
`ChangeSubscriptionConfig`: `id`, unique `keys` (1–128, at most 256 characters each),
|
|
524
|
+
`connect(signal)`, `reconcile(key, context)`, required `reconcileIntervalMs` (10 ms–1 h),
|
|
525
|
+
optional `timeoutMs` (30000; 1 ms–1 h), `backoff`, and `onError`.
|
|
526
|
+
`ChangeConnection` supplies `subscribe({ signal, hint, disconnected })`, which completes subscription
|
|
527
|
+
before the first read; `close()` releases it. `ChangeReconciliation` exposes `signal`
|
|
528
|
+
and a synchronous `commit(callback)` guard against late publication. Drivers must
|
|
529
|
+
honor cancellation. Uncooperative work retains its slot until settled instead of
|
|
530
|
+
allowing overlapping connections/reads. Errors reach `onError`; no raw payload or
|
|
531
|
+
connection string is logged by this resource. Recovery runs after reconnect and
|
|
532
|
+
periodically even when no notification arrives.
|
|
533
|
+
|
|
534
|
+
`WatchHubConfig` adds `maxSources` (1024), `maxSubscribers` (1024), and optional
|
|
535
|
+
`reconcileIntervalMs` (10 ms–1 h). `hub.attach(subscriber, scope?)` accepts a
|
|
536
|
+
`WatchAdmissionScope` containing a **server-verified** `key` (1–512 characters) and
|
|
537
|
+
revocation `signal`. The key separates sharing and is the optional third argument
|
|
538
|
+
of `read(operation, args, scope)`. It must represent account, session and permissions;
|
|
539
|
+
never trust a client-supplied owner ID as that scope.
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
### Notification action and projection receipts
|
|
544
|
+
|
|
545
|
+
`NotificationOutboxConfig.delivery` accepts `NotificationDeliveryConfig`:
|
|
546
|
+
immutable executor `version`, pure `actions(payload)` plan selector (1–128 unique
|
|
547
|
+
names, each at most 128 characters), and idempotent `project(notification, receipts)`.
|
|
548
|
+
`send` receives optional `action` and stable `idempotencyKey`, and returns a JSON
|
|
549
|
+
remote receipt (void becomes null). `NotificationDeliveryStateSchema` validates the
|
|
550
|
+
optional `NotificationDeliveryState` on queued items and completed receipts:
|
|
551
|
+
`version`, `actions`, `receipts` and optional `projectedAt`. Checkpoints share the
|
|
552
|
+
existing atomic StateStore and lease fence. Receipt retention and serialized byte
|
|
553
|
+
budgets still apply. Single-send configuration remains valid without `delivery`.
|
|
554
|
+
A remote result lost before its checkpoint may be sent again; provider idempotency
|
|
555
|
+
or reconciliation is required. A projection may repeat after a crash before its
|
|
556
|
+
checkpoint. Business-transaction enqueue and durable quarantine are not implied.
|
package/llms/application.txt
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Parts of this slice:
|
|
8
8
|
- `llms/application.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md)
|
|
9
|
-
- `llms/application.2.txt`: Guide: Application migration recipes (docs/guide/application-migration-recipes.md) · API reference: `stitchkit/application` (docs/api/reference.md)
|
|
9
|
+
- `llms/application.2.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md) · Guide: Application migration recipes (docs/guide/application-migration-recipes.md) · API reference: `stitchkit/application` (docs/api/reference.md)
|
|
10
10
|
|
|
11
11
|
==============================================================================
|
|
12
12
|
# Guide: Managed application kernel (docs/guide/application-kernel.md)
|
|
@@ -656,7 +656,12 @@ refusals are explicit; accepted ordered frames are never evicted.
|
|
|
656
656
|
The absolute path's parent must already exist and be operator-controlled. One manager owns it via
|
|
657
657
|
an exclusive `.lock`; new files use mode `0600` by default. `maxFiles` includes the active file,
|
|
658
658
|
and a non-newline startup tail is rotated intact rather than guessed or repaired. An abrupt process
|
|
659
|
-
death may leave
|
|
659
|
+
death may leave a lock. The default `refuse` policy leaves recovery to the operator;
|
|
660
|
+
`lock: 'reclaim-stale'` compares machine, boot and process birth identity before
|
|
661
|
+
recovery. A reused PID cannot impersonate a modern owner. Legacy records with a
|
|
662
|
+
live PID, foreign namespaces and unavailable identity refuse automatic recovery;
|
|
663
|
+
see the upgrading guide for quiescent legacy recovery. The same mechanism owns the
|
|
664
|
+
short-lived reclaim guard.
|
|
660
665
|
|
|
661
666
|
`flush()` means every accepted append through that call's boundary settled. It is not `fsync`, a
|
|
662
667
|
durable receipt, exactly-once execution or remote delivery. Timeout/cancellation bound only the
|
|
@@ -986,3 +991,28 @@ so a scheduler stall on a loaded host cannot pull a live lock from under its
|
|
|
986
991
|
holder — after which the heartbeat wins and the lock is abandoned. Temporary files a crashed writer left beside the state are swept on
|
|
987
992
|
the store's first update. Ledger corruption may be declared reconstructable;
|
|
988
993
|
an outbox must fail closed rather than silently discard pending delivery.
|
|
994
|
+
|
|
995
|
+
## Recovering change subscriptions
|
|
996
|
+
|
|
997
|
+
`changeSubscriptionResource` is an optional resource over a consumer-owned driver.
|
|
998
|
+
It uses a finite declared key set, subscribes before reading, reconciles after
|
|
999
|
+
reconnect and periodically repairs lost hints. `reconcileIntervalMs` is explicit;
|
|
1000
|
+
notifications alone cannot prove freshness. Within a key, hints coalesce into one
|
|
1001
|
+
trailing read and a failed read retries with backoff. Use the supplied
|
|
1002
|
+
`context.commit(() => publish(value))` after awaits to reject an obsolete connection.
|
|
1003
|
+
|
|
1004
|
+
Drivers implement `connect(signal)` and return `subscribe({ signal, hint,
|
|
1005
|
+
disconnected })` plus `close()`. Subscribe must establish the notification boundary
|
|
1006
|
+
before resolving. A database LISTEN driver owns its connection, channels, decoding
|
|
1007
|
+
and transaction ordering; no SQL or database driver is included here. The resource
|
|
1008
|
+
owns reconnect, deadlines and shutdown. Drivers must honor abort. If one ignores it,
|
|
1009
|
+
its slot remains occupied until settlement; deadlines cannot safely manufacture
|
|
1010
|
+
successful cleanup or permit an overlapping connection.
|
|
1011
|
+
|
|
1012
|
+
For watched reads, set `reconcileIntervalMs` on the existing `createWatchHub` rather
|
|
1013
|
+
than building a second read loop. Its per-key machinery is shared with managed
|
|
1014
|
+
subscriptions. Limits default to 1024 sources and 1024 subscribers per hub; set
|
|
1015
|
+
explicit finite values for larger workloads. Supply a server-verified admission
|
|
1016
|
+
scope to `attach` and abort it on logout, permission revocation or session replacement.
|
|
1017
|
+
The read callback receives the trusted scope as its third argument. A client owner
|
|
1018
|
+
ID in arguments is not authentication.
|
package/llms/files.txt
CHANGED
|
@@ -27,7 +27,7 @@ available from `stitchkit/contract`.
|
|
|
27
27
|
| `ManagedFileInspector` | _type_ | bounded-prefix read/write inspection callback with a finite cancellation signal that cannot own path or size |
|
|
28
28
|
| `ManagedFileInspectionInput` / `ManagedFileInspection` | _type_ | inspector prefix/name/declared media/signal input and validated metadata-only result |
|
|
29
29
|
| `writeFileAtomic` / `writeFileAtomicSync` / `WriteFileAtomicOptions` | function / _type_ | replace a file atomically: a random staging name created exclusively (never through a planted link), the mode set on the descriptor before the file is visible (default `0o600`, not masked by the umask), `fsync`, rename; a failure leaves the target and no staging file. The asynchronous form keeps the event loop running |
|
|
30
|
-
| `withExclusiveLock` / `ExclusiveLockOptions` / `ExclusiveLock` / `ExclusiveLockOwner` | function / _type_ | run work under an exclusive lock between processes — a file recording its owner (pid, host, machine identity, time); waits up to `timeoutMs` (default 10 s) and stops on `signal`; a dead owner on this machine is taken over, a live, slow or foreign one never is; an ownerless lock only after `ownerlessGraceMs` |
|
|
30
|
+
| `withExclusiveLock` / `ExclusiveLockOptions` / `ExclusiveLock` / `ExclusiveLockOwner` | function / _type_ | run work under an exclusive lock between processes — a file recording its owner (pid, host, machine identity, time and nullable kernel process identity); waits up to `timeoutMs` (default 10 s) and stops on `signal`; a dead owner on this machine is taken over, a live, slow or foreign one never is; an ownerless lock only after `ownerlessGraceMs` |
|
|
31
31
|
| `ExclusiveLockError` | class | `LOCK_TIMEOUT` naming the resource and its holder, or `LOCK_ABORTED` with the signal's reason |
|
|
32
32
|
|
|
33
33
|
---
|
package/llms/live.txt
CHANGED
|
@@ -469,3 +469,10 @@ realtime contract from `stitchkit`, and the server halves live in `stitchkit/app
|
|
|
469
469
|
| `watchDiff` / `applyWatchDelta` / `watchDeltaWins` | functions | build a difference (`undefined` when equal), rebuild the value from one (throws rather than inventing), and whether it is actually smaller than the value |
|
|
470
470
|
|
|
471
471
|
---
|
|
472
|
+
|
|
473
|
+
### Session-scoped watch lifetime
|
|
474
|
+
|
|
475
|
+
`WatchClientConfig.session` captures a `SessionOperation`; `maxKeys` (1024) and
|
|
476
|
+
`maxListenersPerKey` (128) bound retained subscriptions. Its lifetime nonce travels
|
|
477
|
+
in optional `WatchKey.instance`, preventing old-session frames from matching a new
|
|
478
|
+
client on the same socket. This is routing identity, never authorization.
|
package/llms/react.txt
CHANGED
|
@@ -182,3 +182,11 @@ Browser- and server-render-safe React data-layer helpers. Needs the
|
|
|
182
182
|
For the rationale behind these APIs — why `Bun.serve` and not a framework, why
|
|
183
183
|
two context types, why thin wrappers — see the
|
|
184
184
|
[Architecture Decisions](../decisions/).
|
|
185
|
+
|
|
186
|
+
### Watched handles in the query cache
|
|
187
|
+
|
|
188
|
+
`CacheBridgeConfig.watched` accepts `WatchCacheBinding` entries with `handle`,
|
|
189
|
+
`queryKey` and optional `state(frame)` observer. Include the session in query keys.
|
|
190
|
+
`CacheBridgeConfig.session` fences events and removes bound queries when that login
|
|
191
|
+
ends. Watch loss marks a query stale without triggering an independent refetch;
|
|
192
|
+
recovery belongs to the watched read.
|
package/llms/server.3.txt
CHANGED
|
@@ -1029,3 +1029,38 @@ registry, and a name seen once does not live on in a map. This ordering exists o
|
|
|
1029
1029
|
through `emitTo`; a broadcast through `realtime.to(room).emit` reaches the
|
|
1030
1030
|
socket immediately, replay or not, so keep room traffic whose order matters
|
|
1031
1031
|
relative to the snapshot on the registry.
|
|
1032
|
+
|
|
1033
|
+
## Session-scoped watches and query cache
|
|
1034
|
+
|
|
1035
|
+
Pass the captured login operation as `createWatchClient(contract, { transport,
|
|
1036
|
+
session })`. It adds a lifetime nonce to watch keys and detaches on invalidation;
|
|
1037
|
+
a late frame for a previous login cannot match a new client's key on the same socket.
|
|
1038
|
+
Both client and server must support the new optional `WatchKey.instance` field.
|
|
1039
|
+
The nonce is not authorization: the server still admits a verified identity and
|
|
1040
|
+
uses `hub.attach(subscriber, { key: verifiedScope, signal: revocationSignal })`.
|
|
1041
|
+
The scope key must change with session and permission boundaries.
|
|
1042
|
+
|
|
1043
|
+
`createCacheBridge` can bind watched handles directly:
|
|
1044
|
+
|
|
1045
|
+
```ts
|
|
1046
|
+
const bridge = createCacheBridge({
|
|
1047
|
+
socket, queryClient, handlers: {}, session,
|
|
1048
|
+
watched: [{
|
|
1049
|
+
handle: watches.list({ folderId }),
|
|
1050
|
+
queryKey: ['items', session.id, folderId],
|
|
1051
|
+
state: frame => showWatchState(frame),
|
|
1052
|
+
}],
|
|
1053
|
+
})
|
|
1054
|
+
bridge.connect()
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
A value updates that exact query; non-live state marks it stale while retaining its
|
|
1058
|
+
value. The existing phases (`opening`, `live`, `unavailable`, `resync-required`)
|
|
1059
|
+
remain the status model. Do not replace unavailable data with an empty collection.
|
|
1060
|
+
Session invalidation removes bound queries. Include the session identity in query
|
|
1061
|
+
keys and guard any application-level side effects with that same operation.
|
|
1062
|
+
|
|
1063
|
+
Use existing shared watches for paginated lists and selected-detail queries; bind
|
|
1064
|
+
each exact argument set to its query key. No global domain/query registry or new
|
|
1065
|
+
UI components are needed. Reconnect and revision/delta recovery remain owned by the
|
|
1066
|
+
watch client; silent lost notifications are repaired by hub reconciliation.
|
package/llms/stitchkit.2.txt
CHANGED
|
@@ -834,3 +834,44 @@ A delivered item resets the backoff, so a stream that reconnects, works for an
|
|
|
834
834
|
hour and drops again starts its next retry at `minDelayMs` rather than the
|
|
835
835
|
ceiling it reached last time. Aborting the signal ends the iteration promptly,
|
|
836
836
|
including in the middle of a wait.
|
|
837
|
+
|
|
838
|
+
## Operations belong to a login lifetime
|
|
839
|
+
|
|
840
|
+
Use `createSessionScope` when a client can log out or switch accounts. The scope is
|
|
841
|
+
host-owned and context is immutable. Replace it for **every** login, even to the
|
|
842
|
+
same account. Capture once for an entire compound operation:
|
|
843
|
+
|
|
844
|
+
```ts
|
|
845
|
+
import { createClient, createSessionScope } from 'stitchkit'
|
|
846
|
+
|
|
847
|
+
const sessions = createSessionScope<{ accountId: string }>()
|
|
848
|
+
const operation = sessions.replace({ accountId: 'account-a' })
|
|
849
|
+
const client = createClient(contract, {
|
|
850
|
+
baseUrl,
|
|
851
|
+
fetch: operation.bindFetch(fetch, () => ({ Authorization: tokenFor(operation) })),
|
|
852
|
+
})
|
|
853
|
+
const value = await operation.run(() => client.read())
|
|
854
|
+
operation.deliver(() => applyResult(value))
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
Capture before the first request, keep the same operation for a second request or
|
|
858
|
+
one explicitly allowed auth retry, and guard the **actual** final transport send
|
|
859
|
+
or local state change. An async delivery callback needs another check after its
|
|
860
|
+
await; `deliver` itself is synchronous. Guard error delivery too. Cancellation is
|
|
861
|
+
additional protection and cannot undo server effects. `SessionExpiredError` means
|
|
862
|
+
discard the stale operation, not refresh a new user's credentials. For raw/stream
|
|
863
|
+
responses, guard each consumed chunk and final delivery; `run` returning a stream
|
|
864
|
+
does not mean its future contents have been consumed.
|
|
865
|
+
|
|
866
|
+
`createSessionCredentials({ scope, refresh, storage })` coordinates the same scope.
|
|
867
|
+
`login(context, credentials)` creates a generation, `read(operation)` resolves only
|
|
868
|
+
that generation's credentials, and concurrent `refresh(operation)` shares one
|
|
869
|
+
flight. `logout()` invalidates memory immediately and resolves after its ordered
|
|
870
|
+
storage clear (or a newer login superseding that clear). Handle storage and capacity
|
|
871
|
+
errors explicitly; a rejected write is not proof of durable login/logout. Refresh
|
|
872
|
+
network work never holds the storage queue. Callers decide whether a failed command
|
|
873
|
+
may be retried once; do not replay a multi-step callback or treat any `403` as expiry.
|
|
874
|
+
|
|
875
|
+
This is per-instance coordination. Route all writes through it; shared tabs/processes
|
|
876
|
+
need storage-level locking. Replace the local session counter and refresh queue when
|
|
877
|
+
adopting these primitives instead of retaining two independent lifetimes.
|
package/llms/stitchkit.3.txt
CHANGED
|
@@ -145,3 +145,25 @@ can emit / propagate a `traceparent` (see `HttpClientConfig.trace`).
|
|
|
145
145
|
| `TraceContext` | _type_ | `{ traceId, spanId, parentSpanId?, tracestate?, baggage? }` |
|
|
146
146
|
|
|
147
147
|
---
|
|
148
|
+
|
|
149
|
+
### Session lifetime and credential coordination
|
|
150
|
+
|
|
151
|
+
`createSessionScope` (`stitchkit`) returns the generic `SessionScope`: `replace(context)`
|
|
152
|
+
creates a new login lifetime (including same-account relogin), `capture()` returns
|
|
153
|
+
its `SessionOperation<T>`, `clear()` invalidates it, and `stop()` permanently closes
|
|
154
|
+
the host. Operations expose `id`, `generation`, `context`, `signal`, `current()` and
|
|
155
|
+
`assertCurrent()`. `run(callback)` checks both success and failure across an await;
|
|
156
|
+
`deliver(callback)` admits a synchronous final send/state change or returns false.
|
|
157
|
+
`bindFetch(fetch, headers?)` guards every attempt and scopes its abort signal. Wrap
|
|
158
|
+
the complete client call in `run` too: headers are not the response body boundary.
|
|
159
|
+
Expired work throws `SessionExpiredError`, not a refresh instruction.
|
|
160
|
+
|
|
161
|
+
`createSessionCredentials` accepts `SessionCredentialsConfig`:
|
|
162
|
+
`scope`, `refresh(credentials, signal)`, `storage.write(session, credentials)`,
|
|
163
|
+
`storage.clear()`, `maxPendingWrites` (128), and `refreshTimeoutMs` (30000, at most one
|
|
164
|
+
hour). `SessionCredentials` provides `login`, `logout`, `read(operation)` and
|
|
165
|
+
`refresh(operation)`. Concurrent refresh calls in one generation share the same
|
|
166
|
+
promise. Logout invalidates memory before its returned persistence promise settles.
|
|
167
|
+
Storage errors and queue-capacity refusals reject; callers must handle them. All
|
|
168
|
+
writes must pass through the same instance. There is no cross-process/tab lock,
|
|
169
|
+
provider error classifier or automatic retry of arbitrary application callbacks.
|
package/llms/stitchkit.txt
CHANGED
|
@@ -77,11 +77,11 @@ own, recorded as an ADR.
|
|
|
77
77
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
78
78
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
79
79
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
80
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
80
|
+
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the 45 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
81
81
|
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the managed-resource conformance kit |
|
|
82
82
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
83
83
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
84
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 22 of the
|
|
84
|
+
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 22 of the 45 minors since 0.56.2, most recently 0.97.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
|
|
85
85
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
86
86
|
| `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 |
|
|
87
87
|
| `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
|
|
94
|
+
| `stitchkit/application` | browser + server | evolving<br>_redefined in 10 of the 45 minors since 0.56.2, most recently 0.100.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 |
|
package/llms/tools.txt
CHANGED
|
@@ -722,14 +722,15 @@ as one thing. Where they agree, that is what you get; where they disagree — a
|
|
|
722
722
|
`.refine()` only one of them carries, two different bounds on the same number, an
|
|
723
723
|
enum against a free string — the *constraint* is dropped and the **type** is not.
|
|
724
724
|
A field that is a number in every variant is advertised as a number, not as a
|
|
725
|
-
bare description.
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
725
|
+
bare description. Scalar collisions keep every provable kind in a deterministic
|
|
726
|
+
JSON Schema type array. If any alternative is an object or array, the property
|
|
727
|
+
retains distinct structural alternatives in `anyOf`: object properties, typed
|
|
728
|
+
array items, bounds and nullable values remain available to the model. The
|
|
729
|
+
containing discriminated union still becomes one object; flat mode does not
|
|
730
|
+
promise to remove every nested union keyword. Only a branch whose kind is
|
|
730
731
|
actually unknowable, such as a free-form schema or unresolved reference, leaves
|
|
731
732
|
the collision unconstrained. → ADRs [0044](../decisions/0044-a-collided-field-keeps-its-type.md)
|
|
732
|
-
and [
|
|
733
|
+
and [0205](../decisions/0205-flat-tool-collisions-retain-structural-alternatives.md).
|
|
733
734
|
|
|
734
735
|
It is **deep** because the projection walks the generated JSON Schema document,
|
|
735
736
|
including objects, arrays, tuples and schema-definition nodes. Structurally
|
|
@@ -738,8 +739,8 @@ Plain unions and unions hidden behind unresolved external references remain
|
|
|
738
739
|
unions because Stitchkit cannot soundly invent a discriminator.
|
|
739
740
|
|
|
740
741
|
Use the default `flattenUnionInput: false` when the model must see the exact
|
|
741
|
-
relationship between a discriminator and each branch.
|
|
742
|
-
|
|
742
|
+
relationship between a discriminator and each branch. Joined property schemas
|
|
743
|
+
describe allowed values without reconstructing those correlations.
|
|
743
744
|
|
|
744
745
|
The flattened form is **lossy but never executable**. Per-variant refinements
|
|
745
746
|
and incompatible constraints are widened in the presentation document; the
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Upgrading 0.37.0 → 0.37.0 — 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: Upgrading, 0.37.0 → 0.37.0 (docs/guide/upgrading.md)
|
|
7
|
+
|
|
8
|
+
==============================================================================
|
|
9
|
+
# Guide: Upgrading, 0.37.0 → 0.37.0 (docs/guide/upgrading.md)
|
|
10
|
+
==============================================================================
|
|
11
|
+
|
|
12
|
+
## The 0.37 migration
|
|
13
|
+
|
|
14
|
+
Tool presentation is no longer an executable Zod parser. Replace the removed
|
|
15
|
+
flatten helpers with the JSON Schema compiler, and choose the explicit
|
|
16
|
+
`MountableTool` surface when using the advanced collection API:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// before
|
|
20
|
+
const flat = flattenUnionsDeep(zodSchema)
|
|
21
|
+
mountable.schema
|
|
22
|
+
|
|
23
|
+
// after
|
|
24
|
+
const flat = flattenToolJsonSchema(
|
|
25
|
+
z.toJSONSchema(zodSchema, { target: 'draft-07', io: 'input' }),
|
|
26
|
+
)
|
|
27
|
+
mountable.presentationSchema // model/MCP/manifest JSON Schema
|
|
28
|
+
mountable.argumentSchema // executable CLI argument adapter only
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Contract and native handlers keep their original Zod schemas; MCP and agent SDK
|
|
32
|
+
adapters now forward raw arguments so defaults, coercions, refinements and
|
|
33
|
+
transforms execute exactly once inside Stitchkit. There are no compatibility
|
|
34
|
+
exports for `flattenDiscriminatedUnion`, `flattenUnionsDeep` or
|
|
35
|
+
`MountableTool.schema`. → ADR 0050
|
|
36
|
+
|
|
37
|
+
Tool-call hooks now take one options object. Migrate all three callbacks; there
|
|
38
|
+
are no positional overloads:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// before
|
|
42
|
+
beforeToolCall: (toolName, args, context, endpoint) => {}
|
|
43
|
+
afterToolCall: (toolName, args, result, durationMs, context, endpoint, error) => {}
|
|
44
|
+
onToolError: (toolName, error, context, endpoint) => {}
|
|
45
|
+
|
|
46
|
+
// after
|
|
47
|
+
beforeToolCall: ({ toolName, args, context, endpoint }) => {}
|
|
48
|
+
afterToolCall: ({ toolName, args, result, durationMs, context, endpoint, error }) => {}
|
|
49
|
+
onToolError: ({ toolName, error, context, endpoint }) => {}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### MCP schema validation
|
|
53
|
+
|
|
54
|
+
The standalone validator now takes one object and live MCP configs carry the
|
|
55
|
+
same rules under `schemaValidation`. Migrate every positional call and every
|
|
56
|
+
`onIncompatibleSchema` field; there is no old-shape overload:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// before
|
|
60
|
+
validateMcpSchemas(services, 'throw', logger, { requireTypedProperties: true })
|
|
61
|
+
createMcpHandler({ services, onIncompatibleSchema: 'throw' })
|
|
62
|
+
|
|
63
|
+
// after
|
|
64
|
+
validateMcpSchemas({ services, policy: 'throw', logger, requireTypedProperties: true })
|
|
65
|
+
createMcpHandler({ services, schemaValidation: { policy: 'throw' } })
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Put `extend` and `flattenUnionInput` beside `services`, not inside
|
|
69
|
+
`schemaValidation`. The handler applies the profile to the exact prepared schema
|
|
70
|
+
it advertises. Add `requirePortableFormats: true` when every custom JSON Schema
|
|
71
|
+
format must be rejected before a client sees it.
|
|
72
|
+
|
|
73
|
+
Native MCP registration also changed shape in 0.37. Move protected tools to the
|
|
74
|
+
framework registrar; keep an SDK-raw tool only by naming the opt-out:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
// before
|
|
78
|
+
nativeTools: (server, auth) => server.registerTool(name, config, handler)
|
|
79
|
+
|
|
80
|
+
// after — lifecycle, hooks and schema policy apply
|
|
81
|
+
nativeTools: ({ registerTool }, auth) => registerTool({
|
|
82
|
+
name, description, identity, input, output, handler,
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// after — intentionally raw
|
|
86
|
+
nativeTools: ({ rawServer }, auth) => rawServer.registerTool(name, config, handler)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If a tool hook annotated `endpoint` as `MethodDef`, remove that annotation or
|
|
90
|
+
use `OperationIdentity`: native operations have service/action/scope/method but
|
|
91
|
+
no HTTP path.
|
|
92
|
+
|
|
93
|
+
### Node-facing server types
|
|
94
|
+
|
|
95
|
+
`stitchkit/server` remains Bun-concrete: an explicitly annotated `RawRoute`
|
|
96
|
+
still receives `BunServer`. `stitchkit/node` no longer drags Bun declarations
|
|
97
|
+
into a Node project. Its raw routes default the host server to `unknown`, and
|
|
98
|
+
its Socket.IO handle exposes only Node capabilities:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// before — Node entry still leaked Bun-only fields and ambient types
|
|
102
|
+
const route: RawRoute = { handler: (_req, ctx) => ctx.server?.upgrade(...) }
|
|
103
|
+
const socket = await createSocketIOServer(config)
|
|
104
|
+
socket.websocket
|
|
105
|
+
|
|
106
|
+
// after — name a custom embedding host only when one exists
|
|
107
|
+
const route: RawRoute<MyHostServer> = {
|
|
108
|
+
handler: (_req, ctx) => useHost(ctx.server),
|
|
109
|
+
}
|
|
110
|
+
const socket = await createSocketIOServer(config)
|
|
111
|
+
socket.io
|
|
112
|
+
socket.attach(nodeHttpServer)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Node consumers can remove `@types/bun` unless another dependency independently
|
|
116
|
+
requires it.
|
|
117
|
+
|
|
118
|
+
### Managed server shutdown
|
|
119
|
+
|
|
120
|
+
`createServer()` and `serveNode()` now return the same structural managed
|
|
121
|
+
lifecycle. Replace every direct runtime stop and parallel Socket.IO close:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
// before — split ownership
|
|
125
|
+
const socket = await createSocketIOServer(config)
|
|
126
|
+
const server = createServer({
|
|
127
|
+
services,
|
|
128
|
+
websocket: socket.websocket,
|
|
129
|
+
rawRoutes: [socket.route],
|
|
130
|
+
})
|
|
131
|
+
server.stop()
|
|
132
|
+
await socket.io.close()
|
|
133
|
+
|
|
134
|
+
// after — one owner and one total deadline
|
|
135
|
+
const socket = await createSocketIOServer(config)
|
|
136
|
+
const server = createServer({ services, socket })
|
|
137
|
+
const result = await server.shutdown({ gracePeriodMs: 30_000 })
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
On Node, keep the same `socket` field and replace `handle.close()` with
|
|
141
|
+
`handle.shutdown()`. Runtime-specific diagnostics move under `handle.runtime`;
|
|
142
|
+
do not use it as a second shutdown path. Standalone CLI/tools that create a
|
|
143
|
+
Socket.IO handle without an HTTP server call `await socket.close()`.
|
|
144
|
+
|
|
145
|
+
If Bun Socket.IO shares the port with a raw lane, keep the explicit composition
|
|
146
|
+
but let the server mount the Socket.IO route:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
createServer({
|
|
150
|
+
services,
|
|
151
|
+
socket,
|
|
152
|
+
websocket: composeWebSocketHandlers([
|
|
153
|
+
webSocketLane({ match: isRaw, handlers: rawHandlers }),
|
|
154
|
+
socketIoLane(socket.websocket),
|
|
155
|
+
]),
|
|
156
|
+
rawRoutes: [rawUpgradeRoute],
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Move native Bun `routes` entries to `rawRoutes`. Native routes run before the
|
|
161
|
+
Fetch handler and therefore cannot participate in admission or drain. Wire
|
|
162
|
+
`SIGTERM`/`SIGINT` in the application; the first signal starts `shutdown()`, and
|
|
163
|
+
a later signal may abort the same controller. Close MCP, databases and queues
|
|
164
|
+
after the server result—those resources remain application-owned.
|
|
165
|
+
|
|
166
|
+
Move a handshake policy from the Node-only callback shape inside
|
|
167
|
+
`serverOptions` to the runtime-neutral top-level policy. It receives a Web
|
|
168
|
+
`Request`, may be async, and returns whether to admit the handshake:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
// before
|
|
172
|
+
serverOptions: { allowRequest: (request, done) => done(null, allowed(request)) }
|
|
173
|
+
|
|
174
|
+
// after
|
|
175
|
+
allowRequest: (request) => allowed(request)
|
|
176
|
+
```
|