@clowder-ai/plugin-sdk 0.1.0-beta.5
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/dist/contract-mirror.d.ts +120 -0
- package/dist/contract-mirror.d.ts.map +1 -0
- package/dist/contract-mirror.js +179 -0
- package/dist/contract-mirror.js.map +1 -0
- package/dist/events-publisher.d.ts +34 -0
- package/dist/events-publisher.d.ts.map +1 -0
- package/dist/events-publisher.js +62 -0
- package/dist/events-publisher.js.map +1 -0
- package/dist/handshake-client.d.ts +66 -0
- package/dist/handshake-client.d.ts.map +1 -0
- package/dist/handshake-client.js +124 -0
- package/dist/handshake-client.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/standalone-host.d.ts +43 -0
- package/dist/standalone-host.d.ts.map +1 -0
- package/dist/standalone-host.js +195 -0
- package/dist/standalone-host.js.map +1 -0
- package/dist/stdio-runtime.d.ts +50 -0
- package/dist/stdio-runtime.d.ts.map +1 -0
- package/dist/stdio-runtime.js +294 -0
- package/dist/stdio-runtime.js.map +1 -0
- package/dist/wire-dispatch.d.ts +43 -0
- package/dist/wire-dispatch.d.ts.map +1 -0
- package/dist/wire-dispatch.js +999 -0
- package/dist/wire-dispatch.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,GACrB,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public SDK entrypoint.
|
|
3
|
+
*
|
|
4
|
+
* This package exposes:
|
|
5
|
+
* 1. Schema-neutral NDJSON transport (stdio-runtime, S0/#12)
|
|
6
|
+
* 2. Wire dispatch classifier (wire-dispatch, S1)
|
|
7
|
+
*
|
|
8
|
+
* The beta.8 handshake rows and beta.9 events.publish row are executable;
|
|
9
|
+
* remaining production RPC methods stay reserved. The dispatch
|
|
10
|
+
* classifier gates all methods: CLOSED rows validate input shapes, RESERVED
|
|
11
|
+
* rows fail-closed with T-G (input type is `never` in v0 — no legal params
|
|
12
|
+
* exist).
|
|
13
|
+
*/
|
|
14
|
+
export { NdjsonFrameError, StdioRuntimeFatalError, createStdioChannel, startStdioRuntime, } from './stdio-runtime.js';
|
|
15
|
+
export { loadStandaloneManifest, ManifestStartupError, startStandaloneHost, } from './standalone-host.js';
|
|
16
|
+
export { acceptSessionBinding, beginLocalHandshake, prepareActivation, } from './handshake-client.js';
|
|
17
|
+
export { classifyFrame, } from './wire-dispatch.js';
|
|
18
|
+
export { EventsPublishError, createEventsPublisher, } from './events-publisher.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,GAUlB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,GAalB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,aAAa,GAId,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,GAMtB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Readable, Writable } from 'node:stream';
|
|
2
|
+
import { type ManifestValidationError, type PluginManifest } from '@clowder-ai/plugin-contract';
|
|
3
|
+
import { type StdioChannel, type StdioRuntimeFatalError } from './stdio-runtime.js';
|
|
4
|
+
export declare class ManifestStartupError extends Error {
|
|
5
|
+
readonly errors: readonly ManifestValidationError[];
|
|
6
|
+
constructor(errors: readonly ManifestValidationError[]);
|
|
7
|
+
}
|
|
8
|
+
export interface StandaloneHostOptions {
|
|
9
|
+
/** Untrusted manifest content; it is validated before stdio starts. */
|
|
10
|
+
readonly manifest: unknown;
|
|
11
|
+
/** Caller-owned streams are useful for embedding and tests; provide both or neither. */
|
|
12
|
+
readonly input?: Readable;
|
|
13
|
+
readonly output?: Writable;
|
|
14
|
+
/**
|
|
15
|
+
* Runs before the closed drain row is acknowledged with `result: null`.
|
|
16
|
+
* A cleanup that outlives its drain deadline is acknowledged as expired;
|
|
17
|
+
* callers that need cancellation must arrange it within their callback.
|
|
18
|
+
*/
|
|
19
|
+
readonly onDrain?: (input: {
|
|
20
|
+
readonly deadlineUnixMs: number;
|
|
21
|
+
}) => void | Promise<void>;
|
|
22
|
+
readonly onFatal?: (error: StdioRuntimeFatalError) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface StandaloneHost extends StdioChannel {
|
|
25
|
+
readonly manifest: PluginManifest;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Loads and contract-validates a manifest file for a standalone plugin.
|
|
29
|
+
*
|
|
30
|
+
* File and JSON parsing errors deliberately propagate: callers have not yet
|
|
31
|
+
* started a transport, so no protocol peer can observe a partial startup.
|
|
32
|
+
*/
|
|
33
|
+
export declare function loadStandaloneManifest(path: string | URL): Promise<PluginManifest>;
|
|
34
|
+
/**
|
|
35
|
+
* Starts the fail-closed plugin-side standalone shell.
|
|
36
|
+
*
|
|
37
|
+
* A manifest is validated by the published contract runtime before any stdio
|
|
38
|
+
* listener is attached. Lifecycle rows execute locally. beta.8 handshake
|
|
39
|
+
* requests reach the handler only to receive a conservative standard error;
|
|
40
|
+
* no Broker behavior is present in this shell.
|
|
41
|
+
*/
|
|
42
|
+
export declare function startStandaloneHost(options: StandaloneHostOptions): StandaloneHost;
|
|
43
|
+
//# sourceMappingURL=standalone-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standalone-host.d.ts","sourceRoot":"","sources":["../src/standalone-host.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAQL,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACpB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAIL,KAAK,YAAY,EAEjB,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAG5B,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAC;gBAExC,MAAM,EAAE,SAAS,uBAAuB,EAAE;CAKvD;AAED,MAAM,WAAW,qBAAqB;IACpC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC5D;AAED,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;CACnC;AAyBD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC,CAExF;AAoJD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CAsBlF"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { DEADLINE_EXPIRED_CODE, DEADLINE_EXPIRED_MESSAGE, METHOD_NOT_FOUND_CODE, METHOD_NOT_FOUND_MESSAGE, PARSE_ERROR_CODE, PARSE_ERROR_MESSAGE, validateManifest, } from '@clowder-ai/plugin-contract';
|
|
3
|
+
import { createStdioChannel, startStdioRuntime, } from './stdio-runtime.js';
|
|
4
|
+
import { classifyFrame } from './wire-dispatch.js';
|
|
5
|
+
export class ManifestStartupError extends Error {
|
|
6
|
+
errors;
|
|
7
|
+
constructor(errors) {
|
|
8
|
+
super('plugin manifest failed contract validation');
|
|
9
|
+
this.name = 'ManifestStartupError';
|
|
10
|
+
this.errors = errors;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
class StandaloneProtocolError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'StandaloneProtocolError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function requireValidManifest(value) {
|
|
20
|
+
const validation = validateManifest(value);
|
|
21
|
+
if (!validation.valid) {
|
|
22
|
+
throw new ManifestStartupError(validation.errors);
|
|
23
|
+
}
|
|
24
|
+
return validation.manifest;
|
|
25
|
+
}
|
|
26
|
+
function requireStdioManifest(value) {
|
|
27
|
+
const manifest = requireValidManifest(value);
|
|
28
|
+
if (manifest.runtime.transport !== 'stdio') {
|
|
29
|
+
throw new TypeError('standalone stdio host requires a manifest with runtime.transport "stdio"');
|
|
30
|
+
}
|
|
31
|
+
return manifest;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Loads and contract-validates a manifest file for a standalone plugin.
|
|
35
|
+
*
|
|
36
|
+
* File and JSON parsing errors deliberately propagate: callers have not yet
|
|
37
|
+
* started a transport, so no protocol peer can observe a partial startup.
|
|
38
|
+
*/
|
|
39
|
+
export async function loadStandaloneManifest(path) {
|
|
40
|
+
return requireValidManifest(JSON.parse(await readFile(path, 'utf8')));
|
|
41
|
+
}
|
|
42
|
+
function isObject(value) {
|
|
43
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
44
|
+
}
|
|
45
|
+
function requireRequest(value) {
|
|
46
|
+
const { id, method, params } = value;
|
|
47
|
+
if (typeof id !== 'string' || typeof method !== 'string' || !isObject(params) || !isObject(params.input)) {
|
|
48
|
+
throw new StandaloneProtocolError('classifier accepted a frame outside the standalone request boundary');
|
|
49
|
+
}
|
|
50
|
+
return { id, method, input: params.input };
|
|
51
|
+
}
|
|
52
|
+
function deadlineExpiredResponse(id) {
|
|
53
|
+
return {
|
|
54
|
+
jsonrpc: '2.0',
|
|
55
|
+
id,
|
|
56
|
+
error: {
|
|
57
|
+
code: DEADLINE_EXPIRED_CODE,
|
|
58
|
+
message: DEADLINE_EXPIRED_MESSAGE,
|
|
59
|
+
data: {},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function methodNotFoundResponse(id) {
|
|
64
|
+
return {
|
|
65
|
+
jsonrpc: '2.0',
|
|
66
|
+
id,
|
|
67
|
+
error: { code: METHOD_NOT_FOUND_CODE, message: METHOD_NOT_FOUND_MESSAGE },
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function completesBeforeDrainDeadline(onDrain, deadlineUnixMs) {
|
|
71
|
+
if (Date.now() >= deadlineUnixMs) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const cleanup = Promise.resolve().then(() => onDrain?.({ deadlineUnixMs }));
|
|
75
|
+
while (true) {
|
|
76
|
+
const remaining = deadlineUnixMs - Date.now();
|
|
77
|
+
if (remaining <= 0) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
let deadlineTimer;
|
|
81
|
+
try {
|
|
82
|
+
const completed = await Promise.race([
|
|
83
|
+
cleanup.then(() => true),
|
|
84
|
+
new Promise(resolve => {
|
|
85
|
+
deadlineTimer = setTimeout(resolve, Math.min(remaining, 2 ** 31 - 1), false);
|
|
86
|
+
}),
|
|
87
|
+
]);
|
|
88
|
+
if (completed) {
|
|
89
|
+
return Date.now() < deadlineUnixMs;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
if (deadlineTimer !== undefined) {
|
|
94
|
+
clearTimeout(deadlineTimer);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function createFrameHandler(options) {
|
|
100
|
+
const inFlight = new Map();
|
|
101
|
+
return async (frame) => {
|
|
102
|
+
const dispatch = classifyFrame(frame, inFlight);
|
|
103
|
+
if (dispatch.outcome === 'respond') {
|
|
104
|
+
if (dispatch.response === undefined) {
|
|
105
|
+
throw new StandaloneProtocolError('classifier requested a response without an envelope');
|
|
106
|
+
}
|
|
107
|
+
return dispatch.response;
|
|
108
|
+
}
|
|
109
|
+
if (dispatch.outcome === 'close') {
|
|
110
|
+
throw new StandaloneProtocolError(`classifier rejected frame as ${dispatch.disposition ?? 'unknown'}`);
|
|
111
|
+
}
|
|
112
|
+
if (frame.value.method === 'host.grants.changed') {
|
|
113
|
+
// The notification is closed and legal, but S2 has no grant-gated
|
|
114
|
+
// behavior yet. Accepting it without fabricating a response preserves
|
|
115
|
+
// its notification semantics while keeping authorization fail-closed.
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
const request = requireRequest(frame.value);
|
|
119
|
+
if (request.method === 'broker.hello' ||
|
|
120
|
+
request.method === 'broker.ready' ||
|
|
121
|
+
request.method === 'events.publish') {
|
|
122
|
+
// The public contract makes these Host-bound inputs legal at T-M, but
|
|
123
|
+
// this standalone plugin has no Host Broker. Reply conservatively
|
|
124
|
+
// without storing ingress, session state, or activation.
|
|
125
|
+
return methodNotFoundResponse(request.id);
|
|
126
|
+
}
|
|
127
|
+
if (request.method === 'host.lifecycle.ping') {
|
|
128
|
+
const nonce = request.input.nonce;
|
|
129
|
+
if (typeof nonce !== 'string') {
|
|
130
|
+
throw new StandaloneProtocolError('classifier accepted ping without a nonce');
|
|
131
|
+
}
|
|
132
|
+
return { jsonrpc: '2.0', id: request.id, result: { nonce } };
|
|
133
|
+
}
|
|
134
|
+
if (request.method === 'host.lifecycle.drain') {
|
|
135
|
+
const deadlineUnixMs = request.input.deadlineUnixMs;
|
|
136
|
+
if (typeof deadlineUnixMs !== 'number') {
|
|
137
|
+
throw new StandaloneProtocolError('classifier accepted drain without a deadline');
|
|
138
|
+
}
|
|
139
|
+
if (!(await completesBeforeDrainDeadline(options.onDrain, deadlineUnixMs))) {
|
|
140
|
+
return deadlineExpiredResponse(request.id);
|
|
141
|
+
}
|
|
142
|
+
return { jsonrpc: '2.0', id: request.id, result: null };
|
|
143
|
+
}
|
|
144
|
+
// No other unsupported method reaches this branch. Keep the assertion so
|
|
145
|
+
// a future ready row cannot silently create standalone-shell behavior.
|
|
146
|
+
throw new StandaloneProtocolError(`unsupported accepted method: ${request.method}`);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const respondToInvalidJson = error => error.code === 'INVALID_JSON'
|
|
150
|
+
? {
|
|
151
|
+
jsonrpc: '2.0',
|
|
152
|
+
id: null,
|
|
153
|
+
error: { code: PARSE_ERROR_CODE, message: PARSE_ERROR_MESSAGE },
|
|
154
|
+
}
|
|
155
|
+
: undefined;
|
|
156
|
+
function attachManifest(channel, manifest) {
|
|
157
|
+
return {
|
|
158
|
+
manifest,
|
|
159
|
+
send: frame => channel.send(frame),
|
|
160
|
+
close: () => channel.close(),
|
|
161
|
+
get failed() {
|
|
162
|
+
return channel.failed;
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Starts the fail-closed plugin-side standalone shell.
|
|
168
|
+
*
|
|
169
|
+
* A manifest is validated by the published contract runtime before any stdio
|
|
170
|
+
* listener is attached. Lifecycle rows execute locally. beta.8 handshake
|
|
171
|
+
* requests reach the handler only to receive a conservative standard error;
|
|
172
|
+
* no Broker behavior is present in this shell.
|
|
173
|
+
*/
|
|
174
|
+
export function startStandaloneHost(options) {
|
|
175
|
+
const manifest = requireStdioManifest(options.manifest);
|
|
176
|
+
const hasInput = options.input !== undefined;
|
|
177
|
+
const hasOutput = options.output !== undefined;
|
|
178
|
+
if (hasInput !== hasOutput) {
|
|
179
|
+
throw new TypeError('standalone host requires both input and output streams');
|
|
180
|
+
}
|
|
181
|
+
const onFrame = createFrameHandler(options);
|
|
182
|
+
const channel = hasInput
|
|
183
|
+
? createStdioChannel(options.input, options.output, {
|
|
184
|
+
onFrame,
|
|
185
|
+
onFrameError: respondToInvalidJson,
|
|
186
|
+
onFatal: options.onFatal,
|
|
187
|
+
})
|
|
188
|
+
: startStdioRuntime({
|
|
189
|
+
onFrame,
|
|
190
|
+
onFrameError: respondToInvalidJson,
|
|
191
|
+
onFatal: options.onFatal,
|
|
192
|
+
});
|
|
193
|
+
return attachManifest(channel, manifest);
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=standalone-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standalone-host.js","sourceRoot":"","sources":["../src/standalone-host.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Readable, Writable } from 'node:stream';
|
|
2
|
+
import { NdjsonFrameError, type DecodedNdjsonFrame, type JsonObject } from '@clowder-ai/plugin-contract/conformance';
|
|
3
|
+
export { NdjsonFrameError } from '@clowder-ai/plugin-contract/conformance';
|
|
4
|
+
export type { DecodedNdjsonFrame as StdioFrame, JsonObject, NdjsonFrameErrorCode as StdioFrameErrorCode, } from '@clowder-ai/plugin-contract/conformance';
|
|
5
|
+
export type StdioRuntimeFatalReason = 'FRAME_ERROR' | 'HANDLER_ERROR' | 'INPUT_ERROR' | 'OUTPUT_ERROR';
|
|
6
|
+
export interface StdioRuntimeFatalErrorOptions {
|
|
7
|
+
readonly reason: StdioRuntimeFatalReason;
|
|
8
|
+
readonly cause: unknown;
|
|
9
|
+
}
|
|
10
|
+
/** A terminal channel failure. It deliberately never becomes a protocol frame. */
|
|
11
|
+
export declare class StdioRuntimeFatalError extends Error {
|
|
12
|
+
readonly reason: StdioRuntimeFatalReason;
|
|
13
|
+
constructor(options: StdioRuntimeFatalErrorOptions);
|
|
14
|
+
}
|
|
15
|
+
export type StdioFrameHandler = (frame: DecodedNdjsonFrame) => JsonObject | undefined | Promise<JsonObject | undefined>;
|
|
16
|
+
export type StdioFrameErrorHandler = (error: NdjsonFrameError) => JsonObject | undefined | Promise<JsonObject | undefined>;
|
|
17
|
+
export interface StdioChannelOptions {
|
|
18
|
+
/** Defaults to the contract-owned hard cap; callers may only choose a stricter cap. */
|
|
19
|
+
readonly maxFrameBytes?: number;
|
|
20
|
+
readonly onFrame: StdioFrameHandler;
|
|
21
|
+
/**
|
|
22
|
+
* Lets a protocol shell map an otherwise terminal decoder error to its
|
|
23
|
+
* contract-defined response before this schema-neutral runtime closes.
|
|
24
|
+
*/
|
|
25
|
+
readonly onFrameError?: StdioFrameErrorHandler;
|
|
26
|
+
readonly onFatal?: (error: StdioRuntimeFatalError) => void;
|
|
27
|
+
}
|
|
28
|
+
export interface StdioRuntimeOptions extends StdioChannelOptions {
|
|
29
|
+
}
|
|
30
|
+
export interface StdioChannel {
|
|
31
|
+
/** Encode and write exactly one object frame followed by LF. */
|
|
32
|
+
send(frame: JsonObject): Promise<void>;
|
|
33
|
+
/** Stop accepting input without closing a stream owned by the caller. */
|
|
34
|
+
close(): void;
|
|
35
|
+
readonly failed: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Connect a schema-neutral NDJSON channel to caller-owned streams.
|
|
39
|
+
*
|
|
40
|
+
* Frame processing is serialized, preserving request order without creating
|
|
41
|
+
* a production request/result vocabulary or a Host Broker substitute.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createStdioChannel(input: Readable, output: Writable, options: StdioChannelOptions): StdioChannel;
|
|
44
|
+
/**
|
|
45
|
+
* Start the public standalone SDK runtime on the process standard streams.
|
|
46
|
+
* Diagnostics remain out of stdout; callers may observe fatal errors through
|
|
47
|
+
* `onFatal` and choose to write their own stderr diagnostics.
|
|
48
|
+
*/
|
|
49
|
+
export declare function startStdioRuntime(options: StdioRuntimeOptions): StdioChannel;
|
|
50
|
+
//# sourceMappingURL=stdio-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio-runtime.d.ts","sourceRoot":"","sources":["../src/stdio-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAIL,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,YAAY,EACV,kBAAkB,IAAI,UAAU,EAChC,UAAU,EACV,oBAAoB,IAAI,mBAAmB,GAC5C,MAAM,yCAAyC,CAAC;AAEjD,MAAM,MAAM,uBAAuB,GAC/B,aAAa,GACb,eAAe,GACf,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,kFAAkF;AAClF,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;gBAE7B,OAAO,EAAE,6BAA6B;CAOnD;AAED,MAAM,MAAM,iBAAiB,GAAG,CAC9B,KAAK,EAAE,kBAAkB,KACtB,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;AAC9D,MAAM,MAAM,sBAAsB,GAAG,CACnC,KAAK,EAAE,gBAAgB,KACpB,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;AAC9D,MAAM,WAAW,mBAAmB;IAClC,uFAAuF;IACvF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,sBAAsB,CAAC;IAC/C,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC5D;AAED,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;CAAG;AACnE,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,yEAAyE;IACzE,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAaD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,mBAAmB,GAC3B,YAAY,CAsQd;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAY5E"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { encodeNdjsonFrame, MAX_NDJSON_FRAME_BYTES, NdjsonFrameDecoder, NdjsonFrameError, } from '@clowder-ai/plugin-contract/conformance';
|
|
2
|
+
export { NdjsonFrameError } from '@clowder-ai/plugin-contract/conformance';
|
|
3
|
+
/** A terminal channel failure. It deliberately never becomes a protocol frame. */
|
|
4
|
+
export class StdioRuntimeFatalError extends Error {
|
|
5
|
+
reason;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(`stdio runtime stopped after ${options.reason}`, {
|
|
8
|
+
cause: options.cause,
|
|
9
|
+
});
|
|
10
|
+
this.name = 'StdioRuntimeFatalError';
|
|
11
|
+
this.reason = options.reason;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
// Scan a bounded source window at a time. Complete frames are coalesced only
|
|
15
|
+
// once before reaching the contract decoder, so a near-cap partial frame is
|
|
16
|
+
// neither repeatedly copied nor repeatedly scanned by that decoder.
|
|
17
|
+
const MAX_INPUT_DECODE_SLICE_BYTES = 16 * 1024;
|
|
18
|
+
function nextInputSliceEnd(chunk, offset) {
|
|
19
|
+
const boundedEnd = Math.min(offset + MAX_INPUT_DECODE_SLICE_BYTES, chunk.byteLength);
|
|
20
|
+
const newline = chunk.subarray(offset, boundedEnd).indexOf(0x0a);
|
|
21
|
+
return newline === -1 ? boundedEnd : offset + newline + 1;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Connect a schema-neutral NDJSON channel to caller-owned streams.
|
|
25
|
+
*
|
|
26
|
+
* Frame processing is serialized, preserving request order without creating
|
|
27
|
+
* a production request/result vocabulary or a Host Broker substitute.
|
|
28
|
+
*/
|
|
29
|
+
export function createStdioChannel(input, output, options) {
|
|
30
|
+
const readableEncoding = input.readableEncoding;
|
|
31
|
+
if (readableEncoding !== undefined && readableEncoding !== null) {
|
|
32
|
+
throw new RangeError('stdio input must remain in byte mode');
|
|
33
|
+
}
|
|
34
|
+
let decoder = new NdjsonFrameDecoder(options.maxFrameBytes);
|
|
35
|
+
const maxFrameBytes = options.maxFrameBytes ?? MAX_NDJSON_FRAME_BYTES;
|
|
36
|
+
let accepting = true;
|
|
37
|
+
let fatalError;
|
|
38
|
+
let detached = false;
|
|
39
|
+
let processing = false;
|
|
40
|
+
let inputEnded = false;
|
|
41
|
+
let decoderEnded = false;
|
|
42
|
+
let undecodedSegments = [];
|
|
43
|
+
let undecodedBytes = 0;
|
|
44
|
+
let activeWrites = 0;
|
|
45
|
+
let outputDetachmentRequested = false;
|
|
46
|
+
let outputErrorGracePending = false;
|
|
47
|
+
const discardUndecodedFrame = () => {
|
|
48
|
+
undecodedSegments = [];
|
|
49
|
+
undecodedBytes = 0;
|
|
50
|
+
};
|
|
51
|
+
const takeUndecodedFrame = () => {
|
|
52
|
+
if (undecodedSegments.length === 0) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const frame = undecodedSegments.length === 1
|
|
56
|
+
? undecodedSegments[0]
|
|
57
|
+
: Buffer.concat(undecodedSegments, undecodedBytes);
|
|
58
|
+
discardUndecodedFrame();
|
|
59
|
+
return frame;
|
|
60
|
+
};
|
|
61
|
+
const detachInput = () => {
|
|
62
|
+
input.off('data', onData);
|
|
63
|
+
input.off('end', onEnd);
|
|
64
|
+
input.off('error', onInputError);
|
|
65
|
+
input.off('close', onInputClose);
|
|
66
|
+
};
|
|
67
|
+
const detachOutputError = () => {
|
|
68
|
+
output.off('error', onOutputError);
|
|
69
|
+
};
|
|
70
|
+
const maybeDetachOutputError = () => {
|
|
71
|
+
if (outputDetachmentRequested &&
|
|
72
|
+
activeWrites === 0 &&
|
|
73
|
+
!outputErrorGracePending) {
|
|
74
|
+
detachOutputError();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const requestOutputDetachment = () => {
|
|
78
|
+
outputDetachmentRequested = true;
|
|
79
|
+
maybeDetachOutputError();
|
|
80
|
+
};
|
|
81
|
+
const write = (frame) => {
|
|
82
|
+
activeWrites += 1;
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
try {
|
|
85
|
+
output.write(frame, error => {
|
|
86
|
+
if (error === null || error === undefined) {
|
|
87
|
+
resolve();
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
reject(error);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
reject(error);
|
|
96
|
+
}
|
|
97
|
+
}).finally(() => {
|
|
98
|
+
activeWrites -= 1;
|
|
99
|
+
// A Writable may emit its matching error after invoking its write
|
|
100
|
+
// callback. Defer detachment by one turn so that event remains handled.
|
|
101
|
+
outputErrorGracePending = true;
|
|
102
|
+
setImmediate(() => {
|
|
103
|
+
outputErrorGracePending = false;
|
|
104
|
+
maybeDetachOutputError();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
const detach = () => {
|
|
109
|
+
if (detached) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
detached = true;
|
|
113
|
+
detachInput();
|
|
114
|
+
requestOutputDetachment();
|
|
115
|
+
};
|
|
116
|
+
const fail = (reason, cause) => {
|
|
117
|
+
if (fatalError !== undefined) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
accepting = false;
|
|
121
|
+
fatalError = new StdioRuntimeFatalError({ reason, cause });
|
|
122
|
+
discardUndecodedFrame();
|
|
123
|
+
input.pause();
|
|
124
|
+
detach();
|
|
125
|
+
options.onFatal?.(fatalError);
|
|
126
|
+
};
|
|
127
|
+
const send = async (frame) => {
|
|
128
|
+
if (!accepting) {
|
|
129
|
+
throw new NdjsonFrameError('DECODER_CLOSED', 'stdio channel is closed');
|
|
130
|
+
}
|
|
131
|
+
const encoded = encodeNdjsonFrame(frame, options.maxFrameBytes);
|
|
132
|
+
try {
|
|
133
|
+
await write(encoded);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
fail('OUTPUT_ERROR', error);
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const finishDecoder = () => {
|
|
141
|
+
if (!accepting || decoderEnded) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
decoderEnded = true;
|
|
145
|
+
try {
|
|
146
|
+
const pendingFrame = takeUndecodedFrame();
|
|
147
|
+
if (pendingFrame !== undefined) {
|
|
148
|
+
decoder.push(pendingFrame);
|
|
149
|
+
}
|
|
150
|
+
decoder.end();
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
fail('FRAME_ERROR', error);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const onData = (chunk) => {
|
|
157
|
+
if (!accepting) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (processing) {
|
|
161
|
+
fail('INPUT_ERROR', new Error('stdio input emitted data while processing was paused'));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// A data listener puts Readable into flowing mode. Pause before decoding so
|
|
165
|
+
// a slow handler or output write cannot accumulate an unbounded Promise
|
|
166
|
+
// chain from later source chunks.
|
|
167
|
+
processing = true;
|
|
168
|
+
input.pause();
|
|
169
|
+
if (!(chunk instanceof Uint8Array)) {
|
|
170
|
+
fail('INPUT_ERROR', new TypeError('stdio input must emit Uint8Array chunks'));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
void processChunk(chunk);
|
|
174
|
+
};
|
|
175
|
+
const processChunk = async (chunk) => {
|
|
176
|
+
try {
|
|
177
|
+
let offset = 0;
|
|
178
|
+
while (offset < chunk.byteLength && accepting) {
|
|
179
|
+
const nextOffset = nextInputSliceEnd(chunk, offset);
|
|
180
|
+
const segment = chunk.subarray(offset, nextOffset);
|
|
181
|
+
undecodedSegments.push(segment);
|
|
182
|
+
undecodedBytes += segment.byteLength;
|
|
183
|
+
offset = nextOffset;
|
|
184
|
+
if (segment.at(-1) !== 0x0a && undecodedBytes <= maxFrameBytes) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
let frames;
|
|
188
|
+
try {
|
|
189
|
+
const frame = takeUndecodedFrame();
|
|
190
|
+
if (frame === undefined) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
frames = decoder.push(frame);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (error instanceof NdjsonFrameError) {
|
|
197
|
+
const response = options.onFrameError === undefined
|
|
198
|
+
? undefined
|
|
199
|
+
: await options.onFrameError(error);
|
|
200
|
+
if (response !== undefined && accepting) {
|
|
201
|
+
await send(response);
|
|
202
|
+
// The decoder deliberately fails closed after any bad frame.
|
|
203
|
+
// A protocol shell that supplied a response has consumed that
|
|
204
|
+
// complete frame, so it may explicitly resume at the next LF.
|
|
205
|
+
decoder = new NdjsonFrameDecoder(options.maxFrameBytes);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
fail('FRAME_ERROR', error);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
for (const frame of frames) {
|
|
213
|
+
if (!accepting) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const response = await options.onFrame(frame);
|
|
217
|
+
if (response !== undefined && accepting) {
|
|
218
|
+
await send(response);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
fail('HANDLER_ERROR', error);
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
processing = false;
|
|
228
|
+
if (inputEnded) {
|
|
229
|
+
finishDecoder();
|
|
230
|
+
}
|
|
231
|
+
else if (accepting) {
|
|
232
|
+
input.resume();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const onEnd = () => {
|
|
237
|
+
inputEnded = true;
|
|
238
|
+
if (!processing) {
|
|
239
|
+
finishDecoder();
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const onInputError = (error) => fail('INPUT_ERROR', error);
|
|
243
|
+
const onInputClose = () => {
|
|
244
|
+
if (!inputEnded) {
|
|
245
|
+
inputEnded = true;
|
|
246
|
+
if (!processing) {
|
|
247
|
+
finishDecoder();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (fatalError === undefined) {
|
|
251
|
+
detachInput();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const onOutputError = (error) => fail('OUTPUT_ERROR', error);
|
|
255
|
+
input.on('data', onData);
|
|
256
|
+
input.once('end', onEnd);
|
|
257
|
+
input.once('error', onInputError);
|
|
258
|
+
input.once('close', onInputClose);
|
|
259
|
+
output.once('error', onOutputError);
|
|
260
|
+
return {
|
|
261
|
+
send,
|
|
262
|
+
close: () => {
|
|
263
|
+
if (detached) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
accepting = false;
|
|
267
|
+
discardUndecodedFrame();
|
|
268
|
+
detach();
|
|
269
|
+
input.pause();
|
|
270
|
+
},
|
|
271
|
+
get failed() {
|
|
272
|
+
return fatalError !== undefined;
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Start the public standalone SDK runtime on the process standard streams.
|
|
278
|
+
* Diagnostics remain out of stdout; callers may observe fatal errors through
|
|
279
|
+
* `onFatal` and choose to write their own stderr diagnostics.
|
|
280
|
+
*/
|
|
281
|
+
export function startStdioRuntime(options) {
|
|
282
|
+
return createStdioChannel(process.stdin, process.stdout, {
|
|
283
|
+
...options,
|
|
284
|
+
onFatal: error => {
|
|
285
|
+
process.exitCode = 1;
|
|
286
|
+
// The standalone runtime owns process.stdin. A framing fatal closes that
|
|
287
|
+
// transport immediately, instead of remaining alive until a hostile or
|
|
288
|
+
// broken parent eventually sends EOF.
|
|
289
|
+
process.stdin.destroy();
|
|
290
|
+
options.onFatal?.(error);
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=stdio-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio-runtime.js","sourceRoot":"","sources":["../src/stdio-runtime.ts"],"names":[],"mappings":"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"}
|