@superdoc/sdk 2.26.0-next.3 → 2.26.0-next.9
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/README.md +8 -10
- package/dist/embedded-tools.generated.cjs +5 -5
- package/dist/embedded-tools.generated.js +5 -5
- package/dist/generated/client.d.ts +1728 -0
- package/dist/generated/contract.cjs +1 -1
- package/dist/generated/contract.d.ts +0 -10
- package/dist/generated/contract.js +1 -1
- package/dist/runtime/host.cjs +37 -242
- package/dist/runtime/host.d.ts +1 -16
- package/dist/runtime/host.js +36 -241
- package/dist/runtime/process.cjs +0 -26
- package/dist/runtime/process.d.ts +0 -8
- package/dist/runtime/process.js +0 -26
- package/dist/runtime/sdk-policy.d.ts +0 -10
- package/dist/runtime/sdk-version.generated.cjs +1 -1
- package/dist/runtime/sdk-version.generated.d.ts +1 -1
- package/dist/runtime/sdk-version.generated.js +1 -1
- package/dist/runtime/transport-common.d.ts +0 -8
- package/package.json +7 -7
- package/tools/catalog.json +40 -0
- package/tools/generation-receipt.json +57 -19
- package/tools/tools-policy.json +1 -1
- package/tools/tools.anthropic.json +40 -0
- package/tools/tools.generic.json +40 -0
- package/tools/tools.openai.json +40 -0
- package/tools/tools.vercel.json +40 -0
- package/dist/runtime/document-rpc.cjs +0 -351
- package/dist/runtime/document-rpc.d.ts +0 -26
- package/dist/runtime/document-rpc.js +0 -333
- package/dist/runtime/embedded-document-host.cjs +0 -28
- package/dist/runtime/embedded-document-host.d.ts +0 -1
- package/dist/runtime/embedded-document-host.js +0 -23
package/dist/runtime/host.js
CHANGED
|
@@ -5,11 +5,10 @@ import { SdkStateDirectory } from './state-directory.js';
|
|
|
5
5
|
import { registerMutationRevision } from './document-evidence.js';
|
|
6
6
|
import { CONTRACT } from '../generated/contract.js';
|
|
7
7
|
import { SDK_POLICY } from './sdk-policy.js';
|
|
8
|
-
import { DOCUMENT_RPC_DEFAULT_CHANGE_MODE_FEATURE, DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE, DOCUMENT_RPC_REPLACE_FILE_FEATURE, DOCUMENT_RPC_SOURCE_SAVE_FEATURE, buildDocumentInvokeParams, buildDocumentOpenParams, canOpenWithDocumentRpc, documentRpcRequestSupportsResponseTimeout, documentRpcEnabled, mapDocumentLifecycleResult, mapDocumentOpenResult, mapDocumentReplaceFileResult, supportsDocumentRpc, } from './document-rpc.js';
|
|
9
8
|
const HOST_PROTOCOL_VERSION = SDK_POLICY.protocolVersion;
|
|
10
9
|
const CLI_HOST_REQUIRED_FEATURES = SDK_POLICY.cliRequiredFeatures;
|
|
11
10
|
export const COLLABORATION_AUTH_PER_OPEN_FEATURE = SDK_POLICY.features.collaborationAuthPerOpen;
|
|
12
|
-
const
|
|
11
|
+
const HOST_REQUEST_TIMEOUT_FEATURE = SDK_POLICY.features.requestTimeout;
|
|
13
12
|
const CHANGE_MODES = ['direct', 'tracked'];
|
|
14
13
|
const FORWARD_HOST_STDERR = typeof process !== 'undefined' && typeof process.env?.SUPERDOC_DEBUG_TEXT_REWRITE === 'string'
|
|
15
14
|
? process.env.SUPERDOC_DEBUG_TEXT_REWRITE === '1'
|
|
@@ -36,6 +35,30 @@ export function mapCliInvocationResult(operation, value) {
|
|
|
36
35
|
const extracted = value[envelopeKey];
|
|
37
36
|
return extracted === undefined ? value : extracted;
|
|
38
37
|
}
|
|
38
|
+
export function mapDocumentReplaceFileResult(response, sessionId) {
|
|
39
|
+
if (typeof response !== 'object' || response == null || Array.isArray(response)) {
|
|
40
|
+
throw new SuperDocCliError('Host returned invalid document.replaceFile result.', {
|
|
41
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
42
|
+
details: { result: response },
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const record = response;
|
|
46
|
+
if (record.sessionId !== sessionId ||
|
|
47
|
+
record.replaced !== true ||
|
|
48
|
+
typeof record.byteLength !== 'number' ||
|
|
49
|
+
typeof record.revision !== 'string') {
|
|
50
|
+
throw new SuperDocCliError('Host returned invalid document.replaceFile session metadata.', {
|
|
51
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
52
|
+
details: { expectedSessionId: sessionId, result: response },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
contextId: sessionId,
|
|
57
|
+
runtime: 'v2',
|
|
58
|
+
replaced: true,
|
|
59
|
+
document: { byteLength: record.byteLength, revision: record.revision },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
39
62
|
/**
|
|
40
63
|
* Builds the argv passed to `spawn` for `superdoc host --stdio`. Propagates
|
|
41
64
|
* `requestTimeoutMs` to the host via `--request-timeout-ms`, since the SDK
|
|
@@ -50,9 +73,6 @@ export function buildHostSpawnArgs(prefixArgs, options) {
|
|
|
50
73
|
}
|
|
51
74
|
return args;
|
|
52
75
|
}
|
|
53
|
-
export function buildDocumentHostSpawnArgs(prefixArgs) {
|
|
54
|
-
return [...prefixArgs];
|
|
55
|
-
}
|
|
56
76
|
/**
|
|
57
77
|
* Computes the JS-side watchdog timeout for a single JSON-RPC request.
|
|
58
78
|
*
|
|
@@ -78,12 +98,10 @@ export function resolveJsWatchdogTimeout(watchdogTimeoutMs, requestTimeoutMs, ti
|
|
|
78
98
|
}
|
|
79
99
|
return Math.max(watchdogTimeoutMs, HOST_DEFAULT_REQUEST_TIMEOUT_MS + WATCHDOG_HEADROOM_MS);
|
|
80
100
|
}
|
|
81
|
-
/** Transport for the legacy CLI host or the structured document host. */
|
|
82
101
|
export class HostTransport {
|
|
83
102
|
stateDirectory;
|
|
84
103
|
stoppedChildren = new Map();
|
|
85
104
|
hostBin;
|
|
86
|
-
processMode;
|
|
87
105
|
env;
|
|
88
106
|
startupTimeoutMs;
|
|
89
107
|
shutdownTimeoutMs;
|
|
@@ -92,7 +110,6 @@ export class HostTransport {
|
|
|
92
110
|
maxQueueDepth;
|
|
93
111
|
defaultChangeMode;
|
|
94
112
|
user;
|
|
95
|
-
documentRpcEnabled;
|
|
96
113
|
child = null;
|
|
97
114
|
stdoutBuffer = '';
|
|
98
115
|
stdoutDataListener = null;
|
|
@@ -104,15 +121,10 @@ export class HostTransport {
|
|
|
104
121
|
stopping = false;
|
|
105
122
|
activeCalls = new Set();
|
|
106
123
|
hostFeatures = new Set();
|
|
107
|
-
documentRpcSessions = new Set();
|
|
108
124
|
cliLocalSessions = new Set();
|
|
109
|
-
dirtyDocumentRpcSessions = new Set();
|
|
110
|
-
documentRpcMutationStates = new Map();
|
|
111
|
-
indeterminateDiscardCloses = new Set();
|
|
112
125
|
constructor(options) {
|
|
113
126
|
this.stateDirectory = new SdkStateDirectory(options.stateDir);
|
|
114
127
|
this.hostBin = options.hostBin;
|
|
115
|
-
this.processMode = options.processMode ?? 'cli';
|
|
116
128
|
this.env = options.env;
|
|
117
129
|
this.startupTimeoutMs = options.startupTimeoutMs ?? 5_000;
|
|
118
130
|
this.shutdownTimeoutMs = options.shutdownTimeoutMs ?? 5_000;
|
|
@@ -127,17 +139,12 @@ export class HostTransport {
|
|
|
127
139
|
}
|
|
128
140
|
this.defaultChangeMode = options.defaultChangeMode ?? undefined;
|
|
129
141
|
this.user = options.user;
|
|
130
|
-
this.documentRpcEnabled = this.processMode === 'document' || documentRpcEnabled(options.env);
|
|
131
142
|
}
|
|
132
143
|
async connect() {
|
|
133
144
|
await this.runWhileActive(() => this.ensureConnected());
|
|
134
145
|
}
|
|
135
146
|
supportsDocumentFacts(sessionId) {
|
|
136
|
-
return
|
|
137
|
-
(this.documentRpcSessions.has(sessionId) &&
|
|
138
|
-
this.hostFeatures.has('document.currentRevision') &&
|
|
139
|
-
this.hostFeatures.has('document.executionFacts') &&
|
|
140
|
-
this.hostFeatures.has('document.mutationRevision')));
|
|
147
|
+
return this.usesCliDocumentFacts(sessionId);
|
|
141
148
|
}
|
|
142
149
|
usesCliDocumentFacts(sessionId) {
|
|
143
150
|
return this.cliLocalSessions.has(sessionId) && this.hostFeatures.has('cli.invoke.localExecutionFacts');
|
|
@@ -155,18 +162,7 @@ export class HostTransport {
|
|
|
155
162
|
throw new SuperDocCliError('CLI returned an invalid execution revision.', { code: 'HOST_PROTOCOL_ERROR' });
|
|
156
163
|
return page.revision;
|
|
157
164
|
}
|
|
158
|
-
|
|
159
|
-
return undefined;
|
|
160
|
-
}
|
|
161
|
-
await this.ensureConnected();
|
|
162
|
-
const revision = await this.sendJsonRpcRequest('document.currentRevision', { sessionId }, this.resolveWatchdogTimeout(undefined), { requestTimeoutMs: this.resolveDocumentRequestTimeout(undefined) });
|
|
163
|
-
if (typeof revision !== 'string' || revision.trim().length === 0 || revision === 'unknown') {
|
|
164
|
-
throw new SuperDocCliError('Document host returned an invalid current revision.', {
|
|
165
|
-
code: 'HOST_PROTOCOL_ERROR',
|
|
166
|
-
details: { sessionId },
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
return revision;
|
|
165
|
+
return undefined;
|
|
170
166
|
});
|
|
171
167
|
}
|
|
172
168
|
async dispose() {
|
|
@@ -201,16 +197,6 @@ export class HostTransport {
|
|
|
201
197
|
await this.stateDirectory.dispose();
|
|
202
198
|
return;
|
|
203
199
|
}
|
|
204
|
-
try {
|
|
205
|
-
await this.reconcileIndeterminateDiscardCloses();
|
|
206
|
-
await this.persistDirtyDocumentRpcSessions();
|
|
207
|
-
}
|
|
208
|
-
catch (error) {
|
|
209
|
-
if (!this.child && error instanceof SuperDocCliError) {
|
|
210
|
-
this.terminalDisposalError = error;
|
|
211
|
-
}
|
|
212
|
-
throw error;
|
|
213
|
-
}
|
|
214
200
|
const child = this.child;
|
|
215
201
|
try {
|
|
216
202
|
await this.sendJsonRpcRequest('host.shutdown', {}, this.shutdownTimeoutMs);
|
|
@@ -236,29 +222,14 @@ export class HostTransport {
|
|
|
236
222
|
async replaceFile(sessionId, path, options = {}) {
|
|
237
223
|
return this.runWhileActive(async () => {
|
|
238
224
|
await this.ensureConnected();
|
|
239
|
-
if (!this.hostFeatures.has(
|
|
225
|
+
if (!this.hostFeatures.has(SDK_POLICY.features.replaceFile)) {
|
|
240
226
|
throw new SuperDocCliError('The connected host does not support document replacement.', {
|
|
241
227
|
code: 'CAPABILITY_UNSUPPORTED',
|
|
242
|
-
details: { feature:
|
|
228
|
+
details: { feature: SDK_POLICY.features.replaceFile },
|
|
243
229
|
});
|
|
244
230
|
}
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
this.beginDocumentRpcMutation(sessionId);
|
|
248
|
-
try {
|
|
249
|
-
const response = await this.sendJsonRpcRequest(DOCUMENT_RPC_REPLACE_FILE_FEATURE, { sessionId, path }, this.resolveWatchdogTimeout(options.timeoutMs));
|
|
250
|
-
const result = mapDocumentReplaceFileResult(response, sessionId);
|
|
251
|
-
if (tracksDirectSession)
|
|
252
|
-
this.settleDocumentRpcMutation(sessionId, 'applied');
|
|
253
|
-
return result;
|
|
254
|
-
}
|
|
255
|
-
catch (error) {
|
|
256
|
-
if (tracksDirectSession) {
|
|
257
|
-
const indeterminate = error instanceof SuperDocCliError && ['TIMEOUT', 'HOST_TIMEOUT', 'HOST_DISCONNECTED'].includes(error.code);
|
|
258
|
-
this.settleDocumentRpcMutation(sessionId, indeterminate ? 'indeterminate' : 'not-applied');
|
|
259
|
-
}
|
|
260
|
-
throw error;
|
|
261
|
-
}
|
|
231
|
+
const response = await this.sendJsonRpcRequest(SDK_POLICY.features.replaceFile, { sessionId, path }, this.resolveWatchdogTimeout(options.timeoutMs));
|
|
232
|
+
return mapDocumentReplaceFileResult(response, sessionId);
|
|
262
233
|
});
|
|
263
234
|
}
|
|
264
235
|
async invokeWhileActive(operation, params, options) {
|
|
@@ -269,12 +240,6 @@ export class HostTransport {
|
|
|
269
240
|
code: 'INVALID_ARGUMENT',
|
|
270
241
|
});
|
|
271
242
|
}
|
|
272
|
-
if (this.processMode !== 'cli') {
|
|
273
|
-
throw new SuperDocCliError('Per-open collaboration authentication is not supported by the standalone document host.', {
|
|
274
|
-
code: 'CAPABILITY_UNSUPPORTED',
|
|
275
|
-
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
243
|
}
|
|
279
244
|
await this.ensureConnected();
|
|
280
245
|
if (collaborationAuth !== undefined && !this.hostFeatures.has(COLLABORATION_AUTH_PER_OPEN_FEATURE)) {
|
|
@@ -283,88 +248,8 @@ export class HostTransport {
|
|
|
283
248
|
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
284
249
|
});
|
|
285
250
|
}
|
|
286
|
-
const shouldOpenThroughCliTimeoutFallback = this.processMode === 'cli' &&
|
|
287
|
-
(this.requestTimeoutMs !== undefined ||
|
|
288
|
-
(options.timeoutMs !== undefined && !this.hostFeatures.has(DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE)));
|
|
289
|
-
if (this.documentRpcEnabled &&
|
|
290
|
-
supportsDocumentRpc(this.hostFeatures) &&
|
|
291
|
-
(this.defaultChangeMode === undefined || this.hostFeatures.has(DOCUMENT_RPC_DEFAULT_CHANGE_MODE_FEATURE)) &&
|
|
292
|
-
operation.operationId === 'doc.open' &&
|
|
293
|
-
canOpenWithDocumentRpc(params, options) &&
|
|
294
|
-
!shouldOpenThroughCliTimeoutFallback) {
|
|
295
|
-
const opened = buildDocumentOpenParams(params, this.user, this.defaultChangeMode);
|
|
296
|
-
const requestTimeoutMs = this.resolveDocumentRequestTimeout(options.timeoutMs);
|
|
297
|
-
const response = await this.sendJsonRpcRequest('document.open', opened.params, this.resolveWatchdogTimeout(options.timeoutMs), { requestTimeoutMs });
|
|
298
|
-
const result = mapDocumentOpenResult(response, opened.sessionId, params.doc);
|
|
299
|
-
this.documentRpcSessions.add(opened.sessionId);
|
|
300
|
-
this.indeterminateDiscardCloses.delete(opened.sessionId);
|
|
301
|
-
return result;
|
|
302
|
-
}
|
|
303
251
|
const sessionId = typeof params.sessionId === 'string' ? params.sessionId : undefined;
|
|
304
|
-
|
|
305
|
-
const request = buildDocumentInvokeParams(sessionId, operation, params, options, this.hostFeatures);
|
|
306
|
-
const supportsResponseTimeout = documentRpcRequestSupportsResponseTimeout(operation, request);
|
|
307
|
-
const requestTimeoutMs = supportsResponseTimeout
|
|
308
|
-
? this.resolveDocumentRequestTimeout(options.timeoutMs)
|
|
309
|
-
: undefined;
|
|
310
|
-
const documentOperation = operation;
|
|
311
|
-
const requestOptions = typeof request.params.options === 'object' &&
|
|
312
|
-
request.params.options !== null &&
|
|
313
|
-
!Array.isArray(request.params.options)
|
|
314
|
-
? request.params.options
|
|
315
|
-
: undefined;
|
|
316
|
-
const tracksMutation = request.method === 'document.invoke' && documentOperation.mutates === true && requestOptions?.dryRun !== true;
|
|
317
|
-
const includeRevision = request.method === 'document.invoke' &&
|
|
318
|
-
documentOperation.mutates === true &&
|
|
319
|
-
this.hostFeatures.has('document.mutationRevision');
|
|
320
|
-
if (tracksMutation)
|
|
321
|
-
this.beginDocumentRpcMutation(sessionId);
|
|
322
|
-
let result;
|
|
323
|
-
try {
|
|
324
|
-
const response = await this.sendJsonRpcRequest(request.method, { ...request.params, ...(includeRevision ? { includeRevision: true } : {}) }, this.resolveWatchdogTimeout(options.timeoutMs), { requestTimeoutMs });
|
|
325
|
-
result = mapDocumentLifecycleResult(operation.operationId, includeRevision ? response.result : response, sessionId, operation.operationId === 'doc.save' ? request.params.path === undefined : undefined);
|
|
326
|
-
if (includeRevision)
|
|
327
|
-
registerMutationRevision(result, response.revision);
|
|
328
|
-
}
|
|
329
|
-
catch (error) {
|
|
330
|
-
if (tracksMutation) {
|
|
331
|
-
const indeterminate = error instanceof SuperDocCliError && ['TIMEOUT', 'HOST_TIMEOUT', 'HOST_DISCONNECTED'].includes(error.code);
|
|
332
|
-
this.settleDocumentRpcMutation(sessionId, indeterminate ? 'indeterminate' : 'not-applied');
|
|
333
|
-
}
|
|
334
|
-
if (operation.operationId === 'doc.close' &&
|
|
335
|
-
request.params.discard === true &&
|
|
336
|
-
error instanceof SuperDocCliError &&
|
|
337
|
-
error.code === 'TIMEOUT') {
|
|
338
|
-
this.indeterminateDiscardCloses.add(sessionId);
|
|
339
|
-
}
|
|
340
|
-
throw error;
|
|
341
|
-
}
|
|
342
|
-
if (tracksMutation) {
|
|
343
|
-
const failedReceipt = typeof result === 'object' &&
|
|
344
|
-
result !== null &&
|
|
345
|
-
!Array.isArray(result) &&
|
|
346
|
-
result.success === false;
|
|
347
|
-
this.settleDocumentRpcMutation(sessionId, failedReceipt ? 'not-applied' : 'applied');
|
|
348
|
-
}
|
|
349
|
-
if (operation.operationId === 'doc.close') {
|
|
350
|
-
this.documentRpcSessions.delete(sessionId);
|
|
351
|
-
this.clearDirtyDocumentRpcSession(sessionId);
|
|
352
|
-
this.indeterminateDiscardCloses.delete(sessionId);
|
|
353
|
-
}
|
|
354
|
-
else if (operation.operationId === 'doc.save') {
|
|
355
|
-
if (request.params.mode === undefined || request.params.mode === 'review-preserving') {
|
|
356
|
-
this.markDocumentRpcSessionSaved(sessionId);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
return result;
|
|
360
|
-
}
|
|
361
|
-
if (this.processMode === 'document') {
|
|
362
|
-
throw new SuperDocCliError(`Standalone document host does not support ${operation.operationId} through structured RPC v0.`, {
|
|
363
|
-
code: 'DOCUMENT_RPC_INPUT_UNSUPPORTED',
|
|
364
|
-
details: { operationId: operation.operationId },
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
const supportsRequestTimeoutMetadata = this.hostFeatures.has(DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE);
|
|
252
|
+
const supportsRequestTimeoutMetadata = this.hostFeatures.has(HOST_REQUEST_TIMEOUT_FEATURE);
|
|
368
253
|
const cliHostRequestTimeoutMs = this.requestTimeoutMs ?? HOST_DEFAULT_REQUEST_TIMEOUT_MS;
|
|
369
254
|
if (!supportsRequestTimeoutMetadata &&
|
|
370
255
|
options.timeoutMs !== undefined &&
|
|
@@ -372,7 +257,7 @@ export class HostTransport {
|
|
|
372
257
|
throw new SuperDocCliError(`CLI host cannot honor timeoutMs=${options.timeoutMs} above its ${cliHostRequestTimeoutMs}ms request ceiling.`, {
|
|
373
258
|
code: 'DOCUMENT_RPC_INPUT_UNSUPPORTED',
|
|
374
259
|
details: {
|
|
375
|
-
feature:
|
|
260
|
+
feature: HOST_REQUEST_TIMEOUT_FEATURE,
|
|
376
261
|
operationId: operation.operationId,
|
|
377
262
|
timeoutMs: options.timeoutMs,
|
|
378
263
|
hostRequestTimeoutMs: cliHostRequestTimeoutMs,
|
|
@@ -455,9 +340,7 @@ export class HostTransport {
|
|
|
455
340
|
}
|
|
456
341
|
async startHostProcess() {
|
|
457
342
|
const { command, prefixArgs } = resolveInvocation(this.hostBin);
|
|
458
|
-
const args = this.
|
|
459
|
-
? buildDocumentHostSpawnArgs(prefixArgs)
|
|
460
|
-
: buildHostSpawnArgs(prefixArgs, { requestTimeoutMs: this.requestTimeoutMs });
|
|
343
|
+
const args = buildHostSpawnArgs(prefixArgs, { requestTimeoutMs: this.requestTimeoutMs });
|
|
461
344
|
await this.waitForStoppedChildren();
|
|
462
345
|
const env = { ...process.env, ...this.env };
|
|
463
346
|
env.SUPERDOC_CLI_STATE_DIR = await this.stateDirectory.prepare(env);
|
|
@@ -492,7 +375,7 @@ export class HostTransport {
|
|
|
492
375
|
child.on('close', (code, signal) => {
|
|
493
376
|
if (this.child !== child)
|
|
494
377
|
return;
|
|
495
|
-
if (this.stopping
|
|
378
|
+
if (this.stopping) {
|
|
496
379
|
this.cleanupProcess(null);
|
|
497
380
|
return;
|
|
498
381
|
}
|
|
@@ -543,13 +426,7 @@ export class HostTransport {
|
|
|
543
426
|
details: { features },
|
|
544
427
|
});
|
|
545
428
|
}
|
|
546
|
-
const requiredFeatures =
|
|
547
|
-
? [
|
|
548
|
-
...DOCUMENT_HOST_REQUIRED_FEATURES,
|
|
549
|
-
...(this.defaultChangeMode === undefined ? [] : [DOCUMENT_RPC_DEFAULT_CHANGE_MODE_FEATURE]),
|
|
550
|
-
...(this.requestTimeoutMs === undefined ? [] : [DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE]),
|
|
551
|
-
]
|
|
552
|
-
: CLI_HOST_REQUIRED_FEATURES;
|
|
429
|
+
const requiredFeatures = CLI_HOST_REQUIRED_FEATURES;
|
|
553
430
|
for (const requiredFeature of requiredFeatures) {
|
|
554
431
|
if (!features.includes(requiredFeature)) {
|
|
555
432
|
throw new SuperDocCliError(`Host does not support required feature: ${requiredFeature}`, {
|
|
@@ -565,78 +442,6 @@ export class HostTransport {
|
|
|
565
442
|
resolveWatchdogTimeout(timeoutMsOverride) {
|
|
566
443
|
return resolveJsWatchdogTimeout(this.watchdogTimeoutMs, this.requestTimeoutMs, timeoutMsOverride);
|
|
567
444
|
}
|
|
568
|
-
resolveDocumentRequestTimeout(timeoutMsOverride) {
|
|
569
|
-
const requestTimeoutMs = timeoutMsOverride ?? this.requestTimeoutMs;
|
|
570
|
-
if (requestTimeoutMs === undefined)
|
|
571
|
-
return undefined;
|
|
572
|
-
if (this.hostFeatures.has(DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE))
|
|
573
|
-
return requestTimeoutMs;
|
|
574
|
-
if (this.processMode === 'cli' && timeoutMsOverride === undefined)
|
|
575
|
-
return undefined;
|
|
576
|
-
throw new SuperDocCliError(`Structured document RPC host does not support ${DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE}.`, {
|
|
577
|
-
code: 'DOCUMENT_RPC_INPUT_UNSUPPORTED',
|
|
578
|
-
details: { feature: DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE },
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
beginDocumentRpcMutation(sessionId) {
|
|
582
|
-
const state = this.documentRpcMutationStates.get(sessionId) ?? {
|
|
583
|
-
confirmedDirty: this.dirtyDocumentRpcSessions.has(sessionId),
|
|
584
|
-
pendingCount: 0,
|
|
585
|
-
};
|
|
586
|
-
state.pendingCount += 1;
|
|
587
|
-
this.documentRpcMutationStates.set(sessionId, state);
|
|
588
|
-
this.dirtyDocumentRpcSessions.add(sessionId);
|
|
589
|
-
}
|
|
590
|
-
settleDocumentRpcMutation(sessionId, outcome) {
|
|
591
|
-
const state = this.documentRpcMutationStates.get(sessionId);
|
|
592
|
-
if (!state)
|
|
593
|
-
return;
|
|
594
|
-
state.pendingCount = Math.max(0, state.pendingCount - 1);
|
|
595
|
-
if (outcome !== 'not-applied')
|
|
596
|
-
state.confirmedDirty = true;
|
|
597
|
-
if (state.confirmedDirty || state.pendingCount > 0) {
|
|
598
|
-
this.dirtyDocumentRpcSessions.add(sessionId);
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
this.clearDirtyDocumentRpcSession(sessionId);
|
|
602
|
-
}
|
|
603
|
-
clearDirtyDocumentRpcSession(sessionId) {
|
|
604
|
-
this.dirtyDocumentRpcSessions.delete(sessionId);
|
|
605
|
-
this.documentRpcMutationStates.delete(sessionId);
|
|
606
|
-
}
|
|
607
|
-
markDocumentRpcSessionSaved(sessionId) {
|
|
608
|
-
const state = this.documentRpcMutationStates.get(sessionId);
|
|
609
|
-
if (!state || state.pendingCount === 0) {
|
|
610
|
-
this.clearDirtyDocumentRpcSession(sessionId);
|
|
611
|
-
return;
|
|
612
|
-
}
|
|
613
|
-
state.confirmedDirty = false;
|
|
614
|
-
this.dirtyDocumentRpcSessions.add(sessionId);
|
|
615
|
-
}
|
|
616
|
-
async persistDirtyDocumentRpcSessions() {
|
|
617
|
-
if (this.dirtyDocumentRpcSessions.size === 0)
|
|
618
|
-
return;
|
|
619
|
-
if (!this.hostFeatures.has(DOCUMENT_RPC_SOURCE_SAVE_FEATURE)) {
|
|
620
|
-
throw new SuperDocCliError('Document host cannot persist dirty sessions during client disposal because it does not support source saves.', {
|
|
621
|
-
code: 'DOCUMENT_RPC_INPUT_UNSUPPORTED',
|
|
622
|
-
details: { feature: DOCUMENT_RPC_SOURCE_SAVE_FEATURE },
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
for (const sessionId of this.dirtyDocumentRpcSessions) {
|
|
626
|
-
const response = await this.sendJsonRpcRequest('document.save', { sessionId }, this.resolveWatchdogTimeout(undefined));
|
|
627
|
-
mapDocumentLifecycleResult('doc.save', response, sessionId, true);
|
|
628
|
-
this.markDocumentRpcSessionSaved(sessionId);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
async reconcileIndeterminateDiscardCloses() {
|
|
632
|
-
for (const sessionId of this.indeterminateDiscardCloses) {
|
|
633
|
-
const response = await this.sendJsonRpcRequest('document.close', { sessionId, discard: true }, this.resolveWatchdogTimeout(undefined));
|
|
634
|
-
mapDocumentLifecycleResult('doc.close', response, sessionId);
|
|
635
|
-
this.documentRpcSessions.delete(sessionId);
|
|
636
|
-
this.clearDirtyDocumentRpcSession(sessionId);
|
|
637
|
-
this.indeterminateDiscardCloses.delete(sessionId);
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
445
|
async sendJsonRpcRequest(method, params, watchdogTimeoutMs, metadata = {}) {
|
|
641
446
|
const child = this.child;
|
|
642
447
|
if (!child || !child.stdin.writable) {
|
|
@@ -810,17 +615,7 @@ export class HostTransport {
|
|
|
810
615
|
this.cleanupProcess(error);
|
|
811
616
|
}
|
|
812
617
|
cleanupProcess(error) {
|
|
813
|
-
if (error && this.dirtyDocumentRpcSessions.size > 0 && !this.terminalDisposalError) {
|
|
814
|
-
this.terminalDisposalError = new SuperDocCliError('Document host disconnected before dirty sessions could be persisted.', {
|
|
815
|
-
code: 'HOST_DISCONNECTED',
|
|
816
|
-
details: { causeCode: error.code, causeDetails: error.details },
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
618
|
this.hostFeatures.clear();
|
|
820
|
-
this.documentRpcSessions.clear();
|
|
821
|
-
this.dirtyDocumentRpcSessions.clear();
|
|
822
|
-
this.documentRpcMutationStates.clear();
|
|
823
|
-
this.indeterminateDiscardCloses.clear();
|
|
824
619
|
const child = this.child;
|
|
825
620
|
if (child) {
|
|
826
621
|
if (this.stdoutDataListener)
|
package/dist/runtime/process.cjs
CHANGED
|
@@ -5,46 +5,20 @@ var os = require('node:os');
|
|
|
5
5
|
var path = require('node:path');
|
|
6
6
|
var host = require('./host.cjs');
|
|
7
7
|
var embeddedCli = require('./embedded-cli.cjs');
|
|
8
|
-
var embeddedDocumentHost = require('./embedded-document-host.cjs');
|
|
9
8
|
var debugTrace = require('./debug-trace.cjs');
|
|
10
9
|
var errors = require('./errors.cjs');
|
|
11
10
|
|
|
12
11
|
function resolveRuntimeProcess(options = {}, embedded = {
|
|
13
12
|
cli: embeddedCli.resolveEmbeddedCliBinary,
|
|
14
|
-
documentHost: embeddedDocumentHost.resolveEmbeddedDocumentHostBinary,
|
|
15
13
|
}) {
|
|
16
|
-
const configuredDocumentHostPath = options.documentHostPath;
|
|
17
|
-
if (configuredDocumentHostPath !== undefined && configuredDocumentHostPath.trim().length === 0) {
|
|
18
|
-
throw new errors.SuperDocCliError('documentHostPath must be a non-empty path.', {
|
|
19
|
-
code: 'INVALID_ARGUMENT',
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
const configuredDocumentHostBin = options.env?.SUPERDOC_SDK_DOCUMENT_HOST_BIN ?? process.env.SUPERDOC_SDK_DOCUMENT_HOST_BIN;
|
|
23
|
-
const documentHostBin = configuredDocumentHostPath ??
|
|
24
|
-
(configuredDocumentHostBin === 'embedded' ? embedded.documentHost() : configuredDocumentHostBin);
|
|
25
|
-
if (documentHostBin !== undefined && documentHostBin.trim().length === 0) {
|
|
26
|
-
throw new errors.SuperDocCliError('SUPERDOC_SDK_DOCUMENT_HOST_BIN must be a non-empty path.', {
|
|
27
|
-
code: 'INVALID_ARGUMENT',
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
if (documentHostBin !== undefined) {
|
|
31
|
-
return { hostBin: documentHostBin, processMode: 'document' };
|
|
32
|
-
}
|
|
33
14
|
return {
|
|
34
15
|
hostBin: options.env?.SUPERDOC_CLI_BIN ?? process.env.SUPERDOC_CLI_BIN ?? embedded.cli(),
|
|
35
|
-
processMode: 'cli',
|
|
36
16
|
};
|
|
37
17
|
}
|
|
38
18
|
function toSafeInvokeTraceOptions(options) {
|
|
39
19
|
const { collaborationAuth: _collaborationAuth, ...traceOptions } = options;
|
|
40
20
|
return traceOptions;
|
|
41
21
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Internal runtime that delegates operations to a persistent host transport.
|
|
44
|
-
*
|
|
45
|
-
* Uses the standalone document host when explicitly configured. Otherwise it
|
|
46
|
-
* preserves the embedded CLI compatibility path.
|
|
47
|
-
*/
|
|
48
22
|
class SuperDocRuntime {
|
|
49
23
|
transport;
|
|
50
24
|
constructor(options = {}) {
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { CollaborationAuth, DocumentRuntimeKind, DocOpenOptions, InvokeOptions, TransportInvokeOptions, OperationParamSpec, OperationSpec, RuntimeInvoker, SuperDocClientOptions } from './transport-common.js';
|
|
2
2
|
type RuntimeProcessResolution = {
|
|
3
3
|
hostBin: string;
|
|
4
|
-
processMode: 'cli' | 'document';
|
|
5
4
|
};
|
|
6
5
|
type EmbeddedRuntimeResolvers = {
|
|
7
6
|
cli: () => string;
|
|
8
|
-
documentHost: () => string;
|
|
9
7
|
};
|
|
10
8
|
export type ReplaceFileSource = string | Uint8Array | ArrayBuffer;
|
|
11
9
|
export interface ReplaceFileOptions {
|
|
@@ -22,12 +20,6 @@ export interface ReplaceFileResult {
|
|
|
22
20
|
}
|
|
23
21
|
export declare function resolveRuntimeProcess(options?: SuperDocClientOptions, embedded?: EmbeddedRuntimeResolvers): RuntimeProcessResolution;
|
|
24
22
|
export declare function toSafeInvokeTraceOptions(options: TransportInvokeOptions): InvokeOptions;
|
|
25
|
-
/**
|
|
26
|
-
* Internal runtime that delegates operations to a persistent host transport.
|
|
27
|
-
*
|
|
28
|
-
* Uses the standalone document host when explicitly configured. Otherwise it
|
|
29
|
-
* preserves the embedded CLI compatibility path.
|
|
30
|
-
*/
|
|
31
23
|
export declare class SuperDocRuntime {
|
|
32
24
|
private readonly transport;
|
|
33
25
|
constructor(options?: SuperDocClientOptions);
|
package/dist/runtime/process.js
CHANGED
|
@@ -3,45 +3,19 @@ import { tmpdir } from 'node:os';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { HostTransport } from './host.js';
|
|
5
5
|
import { resolveEmbeddedCliBinary } from './embedded-cli.js';
|
|
6
|
-
import { resolveEmbeddedDocumentHostBinary } from './embedded-document-host.js';
|
|
7
6
|
import { writeSdkDebugTrace } from './debug-trace.js';
|
|
8
7
|
import { SuperDocCliError } from './errors.js';
|
|
9
8
|
export function resolveRuntimeProcess(options = {}, embedded = {
|
|
10
9
|
cli: resolveEmbeddedCliBinary,
|
|
11
|
-
documentHost: resolveEmbeddedDocumentHostBinary,
|
|
12
10
|
}) {
|
|
13
|
-
const configuredDocumentHostPath = options.documentHostPath;
|
|
14
|
-
if (configuredDocumentHostPath !== undefined && configuredDocumentHostPath.trim().length === 0) {
|
|
15
|
-
throw new SuperDocCliError('documentHostPath must be a non-empty path.', {
|
|
16
|
-
code: 'INVALID_ARGUMENT',
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
const configuredDocumentHostBin = options.env?.SUPERDOC_SDK_DOCUMENT_HOST_BIN ?? process.env.SUPERDOC_SDK_DOCUMENT_HOST_BIN;
|
|
20
|
-
const documentHostBin = configuredDocumentHostPath ??
|
|
21
|
-
(configuredDocumentHostBin === 'embedded' ? embedded.documentHost() : configuredDocumentHostBin);
|
|
22
|
-
if (documentHostBin !== undefined && documentHostBin.trim().length === 0) {
|
|
23
|
-
throw new SuperDocCliError('SUPERDOC_SDK_DOCUMENT_HOST_BIN must be a non-empty path.', {
|
|
24
|
-
code: 'INVALID_ARGUMENT',
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
if (documentHostBin !== undefined) {
|
|
28
|
-
return { hostBin: documentHostBin, processMode: 'document' };
|
|
29
|
-
}
|
|
30
11
|
return {
|
|
31
12
|
hostBin: options.env?.SUPERDOC_CLI_BIN ?? process.env.SUPERDOC_CLI_BIN ?? embedded.cli(),
|
|
32
|
-
processMode: 'cli',
|
|
33
13
|
};
|
|
34
14
|
}
|
|
35
15
|
export function toSafeInvokeTraceOptions(options) {
|
|
36
16
|
const { collaborationAuth: _collaborationAuth, ...traceOptions } = options;
|
|
37
17
|
return traceOptions;
|
|
38
18
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Internal runtime that delegates operations to a persistent host transport.
|
|
41
|
-
*
|
|
42
|
-
* Uses the standalone document host when explicitly configured. Otherwise it
|
|
43
|
-
* preserves the embedded CLI compatibility path.
|
|
44
|
-
*/
|
|
45
19
|
export class SuperDocRuntime {
|
|
46
20
|
transport;
|
|
47
21
|
constructor(options = {}) {
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
export declare const SDK_POLICY: {
|
|
2
2
|
protocolVersion: string;
|
|
3
3
|
cliRequiredFeatures: readonly string[];
|
|
4
|
-
documentRequiredFeatures: readonly string[];
|
|
5
|
-
documentRpcFeatures: readonly string[];
|
|
6
4
|
features: {
|
|
7
5
|
replaceFile: string;
|
|
8
|
-
defaultChangeMode: string;
|
|
9
|
-
sourceSave: string;
|
|
10
6
|
requestTimeout: string;
|
|
11
7
|
collaborationAuthPerOpen: string;
|
|
12
|
-
documentAuthor: string;
|
|
13
|
-
fullPreset?: string;
|
|
14
8
|
};
|
|
15
|
-
documentOpenFields: readonly string[];
|
|
16
|
-
documentSaveFields: readonly string[];
|
|
17
|
-
documentOptionFields: readonly string[];
|
|
18
|
-
revisionPreflightOperations: readonly string[];
|
|
19
9
|
operationParamAliases: Record<string, Readonly<Record<string, readonly string[]>>>;
|
|
20
10
|
notifications: readonly string[];
|
|
21
11
|
hostDefaultRequestTimeoutMs: number;
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
// AUTO-GENERATED by scripts/embed-version.mjs — DO NOT EDIT.
|
|
4
4
|
// Source of truth: package.json. Regenerated on every SDK build so the
|
|
5
5
|
// SDK retains its own version identity when bundled into another package.
|
|
6
|
-
const SDK_VERSION = '2.26.0-next.
|
|
6
|
+
const SDK_VERSION = '2.26.0-next.9';
|
|
7
7
|
|
|
8
8
|
exports.SDK_VERSION = SDK_VERSION;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "2.26.0-next.
|
|
1
|
+
export declare const SDK_VERSION = "2.26.0-next.9";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// AUTO-GENERATED by scripts/embed-version.mjs — DO NOT EDIT.
|
|
2
2
|
// Source of truth: package.json. Regenerated on every SDK build so the
|
|
3
3
|
// SDK retains its own version identity when bundled into another package.
|
|
4
|
-
export const SDK_VERSION = '2.26.0-next.
|
|
4
|
+
export const SDK_VERSION = '2.26.0-next.9';
|
|
@@ -49,14 +49,6 @@ export interface SuperDocClientOptions {
|
|
|
49
49
|
/** Writable host state root. Takes precedence over SUPERDOC_CLI_STATE_DIR; persists after disposal. */
|
|
50
50
|
stateDir?: string;
|
|
51
51
|
env?: Record<string, string | undefined>;
|
|
52
|
-
/**
|
|
53
|
-
* Standalone document-host entry to use instead of the embedded CLI.
|
|
54
|
-
*
|
|
55
|
-
* The host-only path supports local lifecycle methods and generated Document
|
|
56
|
-
* API operations through structured RPC. Interface-only conveniences fail
|
|
57
|
-
* without CLI fallback.
|
|
58
|
-
*/
|
|
59
|
-
documentHostPath?: string;
|
|
60
52
|
/**
|
|
61
53
|
* Default document engine for `client.open(...)`. Explicit `runtime` on an
|
|
62
54
|
* individual open call takes precedence.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superdoc/sdk",
|
|
3
|
-
"version": "2.26.0-next.
|
|
3
|
+
"version": "2.26.0-next.9",
|
|
4
4
|
"description": "Node SDK for SuperDoc, wrapping the SuperDoc CLI to read and edit .docx files from JavaScript and TypeScript.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"typescript": "^5.9.2"
|
|
39
39
|
},
|
|
40
40
|
"optionalDependencies": {
|
|
41
|
-
"@superdoc/sdk-darwin-arm64": "2.26.0-next.
|
|
42
|
-
"@superdoc/sdk-darwin-x64": "2.26.0-next.
|
|
43
|
-
"@superdoc/sdk-linux-x64": "2.26.0-next.
|
|
44
|
-
"@superdoc/sdk-linux-arm64": "2.26.0-next.
|
|
45
|
-
"@superdoc/sdk-windows-x64": "2.26.0-next.
|
|
41
|
+
"@superdoc/sdk-darwin-arm64": "2.26.0-next.9",
|
|
42
|
+
"@superdoc/sdk-darwin-x64": "2.26.0-next.9",
|
|
43
|
+
"@superdoc/sdk-linux-x64": "2.26.0-next.9",
|
|
44
|
+
"@superdoc/sdk-linux-arm64": "2.26.0-next.9",
|
|
45
|
+
"@superdoc/sdk-windows-x64": "2.26.0-next.9"
|
|
46
46
|
},
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"typecheck": "tsc --noEmit",
|
|
54
54
|
"typecheck:consumer": "tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext ../../../../tests/consumer-typecheck/src/sdk-per-open-collaboration-auth.mts ../../../../tests/consumer-typecheck/src/sdk-replace-file.mts ../../../../tests/consumer-typecheck/src/sdk-retained-paragraph.mts ../../../../tests/consumer-typecheck/src/sdk-state-directory.mts ../../../../tests/consumer-typecheck/src/sdk-agent-evidence.mts ../../../../tests/consumer-typecheck/src/sdk-custom-actions.mts ../../../../tests/consumer-typecheck/src/sd4807-sdk-inspect.mts ../../../../tests/consumer-typecheck/src/sdk-tracked-only-policy.mts ../../../../tests/consumer-typecheck/src/sdk-tracked-review-route.mts ../../../../tests/consumer-typecheck/src/sd5266-sdk-placeholder-null.mts ../../../../tests/consumer-typecheck/src/sdk-schema-types.mts",
|
|
55
55
|
"test:agent-actions": "bun test src/__tests__/actions.test.ts src/__tests__/agent-runtime.test.ts src/__tests__/execution-context.test.ts src/__tests__/custom-actions.test.ts src/__tests__/textbox-snapshot.test.ts",
|
|
56
|
-
"test:
|
|
56
|
+
"test:cli-host": "bun test src/__tests__/diff-direct-styles.e2e.test.ts src/__tests__/default-cli-optimization.e2e.test.ts src/runtime/__tests__/host-spawn-args.test.ts src/runtime/__tests__/cli-host.test.ts src/__tests__/tracked-review-route.test.ts src/__tests__/cli-document-lifecycle.e2e.test.ts src/__tests__/request-timeout-ms.e2e.test.ts src/__tests__/agent-evidence.e2e.test.ts src/__tests__/agent-apply.e2e.test.ts src/__tests__/find-text.e2e.test.ts src/__tests__/custom-actions.e2e.test.ts",
|
|
57
57
|
"smoke:product-action": "node scripts/product-action-smoke.mjs"
|
|
58
58
|
}
|
|
59
59
|
}
|