@orkestrel/tool 0.0.2 → 0.0.4

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.
@@ -1,3 +1,125 @@
1
- export type * from './types.js';
2
- export * from './constants.js';
3
- export * from './factories.js';
1
+ import { TerminalManagerInterface } from '@orkestrel/terminal';
2
+ import { TimerHandler } from '@orkestrel/terminal';
3
+
4
+ /**
5
+ * Build the two `TerminalManagerInterface` (`@orkestrel/terminal`) routes — a GET SSE stream and
6
+ * a POST answer endpoint, both mounted on the SAME `:name`-templated path — that bridge a manager's
7
+ * endpoints onto the wire, byte-compatible with `PromptClient`.
8
+ *
9
+ * @remarks
10
+ * - **GET (SSE).** Optionally token-gated (`401` on mismatch), `404` when `name` names no
11
+ * endpoint. Opens a stream, replays every currently-{@link import('@orkestrel/terminal').PendingPrompt}
12
+ * as a `pending` frame, then live-forwards the manager's own `pending` / `expire` events scoped
13
+ * to `name`. A `keepalive`-interval `: ` comment ping is armed via the injected `timer` (default
14
+ * the host `setTimeout`). On the request's `AbortSignal` firing (client disconnect OR server
15
+ * stop) the keepalive is cancelled, both listeners unsubscribed, and the stream ended — no
16
+ * `shutdown` frame is sent, so a reconnecting client is never told the endpoint is gone.
17
+ * - **POST (answer).** Same token + `404` checks, then reads the body capped at `options.limit`
18
+ * bytes (`413` over, `manager.answer` never called — see {@link TerminalRoutesOptions.limit}),
19
+ * parses the JSON body (`400` on invalid JSON, `422` when it isn't an `{ id, value }`
20
+ * {@link import('@orkestrel/terminal').isAnswerPayload} shape), and routes it through
21
+ * `manager.answer` — `204` on success, `404` for `'terminal'`, `422` for `'unknown'` / `'rejected'`.
22
+ *
23
+ * @remarks
24
+ * The `token` option (a string OR a validator function — {@link TerminalToken}) is validated at
25
+ * GET connect, on EVERY POST, and RE-VALIDATED on every keepalive tick of a live SSE stream — a
26
+ * stream whose presented token stops validating is torn down rather than left streaming forever.
27
+ * Concurrent POST answerers race first-write-wins — a late POST for an already-settled prompt
28
+ * returns `422`.
29
+ *
30
+ * @param manager - The `TerminalManagerInterface` (`@orkestrel/terminal`) whose endpoints are bridged
31
+ * @param options - See {@link TerminalRoutesOptions}
32
+ * @returns Exactly two {@link TerminalRoute} records — GET then POST — sharing one path
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { createTerminalRoutes } from '@src/server'
37
+ * import { createTerminalManager } from '@orkestrel/terminal'
38
+ *
39
+ * const manager = createTerminalManager()
40
+ * manager.add('assistant')
41
+ * const routes = createTerminalRoutes(manager, { token: 'secret' })
42
+ * // mount `routes` against any router accepting `{ method, path, handler }`
43
+ * ```
44
+ */
45
+ export declare function createTerminalRoutes(manager: TerminalManagerInterface, options?: TerminalRoutesOptions): readonly TerminalRoute[];
46
+
47
+ /** The HTTP method literal a {@link TerminalRoute} declares — the exact 7-literal union `@orkestrel/router`'s `Method` accepts. */
48
+ export declare type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
49
+
50
+ /**
51
+ * The default SSE keepalive interval (in milliseconds)
52
+ * {@link import('./factories.js').createTerminalRoutes} arms per open connection — a `: `
53
+ * comment ping a conforming SSE parser ignores, keeping intermediary proxies from timing out an
54
+ * otherwise-idle stream.
55
+ */
56
+ export declare const TERMINAL_KEEPALIVE_MS = 15000;
57
+
58
+ /**
59
+ * The default `:name`-templated path {@link import('./factories.js').createTerminalRoutes}
60
+ * mounts its GET (SSE) + POST (answer) routes under.
61
+ */
62
+ export declare const TERMINAL_ROUTES_PATH = "/terminals/:name";
63
+
64
+ /**
65
+ * One structural route record {@link import('./factories.js').createTerminalRoutes} returns — a
66
+ * plain `{ method, path, handler }` shape carrying NO dependency on `@orkestrel/router`'s own
67
+ * `Route` type, so a consumer mounts it against any router that accepts a two-arg
68
+ * `(request, context) => Response | Promise<Response>` handler keyed by `method` + `path`.
69
+ */
70
+ export declare interface TerminalRoute {
71
+ readonly method: Method;
72
+ readonly path: string;
73
+ readonly handler: (request: Request, context: TerminalRouteContext) => Response | Promise<Response>;
74
+ }
75
+
76
+ /**
77
+ * The minimal route-dispatch context a {@link TerminalRoute} handler reads — exactly the frozen,
78
+ * URL-decoded `:name` path param slice a router hands a matched handler.
79
+ */
80
+ export declare interface TerminalRouteContext {
81
+ readonly params: Readonly<Record<string, string>>;
82
+ }
83
+
84
+ /**
85
+ * Options for {@link import('./factories.js').createTerminalRoutes}.
86
+ *
87
+ * @remarks
88
+ * - `path` — the shared `:name`-templated path both the GET (SSE) and POST (answer) routes
89
+ * mount under; defaults to {@link import('./constants.js').TERMINAL_ROUTES_PATH}.
90
+ * - `token` — a {@link TerminalToken}: a string is compared for equality against the
91
+ * `x-orkestrel-token` header; a function receives the header's value (`undefined` when absent)
92
+ * and returns whether it validates, letting the consumer roll/expire tokens out-of-band.
93
+ * Validated at GET connect, on EVERY POST, and RE-VALIDATED on every keepalive tick of a live
94
+ * SSE stream — a stream whose presented token stops validating (rotated, expired, revoked) is
95
+ * torn down (the abort/self-heal teardown path, no `shutdown` frame) rather than left open
96
+ * forever; the client reconnects and re-authenticates. Omitted ⇒ no auth check. Because
97
+ * re-validation only happens on the keepalive tick, the revocation window equals the keepalive
98
+ * interval — a token rejected/expired between ticks keeps streaming until the next one. A
99
+ * validator function that THROWS is treated as rejection (fail-closed) at every call site.
100
+ * - `keepalive` — the SSE comment-ping interval in milliseconds; defaults to
101
+ * {@link import('./constants.js').TERMINAL_KEEPALIVE_MS}.
102
+ * - `timer` — the injected {@link TimerHandler} driving the keepalive interval (default the host
103
+ * `setTimeout`/`clearTimeout`), so a test drives the keepalive deterministically.
104
+ * - `limit` — the maximum POST answer body size in bytes, streamed and enforced BEFORE JSON
105
+ * parsing (ignoring any `Content-Length` header, so a lying header can never bypass the cap);
106
+ * a body exceeding it is rejected `413` and `manager.answer` is never called. Defaults to
107
+ * `@orkestrel/server`'s own `DEFAULT_BODY_LIMIT` (1 MiB).
108
+ */
109
+ export declare interface TerminalRoutesOptions {
110
+ readonly path?: string;
111
+ readonly token?: TerminalToken;
112
+ readonly keepalive?: number;
113
+ readonly timer?: TimerHandler;
114
+ readonly limit?: number;
115
+ }
116
+
117
+ /**
118
+ * The `token` gate a {@link TerminalRoutesOptions} may configure — a plain string compared for
119
+ * equality against the `x-orkestrel-token` header, OR a validator function the consumer fully
120
+ * controls, enabling expiry/rotation (a JWT `exp` check, a revocation-list lookup, anything
121
+ * time-varying) that a fixed string cannot express. `undefined` disables the auth check entirely.
122
+ */
123
+ export declare type TerminalToken = string | ((value: string | undefined) => boolean);
124
+
125
+ export { }
@@ -1,3 +1,125 @@
1
- export type * from './types.js';
2
- export * from './constants.js';
3
- export * from './factories.js';
1
+ import { TerminalManagerInterface } from '@orkestrel/terminal';
2
+ import { TimerHandler } from '@orkestrel/terminal';
3
+
4
+ /**
5
+ * Build the two `TerminalManagerInterface` (`@orkestrel/terminal`) routes — a GET SSE stream and
6
+ * a POST answer endpoint, both mounted on the SAME `:name`-templated path — that bridge a manager's
7
+ * endpoints onto the wire, byte-compatible with `PromptClient`.
8
+ *
9
+ * @remarks
10
+ * - **GET (SSE).** Optionally token-gated (`401` on mismatch), `404` when `name` names no
11
+ * endpoint. Opens a stream, replays every currently-{@link import('@orkestrel/terminal').PendingPrompt}
12
+ * as a `pending` frame, then live-forwards the manager's own `pending` / `expire` events scoped
13
+ * to `name`. A `keepalive`-interval `: ` comment ping is armed via the injected `timer` (default
14
+ * the host `setTimeout`). On the request's `AbortSignal` firing (client disconnect OR server
15
+ * stop) the keepalive is cancelled, both listeners unsubscribed, and the stream ended — no
16
+ * `shutdown` frame is sent, so a reconnecting client is never told the endpoint is gone.
17
+ * - **POST (answer).** Same token + `404` checks, then reads the body capped at `options.limit`
18
+ * bytes (`413` over, `manager.answer` never called — see {@link TerminalRoutesOptions.limit}),
19
+ * parses the JSON body (`400` on invalid JSON, `422` when it isn't an `{ id, value }`
20
+ * {@link import('@orkestrel/terminal').isAnswerPayload} shape), and routes it through
21
+ * `manager.answer` — `204` on success, `404` for `'terminal'`, `422` for `'unknown'` / `'rejected'`.
22
+ *
23
+ * @remarks
24
+ * The `token` option (a string OR a validator function — {@link TerminalToken}) is validated at
25
+ * GET connect, on EVERY POST, and RE-VALIDATED on every keepalive tick of a live SSE stream — a
26
+ * stream whose presented token stops validating is torn down rather than left streaming forever.
27
+ * Concurrent POST answerers race first-write-wins — a late POST for an already-settled prompt
28
+ * returns `422`.
29
+ *
30
+ * @param manager - The `TerminalManagerInterface` (`@orkestrel/terminal`) whose endpoints are bridged
31
+ * @param options - See {@link TerminalRoutesOptions}
32
+ * @returns Exactly two {@link TerminalRoute} records — GET then POST — sharing one path
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { createTerminalRoutes } from '@src/server'
37
+ * import { createTerminalManager } from '@orkestrel/terminal'
38
+ *
39
+ * const manager = createTerminalManager()
40
+ * manager.add('assistant')
41
+ * const routes = createTerminalRoutes(manager, { token: 'secret' })
42
+ * // mount `routes` against any router accepting `{ method, path, handler }`
43
+ * ```
44
+ */
45
+ export declare function createTerminalRoutes(manager: TerminalManagerInterface, options?: TerminalRoutesOptions): readonly TerminalRoute[];
46
+
47
+ /** The HTTP method literal a {@link TerminalRoute} declares — the exact 7-literal union `@orkestrel/router`'s `Method` accepts. */
48
+ export declare type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
49
+
50
+ /**
51
+ * The default SSE keepalive interval (in milliseconds)
52
+ * {@link import('./factories.js').createTerminalRoutes} arms per open connection — a `: `
53
+ * comment ping a conforming SSE parser ignores, keeping intermediary proxies from timing out an
54
+ * otherwise-idle stream.
55
+ */
56
+ export declare const TERMINAL_KEEPALIVE_MS = 15000;
57
+
58
+ /**
59
+ * The default `:name`-templated path {@link import('./factories.js').createTerminalRoutes}
60
+ * mounts its GET (SSE) + POST (answer) routes under.
61
+ */
62
+ export declare const TERMINAL_ROUTES_PATH = "/terminals/:name";
63
+
64
+ /**
65
+ * One structural route record {@link import('./factories.js').createTerminalRoutes} returns — a
66
+ * plain `{ method, path, handler }` shape carrying NO dependency on `@orkestrel/router`'s own
67
+ * `Route` type, so a consumer mounts it against any router that accepts a two-arg
68
+ * `(request, context) => Response | Promise<Response>` handler keyed by `method` + `path`.
69
+ */
70
+ export declare interface TerminalRoute {
71
+ readonly method: Method;
72
+ readonly path: string;
73
+ readonly handler: (request: Request, context: TerminalRouteContext) => Response | Promise<Response>;
74
+ }
75
+
76
+ /**
77
+ * The minimal route-dispatch context a {@link TerminalRoute} handler reads — exactly the frozen,
78
+ * URL-decoded `:name` path param slice a router hands a matched handler.
79
+ */
80
+ export declare interface TerminalRouteContext {
81
+ readonly params: Readonly<Record<string, string>>;
82
+ }
83
+
84
+ /**
85
+ * Options for {@link import('./factories.js').createTerminalRoutes}.
86
+ *
87
+ * @remarks
88
+ * - `path` — the shared `:name`-templated path both the GET (SSE) and POST (answer) routes
89
+ * mount under; defaults to {@link import('./constants.js').TERMINAL_ROUTES_PATH}.
90
+ * - `token` — a {@link TerminalToken}: a string is compared for equality against the
91
+ * `x-orkestrel-token` header; a function receives the header's value (`undefined` when absent)
92
+ * and returns whether it validates, letting the consumer roll/expire tokens out-of-band.
93
+ * Validated at GET connect, on EVERY POST, and RE-VALIDATED on every keepalive tick of a live
94
+ * SSE stream — a stream whose presented token stops validating (rotated, expired, revoked) is
95
+ * torn down (the abort/self-heal teardown path, no `shutdown` frame) rather than left open
96
+ * forever; the client reconnects and re-authenticates. Omitted ⇒ no auth check. Because
97
+ * re-validation only happens on the keepalive tick, the revocation window equals the keepalive
98
+ * interval — a token rejected/expired between ticks keeps streaming until the next one. A
99
+ * validator function that THROWS is treated as rejection (fail-closed) at every call site.
100
+ * - `keepalive` — the SSE comment-ping interval in milliseconds; defaults to
101
+ * {@link import('./constants.js').TERMINAL_KEEPALIVE_MS}.
102
+ * - `timer` — the injected {@link TimerHandler} driving the keepalive interval (default the host
103
+ * `setTimeout`/`clearTimeout`), so a test drives the keepalive deterministically.
104
+ * - `limit` — the maximum POST answer body size in bytes, streamed and enforced BEFORE JSON
105
+ * parsing (ignoring any `Content-Length` header, so a lying header can never bypass the cap);
106
+ * a body exceeding it is rejected `413` and `manager.answer` is never called. Defaults to
107
+ * `@orkestrel/server`'s own `DEFAULT_BODY_LIMIT` (1 MiB).
108
+ */
109
+ export declare interface TerminalRoutesOptions {
110
+ readonly path?: string;
111
+ readonly token?: TerminalToken;
112
+ readonly keepalive?: number;
113
+ readonly timer?: TimerHandler;
114
+ readonly limit?: number;
115
+ }
116
+
117
+ /**
118
+ * The `token` gate a {@link TerminalRoutesOptions} may configure — a plain string compared for
119
+ * equality against the `x-orkestrel-token` header, OR a validator function the consumer fully
120
+ * controls, enabling expiry/rotation (a JWT `exp` check, a revocation-list lookup, anything
121
+ * time-varying) that a fixed string cannot express. `undefined` disables the auth check entirely.
122
+ */
123
+ export declare type TerminalToken = string | ((value: string | undefined) => boolean);
124
+
125
+ export { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orkestrel/tool",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Concrete LLM-callable tools for the @orkestrel line — workflow authoring, workspace editing, and sub-agent delegation, over the agent tool runtime, with pluggable stores. Part of the @orkestrel line.",
5
5
  "keywords": [
6
6
  "agent",
@@ -25,7 +25,6 @@
25
25
  "sideEffects": false,
26
26
  "main": "./dist/src/core/index.cjs",
27
27
  "module": "./dist/src/core/index.js",
28
- "types": "./dist/src/core/index.d.ts",
29
28
  "exports": {
30
29
  ".": {
31
30
  "import": {
@@ -56,6 +55,7 @@
56
55
  "clean": "node -e \"try{require('node:fs').rmSync('dist',{recursive:true,force:true})}catch{}\"",
57
56
  "copy": "node -e \"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\"",
58
57
  "tmp:txt": "node -e \"const fs=require('node:fs'),p=require('node:path');function walk(d){for(const e of fs.readdirSync(d,{withFileTypes:true})){const f=p.join(d,e.name);if(e.isDirectory()){walk(f)}else if(!e.name.endsWith('.md')&&!e.name.endsWith('.txt')){const t=f+'.txt';if(!fs.existsSync(t)){fs.renameSync(f,t)}else{console.warn('Skipping '+f+' — target exists: '+t)}}}}try{walk('tmp')}catch(e){if(e.code!=='ENOENT')throw e}\"",
58
+ "scaffold": "scaffold",
59
59
  "lint": "oxlint --config .oxlintrc.json --fix .",
60
60
  "check": "tsc --noEmit --project tsconfig.json && npm run check:src",
61
61
  "check:src": "npm run check:src:core && npm run check:src:server",
@@ -76,16 +76,20 @@
76
76
  "prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test"
77
77
  },
78
78
  "dependencies": {
79
- "@orkestrel/agent": "^0.0.5",
80
- "@orkestrel/contract": "^0.0.2",
81
- "@orkestrel/server": "^0.0.5",
82
- "@orkestrel/terminal": "^0.0.2",
83
- "@orkestrel/workflow": "^0.0.5"
79
+ "@orkestrel/agent": "^0.0.8",
80
+ "@orkestrel/contract": "^0.0.7",
81
+ "@orkestrel/database": "^0.0.5",
82
+ "@orkestrel/relation": "^0.0.3",
83
+ "@orkestrel/server": "^0.0.6",
84
+ "@orkestrel/terminal": "^0.0.4",
85
+ "@orkestrel/workflow": "^0.0.6"
84
86
  },
85
87
  "devDependencies": {
86
- "@microsoft/api-extractor": "^7.58.11",
87
- "@orkestrel/guide": "^0.0.2",
88
+ "@microsoft/api-extractor": "^7.58.12",
89
+ "@orkestrel/guide": "^0.0.5",
90
+ "@orkestrel/scaffold": "^0.0.2",
88
91
  "@types/node": "^26.1.1",
92
+ "@vitest/browser-playwright": "^4.1.10",
89
93
  "oxfmt": "^0.59.0",
90
94
  "oxlint": "^1.74.0",
91
95
  "typescript": "^6.0.3",
@@ -1,12 +0,0 @@
1
- /**
2
- * The default `:name`-templated path {@link import('./factories.js').createTerminalRoutes}
3
- * mounts its GET (SSE) + POST (answer) routes under.
4
- */
5
- export declare const TERMINAL_ROUTES_PATH = "/terminals/:name";
6
- /**
7
- * The default SSE keepalive interval (in milliseconds)
8
- * {@link import('./factories.js').createTerminalRoutes} arms per open connection — a `: `
9
- * comment ping a conforming SSE parser ignores, keeping intermediary proxies from timing out an
10
- * otherwise-idle stream.
11
- */
12
- export declare const TERMINAL_KEEPALIVE_MS = 15000;
@@ -1,44 +0,0 @@
1
- import { TerminalManagerInterface } from '@orkestrel/terminal';
2
- import { TerminalRoute, TerminalRoutesOptions } from './types.js';
3
- /**
4
- * Build the two `TerminalManagerInterface` (`@orkestrel/terminal`) routes — a GET SSE stream and
5
- * a POST answer endpoint, both mounted on the SAME `:name`-templated path — that bridge a manager's
6
- * endpoints onto the wire, byte-compatible with `PromptClient`.
7
- *
8
- * @remarks
9
- * - **GET (SSE).** Optionally token-gated (`401` on mismatch), `404` when `name` names no
10
- * endpoint. Opens a stream, replays every currently-{@link import('@orkestrel/terminal').PendingPrompt}
11
- * as a `pending` frame, then live-forwards the manager's own `pending` / `expire` events scoped
12
- * to `name`. A `keepalive`-interval `: ` comment ping is armed via the injected `timer` (default
13
- * the host `setTimeout`). On the request's `AbortSignal` firing (client disconnect OR server
14
- * stop) the keepalive is cancelled, both listeners unsubscribed, and the stream ended — no
15
- * `shutdown` frame is sent, so a reconnecting client is never told the endpoint is gone.
16
- * - **POST (answer).** Same token + `404` checks, then reads the body capped at `options.limit`
17
- * bytes (`413` over, `manager.answer` never called — see {@link TerminalRoutesOptions.limit}),
18
- * parses the JSON body (`400` on invalid JSON, `422` when it isn't an `{ id, value }`
19
- * {@link import('@orkestrel/terminal').isAnswerPayload} shape), and routes it through
20
- * `manager.answer` — `204` on success, `404` for `'terminal'`, `422` for `'unknown'` / `'rejected'`.
21
- *
22
- * @remarks
23
- * The `token` option (a string OR a validator function — {@link TerminalToken}) is validated at
24
- * GET connect, on EVERY POST, and RE-VALIDATED on every keepalive tick of a live SSE stream — a
25
- * stream whose presented token stops validating is torn down rather than left streaming forever.
26
- * Concurrent POST answerers race first-write-wins — a late POST for an already-settled prompt
27
- * returns `422`.
28
- *
29
- * @param manager - The `TerminalManagerInterface` (`@orkestrel/terminal`) whose endpoints are bridged
30
- * @param options - See {@link TerminalRoutesOptions}
31
- * @returns Exactly two {@link TerminalRoute} records — GET then POST — sharing one path
32
- *
33
- * @example
34
- * ```ts
35
- * import { createTerminalRoutes } from '@src/server'
36
- * import { createTerminalManager } from '@orkestrel/terminal'
37
- *
38
- * const manager = createTerminalManager()
39
- * manager.add('assistant')
40
- * const routes = createTerminalRoutes(manager, { token: 'secret' })
41
- * // mount `routes` against any router accepting `{ method, path, handler }`
42
- * ```
43
- */
44
- export declare function createTerminalRoutes(manager: TerminalManagerInterface, options?: TerminalRoutesOptions): readonly TerminalRoute[];
@@ -1,60 +0,0 @@
1
- import { TimerHandler } from '@orkestrel/terminal';
2
- /** The HTTP method literal a {@link TerminalRoute} declares — the exact 7-literal union `@orkestrel/router`'s `Method` accepts. */
3
- export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
4
- /**
5
- * The minimal route-dispatch context a {@link TerminalRoute} handler reads — exactly the frozen,
6
- * URL-decoded `:name` path param slice a router hands a matched handler.
7
- */
8
- export interface TerminalRouteContext {
9
- readonly params: Readonly<Record<string, string>>;
10
- }
11
- /**
12
- * One structural route record {@link import('./factories.js').createTerminalRoutes} returns — a
13
- * plain `{ method, path, handler }` shape carrying NO dependency on `@orkestrel/router`'s own
14
- * `Route` type, so a consumer mounts it against any router that accepts a two-arg
15
- * `(request, context) => Response | Promise<Response>` handler keyed by `method` + `path`.
16
- */
17
- export interface TerminalRoute {
18
- readonly method: Method;
19
- readonly path: string;
20
- readonly handler: (request: Request, context: TerminalRouteContext) => Response | Promise<Response>;
21
- }
22
- /**
23
- * The `token` gate a {@link TerminalRoutesOptions} may configure — a plain string compared for
24
- * equality against the `x-orkestrel-token` header, OR a validator function the consumer fully
25
- * controls, enabling expiry/rotation (a JWT `exp` check, a revocation-list lookup, anything
26
- * time-varying) that a fixed string cannot express. `undefined` disables the auth check entirely.
27
- */
28
- export type TerminalToken = string | ((value: string | undefined) => boolean);
29
- /**
30
- * Options for {@link import('./factories.js').createTerminalRoutes}.
31
- *
32
- * @remarks
33
- * - `path` — the shared `:name`-templated path both the GET (SSE) and POST (answer) routes
34
- * mount under; defaults to {@link import('./constants.js').TERMINAL_ROUTES_PATH}.
35
- * - `token` — a {@link TerminalToken}: a string is compared for equality against the
36
- * `x-orkestrel-token` header; a function receives the header's value (`undefined` when absent)
37
- * and returns whether it validates, letting the consumer roll/expire tokens out-of-band.
38
- * Validated at GET connect, on EVERY POST, and RE-VALIDATED on every keepalive tick of a live
39
- * SSE stream — a stream whose presented token stops validating (rotated, expired, revoked) is
40
- * torn down (the abort/self-heal teardown path, no `shutdown` frame) rather than left open
41
- * forever; the client reconnects and re-authenticates. Omitted ⇒ no auth check. Because
42
- * re-validation only happens on the keepalive tick, the revocation window equals the keepalive
43
- * interval — a token rejected/expired between ticks keeps streaming until the next one. A
44
- * validator function that THROWS is treated as rejection (fail-closed) at every call site.
45
- * - `keepalive` — the SSE comment-ping interval in milliseconds; defaults to
46
- * {@link import('./constants.js').TERMINAL_KEEPALIVE_MS}.
47
- * - `timer` — the injected {@link TimerHandler} driving the keepalive interval (default the host
48
- * `setTimeout`/`clearTimeout`), so a test drives the keepalive deterministically.
49
- * - `limit` — the maximum POST answer body size in bytes, streamed and enforced BEFORE JSON
50
- * parsing (ignoring any `Content-Length` header, so a lying header can never bypass the cap);
51
- * a body exceeding it is rejected `413` and `manager.answer` is never called. Defaults to
52
- * `@orkestrel/server`'s own `DEFAULT_BODY_LIMIT` (1 MiB).
53
- */
54
- export interface TerminalRoutesOptions {
55
- readonly path?: string;
56
- readonly token?: TerminalToken;
57
- readonly keepalive?: number;
58
- readonly timer?: TimerHandler;
59
- readonly limit?: number;
60
- }