stitchkit 0.118.0 → 0.118.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/CHANGELOG.md +12 -0
- package/dist/entrypoints/server.d.ts +1 -1
- package/dist/entrypoints/server.d.ts.map +1 -1
- package/dist/entrypoints/server.js +31 -17
- package/dist/server/file.d.ts +12 -6
- package/dist/server/file.d.ts.map +1 -1
- package/llms/server.2.txt +19 -6
- package/llms/server.5.txt +2 -1
- package/llms/testing.txt +3 -3
- package/llms-full.txt +24 -10
- package/llms.txt +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,18 @@ additive**; the first breaking change landed in 0.10.0. Grep the file for
|
|
|
15
15
|
|
|
16
16
|
## [Unreleased]
|
|
17
17
|
|
|
18
|
+
## [0.118.1] - 2026-11-03
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `stitchkit/server` — `staticRoute(prefix, dir, { cacheControl })` sets `Cache-Control` on every file the route serves, its `304`s and ranges included. [ADR 0281](docs/decisions/0281-static-files-are-served-by-one-responder.md)
|
|
23
|
+
**Affects:** `stitchkit/server` staticRoute, StaticRouteOptions
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- `stitchkit/server` — `staticRoute` serves a file the way `serveFile` does. It read the whole file into memory and answered without `ETag`, `Last-Modified` or `Accept-Ranges`, so a browser re-downloaded every image and video on every visit, and a `<video>` that needs `206` (Safari, a Telegram Mini App on iOS) got the whole file. It now streams the body, revalidates to `304` and answers a single range with `206` or `416`; containment refusals are unchanged. `serveFile` runs on Node as well as Bun, and on both a directory is `404`. [ADR 0281](docs/decisions/0281-static-files-are-served-by-one-responder.md)
|
|
28
|
+
**Affects:** `stitchkit/server` staticRoute(behaviour), serveFile(behaviour)
|
|
29
|
+
|
|
18
30
|
## [0.118.0] - 2026-11-03
|
|
19
31
|
|
|
20
32
|
### ⚠️ Breaking changes
|
|
@@ -9,7 +9,7 @@ export { type CacheOptions, cacheHeaders, createCache } from '../server/cache.js
|
|
|
9
9
|
export { createHandler } from '../server/create.js';
|
|
10
10
|
export { createErrorHook, type ErrorHookBase, type ErrorHookConfig, type ErrorHookMapping, type ResolvedError, } from '../server/error-hook.js';
|
|
11
11
|
export { createEventBus, type DefaultEventMap, type EventBus, type EventBusOptions, type EventHandler, } from '../server/event-bus.js';
|
|
12
|
-
export { type ByteRange, parseByteRange, type ServeFileOptions, serveFile, staticRoute, weakETag, } from '../server/file.js';
|
|
12
|
+
export { type ByteRange, parseByteRange, type ServeFileOptions, type StaticRouteOptions, serveFile, staticRoute, weakETag, } from '../server/file.js';
|
|
13
13
|
export { createImplement, createMultipartStream, createScopedImplement, defineMultipartStream, type ImplementOptions, implement, type MissingHandlerPolicy, type MultipartStreamConfig, type StreamScope, } from '../server/implement.js';
|
|
14
14
|
export { createImplementRegistry, createScopedImplementRegistry, type ExactRegistryHandlers, type ExactScopedRegistryHandlers, type ImplementationRegistry, implementRegistry, type KeyedServices, type RegistryHandlers, type ScopedImplementationRegistry, type ScopedRegistryHandlers, } from '../server/implement-registry.js';
|
|
15
15
|
export { composeLifecycleHooks } from '../server/lifecycle.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/entrypoints/server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/entrypoints/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -853,7 +853,8 @@ function createEventBus(options = {}) {
|
|
|
853
853
|
};
|
|
854
854
|
}
|
|
855
855
|
// src/server/file.ts
|
|
856
|
-
import {
|
|
856
|
+
import { createReadStream } from "node:fs";
|
|
857
|
+
import { stat } from "node:fs/promises";
|
|
857
858
|
import { resolve } from "node:path";
|
|
858
859
|
|
|
859
860
|
// src/server/mime.ts
|
|
@@ -893,7 +894,7 @@ function mimeForPath(path) {
|
|
|
893
894
|
}
|
|
894
895
|
|
|
895
896
|
// src/server/file.ts
|
|
896
|
-
function staticRoute(prefix, dir) {
|
|
897
|
+
function staticRoute(prefix, dir, options = {}) {
|
|
897
898
|
const cleanPrefix = prefix.replace(/\/+$/, "");
|
|
898
899
|
const root = resolve(dir.replace(/\/+$/, ""));
|
|
899
900
|
return {
|
|
@@ -913,15 +914,7 @@ function staticRoute(prefix, dir) {
|
|
|
913
914
|
const realTarget = await realPathWithinDir(root, target);
|
|
914
915
|
if (realTarget === null)
|
|
915
916
|
return new Response("Not found", { status: 404 });
|
|
916
|
-
|
|
917
|
-
if (!info?.isFile())
|
|
918
|
-
return new Response("Not found", { status: 404 });
|
|
919
|
-
return new Response(await readFile(realTarget), {
|
|
920
|
-
headers: {
|
|
921
|
-
"Content-Type": mimeForPath(realTarget),
|
|
922
|
-
"X-Content-Type-Options": "nosniff"
|
|
923
|
-
}
|
|
924
|
-
});
|
|
917
|
+
return serveFile(req, { path: realTarget, cacheControl: options.cacheControl });
|
|
925
918
|
}
|
|
926
919
|
};
|
|
927
920
|
}
|
|
@@ -1021,12 +1014,12 @@ async function serveFile(req, opts) {
|
|
|
1021
1014
|
headers: { Allow: "GET, HEAD" }
|
|
1022
1015
|
});
|
|
1023
1016
|
}
|
|
1024
|
-
const
|
|
1025
|
-
if (!
|
|
1017
|
+
const info = await stat(opts.path).catch(() => null);
|
|
1018
|
+
if (!info?.isFile()) {
|
|
1026
1019
|
return new Response("Not found", { status: 404 });
|
|
1027
1020
|
}
|
|
1028
|
-
const size =
|
|
1029
|
-
const mtimeMs =
|
|
1021
|
+
const size = info.size;
|
|
1022
|
+
const mtimeMs = info.mtimeMs;
|
|
1030
1023
|
const contentType = opts.contentType ?? mimeForPath(opts.path);
|
|
1031
1024
|
const useEtag = opts.etag !== false;
|
|
1032
1025
|
const useLastModified = opts.lastModified !== false;
|
|
@@ -1065,12 +1058,33 @@ async function serveFile(req, opts) {
|
|
|
1065
1058
|
base.set("Content-Type", contentType);
|
|
1066
1059
|
base.set("Content-Range", `bytes ${range.start}-${range.end}/${size}`);
|
|
1067
1060
|
base.set("Content-Length", String(length));
|
|
1068
|
-
const body = isHead ? null :
|
|
1061
|
+
const body = isHead ? null : fileBody(opts.path, range.start, range.end);
|
|
1069
1062
|
return new Response(body, { status: 206, headers: base });
|
|
1070
1063
|
}
|
|
1071
1064
|
base.set("Content-Type", contentType);
|
|
1072
1065
|
base.set("Content-Length", String(size));
|
|
1073
|
-
return new Response(isHead ? null :
|
|
1066
|
+
return new Response(isHead || size === 0 ? null : fileBody(opts.path, 0, size - 1), {
|
|
1067
|
+
status: 200,
|
|
1068
|
+
headers: base
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
function fileBody(path, start, end) {
|
|
1072
|
+
if ("Bun" in globalThis)
|
|
1073
|
+
return Bun.file(path).slice(start, end + 1);
|
|
1074
|
+
const source = createReadStream(path, { start, end });
|
|
1075
|
+
const chunks = source[Symbol.asyncIterator]();
|
|
1076
|
+
return new ReadableStream({
|
|
1077
|
+
async pull(controller) {
|
|
1078
|
+
const next = await chunks.next();
|
|
1079
|
+
if (next.done)
|
|
1080
|
+
controller.close();
|
|
1081
|
+
else
|
|
1082
|
+
controller.enqueue(next.value);
|
|
1083
|
+
},
|
|
1084
|
+
cancel() {
|
|
1085
|
+
source.destroy();
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1074
1088
|
}
|
|
1075
1089
|
// src/server/lifecycle.ts
|
|
1076
1090
|
function composeLifecycleHooks(...hooks) {
|
package/dist/server/file.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { RawRoute } from './types.js';
|
|
2
|
+
/** What a `staticRoute` adds to every file it serves. */
|
|
3
|
+
export interface StaticRouteOptions {
|
|
4
|
+
/** Value for the `Cache-Control` header, verbatim. */
|
|
5
|
+
cacheControl?: string;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
|
-
* Build a
|
|
4
|
-
*
|
|
8
|
+
* Build a static-file route. URL-derived paths pass both lexical and realpath
|
|
9
|
+
* containment checks, so an in-root symlink cannot escape `dir`; the file
|
|
10
|
+
* itself is answered by `serveFile` (Range, validators, `304`, streaming).
|
|
5
11
|
*/
|
|
6
|
-
export declare function staticRoute(prefix: string, dir: string): RawRoute;
|
|
12
|
+
export declare function staticRoute(prefix: string, dir: string, options?: StaticRouteOptions): RawRoute;
|
|
7
13
|
/** An inclusive byte range `[start, end]`. */
|
|
8
14
|
export interface ByteRange {
|
|
9
15
|
start: number;
|
|
@@ -49,10 +55,10 @@ export interface ServeFileOptions {
|
|
|
49
55
|
* `405` (non GET/HEAD), `404` (missing), `304` (fresh per `If-None-Match` /
|
|
50
56
|
* `If-Modified-Since`), `200` (full — no/ignored Range), `206` (range), or `416`
|
|
51
57
|
* (unsatisfiable range). Always sets `Accept-Ranges: bytes` and `nosniff`; a
|
|
52
|
-
* `HEAD` returns every header with an empty body.
|
|
58
|
+
* `HEAD` returns every header with an empty body. A directory is `404`.
|
|
53
59
|
*
|
|
54
|
-
* Bun
|
|
55
|
-
* URL-derived paths use `staticRoute` or `isWithinDir`. → ADR 0023.
|
|
60
|
+
* Runs on Bun and Node. The caller is responsible for path containment — for
|
|
61
|
+
* URL-derived paths use `staticRoute` or `isWithinDir`. → ADR 0023, ADR 0281.
|
|
56
62
|
*/
|
|
57
63
|
export declare function serveFile(req: Request, opts: ServeFileOptions): Promise<Response>;
|
|
58
64
|
//# sourceMappingURL=file.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/server/file.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/server/file.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,kBAAuB,GAC/B,QAAQ,CAqBV;AAED,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,IAAI,EAAE,MAAM,GACX,SAAS,GAAG,eAAe,GAAG,IAAI,CAkCpC;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D;AA6ED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IACtC,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6CAA6C;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0EvF"}
|
package/llms/server.2.txt
CHANGED
|
@@ -97,11 +97,24 @@ contract route does.
|
|
|
97
97
|
|
|
98
98
|
### Serving files & Range requests
|
|
99
99
|
|
|
100
|
-
`staticRoute
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
`staticRoute(prefix, dir, { cacheControl })` serves a directory: it checks
|
|
101
|
+
containment, then answers the file through `serveFile`, so a static image or
|
|
102
|
+
video carries `ETag`, `Last-Modified` and `Accept-Ranges`, revalidates to `304`
|
|
103
|
+
and seeks with `206`. `cacheControl` sets `Cache-Control` on every answer; by
|
|
104
|
+
default none is sent.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { createServer, staticRoute } from 'stitchkit/server'
|
|
108
|
+
|
|
109
|
+
createServer({
|
|
110
|
+
rawRoutes: [staticRoute('/static', './public', { cacheControl: 'public, max-age=3600' })],
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The route answers `GET`. To serve a file chosen by your own logic — through a
|
|
115
|
+
contract, with `HEAD`, a download name or a custom type — call **`serveFile`**
|
|
116
|
+
directly. It runs on Bun and Node, streams the requested byte range and speaks
|
|
117
|
+
the conditional-request half of RFC 7233 / 9110:
|
|
105
118
|
|
|
106
119
|
```ts
|
|
107
120
|
import { defineContract } from 'stitchkit/contract'
|
|
@@ -151,7 +164,7 @@ emit none.
|
|
|
151
164
|
`serveFile` takes an explicit `path` and trusts it — **the caller owns
|
|
152
165
|
containment**. For a URL-derived path use `staticRoute` (which enforces it) or
|
|
153
166
|
`isWithinDir` first. The byte-range parser is exported on its own as
|
|
154
|
-
`parseByteRange(header, size)` for direct use and testing. → ADR 0023.
|
|
167
|
+
`parseByteRange(header, size)` for direct use and testing. → ADR 0023, ADR 0281.
|
|
155
168
|
|
|
156
169
|
## Server primitives
|
|
157
170
|
|
package/llms/server.5.txt
CHANGED
|
@@ -47,7 +47,8 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
47
47
|
| `KeyedServices` | _type_ | registry result: the mount-ordered `ServiceDef[]` carrying the same services under `.byKey` |
|
|
48
48
|
| `RegistryHandlers` | _type_ | exact backend handler registry inferred from a contract registry |
|
|
49
49
|
| `ExactRegistryHandlers` | _type_ | fail-first handler shape that rejects extra registry and endpoint keys |
|
|
50
|
-
| `staticRoute` | function | a raw route that serves a directory |
|
|
50
|
+
| `staticRoute` | function | a raw route that serves a contained directory through `serveFile` (`Range` / `304` / validators) |
|
|
51
|
+
| `StaticRouteOptions` | _type_ | `{ cacheControl }` — what `staticRoute` adds to every file it serves |
|
|
51
52
|
| `serveFile` | function | serve a file with `Range` / `304` / `HEAD` — [guide](../guide/server.md#serving-files--range-requests) |
|
|
52
53
|
| `parseByteRange` | function | parse a single `Range` header → range / `unsatisfiable` / `null` |
|
|
53
54
|
| `isWithinDir` | function | path containment — `(root, resolvedTarget) => boolean`; call it before `serveFile` on any URL-derived path |
|
package/llms/testing.txt
CHANGED
|
@@ -608,9 +608,9 @@ Notes for a Node host:
|
|
|
608
608
|
- **Socket.IO** attaches to the Node HTTP server via `serveNode({ socket })`, and
|
|
609
609
|
on Node the default transport is `['websocket']` — set the client to match
|
|
610
610
|
(`transports: ['websocket']`). See [realtime](./realtime.md).
|
|
611
|
-
- **Bun-only helpers** do not run on Node:
|
|
612
|
-
|
|
613
|
-
|
|
611
|
+
- **Bun-only helpers** do not run on Node: the raw WebSocket lane. `serveFile`
|
|
612
|
+
and `staticRoute` work on both — on Node the body is a `node:fs` read stream —
|
|
613
|
+
but in production prefer a CDN / the static front-end below.
|
|
614
614
|
|
|
615
615
|
### Production checklist
|
|
616
616
|
|
package/llms-full.txt
CHANGED
|
@@ -2236,11 +2236,24 @@ contract route does.
|
|
|
2236
2236
|
|
|
2237
2237
|
### Serving files & Range requests
|
|
2238
2238
|
|
|
2239
|
-
`staticRoute
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2239
|
+
`staticRoute(prefix, dir, { cacheControl })` serves a directory: it checks
|
|
2240
|
+
containment, then answers the file through `serveFile`, so a static image or
|
|
2241
|
+
video carries `ETag`, `Last-Modified` and `Accept-Ranges`, revalidates to `304`
|
|
2242
|
+
and seeks with `206`. `cacheControl` sets `Cache-Control` on every answer; by
|
|
2243
|
+
default none is sent.
|
|
2244
|
+
|
|
2245
|
+
```ts
|
|
2246
|
+
import { createServer, staticRoute } from 'stitchkit/server'
|
|
2247
|
+
|
|
2248
|
+
createServer({
|
|
2249
|
+
rawRoutes: [staticRoute('/static', './public', { cacheControl: 'public, max-age=3600' })],
|
|
2250
|
+
})
|
|
2251
|
+
```
|
|
2252
|
+
|
|
2253
|
+
The route answers `GET`. To serve a file chosen by your own logic — through a
|
|
2254
|
+
contract, with `HEAD`, a download name or a custom type — call **`serveFile`**
|
|
2255
|
+
directly. It runs on Bun and Node, streams the requested byte range and speaks
|
|
2256
|
+
the conditional-request half of RFC 7233 / 9110:
|
|
2244
2257
|
|
|
2245
2258
|
```ts
|
|
2246
2259
|
import { defineContract } from 'stitchkit/contract'
|
|
@@ -2290,7 +2303,7 @@ emit none.
|
|
|
2290
2303
|
`serveFile` takes an explicit `path` and trusts it — **the caller owns
|
|
2291
2304
|
containment**. For a URL-derived path use `staticRoute` (which enforces it) or
|
|
2292
2305
|
`isWithinDir` first. The byte-range parser is exported on its own as
|
|
2293
|
-
`parseByteRange(header, size)` for direct use and testing. → ADR 0023.
|
|
2306
|
+
`parseByteRange(header, size)` for direct use and testing. → ADR 0023, ADR 0281.
|
|
2294
2307
|
|
|
2295
2308
|
## Server primitives
|
|
2296
2309
|
|
|
@@ -15141,9 +15154,9 @@ Notes for a Node host:
|
|
|
15141
15154
|
- **Socket.IO** attaches to the Node HTTP server via `serveNode({ socket })`, and
|
|
15142
15155
|
on Node the default transport is `['websocket']` — set the client to match
|
|
15143
15156
|
(`transports: ['websocket']`). See [realtime](./realtime.md).
|
|
15144
|
-
- **Bun-only helpers** do not run on Node:
|
|
15145
|
-
|
|
15146
|
-
|
|
15157
|
+
- **Bun-only helpers** do not run on Node: the raw WebSocket lane. `serveFile`
|
|
15158
|
+
and `staticRoute` work on both — on Node the body is a `node:fs` read stream —
|
|
15159
|
+
but in production prefer a CDN / the static front-end below.
|
|
15147
15160
|
|
|
15148
15161
|
### Production checklist
|
|
15149
15162
|
|
|
@@ -22558,7 +22571,8 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
22558
22571
|
| `KeyedServices` | _type_ | registry result: the mount-ordered `ServiceDef[]` carrying the same services under `.byKey` |
|
|
22559
22572
|
| `RegistryHandlers` | _type_ | exact backend handler registry inferred from a contract registry |
|
|
22560
22573
|
| `ExactRegistryHandlers` | _type_ | fail-first handler shape that rejects extra registry and endpoint keys |
|
|
22561
|
-
| `staticRoute` | function | a raw route that serves a directory |
|
|
22574
|
+
| `staticRoute` | function | a raw route that serves a contained directory through `serveFile` (`Range` / `304` / validators) |
|
|
22575
|
+
| `StaticRouteOptions` | _type_ | `{ cacheControl }` — what `staticRoute` adds to every file it serves |
|
|
22562
22576
|
| `serveFile` | function | serve a file with `Range` / `304` / `HEAD` — [guide](../guide/server.md#serving-files--range-requests) |
|
|
22563
22577
|
| `parseByteRange` | function | parse a single `Range` header → range / `unsatisfiable` / `null` |
|
|
22564
22578
|
| `isWithinDir` | function | path containment — `(root, resolvedTarget) => boolean`; call it before `serveFile` on any URL-derived path |
|
package/llms.txt
CHANGED
|
@@ -24,7 +24,7 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
|
|
|
24
24
|
- **stitchkit/remote**: [llms/remote.txt](llms/remote.txt) 1.0 KB
|
|
25
25
|
- **stitchkit/contract**: [llms/contract.txt](llms/contract.txt) 31.9 KB
|
|
26
26
|
- **stitchkit/primitives**: [llms/primitives.txt](llms/primitives.txt) 13.2 KB
|
|
27
|
-
- **stitchkit/server**: [llms/server.txt](llms/server.txt) 44.2 KB → [llms/server.2.txt](llms/server.2.txt) 20.
|
|
27
|
+
- **stitchkit/server**: [llms/server.txt](llms/server.txt) 44.2 KB → [llms/server.2.txt](llms/server.2.txt) 20.9 KB → [llms/server.3.txt](llms/server.3.txt) 47.0 KB → [llms/server.4.txt](llms/server.4.txt) 38.6 KB → [llms/server.5.txt](llms/server.5.txt) 23.1 KB
|
|
28
28
|
- **stitchkit/observability**: [llms/observability.txt](llms/observability.txt) 46.9 KB
|
|
29
29
|
- **stitchkit/agent-runtime**: [llms/agent-runtime.txt](llms/agent-runtime.txt) 44.3 KB → [llms/agent-runtime.2.txt](llms/agent-runtime.2.txt) 46.7 KB → [llms/agent-runtime.3.txt](llms/agent-runtime.3.txt) 43.4 KB
|
|
30
30
|
- **stitchkit/agent-runtime/testing**: [llms/agent-runtime-testing.txt](llms/agent-runtime-testing.txt) 2.6 KB
|
package/package.json
CHANGED