@superdoc/sdk 2.8.0 → 2.9.0-next.1
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 +21 -0
- package/dist/generated/contract.cjs +1 -0
- package/dist/generated/contract.js +2 -0
- package/dist/index.cjs +21 -11
- package/dist/index.d.ts +4 -3
- package/dist/index.js +21 -11
- package/dist/presets/core.cjs +62 -10
- package/dist/presets/core.js +62 -10
- package/dist/runtime/host.cjs +23 -0
- package/dist/runtime/host.d.ts +3 -2
- package/dist/runtime/host.js +23 -1
- package/dist/runtime/process.cjs +6 -1
- package/dist/runtime/process.d.ts +4 -3
- package/dist/runtime/process.js +5 -1
- 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.cjs +22 -0
- package/dist/runtime/transport-common.d.ts +11 -0
- package/dist/runtime/transport-common.js +21 -0
- package/package.json +8 -7
- package/tools/__pycache__/__init__.cpython-311.pyc +0 -0
- package/tools/__pycache__/intent_dispatch_generated.cpython-311.pyc +0 -0
package/README.md
CHANGED
|
@@ -25,6 +25,27 @@ await document.close();
|
|
|
25
25
|
await client.dispose();
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
For token-authenticated Hocuspocus or y-websocket rooms, pass the credential as
|
|
29
|
+
an option on that document's open request:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
const document = await client.open(
|
|
33
|
+
{
|
|
34
|
+
doc: './contract.docx',
|
|
35
|
+
collaboration: {
|
|
36
|
+
providerType: 'hocuspocus',
|
|
37
|
+
url: 'wss://collaboration.example.com',
|
|
38
|
+
documentId: 'contract-123',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{ collaborationAuth: { type: 'token', token: userToken } },
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The credential applies only to that open request. It is not part of the
|
|
46
|
+
collaboration profile or command-line arguments. Per-open token authentication
|
|
47
|
+
is not supported for Liveblocks or the standalone document host.
|
|
48
|
+
|
|
28
49
|
See the [Node.js SDK guide](https://docs.superdoc.dev/agents/automation/node-sdk) for a complete workflow.
|
|
29
50
|
|
|
30
51
|
## License
|
|
@@ -2901,6 +2901,7 @@ export const CONTRACT = {
|
|
|
2901
2901
|
"transport": "stdio",
|
|
2902
2902
|
"features": [
|
|
2903
2903
|
"cli.invoke",
|
|
2904
|
+
"collaboration.auth.perOpen",
|
|
2904
2905
|
"document.open",
|
|
2905
2906
|
"document.open.defaultChangeMode",
|
|
2906
2907
|
"document.currentRevision",
|
|
@@ -2931,6 +2932,7 @@ export const CONTRACT = {
|
|
|
2931
2932
|
"protocolVersion": "1.0",
|
|
2932
2933
|
"features": [
|
|
2933
2934
|
"cli.invoke",
|
|
2935
|
+
"collaboration.auth.perOpen",
|
|
2934
2936
|
"document.open",
|
|
2935
2937
|
"document.open.defaultChangeMode",
|
|
2936
2938
|
"document.currentRevision",
|
package/dist/index.cjs
CHANGED
|
@@ -113,6 +113,7 @@ class SuperDocClient {
|
|
|
113
113
|
rawApi;
|
|
114
114
|
defaultDocumentRuntime;
|
|
115
115
|
handles = new Map();
|
|
116
|
+
pendingSessionIds = new Set();
|
|
116
117
|
constructor(options = {}) {
|
|
117
118
|
this.defaultDocumentRuntime = options.runtime;
|
|
118
119
|
this.runtime = new process.SuperDocRuntime(options);
|
|
@@ -133,18 +134,27 @@ class SuperDocClient {
|
|
|
133
134
|
? { ...params, runtime: this.defaultDocumentRuntime }
|
|
134
135
|
: params;
|
|
135
136
|
const explicitSessionId = openParams.sessionId;
|
|
136
|
-
if (typeof explicitSessionId === 'string'
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
if (typeof explicitSessionId === 'string') {
|
|
138
|
+
if (this.handles.has(explicitSessionId) || this.pendingSessionIds.has(explicitSessionId)) {
|
|
139
|
+
throw new errors.SuperDocCliError(`Session id already open in this client: ${explicitSessionId}`, {
|
|
140
|
+
code: 'SESSION_ALREADY_OPEN',
|
|
141
|
+
details: { sessionId: explicitSessionId },
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
this.pendingSessionIds.add(explicitSessionId);
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const result = (await this.rawApi.open(openParams, options));
|
|
148
|
+
const contextId = result.contextId;
|
|
149
|
+
const boundRuntime = new BoundRuntime(this.runtime, contextId);
|
|
150
|
+
const handle = new SuperDocDocument(boundRuntime, contextId, result, this);
|
|
151
|
+
this.handles.set(contextId, handle);
|
|
152
|
+
return handle;
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
if (typeof explicitSessionId === 'string')
|
|
156
|
+
this.pendingSessionIds.delete(explicitSessionId);
|
|
141
157
|
}
|
|
142
|
-
const result = (await this.rawApi.open(openParams, options));
|
|
143
|
-
const contextId = result.contextId;
|
|
144
|
-
const boundRuntime = new BoundRuntime(this.runtime, contextId);
|
|
145
|
-
const handle = new SuperDocDocument(boundRuntime, contextId, result, this);
|
|
146
|
-
this.handles.set(contextId, handle);
|
|
147
|
-
return handle;
|
|
148
158
|
}
|
|
149
159
|
async describe(_params = {}, _options) {
|
|
150
160
|
return introspection.describeContract();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type BoundDocApi, type DocCloseBoundParams, type DocCloseResult, type DocFormatApplyBoundParams, type DocFormatApplyResult, type DocOpenParams as GeneratedDocOpenParams, type DocOpenResult, type DocSaveBoundParams, type DocSaveResult } from './generated/client.js';
|
|
2
|
-
import { SuperDocRuntime, type SuperDocClientOptions, type InvokeOptions, type OperationSpec, type RuntimeInvoker } from './runtime/process.js';
|
|
2
|
+
import { SuperDocRuntime, type SuperDocClientOptions, type DocOpenOptions, type InvokeOptions, type OperationSpec, type RuntimeInvoker } from './runtime/process.js';
|
|
3
3
|
/**
|
|
4
4
|
* Wraps a raw runtime and injects a fixed sessionId into every invoke call.
|
|
5
5
|
* Implements RuntimeInvoker so generated code can use it directly.
|
|
@@ -64,6 +64,7 @@ export declare class SuperDocClient {
|
|
|
64
64
|
private readonly rawApi;
|
|
65
65
|
private readonly defaultDocumentRuntime;
|
|
66
66
|
private readonly handles;
|
|
67
|
+
private readonly pendingSessionIds;
|
|
67
68
|
constructor(options?: SuperDocClientOptions);
|
|
68
69
|
connect(): Promise<void>;
|
|
69
70
|
/**
|
|
@@ -73,7 +74,7 @@ export declare class SuperDocClient {
|
|
|
73
74
|
* automatically. The same file can be opened multiple times with
|
|
74
75
|
* different session ids (useful for diff workflows).
|
|
75
76
|
*/
|
|
76
|
-
open(params: DocOpenParams, options?:
|
|
77
|
+
open(params: DocOpenParams, options?: DocOpenOptions): Promise<SuperDocDocument>;
|
|
77
78
|
describe(_params?: Record<string, unknown>, _options?: InvokeOptions): Promise<unknown>;
|
|
78
79
|
describeCommand(params: DocDescribeCommandParams, _options?: InvokeOptions): Promise<unknown>;
|
|
79
80
|
dispose(): Promise<void>;
|
|
@@ -93,5 +94,5 @@ export type { GetSystemPromptOptions, GetToolsOptions, GetToolsResult, PresetDes
|
|
|
93
94
|
export { createAgentToolkit } from './tools.js';
|
|
94
95
|
export type { AgentToolkit, CreateAgentToolkitInput } from './tools.js';
|
|
95
96
|
export { SuperDocCliError } from './runtime/errors.js';
|
|
96
|
-
export type { InvokeOptions, OperationSpec, OperationParamSpec, RuntimeInvoker, SuperDocClientOptions, } from './runtime/process.js';
|
|
97
|
+
export type { CollaborationAuth, DocOpenOptions, InvokeOptions, OperationSpec, OperationParamSpec, RuntimeInvoker, SuperDocClientOptions, } from './runtime/process.js';
|
|
97
98
|
export type { DocOpenResult } from './generated/client.js';
|
package/dist/index.js
CHANGED
|
@@ -105,6 +105,7 @@ export class SuperDocClient {
|
|
|
105
105
|
rawApi;
|
|
106
106
|
defaultDocumentRuntime;
|
|
107
107
|
handles = new Map();
|
|
108
|
+
pendingSessionIds = new Set();
|
|
108
109
|
constructor(options = {}) {
|
|
109
110
|
this.defaultDocumentRuntime = options.runtime;
|
|
110
111
|
this.runtime = new SuperDocRuntime(options);
|
|
@@ -125,18 +126,27 @@ export class SuperDocClient {
|
|
|
125
126
|
? { ...params, runtime: this.defaultDocumentRuntime }
|
|
126
127
|
: params;
|
|
127
128
|
const explicitSessionId = openParams.sessionId;
|
|
128
|
-
if (typeof explicitSessionId === 'string'
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
if (typeof explicitSessionId === 'string') {
|
|
130
|
+
if (this.handles.has(explicitSessionId) || this.pendingSessionIds.has(explicitSessionId)) {
|
|
131
|
+
throw new SuperDocCliError(`Session id already open in this client: ${explicitSessionId}`, {
|
|
132
|
+
code: 'SESSION_ALREADY_OPEN',
|
|
133
|
+
details: { sessionId: explicitSessionId },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
this.pendingSessionIds.add(explicitSessionId);
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const result = (await this.rawApi.open(openParams, options));
|
|
140
|
+
const contextId = result.contextId;
|
|
141
|
+
const boundRuntime = new BoundRuntime(this.runtime, contextId);
|
|
142
|
+
const handle = new SuperDocDocument(boundRuntime, contextId, result, this);
|
|
143
|
+
this.handles.set(contextId, handle);
|
|
144
|
+
return handle;
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
if (typeof explicitSessionId === 'string')
|
|
148
|
+
this.pendingSessionIds.delete(explicitSessionId);
|
|
133
149
|
}
|
|
134
|
-
const result = (await this.rawApi.open(openParams, options));
|
|
135
|
-
const contextId = result.contextId;
|
|
136
|
-
const boundRuntime = new BoundRuntime(this.runtime, contextId);
|
|
137
|
-
const handle = new SuperDocDocument(boundRuntime, contextId, result, this);
|
|
138
|
-
this.handles.set(contextId, handle);
|
|
139
|
-
return handle;
|
|
140
150
|
}
|
|
141
151
|
async describe(_params = {}, _options) {
|
|
142
152
|
return describeContract();
|
package/dist/presets/core.cjs
CHANGED
|
@@ -392,26 +392,78 @@ async function coreGetCatalog() {
|
|
|
392
392
|
};
|
|
393
393
|
}
|
|
394
394
|
/**
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
395
|
+
* Sentence boundary: terminal punctuation, whitespace, then something that
|
|
396
|
+
* plausibly opens a sentence — including lowercase, because prompt sentences
|
|
397
|
+
* regularly start with an action name ("comment_paragraphs applies ...").
|
|
398
|
+
* The lookbehind guards keep "e.g."/"i.e." from splitting mid-sentence; a
|
|
399
|
+
* false split is still safe because kept fragments are rejoined with their
|
|
400
|
+
* original whitespace, and erring toward MORE splits only narrows what a
|
|
401
|
+
* mention takes down with it.
|
|
402
|
+
*/
|
|
403
|
+
const SENTENCE_BOUNDARY = /((?<![ei]\.[ge]\.)(?<=[.!?])\s+(?=[A-Za-z"(]))/;
|
|
404
|
+
function mentionsAnyAction(text, excludedActions) {
|
|
405
|
+
for (const name of excludedActions) {
|
|
406
|
+
if (new RegExp(`\\b${name}\\b`).test(text))
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Drop the sentences of one prompt line that mention an excluded action.
|
|
413
|
+
* Returns null when nothing usable is left, so the caller drops the line.
|
|
414
|
+
*/
|
|
415
|
+
function stripExcludedActionSentences(line, excludedActions) {
|
|
416
|
+
if (!mentionsAnyAction(line, excludedActions))
|
|
417
|
+
return line;
|
|
418
|
+
// split() with a capturing group keeps the inter-sentence whitespace as
|
|
419
|
+
// separate array elements: even indexes are sentences, odd their separators.
|
|
420
|
+
const parts = line.split(SENTENCE_BOUNDARY);
|
|
421
|
+
const kept = [];
|
|
422
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
423
|
+
if (mentionsAnyAction(parts[i], excludedActions))
|
|
424
|
+
continue;
|
|
425
|
+
kept.push(parts[i]);
|
|
426
|
+
if (i + 1 < parts.length)
|
|
427
|
+
kept.push(parts[i + 1]);
|
|
428
|
+
}
|
|
429
|
+
let result = kept.join('').trimEnd();
|
|
430
|
+
// Losing the first sentence must not lose the bullet marker with it.
|
|
431
|
+
if (result && /^- /.test(line) && !/^- /.test(result))
|
|
432
|
+
result = `- ${result}`;
|
|
433
|
+
// Nothing left beyond the marker means the whole line was about excluded
|
|
434
|
+
// actions — drop it entirely rather than leaving an empty bullet.
|
|
435
|
+
return /[a-zA-Z0-9]/.test(result.replace(/^- /, '')) ? result : null;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Remove excluded actions from the prompt: drop their per-action
|
|
439
|
+
* documentation lines (entries render as single "- name: ..." lines — the
|
|
440
|
+
* drift-guard test enforces the format), then drop any remaining sentence
|
|
441
|
+
* that still mentions one. Guidance prose ("use move_range to relocate a
|
|
442
|
+
* section") is instruction, not a passing cross-reference: leaving it coaches
|
|
443
|
+
* the model into calls the schema forbids and dispatch rejects.
|
|
400
444
|
*/
|
|
401
445
|
function stripExcludedActionLines(prompt, excludedActions) {
|
|
402
446
|
if (excludedActions.size === 0)
|
|
403
447
|
return prompt;
|
|
404
448
|
return prompt
|
|
405
449
|
.split('\n')
|
|
406
|
-
.
|
|
450
|
+
.map((line) => {
|
|
407
451
|
const match = /^- ([a-z_]+)(?: \/ ([a-z_]+))?:/.exec(line);
|
|
408
452
|
if (!match)
|
|
409
|
-
return
|
|
453
|
+
return line;
|
|
410
454
|
const names = [match[1], match[2]].filter((n) => Boolean(n));
|
|
411
|
-
|
|
412
|
-
//
|
|
413
|
-
|
|
455
|
+
const callable = names.filter((name) => !excludedActions.has(name));
|
|
456
|
+
// Drop the line only when EVERY action it documents is excluded; a
|
|
457
|
+
// paired accept/reject line survives if one side remains callable, but
|
|
458
|
+
// its header keeps only the callable name.
|
|
459
|
+
if (callable.length === 0)
|
|
460
|
+
return null;
|
|
461
|
+
if (callable.length === names.length)
|
|
462
|
+
return line;
|
|
463
|
+
return `- ${callable.join(' / ')}:${line.slice(match[0].length)}`;
|
|
414
464
|
})
|
|
465
|
+
.map((line) => (line === null ? null : stripExcludedActionSentences(line, excludedActions)))
|
|
466
|
+
.filter((line) => line !== null)
|
|
415
467
|
.join('\n');
|
|
416
468
|
}
|
|
417
469
|
async function coreGetSystemPrompt(options) {
|
package/dist/presets/core.js
CHANGED
|
@@ -388,26 +388,78 @@ async function coreGetCatalog() {
|
|
|
388
388
|
};
|
|
389
389
|
}
|
|
390
390
|
/**
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
391
|
+
* Sentence boundary: terminal punctuation, whitespace, then something that
|
|
392
|
+
* plausibly opens a sentence — including lowercase, because prompt sentences
|
|
393
|
+
* regularly start with an action name ("comment_paragraphs applies ...").
|
|
394
|
+
* The lookbehind guards keep "e.g."/"i.e." from splitting mid-sentence; a
|
|
395
|
+
* false split is still safe because kept fragments are rejoined with their
|
|
396
|
+
* original whitespace, and erring toward MORE splits only narrows what a
|
|
397
|
+
* mention takes down with it.
|
|
398
|
+
*/
|
|
399
|
+
const SENTENCE_BOUNDARY = /((?<![ei]\.[ge]\.)(?<=[.!?])\s+(?=[A-Za-z"(]))/;
|
|
400
|
+
function mentionsAnyAction(text, excludedActions) {
|
|
401
|
+
for (const name of excludedActions) {
|
|
402
|
+
if (new RegExp(`\\b${name}\\b`).test(text))
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Drop the sentences of one prompt line that mention an excluded action.
|
|
409
|
+
* Returns null when nothing usable is left, so the caller drops the line.
|
|
410
|
+
*/
|
|
411
|
+
function stripExcludedActionSentences(line, excludedActions) {
|
|
412
|
+
if (!mentionsAnyAction(line, excludedActions))
|
|
413
|
+
return line;
|
|
414
|
+
// split() with a capturing group keeps the inter-sentence whitespace as
|
|
415
|
+
// separate array elements: even indexes are sentences, odd their separators.
|
|
416
|
+
const parts = line.split(SENTENCE_BOUNDARY);
|
|
417
|
+
const kept = [];
|
|
418
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
419
|
+
if (mentionsAnyAction(parts[i], excludedActions))
|
|
420
|
+
continue;
|
|
421
|
+
kept.push(parts[i]);
|
|
422
|
+
if (i + 1 < parts.length)
|
|
423
|
+
kept.push(parts[i + 1]);
|
|
424
|
+
}
|
|
425
|
+
let result = kept.join('').trimEnd();
|
|
426
|
+
// Losing the first sentence must not lose the bullet marker with it.
|
|
427
|
+
if (result && /^- /.test(line) && !/^- /.test(result))
|
|
428
|
+
result = `- ${result}`;
|
|
429
|
+
// Nothing left beyond the marker means the whole line was about excluded
|
|
430
|
+
// actions — drop it entirely rather than leaving an empty bullet.
|
|
431
|
+
return /[a-zA-Z0-9]/.test(result.replace(/^- /, '')) ? result : null;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Remove excluded actions from the prompt: drop their per-action
|
|
435
|
+
* documentation lines (entries render as single "- name: ..." lines — the
|
|
436
|
+
* drift-guard test enforces the format), then drop any remaining sentence
|
|
437
|
+
* that still mentions one. Guidance prose ("use move_range to relocate a
|
|
438
|
+
* section") is instruction, not a passing cross-reference: leaving it coaches
|
|
439
|
+
* the model into calls the schema forbids and dispatch rejects.
|
|
396
440
|
*/
|
|
397
441
|
function stripExcludedActionLines(prompt, excludedActions) {
|
|
398
442
|
if (excludedActions.size === 0)
|
|
399
443
|
return prompt;
|
|
400
444
|
return prompt
|
|
401
445
|
.split('\n')
|
|
402
|
-
.
|
|
446
|
+
.map((line) => {
|
|
403
447
|
const match = /^- ([a-z_]+)(?: \/ ([a-z_]+))?:/.exec(line);
|
|
404
448
|
if (!match)
|
|
405
|
-
return
|
|
449
|
+
return line;
|
|
406
450
|
const names = [match[1], match[2]].filter((n) => Boolean(n));
|
|
407
|
-
|
|
408
|
-
//
|
|
409
|
-
|
|
451
|
+
const callable = names.filter((name) => !excludedActions.has(name));
|
|
452
|
+
// Drop the line only when EVERY action it documents is excluded; a
|
|
453
|
+
// paired accept/reject line survives if one side remains callable, but
|
|
454
|
+
// its header keeps only the callable name.
|
|
455
|
+
if (callable.length === 0)
|
|
456
|
+
return null;
|
|
457
|
+
if (callable.length === names.length)
|
|
458
|
+
return line;
|
|
459
|
+
return `- ${callable.join(' / ')}:${line.slice(match[0].length)}`;
|
|
410
460
|
})
|
|
461
|
+
.map((line) => (line === null ? null : stripExcludedActionSentences(line, excludedActions)))
|
|
462
|
+
.filter((line) => line !== null)
|
|
411
463
|
.join('\n');
|
|
412
464
|
}
|
|
413
465
|
async function coreGetSystemPrompt(options) {
|
package/dist/runtime/host.cjs
CHANGED
|
@@ -8,6 +8,7 @@ var documentRpc = require('./document-rpc.cjs');
|
|
|
8
8
|
|
|
9
9
|
const HOST_PROTOCOL_VERSION = '1.0';
|
|
10
10
|
const CLI_HOST_REQUIRED_FEATURES = ['cli.invoke', 'host.shutdown'];
|
|
11
|
+
const COLLABORATION_AUTH_PER_OPEN_FEATURE = 'collaboration.auth.perOpen';
|
|
11
12
|
const DOCUMENT_HOST_REQUIRED_FEATURES = [...documentRpc.DOCUMENT_RPC_FEATURES, 'host.shutdown'];
|
|
12
13
|
const CHANGE_MODES = ['direct', 'tracked'];
|
|
13
14
|
const FORWARD_HOST_STDERR = typeof process !== 'undefined' && typeof process.env?.SUPERDOC_DEBUG_TEXT_REWRITE === 'string'
|
|
@@ -187,7 +188,27 @@ class HostTransport {
|
|
|
187
188
|
return this.runWhileActive(() => this.invokeWhileActive(operation, params, options));
|
|
188
189
|
}
|
|
189
190
|
async invokeWhileActive(operation, params, options) {
|
|
191
|
+
const collaborationAuth = options.collaborationAuth === undefined ? undefined : transportCommon.normalizeCollaborationAuth(options.collaborationAuth);
|
|
192
|
+
if (collaborationAuth !== undefined) {
|
|
193
|
+
if (operation.operationId !== 'doc.open') {
|
|
194
|
+
throw new errors.SuperDocCliError('collaborationAuth is supported only for doc.open requests.', {
|
|
195
|
+
code: 'INVALID_ARGUMENT',
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (this.processMode !== 'cli') {
|
|
199
|
+
throw new errors.SuperDocCliError('Per-open collaboration authentication is not supported by the standalone document host.', {
|
|
200
|
+
code: 'CAPABILITY_UNSUPPORTED',
|
|
201
|
+
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
190
205
|
await this.ensureConnected();
|
|
206
|
+
if (collaborationAuth !== undefined && !this.hostFeatures.has(COLLABORATION_AUTH_PER_OPEN_FEATURE)) {
|
|
207
|
+
throw new errors.SuperDocCliError('The connected CLI host does not support per-open collaboration authentication.', {
|
|
208
|
+
code: 'CAPABILITY_UNSUPPORTED',
|
|
209
|
+
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
210
|
+
});
|
|
211
|
+
}
|
|
191
212
|
const shouldOpenThroughCliTimeoutFallback = this.processMode === 'cli' &&
|
|
192
213
|
(this.requestTimeoutMs !== undefined ||
|
|
193
214
|
(options.timeoutMs !== undefined && !this.hostFeatures.has(documentRpc.DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE)));
|
|
@@ -282,6 +303,7 @@ class HostTransport {
|
|
|
282
303
|
const response = await this.sendJsonRpcRequest('cli.invoke', {
|
|
283
304
|
argv,
|
|
284
305
|
stdinBase64,
|
|
306
|
+
...(collaborationAuth === undefined ? {} : { collaborationAuth }),
|
|
285
307
|
}, watchdogTimeout);
|
|
286
308
|
if (typeof response !== 'object' || response == null || Array.isArray(response)) {
|
|
287
309
|
throw new errors.SuperDocCliError('Host returned invalid cli.invoke result.', {
|
|
@@ -669,6 +691,7 @@ class HostTransport {
|
|
|
669
691
|
}
|
|
670
692
|
}
|
|
671
693
|
|
|
694
|
+
exports.COLLABORATION_AUTH_PER_OPEN_FEATURE = COLLABORATION_AUTH_PER_OPEN_FEATURE;
|
|
672
695
|
exports.HostTransport = HostTransport;
|
|
673
696
|
exports.buildDocumentHostSpawnArgs = buildDocumentHostSpawnArgs;
|
|
674
697
|
exports.buildHostSpawnArgs = buildHostSpawnArgs;
|
package/dist/runtime/host.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type OperationSpec, type SuperDocClientOptions, type TransportInvokeOptions } from './transport-common.js';
|
|
2
|
+
export declare const COLLABORATION_AUTH_PER_OPEN_FEATURE = "collaboration.auth.perOpen";
|
|
2
3
|
export declare function mapCliInvocationResult(operation: OperationSpec, value: unknown): unknown;
|
|
3
4
|
/**
|
|
4
5
|
* Builds the argv passed to `spawn` for `superdoc host --stdio`. Propagates
|
|
@@ -62,7 +63,7 @@ export declare class HostTransport {
|
|
|
62
63
|
connect(): Promise<void>;
|
|
63
64
|
dispose(): Promise<void>;
|
|
64
65
|
private disposeAfterActiveCalls;
|
|
65
|
-
invoke<TData = unknown>(operation: OperationSpec, params?: Record<string, unknown>, options?:
|
|
66
|
+
invoke<TData = unknown>(operation: OperationSpec, params?: Record<string, unknown>, options?: TransportInvokeOptions): Promise<TData>;
|
|
66
67
|
private invokeWhileActive;
|
|
67
68
|
private runWhileActive;
|
|
68
69
|
private ensureConnected;
|
package/dist/runtime/host.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { createInterface } from 'node:readline';
|
|
3
|
-
import { buildOperationArgv, resolveInvocation, } from './transport-common.js';
|
|
3
|
+
import { buildOperationArgv, normalizeCollaborationAuth, resolveInvocation, } from './transport-common.js';
|
|
4
4
|
import { SuperDocCliError } from './errors.js';
|
|
5
5
|
import { DOCUMENT_RPC_FEATURES, DOCUMENT_RPC_DEFAULT_CHANGE_MODE_FEATURE, DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE, DOCUMENT_RPC_SOURCE_SAVE_FEATURE, buildDocumentInvokeParams, buildDocumentOpenParams, canOpenWithDocumentRpc, documentRpcRequestSupportsResponseTimeout, documentRpcEnabled, mapDocumentLifecycleResult, mapDocumentOpenResult, supportsDocumentRpc, } from './document-rpc.js';
|
|
6
6
|
const HOST_PROTOCOL_VERSION = '1.0';
|
|
7
7
|
const CLI_HOST_REQUIRED_FEATURES = ['cli.invoke', 'host.shutdown'];
|
|
8
|
+
export const COLLABORATION_AUTH_PER_OPEN_FEATURE = 'collaboration.auth.perOpen';
|
|
8
9
|
const DOCUMENT_HOST_REQUIRED_FEATURES = [...DOCUMENT_RPC_FEATURES, 'host.shutdown'];
|
|
9
10
|
const CHANGE_MODES = ['direct', 'tracked'];
|
|
10
11
|
const FORWARD_HOST_STDERR = typeof process !== 'undefined' && typeof process.env?.SUPERDOC_DEBUG_TEXT_REWRITE === 'string'
|
|
@@ -184,7 +185,27 @@ export class HostTransport {
|
|
|
184
185
|
return this.runWhileActive(() => this.invokeWhileActive(operation, params, options));
|
|
185
186
|
}
|
|
186
187
|
async invokeWhileActive(operation, params, options) {
|
|
188
|
+
const collaborationAuth = options.collaborationAuth === undefined ? undefined : normalizeCollaborationAuth(options.collaborationAuth);
|
|
189
|
+
if (collaborationAuth !== undefined) {
|
|
190
|
+
if (operation.operationId !== 'doc.open') {
|
|
191
|
+
throw new SuperDocCliError('collaborationAuth is supported only for doc.open requests.', {
|
|
192
|
+
code: 'INVALID_ARGUMENT',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (this.processMode !== 'cli') {
|
|
196
|
+
throw new SuperDocCliError('Per-open collaboration authentication is not supported by the standalone document host.', {
|
|
197
|
+
code: 'CAPABILITY_UNSUPPORTED',
|
|
198
|
+
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
187
202
|
await this.ensureConnected();
|
|
203
|
+
if (collaborationAuth !== undefined && !this.hostFeatures.has(COLLABORATION_AUTH_PER_OPEN_FEATURE)) {
|
|
204
|
+
throw new SuperDocCliError('The connected CLI host does not support per-open collaboration authentication.', {
|
|
205
|
+
code: 'CAPABILITY_UNSUPPORTED',
|
|
206
|
+
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
207
|
+
});
|
|
208
|
+
}
|
|
188
209
|
const shouldOpenThroughCliTimeoutFallback = this.processMode === 'cli' &&
|
|
189
210
|
(this.requestTimeoutMs !== undefined ||
|
|
190
211
|
(options.timeoutMs !== undefined && !this.hostFeatures.has(DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE)));
|
|
@@ -279,6 +300,7 @@ export class HostTransport {
|
|
|
279
300
|
const response = await this.sendJsonRpcRequest('cli.invoke', {
|
|
280
301
|
argv,
|
|
281
302
|
stdinBase64,
|
|
303
|
+
...(collaborationAuth === undefined ? {} : { collaborationAuth }),
|
|
282
304
|
}, watchdogTimeout);
|
|
283
305
|
if (typeof response !== 'object' || response == null || Array.isArray(response)) {
|
|
284
306
|
throw new SuperDocCliError('Host returned invalid cli.invoke result.', {
|
package/dist/runtime/process.cjs
CHANGED
|
@@ -32,6 +32,10 @@ function resolveRuntimeProcess(options = {}, embedded = {
|
|
|
32
32
|
processMode: 'cli',
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
function toSafeInvokeTraceOptions(options) {
|
|
36
|
+
const { collaborationAuth: _collaborationAuth, ...traceOptions } = options;
|
|
37
|
+
return traceOptions;
|
|
38
|
+
}
|
|
35
39
|
/**
|
|
36
40
|
* Internal runtime that delegates operations to a persistent host transport.
|
|
37
41
|
*
|
|
@@ -60,7 +64,7 @@ class SuperDocRuntime {
|
|
|
60
64
|
phase: 'start',
|
|
61
65
|
operationId: operation.operationId,
|
|
62
66
|
params,
|
|
63
|
-
options,
|
|
67
|
+
options: toSafeInvokeTraceOptions(options),
|
|
64
68
|
});
|
|
65
69
|
try {
|
|
66
70
|
const result = await this.transport.invoke(operation, params, options);
|
|
@@ -88,3 +92,4 @@ class SuperDocRuntime {
|
|
|
88
92
|
|
|
89
93
|
exports.SuperDocRuntime = SuperDocRuntime;
|
|
90
94
|
exports.resolveRuntimeProcess = resolveRuntimeProcess;
|
|
95
|
+
exports.toSafeInvokeTraceOptions = toSafeInvokeTraceOptions;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocumentRuntimeKind, InvokeOptions, OperationParamSpec, OperationSpec, RuntimeInvoker, SuperDocClientOptions } from './transport-common.js';
|
|
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
4
|
processMode: 'cli' | 'document';
|
|
@@ -8,6 +8,7 @@ type EmbeddedRuntimeResolvers = {
|
|
|
8
8
|
documentHost: () => string;
|
|
9
9
|
};
|
|
10
10
|
export declare function resolveRuntimeProcess(options?: SuperDocClientOptions, embedded?: EmbeddedRuntimeResolvers): RuntimeProcessResolution;
|
|
11
|
+
export declare function toSafeInvokeTraceOptions(options: TransportInvokeOptions): InvokeOptions;
|
|
11
12
|
/**
|
|
12
13
|
* Internal runtime that delegates operations to a persistent host transport.
|
|
13
14
|
*
|
|
@@ -19,6 +20,6 @@ export declare class SuperDocRuntime {
|
|
|
19
20
|
constructor(options?: SuperDocClientOptions);
|
|
20
21
|
connect(): Promise<void>;
|
|
21
22
|
dispose(): Promise<void>;
|
|
22
|
-
invoke<TData = unknown>(operation: OperationSpec, params?: Record<string, unknown>, options?:
|
|
23
|
+
invoke<TData = unknown>(operation: OperationSpec, params?: Record<string, unknown>, options?: TransportInvokeOptions): Promise<TData>;
|
|
23
24
|
}
|
|
24
|
-
export type { DocumentRuntimeKind, InvokeOptions, OperationParamSpec, OperationSpec, RuntimeInvoker, SuperDocClientOptions, };
|
|
25
|
+
export type { CollaborationAuth, DocumentRuntimeKind, DocOpenOptions, InvokeOptions, OperationParamSpec, OperationSpec, RuntimeInvoker, SuperDocClientOptions, };
|
package/dist/runtime/process.js
CHANGED
|
@@ -29,6 +29,10 @@ export function resolveRuntimeProcess(options = {}, embedded = {
|
|
|
29
29
|
processMode: 'cli',
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
|
+
export function toSafeInvokeTraceOptions(options) {
|
|
33
|
+
const { collaborationAuth: _collaborationAuth, ...traceOptions } = options;
|
|
34
|
+
return traceOptions;
|
|
35
|
+
}
|
|
32
36
|
/**
|
|
33
37
|
* Internal runtime that delegates operations to a persistent host transport.
|
|
34
38
|
*
|
|
@@ -57,7 +61,7 @@ export class SuperDocRuntime {
|
|
|
57
61
|
phase: 'start',
|
|
58
62
|
operationId: operation.operationId,
|
|
59
63
|
params,
|
|
60
|
-
options,
|
|
64
|
+
options: toSafeInvokeTraceOptions(options),
|
|
61
65
|
});
|
|
62
66
|
try {
|
|
63
67
|
const result = await this.transport.invoke(operation, params, options);
|
|
@@ -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.
|
|
6
|
+
const SDK_VERSION = '2.9.0-next.1';
|
|
7
7
|
|
|
8
8
|
exports.SDK_VERSION = SDK_VERSION;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "2.
|
|
1
|
+
export declare const SDK_VERSION = "2.9.0-next.1";
|
|
@@ -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.
|
|
4
|
+
export const SDK_VERSION = '2.9.0-next.1';
|
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
var errors = require('./errors.cjs');
|
|
4
4
|
|
|
5
|
+
function normalizeCollaborationAuth(value) {
|
|
6
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
7
|
+
throw new errors.SuperDocCliError('collaborationAuth must be an object.', { code: 'INVALID_ARGUMENT' });
|
|
8
|
+
}
|
|
9
|
+
const record = value;
|
|
10
|
+
const unknownField = Object.keys(record).find((key) => key !== 'type' && key !== 'token');
|
|
11
|
+
if (unknownField) {
|
|
12
|
+
throw new errors.SuperDocCliError(`collaborationAuth.${unknownField} is not supported.`, {
|
|
13
|
+
code: 'INVALID_ARGUMENT',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
if (record.type !== 'token') {
|
|
17
|
+
throw new errors.SuperDocCliError('collaborationAuth.type must be "token".', { code: 'INVALID_ARGUMENT' });
|
|
18
|
+
}
|
|
19
|
+
if (typeof record.token !== 'string' || record.token.length === 0) {
|
|
20
|
+
throw new errors.SuperDocCliError('collaborationAuth.token must be a non-empty string.', {
|
|
21
|
+
code: 'INVALID_ARGUMENT',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return { type: 'token', token: record.token };
|
|
25
|
+
}
|
|
5
26
|
function hasExtension(filePath, extension) {
|
|
6
27
|
return filePath.toLowerCase().endsWith(extension);
|
|
7
28
|
}
|
|
@@ -165,4 +186,5 @@ function buildOperationArgv(operation, params, options, runtimeTimeoutMs, defaul
|
|
|
165
186
|
|
|
166
187
|
exports.applyOperationParamAliases = applyOperationParamAliases;
|
|
167
188
|
exports.buildOperationArgv = buildOperationArgv;
|
|
189
|
+
exports.normalizeCollaborationAuth = normalizeCollaborationAuth;
|
|
168
190
|
exports.resolveInvocation = resolveInvocation;
|
|
@@ -19,6 +19,17 @@ export interface InvokeOptions {
|
|
|
19
19
|
expectedRevision?: string | number;
|
|
20
20
|
changeMode?: ChangeMode;
|
|
21
21
|
}
|
|
22
|
+
export interface CollaborationAuth {
|
|
23
|
+
type: 'token';
|
|
24
|
+
token: string;
|
|
25
|
+
}
|
|
26
|
+
export interface DocOpenOptions extends InvokeOptions {
|
|
27
|
+
collaborationAuth?: CollaborationAuth;
|
|
28
|
+
}
|
|
29
|
+
export interface TransportInvokeOptions extends InvokeOptions {
|
|
30
|
+
collaborationAuth?: CollaborationAuth;
|
|
31
|
+
}
|
|
32
|
+
export declare function normalizeCollaborationAuth(value: unknown): CollaborationAuth;
|
|
22
33
|
/**
|
|
23
34
|
* Minimal invoke interface that both SuperDocRuntime and BoundRuntime satisfy.
|
|
24
35
|
* Generated code depends on this interface, not on the concrete runtime class.
|
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
import { SuperDocCliError } from './errors.js';
|
|
2
|
+
export function normalizeCollaborationAuth(value) {
|
|
3
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
4
|
+
throw new SuperDocCliError('collaborationAuth must be an object.', { code: 'INVALID_ARGUMENT' });
|
|
5
|
+
}
|
|
6
|
+
const record = value;
|
|
7
|
+
const unknownField = Object.keys(record).find((key) => key !== 'type' && key !== 'token');
|
|
8
|
+
if (unknownField) {
|
|
9
|
+
throw new SuperDocCliError(`collaborationAuth.${unknownField} is not supported.`, {
|
|
10
|
+
code: 'INVALID_ARGUMENT',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
if (record.type !== 'token') {
|
|
14
|
+
throw new SuperDocCliError('collaborationAuth.type must be "token".', { code: 'INVALID_ARGUMENT' });
|
|
15
|
+
}
|
|
16
|
+
if (typeof record.token !== 'string' || record.token.length === 0) {
|
|
17
|
+
throw new SuperDocCliError('collaborationAuth.token must be a non-empty string.', {
|
|
18
|
+
code: 'INVALID_ARGUMENT',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return { type: 'token', token: record.token };
|
|
22
|
+
}
|
|
2
23
|
function hasExtension(filePath, extension) {
|
|
3
24
|
return filePath.toLowerCase().endsWith(extension);
|
|
4
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superdoc/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0-next.1",
|
|
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",
|
|
@@ -37,19 +37,20 @@
|
|
|
37
37
|
"typescript": "^5.9.2"
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
|
-
"@superdoc/sdk-darwin-arm64": "2.
|
|
41
|
-
"@superdoc/sdk-darwin-x64": "2.
|
|
42
|
-
"@superdoc/sdk-linux-x64": "2.
|
|
43
|
-
"@superdoc/sdk-linux-arm64": "2.
|
|
44
|
-
"@superdoc/sdk-windows-x64": "2.
|
|
40
|
+
"@superdoc/sdk-darwin-arm64": "2.9.0-next.1",
|
|
41
|
+
"@superdoc/sdk-darwin-x64": "2.9.0-next.1",
|
|
42
|
+
"@superdoc/sdk-linux-x64": "2.9.0-next.1",
|
|
43
|
+
"@superdoc/sdk-linux-arm64": "2.9.0-next.1",
|
|
44
|
+
"@superdoc/sdk-windows-x64": "2.9.0-next.1"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
|
-
"build": "rm -rf dist && node scripts/embed-version.mjs && node scripts/embed-prompts.mjs && node scripts/embed-tools.mjs && tsc && rollup -c rollup.cjs.config.mjs && rm -rf dist/prompts && mkdir -p dist/prompts && cp src/prompts/*.md dist/prompts/ && pnpm run audit:publish",
|
|
50
|
+
"build": "rm -rf dist && node scripts/embed-version.mjs && node scripts/embed-prompts.mjs && node scripts/embed-tools.mjs && tsc && pnpm run typecheck:consumer && rollup -c rollup.cjs.config.mjs && rm -rf dist/prompts && mkdir -p dist/prompts && cp src/prompts/*.md dist/prompts/ && pnpm run audit:publish",
|
|
51
51
|
"audit:publish": "node ../../../../scripts/audit-publish-artifact.mjs dist --label sdk-node-dist",
|
|
52
52
|
"typecheck": "tsc --noEmit",
|
|
53
|
+
"typecheck:consumer": "tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext ../../../../tests/consumer-typecheck/src/sdk-per-open-collaboration-auth.mts",
|
|
53
54
|
"test:document-host": "bun test src/runtime/__tests__/host-spawn-args.test.ts src/runtime/__tests__/document-rpc.test.ts src/__tests__/structured-document-rpc.e2e.test.ts src/__tests__/request-timeout-ms.e2e.test.ts",
|
|
54
55
|
"smoke:product-action": "node scripts/product-action-smoke.mjs"
|
|
55
56
|
}
|
|
Binary file
|
|
Binary file
|