@godspeedai/cognate-protocol-connect-bun 0.1.1 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +82 -5
  2. package/package.json +3 -3
  3. package/src/index.ts +14 -3
package/README.md CHANGED
@@ -1,9 +1,86 @@
1
1
  # @godspeedai/cognate-protocol-connect-bun
2
2
 
3
- Serves the Connect runtime service on `Bun.serve` and provides a fetch transport.
3
+ Serves a Cognate `RuntimeService` over the Connect protocol on `Bun.serve` — with authentication, payload limits, and deadlines already wired — and provides the matching fetch-based client transport.
4
4
 
5
- - `serveRuntime({ service, authenticate, port, limits })` — unauthenticated → HTTP 401 `unauthenticated`; bodies over `maxBodyBytes` → `resource_exhausted`; JSON deeper than `maxJsonDepth` → `invalid_argument`; unary calls bounded by `defaultDeadlineMs` → `deadline_exceeded` (CG-WIR-004).
6
- - `connectTransport(baseUrl, { useBinaryFormat })` — connect-web fetch transport, usable from Bun and browsers.
7
- - `devTokenAuthenticator` / `devToken` — `Bearer <tenant>:<principal>`; development only, not an authentication system.
5
+ **When to use this package:** you expose a Cognate runtime over HTTP, or you call one from Bun, and you want the transport handled. It composes [`@godspeedai/cognate-protocol-connect`](https://www.npmjs.com/package/@godspeedai/cognate-protocol-connect) (the transport-neutral route mapping); install this one when your server is Bun. For a different HTTP host, use `@godspeedai/cognate-protocol-connect` directly and register its routes on your own router.
8
6
 
9
- Supported modes over HTTP/1.1: unary, server streaming (DEBT-004). Proof of second-process control: `tests/integration/second-process.test.ts` (CG-WIR-002).
7
+ ## Installation
8
+
9
+ ```sh
10
+ bun add @godspeedai/cognate-protocol-connect-bun
11
+ ```
12
+
13
+ Requires [Bun](https://bun.sh) >= 1.4.0 (the server is a `Bun.serve` transport). Depends on `@connectrpc/connect`, `@connectrpc/connect-web`, and `@godspeedai/cognate-protocol-connect`.
14
+
15
+ ## Quick start
16
+
17
+ Serve a runtime and call it from a second process:
18
+
19
+ ```ts
20
+ import { createRuntime } from "@godspeedai/cognate-runtime-bun";
21
+ import { devTokenAuthenticator, serveRuntime } from "@godspeedai/cognate-protocol-connect-bun";
22
+
23
+ const runtime = await createRuntime({
24
+ store: "./app.sqlite",
25
+ agents: [/* your AgentDefinitions */],
26
+ policy, // kernel invocation policy
27
+ actions, // action authorization
28
+ });
29
+
30
+ const server = serveRuntime({
31
+ service: runtime.service,
32
+ authenticate: devTokenAuthenticator, // dev helper; bring your own for production
33
+ port: 3000,
34
+ limits: { maxBodyBytes: 1_048_576, maxJsonDepth: 32, defaultDeadlineMs: 30_000 },
35
+ });
36
+
37
+ console.log(server.url); // http://127.0.0.1:3000
38
+ await server.stop();
39
+ ```
40
+
41
+ On the client side, build a transport and a remote `RuntimeService`:
42
+
43
+ ```ts
44
+ import { createRemoteRuntimeService } from "@godspeedai/cognate-protocol-connect";
45
+ import { connectTransport, devToken } from "@godspeedai/cognate-protocol-connect-bun";
46
+
47
+ const service = createRemoteRuntimeService(
48
+ connectTransport("http://127.0.0.1:3000", { useBinaryFormat: false }),
49
+ devToken, // (caller) => "tenant:principal" Bearer token
50
+ );
51
+
52
+ const caller = { actor: { id: "alice", kind: "user" }, tenant: "tenant-a" };
53
+ const run = await service.startRun(caller, { agent: "agent.echo", input: { text: "hi" } });
54
+ ```
55
+
56
+ ## Request handling
57
+
58
+ Every request passes through the same gate, in order:
59
+
60
+ 1. **Authentication** — `authenticate(headers)` resolves the caller; no caller means HTTP 401 with the Connect code `unauthenticated`.
61
+ 2. **Body size** — a declared `content-length` over `maxBodyBytes` (default 1 MiB) is rejected with `resource_exhausted`.
62
+ 3. **JSON depth** — values nested deeper than `maxJsonDepth` (default 32) are rejected with `invalid_argument`; malformed messages likewise.
63
+ 4. **Deadline** — unary calls without a shorter client deadline are bounded by `defaultDeadlineMs` (default 30 s); an overrun surfaces as `deadline_exceeded`.
64
+
65
+ Errors are returned as Connect JSON (`{ code, message }`), and `ServiceError` codes from your service round-trip to Connect codes and back exactly.
66
+
67
+ ## Development tokens
68
+
69
+ `devTokenAuthenticator` accepts `Authorization: Bearer <tenant>:<principalId>` and `devToken` renders a caller back to that form. They exist for development and tests — **this is not an authentication system**; swap in your own `authenticate` before exposing the server to anything real.
70
+
71
+ ## Limitations
72
+
73
+ - HTTP/1.1 only, supporting unary and server-streaming calls; the protocol defines no client-streaming or bidirectional methods.
74
+ - The body-size check uses the declared `content-length` header.
75
+ - `serveRuntime` binds an ephemeral port when `port` is omitted; read the actual address from `server.url`.
76
+
77
+ ## Related packages
78
+
79
+ - [`@godspeedai/cognate-protocol-connect`](https://www.npmjs.com/package/@godspeedai/cognate-protocol-connect) — the transport-neutral route mapping and remote client this package builds on.
80
+ - [`@godspeedai/cognate-runtime-bun`](https://www.npmjs.com/package/@godspeedai/cognate-runtime-bun) — the runtime whose `.service` you serve.
81
+ - [`@godspeedai/cognate-ag-ui`](https://www.npmjs.com/package/@godspeedai/cognate-ag-ui) — an SSE endpoint for AG-UI clients that rides on the same service.
82
+ - [`@godspeedai/cognate`](https://www.npmjs.com/package/@godspeedai/cognate) — the SDK umbrella.
83
+
84
+ ## License
85
+
86
+ Apache-2.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@godspeedai/cognate-protocol-connect-bun",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Serves the Connect runtime service on Bun.serve with authentication, payload limits, and deadlines; provides a fetch transport.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,8 +22,8 @@
22
22
  ".": "./src/index.ts"
23
23
  },
24
24
  "dependencies": {
25
- "@godspeedai/cognate-protocol-connect": "^0.1.1",
26
- "@godspeedai/cognate-runtime-api": "^0.1.1",
25
+ "@godspeedai/cognate-protocol-connect": "^0.2.0",
26
+ "@godspeedai/cognate-runtime-api": "^0.2.0",
27
27
  "@connectrpc/connect": "2.2.0",
28
28
  "@connectrpc/connect-web": "2.2.0"
29
29
  },
package/src/index.ts CHANGED
@@ -80,7 +80,12 @@ export function serveRuntime(options: ServeOptions): RuntimeServer {
80
80
  request = new Request(request.url, { method: request.method, headers, body: request.body ?? undefined, duplex: request.body ? "half" : undefined } as RequestInit);
81
81
  }
82
82
 
83
- return connectFetch(request);
83
+ const response = await connectFetch(request);
84
+ // Bun's fetch caches repeated identical unary POST responses (DEBT-027); the header protects
85
+ // every client — including hand-rolled createConnectTransport calls without a fetch override.
86
+ const headers = new Headers(response.headers);
87
+ headers.set("cache-control", "no-store");
88
+ return new Response(response.body, { status: response.status, headers });
84
89
  },
85
90
  });
86
91
 
@@ -92,9 +97,15 @@ export function serveRuntime(options: ServeOptions): RuntimeServer {
92
97
  };
93
98
  }
94
99
 
95
- /** A fetch-based Connect transport usable from Bun and browsers. */
100
+ /** A fetch-based Connect transport usable from Bun and browsers.
101
+ *
102
+ * Bun's fetch caches repeated identical unary POST responses (observed on Bun 1.4.0: a client
103
+ * re-reading a projection kept receiving its first response until the cache entry was bypassed;
104
+ * recorded as DEBT-027), so this helper defaults to `cache: "no-store"` — a Bun runtime has no HTTP
105
+ * cache to benefit from anyway. Pass `fetch` explicitly to override. */
96
106
  export function connectTransport(baseUrl: string, options?: { readonly useBinaryFormat?: boolean }): Transport {
97
- return createConnectTransport({ baseUrl, useBinaryFormat: options?.useBinaryFormat ?? false });
107
+ const fetchNoCache = ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, { ...init, cache: "no-store" })) as typeof globalThis.fetch;
108
+ return createConnectTransport({ baseUrl, useBinaryFormat: options?.useBinaryFormat ?? false, fetch: fetchNoCache });
98
109
  }
99
110
 
100
111
  /** Test/dev authenticator: `Bearer <tenant>:<principalId>`. Not for production use. */