@procedures/client 0.18.1 → 0.20.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 +60 -0
- package/README.md +25 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/server/strategies.d.ts +17 -0
- package/dist/adapters/http/server/strategies.d.ts.map +1 -1
- package/dist/adapters/http/server/strategies.js.map +1 -1
- package/dist/adapters/http/server/types.d.ts +6 -3
- package/dist/adapters/http/server/types.d.ts.map +1 -1
- package/dist/adapters/port/transport.d.ts +10 -1
- package/dist/adapters/port/transport.d.ts.map +1 -1
- package/dist/adapters/port/transport.js +5 -1
- package/dist/adapters/port/transport.js.map +1 -1
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.js +8 -2
- package/dist/adapters/websocket/client/transport.js.map +1 -1
- package/dist/adapters/websocket/client/types.d.ts +3 -0
- package/dist/adapters/websocket/client/types.d.ts.map +1 -1
- package/dist/adapters/websocket/client/types.js.map +1 -1
- package/dist/browser.d.ts +7 -7
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +7 -7
- package/dist/browser.js.map +1 -1
- package/dist/index.d.ts +10 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -13
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +4 -5
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +4 -5
- package/dist/node.js.map +1 -1
- package/dist/server/browser-guard.d.ts +16 -4
- package/dist/server/browser-guard.d.ts.map +1 -1
- package/dist/server/browser-guard.js.map +1 -1
- package/dist/server/index.d.ts +3 -66
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -22
- package/dist/server/index.js.map +1 -1
- package/dist/server/procedure-server.d.ts +13 -8
- package/dist/server/procedure-server.d.ts.map +1 -1
- package/dist/server/procedure-server.js +15 -3
- package/dist/server/procedure-server.js.map +1 -1
- package/dist/server/request-auth.d.ts +16 -1
- package/dist/server/request-auth.d.ts.map +1 -1
- package/dist/server/request-auth.js +18 -0
- package/dist/server/request-auth.js.map +1 -1
- package/dist/server/types.d.ts +22 -6
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +6 -0
- package/dist/server/types.js.map +1 -1
- package/package.json +2 -1
- package/src/adapters/http/server/strategies.ts +16 -0
- package/src/adapters/http/server/types.ts +6 -3
- package/src/adapters/port/transport.ts +15 -2
- package/src/adapters/websocket/client/transport.ts +10 -3
- package/src/adapters/websocket/client/types.ts +3 -0
- package/src/browser.ts +7 -6
- package/src/index.ts +11 -25
- package/src/node.ts +5 -6
- package/src/server/browser-guard.ts +19 -7
- package/src/server/index.ts +3 -90
- package/src/server/procedure-server.ts +23 -9
- package/src/server/request-auth.ts +20 -1
- package/src/server/types.ts +23 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# @procedures/client
|
|
2
2
|
|
|
3
|
+
## 0.20.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5f49860: The root of `@procedures/client` and the entry `@procedures/client/server` do not export the server transports (CLI-6 step 2). Thus the root imports no `http`, no `ws` and no `express`, and its declarations name none of them (CLI-61). This change is a break of the server stack, thus it is its own MINOR (decision D13). The PATCH 0.14.1 marked each removed name as `@deprecated`.
|
|
8
|
+
|
|
9
|
+
- Removed from the root and from `./server`: `HttpServerTransport`, `HttpServerTransportOptions`, `HttpUrlStrategy`, `WebSocketServerTransport`, `WebSocketServerTransportOptions`, `WebSocketAuthHandler`, `WebSocketConnectionHandler` and `WebSocketMessage`. `@procedures/client/node` exports each of them, as before.
|
|
10
|
+
- Changed: `HttpUrlStrategy` takes a structural request, `UrlStrategyRequest`, not the `Request` of Express. `UrlStrategyRequest` has `method`, `path`, `url` and `headers`, and the optional `query` and `body`. A `Request` of Express agrees with it, and so does the `UrlRequest` of `procedureHandler`. `HttpServerTransport` still gives the strategy the request of Express. `@procedures/client/node` exports `UrlStrategyRequest`.
|
|
11
|
+
- Changed: the headers of `GuardedRequest` (the request of `checkBrowserRequest`) and of `hasAmbientCredentials` have the new structural type `GuardedHeaders`, not `IncomingHttpHeaders` of `node:http`. The headers of an `IncomingMessage` agree with it, so a call with a request of Node does not change.
|
|
12
|
+
- New: the root exports the types `RoutedRequest` and `GuardedHeaders`. `./server` exports `RoutedRequest`.
|
|
13
|
+
- New: the root is a browser entry (`client.browser`). The CI check bundles it for a browser, and a test examines the declarations of each entry other than `./node`. A project that checks the declarations of its libraries (`skipLibCheck: false`) and imports the root needs no `@types/express`.
|
|
14
|
+
|
|
15
|
+
MINOR: before 1.0.0, a break of the public API raises the MINOR. The removal of exports and the new parameter type of `HttpUrlStrategy` break the API.
|
|
16
|
+
|
|
17
|
+
Migration:
|
|
18
|
+
|
|
19
|
+
- Import `HttpServerTransport`, `WebSocketServerTransport` and their types from `@procedures/client/node`.
|
|
20
|
+
- A URL strategy whose parameter has the type `express.Request` does not compile as an `HttpUrlStrategy`. Give the parameter the type `UrlStrategyRequest` of `@procedures/client/node`, or give it no type: `HttpUrlStrategy` gives it the type.
|
|
21
|
+
- A strategy that reads a part of the Express request outside `UrlStrategyRequest`, for example `req.params`, casts the request: `(req as express.Request).params`.
|
|
22
|
+
- Code that reads a header of `GuardedHeaders` without a declared property, for example `accept`, gets `string | string[] | undefined`. Examine the value with `typeof` before use.
|
|
23
|
+
- Before, an import of the root also loaded the types of Node (`@types/node`) into the program. A project that used `process`, `Buffer`, `URL`, `setTimeout` or a `node:` module without `@types/node` in its own configuration compiled only because of that. Such a project fails to compile after this release. Add `@types/node` to its development dependencies and `"types": ["node"]` to its `tsconfig.json`. In this repository, `@procedures/archive`, `@procedures/env`, `@procedures/gh`, `@procedures/http`, `@procedures/llm`, `@procedures/npm` and `@procedures/schedule` got the `node` feature of `cue-config` for this reason. Their APIs do not change.
|
|
24
|
+
|
|
25
|
+
The migration steps of the known consumers:
|
|
26
|
+
|
|
27
|
+
- The site: no change. It imports none of these names. It names `HttpServerTransport` and `WebSocketServerTransport` only in the text of its journey.
|
|
28
|
+
- MiniMongo: no change. It imports none of these names, and its host uses `runProcedureHost`. Its `vite.config.ts` maps the root to `@procedures/client/browser`. The map can stay, because the root is also a browser entry.
|
|
29
|
+
- Graph: no change. It imports none of these names.
|
|
30
|
+
- jarvis: no change. It imports none of these names.
|
|
31
|
+
- The procedures image of the harness of `systems` (`packages/harness/image/procedures/server-ws.mjs`) imports `WebSocketServerTransport` from the root. It pins `@procedures/client` 0.7.0. When it moves to this MINOR or a later version, import `WebSocketServerTransport` from `@procedures/client/node`.
|
|
32
|
+
- `headroom` (`packages/daemon/src/gateway.ts`) gives `checkBrowserRequest` of the root a request of `node:http`: no change.
|
|
33
|
+
|
|
34
|
+
## 0.19.0
|
|
35
|
+
|
|
36
|
+
### Minor Changes
|
|
37
|
+
|
|
38
|
+
- 5cb934d: Breaking: a `ProcedureServer` with a token or a request hook (`principalOf`) refuses a request without credentials (CLI-1). The error code is `UNAUTHORIZED`, and the hook does not run for it. Before, such a request skipped the token check and the request hook. Thus a face that set no credentials, for example a custom transport, went around the authentication.
|
|
39
|
+
|
|
40
|
+
New: the local marker `LOCAL_CREDENTIALS`, with `isLocalCredentials()` and its key `LOCAL_MARKER`. A local face sets it. Only a local request skips the token and the request hook.
|
|
41
|
+
|
|
42
|
+
The server examines a request in one of three ways:
|
|
43
|
+
|
|
44
|
+
- A local request skips the token and the request hook.
|
|
45
|
+
- A request without credentials gets `UNAUTHORIZED` when the server has a token or a request hook.
|
|
46
|
+
- A request with credentials goes through the request hook and the token check, as before.
|
|
47
|
+
|
|
48
|
+
- The local faces are MCP over stdio, an SDK transport of `McpServerTransport` and `PortTransport`. The peer of stdio is the parent process. Only the holder of the other end of a port can send to it.
|
|
49
|
+
- A network face never sets the marker: HTTP, WebSocket and MCP over Streamable HTTP. The key of the marker is a symbol. JSON, structured clone, a header, a cookie and a query cannot carry it.
|
|
50
|
+
- The calls of a WebSocket server to the `serve` handler of its client are not local. Their credentials are empty, so a `serve` server with a token refuses them.
|
|
51
|
+
- `PortTransport` has the new option `credentials`. Give `{}` for a port that a part outside the application can reach, for example a `Window`.
|
|
52
|
+
- The nested calls of a procedure do not go through the token check. They keep the principal of their caller.
|
|
53
|
+
|
|
54
|
+
Migration:
|
|
55
|
+
|
|
56
|
+
- A custom transport or face that sends no credentials to a server with a token or a request hook now gets `UNAUTHORIZED`. Set the credentials of its request (`requestCredentials()`), or `LOCAL_CREDENTIALS` for a face in this process.
|
|
57
|
+
- Code that calls `server.handle()` of a server with a token or a request hook gives `credentials: LOCAL_CREDENTIALS`.
|
|
58
|
+
- The site: no change. Its servers have no token and no request hook, and its workers serve over `PortTransport`, which sets the marker.
|
|
59
|
+
- MiniMongo: no change. `scripts/dev.ts` starts a server without a token and without a request hook. Its HTTP and WebSocket faces set the credentials of each request.
|
|
60
|
+
- Graph: no change. The procedure host (`packages/server/graph-host.ts`) has a request hook (`graphPrincipalOf` of `packages/server/graph-procedures.ts`) and no token. All its faces send credentials: HTTP, WebSocket and MCP over Streamable HTTP (`mcpFace`). No code of Graph calls `handle()` directly. The MCP host (`packages/mcp/src/host.ts`) operates over stdio, which is local.
|
|
61
|
+
- jarvis: no change. The loopback server and the remote server of `packages/http/src/procedures.ts` have a request hook (`principalOf`), and the remote server has a token. `makeProcedureHandler` mounts `procedureHandler`, which sends the credentials of each request. A test that calls `handle()` of such a server gives `LOCAL_CREDENTIALS`, or credentials with the token.
|
|
62
|
+
|
|
3
63
|
## 0.18.1
|
|
4
64
|
|
|
5
65
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -297,7 +297,7 @@ interface WebSocketTransportOptions {
|
|
|
297
297
|
// dead peer, its socket stays open until the kernel stops it (924.6 s in the cells of R36).
|
|
298
298
|
import { WebSocketTransport } from "@procedures/client/node";
|
|
299
299
|
|
|
300
|
-
// The server transports are in the Node entry
|
|
300
|
+
// The server transports are only in the Node entry (CLI-6)
|
|
301
301
|
import { WebSocketServerTransport } from "@procedures/client/node";
|
|
302
302
|
|
|
303
303
|
// The server pings each connection, and closes one that misses 2 pongs (option heartbeat)
|
|
@@ -604,7 +604,7 @@ interface HttpServerTransportOptions {
|
|
|
604
604
|
port?: number; // default: 3000
|
|
605
605
|
host?: string; // default: "127.0.0.1"
|
|
606
606
|
basePath?: string; // default: "/api"
|
|
607
|
-
urlStrategy?: HttpUrlStrategy;
|
|
607
|
+
urlStrategy?: HttpUrlStrategy; // (req: UrlStrategyRequest) => Method | null
|
|
608
608
|
cors?: boolean;
|
|
609
609
|
corsOptions?: { origin?: string | string[]; methods?: string[]; allowedHeaders?: string[]; credentials?: boolean };
|
|
610
610
|
bodyLimit?: number; // default: 1 MiB
|
|
@@ -613,6 +613,8 @@ interface HttpServerTransportOptions {
|
|
|
613
613
|
}
|
|
614
614
|
```
|
|
615
615
|
|
|
616
|
+
A URL strategy gets a `UrlStrategyRequest`: the method, the path, the URL, the headers, the query and the body. The type is structural. A `Request` of Express agrees with it, and so does the `UrlRequest` of `procedureHandler`.
|
|
617
|
+
|
|
616
618
|
A client that accepts `application/x-ndjson` gets a stream as NDJSON lines ([WIRE-PROTOCOL.md](../documentation/WIRE-PROTOCOL.md)).
|
|
617
619
|
|
|
618
620
|
- After each quiet time of `keepAlive`, the server writes a keep-alive line: a blank line. Thus a proxy or a client with an idle timeout does not close a long, quiet stream.
|
|
@@ -707,7 +709,7 @@ interface ProcedureServerOptions {
|
|
|
707
709
|
storage?: StorageConfig;
|
|
708
710
|
transports?: ServerTransport[];
|
|
709
711
|
events?: EventPublisherOptions | EventPublisher; // the remote events: refer to "Remote events"
|
|
710
|
-
token?: string; // the token that each
|
|
712
|
+
token?: string; // the token that each request presents, except a local request
|
|
711
713
|
principalOf?: PrincipalOf; // the request hook: refer to "The request hook"
|
|
712
714
|
authenticate?: (request: ServerRequest) => Principal | undefined | Promise<Principal | undefined>;
|
|
713
715
|
}
|
|
@@ -735,9 +737,27 @@ const server = new ProcedureServer({
|
|
|
735
737
|
- `principal`: the principal of the request, for example the user of a session cookie. The procedure reads it as `ctx.principal`, and its nested calls get the same principal.
|
|
736
738
|
- `narrowing`: a narrower capability that the request asks for. The server narrows the capability of the call with it. A request for more has no effect.
|
|
737
739
|
- An empty object accepts the request without a principal. Undefined, or an error, refuses the request with `UNAUTHORIZED`.
|
|
738
|
-
- `authenticate` operates after the hook and can read `request.principal`. A request
|
|
740
|
+
- `authenticate` operates after the hook and can read `request.principal`. A local request does not go through the hook.
|
|
739
741
|
- `hostPolicy({ principalOf })` gives the hook to each server of the policy.
|
|
740
742
|
|
|
743
|
+
#### Local requests
|
|
744
|
+
|
|
745
|
+
Each face sets the credentials of its requests, or the local marker `LOCAL_CREDENTIALS` (CLI-1). A local request comes from this application, so the token and the request hook do not apply to it.
|
|
746
|
+
|
|
747
|
+
- The local faces are MCP over stdio, an SDK transport of `McpServerTransport` and `PortTransport`. The peer of stdio is the parent process. Only the holder of the other end of a port can send to it.
|
|
748
|
+
- A network face never sets the marker: HTTP, WebSocket, and MCP over Streamable HTTP. The key of the marker is a symbol, so JSON, a header, a cookie or a query cannot carry it.
|
|
749
|
+
- A server with a token or a request hook refuses a request without credentials with `UNAUTHORIZED`. The hook does not operate for it. Before, such a request skipped the token and the hook.
|
|
750
|
+
- A call of the code of the application to `server.handle()` sets the marker itself:
|
|
751
|
+
|
|
752
|
+
```typescript
|
|
753
|
+
import { LOCAL_CREDENTIALS } from "@procedures/client";
|
|
754
|
+
|
|
755
|
+
await server.handle({ id: "1", method, payload, metadata: {}, credentials: LOCAL_CREDENTIALS });
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
- The nested calls of a procedure do not go through the token check again. They keep the principal of their caller.
|
|
759
|
+
- A `PortTransport` that a part outside the application can reach takes `credentials: {}`. Then the token applies. A `Window` is such a port.
|
|
760
|
+
|
|
741
761
|
#### Cookies and CSRF
|
|
742
762
|
|
|
743
763
|
A browser sends the cookies of a server by itself, also for a request that a page of another site starts. Thus a server that reads cookies trusts a request only from a named origin.
|
|
@@ -791,7 +811,7 @@ import { ... } from "@procedures/client/events";
|
|
|
791
811
|
|
|
792
812
|
| Entry | Use |
|
|
793
813
|
|---|---|
|
|
794
|
-
| `@procedures/client` | Node. The browser entry
|
|
814
|
+
| `@procedures/client` | Node or a browser bundle. The browser entry, the URL strategies and the browser checks of the server. It imports no `http`, `ws` or `express`, and its declarations name none of them (CLI-6). Its `WebSocketTransport` uses the global `WebSocket`. |
|
|
795
815
|
| `@procedures/client/browser` | A browser bundle. It does not import `http` or `ws`. |
|
|
796
816
|
| `@procedures/client/node` | Node. A `WebSocketTransport` whose sockets are of the `ws` package: a drop ends a socket at once. `writeNdjsonStream`: the NDJSON stream response of `HttpServerTransport`, for a `ServerResponse` of `node:http`. `procedureHandler` and `upgradeHandler`: the procedure faces of HTTP and WebSocket, without a framework. `HttpServerTransport` and `WebSocketServerTransport`: the server transports. |
|
|
797
817
|
| `@procedures/client/register` | It registers the core procedures in the global registry. |
|