stitchkit 0.47.0 → 0.48.1
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/README.md +9 -0
- package/dist/browser/client.d.ts +3 -0
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/http.d.ts +7 -4
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/contract/define.d.ts +11 -3
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/{index-nrytvb30.js → index-03j2t778.js} +5 -8
- package/dist/{index-kp8xamqp.js → index-0hj37z43.js} +4 -2
- package/dist/index-48ffdxgk.js +6 -0
- package/dist/index-h05ygjqx.js +149 -0
- package/dist/{index-ee621cmy.js → index-jewp9r0a.js} +5 -139
- package/dist/index-p9d4cxt5.js +436 -0
- package/dist/{index-44xysy8r.js → index-ts21eyz4.js} +141 -19
- package/dist/{index-8ekq6res.js → index-v58mwa19.js} +4 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -27
- package/dist/node.d.ts +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +8 -3
- package/dist/observability/audit.d.ts +4 -1
- package/dist/observability/audit.d.ts.map +1 -1
- package/dist/observability/index.d.ts +1 -0
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +150 -16
- package/dist/observability/status.d.ts +105 -0
- package/dist/observability/status.d.ts.map +1 -0
- package/dist/server/implement.d.ts +16 -6
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +14 -6
- package/dist/server/router.d.ts +4 -1
- package/dist/server/router.d.ts.map +1 -1
- package/dist/testing.d.ts +34 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +36 -0
- package/dist/tools/mcp.d.ts +1 -0
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools.js +21 -430
- package/llms-full.txt +177 -22
- package/package.json +7 -3
package/llms-full.txt
CHANGED
|
@@ -33,7 +33,7 @@ realtime, `@tanstack/react-query` + `react-query-kit` for React). See
|
|
|
33
33
|
|
|
34
34
|
## Entrypoints
|
|
35
35
|
|
|
36
|
-
stitchkit ships
|
|
36
|
+
stitchkit ships nine entrypoints. Each is import-safe for one environment —
|
|
37
37
|
keeping server-only code (`Bun.serve`, the MCP SDK) out of browser bundles.
|
|
38
38
|
|
|
39
39
|
| Import | Use in | Holds |
|
|
@@ -45,6 +45,7 @@ keeping server-only code (`Bun.serve`, the MCP SDK) out of browser bundles.
|
|
|
45
45
|
| `stitchkit/tools` | server | `createMcpHandler`, `mountMcp`, `mountAgent`, the OAuth provider, native tools |
|
|
46
46
|
| `stitchkit/cli` | server | `createCli` — the CLI transport, light (no MCP SDK / `ai`) |
|
|
47
47
|
| `stitchkit/observability` | server | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
48
|
+
| `stitchkit/testing` | tests on Bun or Node | in-process generated clients over a real Fetch handler, without a TCP port |
|
|
48
49
|
| `stitchkit/react` | browser | `createCursorQuery`, `createCacheBridge` |
|
|
49
50
|
|
|
50
51
|
Rule of thumb: browser code imports `stitchkit` and `stitchkit/react`; server
|
|
@@ -685,6 +686,30 @@ export const implement = createImplement<AppContext>()
|
|
|
685
686
|
// every implement() call now has ctx.user typed
|
|
686
687
|
```
|
|
687
688
|
|
|
689
|
+
### `implementRegistry` — one backend registry
|
|
690
|
+
|
|
691
|
+
When contracts already live in one literal registry, bind the backend from that
|
|
692
|
+
same source instead of maintaining a parallel `services` list:
|
|
693
|
+
|
|
694
|
+
```ts
|
|
695
|
+
import { implementRegistry } from 'stitchkit/server'
|
|
696
|
+
|
|
697
|
+
export const apiServices = implementRegistry(apiContractRegistry, {
|
|
698
|
+
users: usersHandlers,
|
|
699
|
+
posts: postsHandlers,
|
|
700
|
+
})
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
Every registry key is required, extra keys fail, and each handler map is checked
|
|
704
|
+
against its own contract. The returned service order follows the contract
|
|
705
|
+
registry order. `createImplementRegistry<AppContext>()` fixes the application
|
|
706
|
+
context once, like `createImplement` does for a single contract. Runtime callers
|
|
707
|
+
also fail first on missing/extra keys and duplicate contract prefixes.
|
|
708
|
+
|
|
709
|
+
The registry is intentionally flat: every key must point to one concrete
|
|
710
|
+
`defineContract()` result. Composed namespace arrays are mounted explicitly with
|
|
711
|
+
`implement()` because they do not have a one-key-to-one-handler-map boundary.
|
|
712
|
+
|
|
688
713
|
## `createServer`
|
|
689
714
|
|
|
690
715
|
`createServer(config)` builds the router and starts `Bun.serve()`. It returns
|
|
@@ -991,6 +1016,21 @@ not retain the text. `maxJsonBodyBytes` may also be set once on `createServer` /
|
|
|
991
1016
|
`createHandler`; a route value wins. Both limits are opt-in and abort an
|
|
992
1017
|
oversized stream before it is fully buffered. → ADR 0051
|
|
993
1018
|
|
|
1019
|
+
### Choosing an HTTP boundary
|
|
1020
|
+
|
|
1021
|
+
| Need | Contract declaration | What remains framework-owned |
|
|
1022
|
+
|------|----------------------|------------------------------|
|
|
1023
|
+
| Typed JSON request/response | ordinary `input` / `output` | routing, auth, schemas, hooks, client, OpenAPI |
|
|
1024
|
+
| HMAC-signed JSON | `rawBody: true` + `input` / `output` | the same pipeline plus the exact decoded request text |
|
|
1025
|
+
| File upload | typed `multipart` descriptor | file cardinality/limits, text input validation and client form encoding |
|
|
1026
|
+
| File, stream or redirect response behind contract auth | `rawResponse: true` | request parsing, route identity, auth and typed URL/client surface |
|
|
1027
|
+
| Transport that cannot be expressed as the contract pipeline | `RawRoute` | only raw routing, CORS, request hook and error normalisation |
|
|
1028
|
+
|
|
1029
|
+
`rawBody` is for JSON signatures: verify `ctx.rawBody` against the signature
|
|
1030
|
+
header, then use the already validated `ctx.input`. A provider-specific binary
|
|
1031
|
+
signature protocol, OAuth callback or WebSocket upgrade can be a real raw route,
|
|
1032
|
+
but it must own its validation and authorization explicitly.
|
|
1033
|
+
|
|
994
1034
|
## Typed JSON response metadata
|
|
995
1035
|
|
|
996
1036
|
A JSON endpoint that must attach dynamic HTTP headers while preserving typed
|
|
@@ -1158,6 +1198,13 @@ wildcard — and the two combine: `/app/:slug/*filePath` matches `/app/x/a/b` wi
|
|
|
1158
1198
|
deep-link fallback). List more specific routes before the wildcard — the first
|
|
1159
1199
|
match wins. `staticRoute()` builds a raw route that serves a directory.
|
|
1160
1200
|
|
|
1201
|
+
At startup Stitchkit rejects exact duplicates, equivalent parameter shapes
|
|
1202
|
+
(`/users/:id` vs `/users/:userId`) and any later raw route completely hidden by
|
|
1203
|
+
an earlier raw route. Partial overlap stays legal, including the recommended
|
|
1204
|
+
specific-before-wildcard order. `GET` and `HEAD` remain independent because that
|
|
1205
|
+
is how the actual raw matcher dispatches them. Raw-vs-contract overlap remains a
|
|
1206
|
+
startup diagnostic naming the bypassed contract identity and scope.
|
|
1207
|
+
|
|
1161
1208
|
### Raw-route helpers
|
|
1162
1209
|
|
|
1163
1210
|
A raw route gives up the contract pipeline, so three things get re-implemented in
|
|
@@ -1483,7 +1530,7 @@ without repeating transport configuration.
|
|
|
1483
1530
|
| `baseUrl` | — | URL prefix for every request |
|
|
1484
1531
|
| `timeout` | `30000` | request timeout, ms |
|
|
1485
1532
|
| `credentials` | `'include'` | fetch credentials mode |
|
|
1486
|
-
| `retry` | 2
|
|
1533
|
+
| `retry` | 2 retries after the initial GET; network errors only | transport retry policy |
|
|
1487
1534
|
| `headers` | — | extra headers — an object, or a function re-run per request |
|
|
1488
1535
|
| `suppressUnauthorizedFor` | `[]` | exact contract-derived operation matchers whose expected 401 does not emit `unauthorized` |
|
|
1489
1536
|
| `parseError` | built-in | map an error body to `{ code, message, details, hint }` |
|
|
@@ -1509,7 +1556,10 @@ end-to-end. A `traceparent` you set yourself (via `headers`) always wins.
|
|
|
1509
1556
|
Retry is deliberately conservative: only a connection that never landed (a
|
|
1510
1557
|
network error), only on idempotent `GET`. A server that *responded* with a 5xx
|
|
1511
1558
|
is the data layer's call (TanStack Query), not the transport's — retrying in
|
|
1512
|
-
both places multiplies attempts.
|
|
1559
|
+
both places multiplies attempts. `retry.limit` counts retries after the initial
|
|
1560
|
+
attempt, so the default `2` permits at most three total attempts. The default
|
|
1561
|
+
`statusCodes: []` does not replay HTTP responses; explicit `methods` or
|
|
1562
|
+
`statusCodes` expand that policy when a project has a proven idempotent case.
|
|
1513
1563
|
|
|
1514
1564
|
## `createClient`
|
|
1515
1565
|
|
|
@@ -1560,14 +1610,15 @@ contract:
|
|
|
1560
1610
|
|
|
1561
1611
|
### Per-call cancellation
|
|
1562
1612
|
|
|
1563
|
-
Every endpoint
|
|
1564
|
-
`
|
|
1565
|
-
|
|
1613
|
+
Every endpoint callable exposes a `withOptions` method accepting required
|
|
1614
|
+
`ClientRequestOptions`. The ordinary callable contains only contract arguments,
|
|
1615
|
+
so it can be passed directly to callback APIs such as `react-query-kit` without
|
|
1616
|
+
mistaking their callback context for Stitchkit transport options:
|
|
1566
1617
|
|
|
1567
1618
|
```ts
|
|
1568
1619
|
const controller = new AbortController()
|
|
1569
1620
|
|
|
1570
|
-
const pending = api.upload(
|
|
1621
|
+
const pending = api.upload.withOptions(
|
|
1571
1622
|
{ file: selectedFile, title: 'Draft' },
|
|
1572
1623
|
{ signal: controller.signal },
|
|
1573
1624
|
)
|
|
@@ -1590,6 +1641,12 @@ Abort and timeout do not emit `network_error` and are not retried. The same
|
|
|
1590
1641
|
options work for query, JSON, multipart and raw-response calls. Stitchkit does
|
|
1591
1642
|
not expose upload progress: Fetch has no portable upload-progress primitive.
|
|
1592
1643
|
|
|
1644
|
+
For an endpoint without contract arguments, pass only the options object:
|
|
1645
|
+
|
|
1646
|
+
```ts
|
|
1647
|
+
await api.health.withOptions({ signal: controller.signal })
|
|
1648
|
+
```
|
|
1649
|
+
|
|
1593
1650
|
### Many contracts at once
|
|
1594
1651
|
|
|
1595
1652
|
```ts
|
|
@@ -1823,6 +1880,10 @@ export const useUsers = createQuery({ queryKey: ['users'], fetcher: () => a
|
|
|
1823
1880
|
export const useCreateUser = createMutation({ mutationFn: api.create })
|
|
1824
1881
|
```
|
|
1825
1882
|
|
|
1883
|
+
Generated methods intentionally keep their ordinary call signature limited to
|
|
1884
|
+
contract variables. Use `api.create.withOptions(variables, { signal })` only for
|
|
1885
|
+
an imperative call that needs per-request cancellation.
|
|
1886
|
+
|
|
1826
1887
|
### Cursor pagination
|
|
1827
1888
|
|
|
1828
1889
|
For a cursor-paginated list, `createCursorQuery` is the canonical helper:
|
|
@@ -2240,15 +2301,18 @@ validateMcpSchemas({
|
|
|
2240
2301
|
extend,
|
|
2241
2302
|
flattenUnionInput: true,
|
|
2242
2303
|
requireTypedProperties: true,
|
|
2243
|
-
allowUntyped: ['docs_create.payload'], // deliberately free-form
|
|
2244
2304
|
requirePortableFormats: true,
|
|
2245
2305
|
allowFormats: [],
|
|
2246
2306
|
})
|
|
2247
2307
|
```
|
|
2248
2308
|
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2309
|
+
For an arbitrary **JSON value**, declare `z.json()`: its recursive JSON Schema
|
|
2310
|
+
describes strings, numbers, booleans, null, arrays and objects, so strict schema
|
|
2311
|
+
validation needs no exception. `z.unknown()` means an unknown runtime value —
|
|
2312
|
+
including values JSON cannot represent — and therefore gives a model no usable
|
|
2313
|
+
shape. The guard is off by default for existing contracts. `allowUntyped` takes
|
|
2314
|
+
dotted `tool.property` paths and is reserved for a presentation value that is
|
|
2315
|
+
genuinely impossible to represent as JSON Schema. On `createMcpHandler`, put the policy under
|
|
2252
2316
|
`schemaValidation`; the handler supplies its real `extend` and
|
|
2253
2317
|
`flattenUnionInput`, so the check cannot vet a different document from the one
|
|
2254
2318
|
advertised.
|
|
@@ -3970,8 +4034,8 @@ export const observability = createObservability({
|
|
|
3970
4034
|
},
|
|
3971
4035
|
})
|
|
3972
4036
|
|
|
3973
|
-
|
|
3974
|
-
await observability.close()
|
|
4037
|
+
const status = observability.getStatus()
|
|
4038
|
+
const drained = await observability.close()
|
|
3975
4039
|
```
|
|
3976
4040
|
|
|
3977
4041
|
`maxPending` defaults to `1000` per sink and must be a positive safe integer.
|
|
@@ -3982,9 +4046,15 @@ cancelled. Sink, filter and diagnostic-callback failures remain isolated from
|
|
|
3982
4046
|
the observed request or tool call and are reported through `onSinkError` when
|
|
3983
4047
|
configured; `onSinkError`/`onDrop` cannot create unhandled rejections.
|
|
3984
4048
|
|
|
4049
|
+
`getStatus()` returns immutable per-surface and aggregate counters: capacity,
|
|
4050
|
+
received, accepted, filtered, completed, dropped, failed, preparation failures,
|
|
4051
|
+
preparing/pending work and the closed flag. Read it from readiness or metrics
|
|
4052
|
+
without parsing callback logs.
|
|
4053
|
+
|
|
3985
4054
|
`flush()` snapshots the current generation and waits only for events admitted
|
|
3986
4055
|
up to that call. `close()` atomically stops admission, drains every accepted
|
|
3987
|
-
generation and
|
|
4056
|
+
generation and returns the final counters plus `durationMs`; repeated calls
|
|
4057
|
+
return the same report. Graceful shutdown order is therefore:
|
|
3988
4058
|
|
|
3989
4059
|
1. stop HTTP/MCP admission;
|
|
3990
4060
|
2. wait for active requests and tool calls;
|
|
@@ -4420,7 +4490,33 @@ never block or break the request. Swallow the sink's own errors.
|
|
|
4420
4490
|
stitchkit's own test suite runs on `bun:test`. The contract makes most of an
|
|
4421
4491
|
API testable without a live socket.
|
|
4422
4492
|
|
|
4423
|
-
### Test
|
|
4493
|
+
### Test generated clients in process
|
|
4494
|
+
|
|
4495
|
+
`createHandlerTestClient` runs the real generated client against the real Fetch
|
|
4496
|
+
handler without opening a TCP port. It keeps URL construction, headers/cookies,
|
|
4497
|
+
multipart encoding, cancellation, output validation, `ApiError` and
|
|
4498
|
+
`x-request-id` correlation in the test path:
|
|
4499
|
+
|
|
4500
|
+
```ts
|
|
4501
|
+
import { createHandlerTestClient } from 'stitchkit/testing'
|
|
4502
|
+
|
|
4503
|
+
const api = createHandlerTestClient({
|
|
4504
|
+
contract: notes,
|
|
4505
|
+
handler,
|
|
4506
|
+
pathPrefix: 'api',
|
|
4507
|
+
client: { headers: { cookie: 'session=test' } },
|
|
4508
|
+
})
|
|
4509
|
+
|
|
4510
|
+
expect(await api.create({ text: 'hi' })).toEqual({ id: '1', text: 'hi' })
|
|
4511
|
+
```
|
|
4512
|
+
|
|
4513
|
+
`contractConfig` accepts the same scoped `pathPrefix` / `stripPrefixKeys` as
|
|
4514
|
+
`createClient`. `createHandlerTestClients` is the batch form for a literal
|
|
4515
|
+
contract registry. Both helpers are Fetch-only: they construct ordinary
|
|
4516
|
+
absolute `Request` objects and call `createHandler` directly, so Bun and Node
|
|
4517
|
+
exercise the same framework pipeline.
|
|
4518
|
+
|
|
4519
|
+
### Test handlers with raw Requests
|
|
4424
4520
|
|
|
4425
4521
|
`createHandler` is the router as a plain `(req) => Promise<Response>` function —
|
|
4426
4522
|
no `Bun.serve`, no port. Drive it with a `Request`:
|
|
@@ -4450,8 +4546,8 @@ test('create returns the note', async () => {
|
|
|
4450
4546
|
})
|
|
4451
4547
|
```
|
|
4452
4548
|
|
|
4453
|
-
This exercises the
|
|
4454
|
-
|
|
4549
|
+
This lower-level form exercises the same pipeline while letting a test inspect
|
|
4550
|
+
the raw `Response` itself.
|
|
4455
4551
|
|
|
4456
4552
|
### Test handlers directly
|
|
4457
4553
|
|
|
@@ -4817,7 +4913,40 @@ current one *up to* your target, and apply each snippet.
|
|
|
4817
4913
|
runtime): bootstrap the server, one HTTP request, and any feature you rely on
|
|
4818
4914
|
(Socket.IO connect, an MCP tool call, a multipart upload, …).
|
|
4819
4915
|
|
|
4820
|
-
##
|
|
4916
|
+
## Released migration: 0.48.0
|
|
4917
|
+
|
|
4918
|
+
### Typed-client request options move to `.withOptions`
|
|
4919
|
+
|
|
4920
|
+
Generated endpoint methods reserve their ordinary call signature for contract
|
|
4921
|
+
variables. This keeps them directly assignable to callback APIs whose runtime
|
|
4922
|
+
supplies its own second context argument, including `react-query-kit` and
|
|
4923
|
+
TanStack Query. Move imperative cancellation to the callable's explicit method:
|
|
4924
|
+
|
|
4925
|
+
```ts
|
|
4926
|
+
// before — endpoint with arguments
|
|
4927
|
+
await api.create({ name: 'Max' }, { signal })
|
|
4928
|
+
|
|
4929
|
+
// after
|
|
4930
|
+
await api.create.withOptions({ name: 'Max' }, { signal })
|
|
4931
|
+
|
|
4932
|
+
// before — endpoint without arguments
|
|
4933
|
+
await api.health({ signal })
|
|
4934
|
+
|
|
4935
|
+
// after
|
|
4936
|
+
await api.health.withOptions({ signal })
|
|
4937
|
+
```
|
|
4938
|
+
|
|
4939
|
+
Direct query and mutation composition remains unchanged:
|
|
4940
|
+
|
|
4941
|
+
```ts
|
|
4942
|
+
createMutation({ mutationFn: api.create })
|
|
4943
|
+
createQuery({ queryKey: ['search'], fetcher: api.search })
|
|
4944
|
+
```
|
|
4945
|
+
|
|
4946
|
+
There is no positional-options alias. Ordinary generated methods ignore extra
|
|
4947
|
+
runtime callback arguments; only `.withOptions` reads `ClientRequestOptions`.
|
|
4948
|
+
|
|
4949
|
+
## Released migration: 0.47.0
|
|
4821
4950
|
|
|
4822
4951
|
### HTTP auth moves to the pre-body `authorize` phase
|
|
4823
4952
|
|
|
@@ -5584,7 +5713,8 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
5584
5713
|
| `createUrlBuilders` | function | build one exact URL builder per contract in a registry |
|
|
5585
5714
|
| `UrlBuilderConfig` | _type_ | explicit `{ baseUrl }` source for a URL builder |
|
|
5586
5715
|
| `ClientConfig` | _type_ | config for `createClient`'s bare-fetch mode (2nd arg, no `HttpClient`) |
|
|
5587
|
-
| `
|
|
5716
|
+
| `ClientFetch` | _type_ | injectable Fetch-compatible transport used by framework testing adapters |
|
|
5717
|
+
| `ClientRequestOptions` | _type_ | per-call `{ signal?: AbortSignal }` passed through an endpoint callable's `.withOptions(...)`; caller abort is distinct from timeout — [guide](../guide/client.md#per-call-cancellation) |
|
|
5588
5718
|
| `ContractClientConfig` | _type_ | per-tenant / resource-scoped client config — dynamic `pathPrefix` + `stripPrefixKeys` ([guide](../guide/client.md#contractclientconfig--per-tenant--resource-scoped-clients)) |
|
|
5589
5719
|
| `contractEndpointMatchers` | function | compile exact pathname matchers for selected HTTP contract operations and expected-401 policy |
|
|
5590
5720
|
| `PathPrefixArgs` | _type_ | required string-valued keys exposed to a typed dynamic `pathPrefix` callback |
|
|
@@ -5592,7 +5722,7 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
5592
5722
|
| `ApiError` | class | a non-2xx response, with `code` / `status` / `details` / `hint` and optional readonly `traceId` from `x-request-id` |
|
|
5593
5723
|
| `HttpClient` | _type_ | the transport interface `createClient` builds on |
|
|
5594
5724
|
| `ConfiguredHttpClient` | _type_ | a framework-created `HttpClient` carrying its readonly `baseUrl` for URL builders |
|
|
5595
|
-
| `HttpClientConfig` | _type_ | config for `createHttpClient` |
|
|
5725
|
+
| `HttpClientConfig` | _type_ | config for `createHttpClient`; retry `limit` counts retries after the initial attempt (default 2 = at most 3 GET attempts), with `statusCodes: []` by default — [details](../guide/client.md#createhttpclient) |
|
|
5596
5726
|
| `UnauthorizedMatcher` | _type_ | exact `(pathname) => boolean` policy accepted by `suppressUnauthorizedFor` |
|
|
5597
5727
|
| `RequestOptions` | _type_ | per-call options — params, timeout, response type |
|
|
5598
5728
|
| `HeaderProvider` | _type_ | static or per-request headers |
|
|
@@ -5745,6 +5875,11 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
5745
5875
|
| `createHandler` | function | the router as a bare `(req) => Response` — [guide](../guide/server.md#createserver) |
|
|
5746
5876
|
| `implement` | function | bind a contract to typed handlers — [guide](../guide/server.md#implement) |
|
|
5747
5877
|
| `createImplement` | function | fix the handler context type once |
|
|
5878
|
+
| `implementRegistry` | function | bind one exact contract registry to one exact backend handler registry |
|
|
5879
|
+
| `createImplementRegistry` | function | context-typed factory for `implementRegistry` |
|
|
5880
|
+
| `ImplementationRegistry` | _type_ | flat literal registry of concrete contracts accepted by `implementRegistry` |
|
|
5881
|
+
| `RegistryHandlers` | _type_ | exact backend handler registry inferred from a contract registry |
|
|
5882
|
+
| `ExactRegistryHandlers` | _type_ | fail-first handler shape that rejects extra registry and endpoint keys |
|
|
5748
5883
|
| `staticRoute` | function | a raw route that serves a directory |
|
|
5749
5884
|
| `serveFile` | function | serve a file with `Range` / `304` / `HEAD` — [guide](../guide/server.md#serving-files--range-requests) |
|
|
5750
5885
|
| `parseByteRange` | function | parse a single `Range` header → range / `unsatisfiable` / `null` |
|
|
@@ -5894,7 +6029,11 @@ audit event. See the [Observability guide](../guide/observability.md).
|
|
|
5894
6029
|
| `createObservability` | function | configure framework-owned request completion and canonical tool event sinks — [guide](../guide/observability.md#createobservability) |
|
|
5895
6030
|
| `RequestEvent` | _type_ | the normalised audit event handed to the sink |
|
|
5896
6031
|
| `ObservabilityConfig` | _type_ | independent request and tool sink configuration |
|
|
5897
|
-
| `Observability` | _type_ | `{ request?, toolCall, flush(), close() }` with bounded sink lifecycle |
|
|
6032
|
+
| `Observability` | _type_ | `{ request?, toolCall, getStatus(), flush(), close() }` with bounded sink lifecycle |
|
|
6033
|
+
| `ObservabilitySinkStatus` | _type_ | immutable counters for one bounded request/tool sink |
|
|
6034
|
+
| `ObservabilityStatus` | _type_ | per-surface plus aggregate operational snapshot |
|
|
6035
|
+
| `ObservabilityDrainReport` | _type_ | final closed/drained snapshot plus duration |
|
|
6036
|
+
| `ObservabilitySinkStatusSchema` / `ObservabilityStatusSchema` / `ObservabilityDrainReportSchema` | schema | runtime schemas for status/report integration boundaries |
|
|
5898
6037
|
| `RequestEventSinkConfig` | _type_ | `write`, filter/sanitisation, `maxPending`, `onSinkError` and `onDrop` |
|
|
5899
6038
|
| `RequestObservabilityConfig` | _type_ | request sink plus opt-in payload capture |
|
|
5900
6039
|
| `SinkDropReason` | _type_ | `'capacity' \| 'closed'` |
|
|
@@ -5961,7 +6100,7 @@ payload.
|
|
|
5961
6100
|
| `createMcpHandler` | function | a stateless dual-era Streamable-HTTP MCP handler — [guide](../guide/mcp-and-agents.md#mcp--createmcphandler) |
|
|
5962
6101
|
| `createMcpHttpRoute` | function | framework-owned `RawRoute` adapter for an MCP HTTP handler |
|
|
5963
6102
|
| `createStdioMcpServer` | function | a complete stdio MCP server — [guide](../guide/mcp-and-agents.md#mcp-over-stdio--createstdiomcpserver) |
|
|
5964
|
-
| `buildMcpServer` | function | build an `McpServer` from contract/runtime surfaces
|
|
6103
|
+
| `buildMcpServer` | function | build an `McpServer` from contract/runtime surfaces; no-auth configs omit the second argument |
|
|
5965
6104
|
| `mountMcp` | function | add contract tools to an existing `McpServer` — [guide](../guide/mcp-and-agents.md#mountmcp) |
|
|
5966
6105
|
| `implementRemote` | function | bind a contract to a remote HTTP API — [guide](../guide/mcp-and-agents.md#proxying-a-remote-api--implementremote) |
|
|
5967
6106
|
| `mountAgent` | function | a Vercel AI SDK `ToolSet` from a service — [guide](../guide/mcp-and-agents.md#ai-agents--mountagent) |
|
|
@@ -6123,6 +6262,22 @@ Advanced building blocks — the shared machinery the mounts are built on.
|
|
|
6123
6262
|
|
|
6124
6263
|
---
|
|
6125
6264
|
|
|
6265
|
+
## `stitchkit/testing`
|
|
6266
|
+
|
|
6267
|
+
Fetch-only integration helpers that preserve the real generated-client and
|
|
6268
|
+
handler pipeline without opening a TCP port.
|
|
6269
|
+
|
|
6270
|
+
| Export | Kind | Summary |
|
|
6271
|
+
|--------|------|---------|
|
|
6272
|
+
| `createHandlerTestClient` | function | one contract client backed by an in-process `FetchHandler` |
|
|
6273
|
+
| `createHandlerTestClients` | function | exact contract-registry batch form |
|
|
6274
|
+
| `HandlerTestClientDefaults` | _type_ | ordinary bare-client defaults with handler-owned `baseUrl` and `fetch` removed |
|
|
6275
|
+
| `HandlerTestClientConfig` | _type_ | handler, contract, path prefix, scoped config and client request defaults |
|
|
6276
|
+
| `HandlerTestClientsConfig` | _type_ | batch helper configuration |
|
|
6277
|
+
| `HandlerTestTransportConfig` | _type_ | shared in-process handler, origin, prefix, client defaults and optional server handle |
|
|
6278
|
+
|
|
6279
|
+
---
|
|
6280
|
+
|
|
6126
6281
|
## `stitchkit/node`
|
|
6127
6282
|
|
|
6128
6283
|
Server-only, for Node ≥ 22 (Bun uses `stitchkit/server`). The runtime-agnostic
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stitchkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.1",
|
|
4
4
|
"description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -72,6 +72,10 @@
|
|
|
72
72
|
"types": "./dist/observability/index.d.ts",
|
|
73
73
|
"import": "./dist/observability/index.js"
|
|
74
74
|
},
|
|
75
|
+
"./testing": {
|
|
76
|
+
"types": "./dist/testing.d.ts",
|
|
77
|
+
"import": "./dist/testing.js"
|
|
78
|
+
},
|
|
75
79
|
"./node": {
|
|
76
80
|
"types": "./dist/node.d.ts",
|
|
77
81
|
"import": "./dist/node.js"
|
|
@@ -83,7 +87,7 @@
|
|
|
83
87
|
"scripts": {
|
|
84
88
|
"check": "bun x tsc --noEmit",
|
|
85
89
|
"build:browser": "bun build src/index.ts src/react.ts src/contract/index.ts --outdir dist --target node --packages external --splitting --root src",
|
|
86
|
-
"build:server": "bun build src/server/index.ts src/node.ts src/tools.ts src/cli.ts src/observability/index.ts --outdir dist --target node --packages external --splitting --root src",
|
|
90
|
+
"build:server": "bun build src/server/index.ts src/node.ts src/tools.ts src/cli.ts src/testing.ts src/observability/index.ts --outdir dist --target node --packages external --splitting --root src",
|
|
87
91
|
"build:js": "bun run build:browser && bun run build:server",
|
|
88
92
|
"build:types": "bun x tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
89
93
|
"build": "rm -rf dist && bun run build:js && bun run build:types && bun scripts/check-browser-clean.mjs && bun scripts/check-env-live.mjs && bun scripts/check-public-types.mjs",
|
|
@@ -161,7 +165,7 @@
|
|
|
161
165
|
"@types/json-schema": "^7.0.15",
|
|
162
166
|
"@types/react": "^19.2.18",
|
|
163
167
|
"@typescript/typescript6": "^6.0.2",
|
|
164
|
-
"ai": "^7.0.
|
|
168
|
+
"ai": "^7.0.65",
|
|
165
169
|
"react": "^19.2.8",
|
|
166
170
|
"react-query-kit": "^3.3.4",
|
|
167
171
|
"socket.io": "^4.8.3",
|