@superdoc/sdk 2.4.1 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/embedded-tools.generated.cjs +5 -5
- package/dist/embedded-tools.generated.js +5 -5
- package/dist/generated/client.d.ts +5 -0
- package/dist/generated/contract.cjs +38 -3
- package/dist/generated/contract.js +42 -3
- package/dist/runtime/document-rpc.cjs +189 -0
- package/dist/runtime/document-rpc.d.ts +15 -0
- package/dist/runtime/document-rpc.js +177 -0
- package/dist/runtime/host.cjs +73 -12
- package/dist/runtime/host.d.ts +9 -5
- package/dist/runtime/host.js +72 -12
- package/dist/runtime/process.cjs +13 -5
- package/dist/runtime/process.d.ts +3 -3
- package/dist/runtime/process.js +13 -5
- package/package.json +7 -6
- package/tools/__pycache__/__init__.cpython-311.pyc +0 -0
- package/tools/__pycache__/intent_dispatch_generated.cpython-311.pyc +0 -0
- package/tools/catalog.json +2 -2
- package/tools/tools-policy.json +1 -1
- package/tools/tools.anthropic.json +2 -2
- package/tools/tools.generic.json +2 -2
- package/tools/tools.openai.json +2 -2
- package/tools/tools.vercel.json +2 -2
|
@@ -3065,6 +3065,7 @@ export interface DocBlocksListParams {
|
|
|
3065
3065
|
limit?: number;
|
|
3066
3066
|
nodeTypes?: Array<"paragraph" | "heading" | "listItem" | "table" | "tableRow" | "tableCell" | "tableOfContents" | "image" | "sdt">;
|
|
3067
3067
|
includeText?: boolean;
|
|
3068
|
+
reviewMode?: string;
|
|
3068
3069
|
}
|
|
3069
3070
|
export interface DocBlocksDeleteParams {
|
|
3070
3071
|
doc?: string;
|
|
@@ -17345,6 +17346,7 @@ export interface DocListsSetLevelNumberingParams {
|
|
|
17345
17346
|
numFmt?: string;
|
|
17346
17347
|
lvlText?: string;
|
|
17347
17348
|
start?: number;
|
|
17349
|
+
isLgl?: boolean;
|
|
17348
17350
|
input?: Record<string, unknown> | unknown[];
|
|
17349
17351
|
}
|
|
17350
17352
|
export interface DocListsSetLevelBulletParams {
|
|
@@ -37454,6 +37456,7 @@ export type DocBlocksListResult = {
|
|
|
37454
37456
|
ref?: string;
|
|
37455
37457
|
}>;
|
|
37456
37458
|
revision: string;
|
|
37459
|
+
reviewMode: "final" | "original" | "redline";
|
|
37457
37460
|
};
|
|
37458
37461
|
export type DocBlocksDeleteResult = {
|
|
37459
37462
|
success: true;
|
|
@@ -117209,6 +117212,7 @@ export interface DocBlocksListBoundParams {
|
|
|
117209
117212
|
limit?: number;
|
|
117210
117213
|
nodeTypes?: Array<"paragraph" | "heading" | "listItem" | "table" | "tableRow" | "tableCell" | "tableOfContents" | "image" | "sdt">;
|
|
117211
117214
|
includeText?: boolean;
|
|
117215
|
+
reviewMode?: string;
|
|
117212
117216
|
}
|
|
117213
117217
|
export interface DocBlocksDeleteBoundParams {
|
|
117214
117218
|
out?: string;
|
|
@@ -131245,6 +131249,7 @@ export interface DocListsSetLevelNumberingBoundParams {
|
|
|
131245
131249
|
numFmt?: string;
|
|
131246
131250
|
lvlText?: string;
|
|
131247
131251
|
start?: number;
|
|
131252
|
+
isLgl?: boolean;
|
|
131248
131253
|
input?: Record<string, unknown> | unknown[];
|
|
131249
131254
|
}
|
|
131250
131255
|
export interface DocListsSetLevelBulletBoundParams {
|
|
@@ -24279,7 +24279,7 @@ const CONTRACT = {
|
|
|
24279
24279
|
"list"
|
|
24280
24280
|
],
|
|
24281
24281
|
"category": "core",
|
|
24282
|
-
"description": "List top-level blocks in document order with IDs, types, text previews, and optional full text when includeText:true. Supports pagination via offset/limit, optional nodeType filtering,
|
|
24282
|
+
"description": "List top-level blocks in document order with IDs, types, text previews, and optional full text when includeText:true. Supports pagination via offset/limit, optional nodeType filtering, single-story scoping via `in: <StoryLocator>`, and final/original/redline projection of numbering metadata without changing block membership.",
|
|
24283
24283
|
"requiresDocumentContext": true,
|
|
24284
24284
|
"docRequirement": "optional",
|
|
24285
24285
|
"responseEnvelopeKey": "result",
|
|
@@ -24539,6 +24539,25 @@ const CONTRACT = {
|
|
|
24539
24539
|
"type": "boolean",
|
|
24540
24540
|
"flag": "include-text",
|
|
24541
24541
|
"description": "When true, includes the full flattened block text in each block entry."
|
|
24542
|
+
},
|
|
24543
|
+
{
|
|
24544
|
+
"name": "reviewMode",
|
|
24545
|
+
"kind": "flag",
|
|
24546
|
+
"type": "string",
|
|
24547
|
+
"flag": "review-mode",
|
|
24548
|
+
"schema": {
|
|
24549
|
+
"oneOf": [
|
|
24550
|
+
{
|
|
24551
|
+
"const": "final"
|
|
24552
|
+
},
|
|
24553
|
+
{
|
|
24554
|
+
"const": "original"
|
|
24555
|
+
},
|
|
24556
|
+
{
|
|
24557
|
+
"const": "redline"
|
|
24558
|
+
}
|
|
24559
|
+
]
|
|
24560
|
+
}
|
|
24542
24561
|
}
|
|
24543
24562
|
],
|
|
24544
24563
|
"constraints": null,
|
|
@@ -24582,6 +24601,9 @@ const CONTRACT = {
|
|
|
24582
24601
|
"includeText": {
|
|
24583
24602
|
"type": "boolean",
|
|
24584
24603
|
"description": "When true, includes the full flattened block text in each block entry."
|
|
24604
|
+
},
|
|
24605
|
+
"reviewMode": {
|
|
24606
|
+
"$ref": "#/$defs/SDProjectionReviewMode"
|
|
24585
24607
|
}
|
|
24586
24608
|
},
|
|
24587
24609
|
"additionalProperties": false
|
|
@@ -24730,13 +24752,17 @@ const CONTRACT = {
|
|
|
24730
24752
|
},
|
|
24731
24753
|
"revision": {
|
|
24732
24754
|
"type": "string"
|
|
24755
|
+
},
|
|
24756
|
+
"reviewMode": {
|
|
24757
|
+
"$ref": "#/$defs/SDProjectionReviewMode"
|
|
24733
24758
|
}
|
|
24734
24759
|
},
|
|
24735
24760
|
"additionalProperties": false,
|
|
24736
24761
|
"required": [
|
|
24737
24762
|
"total",
|
|
24738
24763
|
"blocks",
|
|
24739
|
-
"revision"
|
|
24764
|
+
"revision",
|
|
24765
|
+
"reviewMode"
|
|
24740
24766
|
]
|
|
24741
24767
|
},
|
|
24742
24768
|
"intentGroup": "get_content",
|
|
@@ -138369,7 +138395,7 @@ const CONTRACT = {
|
|
|
138369
138395
|
"set-level-numbering"
|
|
138370
138396
|
],
|
|
138371
138397
|
"category": "lists",
|
|
138372
|
-
"description": "Advanced alias for lists.setLevelNumberStyle/setLevelText/setLevelStart. Set format, pattern, and
|
|
138398
|
+
"description": "Advanced alias for lists.setLevelNumberStyle/setLevelText/setLevelStart. Set format, pattern, start, and legal numbering in one call (abstract-scoped, no clone-on-write).",
|
|
138373
138399
|
"requiresDocumentContext": true,
|
|
138374
138400
|
"docRequirement": "optional",
|
|
138375
138401
|
"responseEnvelopeKey": "result",
|
|
@@ -138645,6 +138671,12 @@ const CONTRACT = {
|
|
|
138645
138671
|
"kind": "flag",
|
|
138646
138672
|
"type": "number"
|
|
138647
138673
|
},
|
|
138674
|
+
{
|
|
138675
|
+
"name": "isLgl",
|
|
138676
|
+
"kind": "flag",
|
|
138677
|
+
"type": "boolean",
|
|
138678
|
+
"flag": "is-lgl"
|
|
138679
|
+
},
|
|
138648
138680
|
{
|
|
138649
138681
|
"name": "input",
|
|
138650
138682
|
"kind": "jsonFlag",
|
|
@@ -138677,6 +138709,9 @@ const CONTRACT = {
|
|
|
138677
138709
|
},
|
|
138678
138710
|
"start": {
|
|
138679
138711
|
"type": "integer"
|
|
138712
|
+
},
|
|
138713
|
+
"isLgl": {
|
|
138714
|
+
"type": "boolean"
|
|
138680
138715
|
}
|
|
138681
138716
|
},
|
|
138682
138717
|
"additionalProperties": false,
|
|
@@ -2901,6 +2901,10 @@ export const CONTRACT = {
|
|
|
2901
2901
|
"transport": "stdio",
|
|
2902
2902
|
"features": [
|
|
2903
2903
|
"cli.invoke",
|
|
2904
|
+
"document.open",
|
|
2905
|
+
"document.invoke",
|
|
2906
|
+
"document.save",
|
|
2907
|
+
"document.close",
|
|
2904
2908
|
"host.shutdown",
|
|
2905
2909
|
"host.describe",
|
|
2906
2910
|
"host.describe.command"
|
|
@@ -27186,7 +27190,7 @@ export const CONTRACT = {
|
|
|
27186
27190
|
"list"
|
|
27187
27191
|
],
|
|
27188
27192
|
"category": "core",
|
|
27189
|
-
"description": "List top-level blocks in document order with IDs, types, text previews, and optional full text when includeText:true. Supports pagination via offset/limit, optional nodeType filtering,
|
|
27193
|
+
"description": "List top-level blocks in document order with IDs, types, text previews, and optional full text when includeText:true. Supports pagination via offset/limit, optional nodeType filtering, single-story scoping via `in: <StoryLocator>`, and final/original/redline projection of numbering metadata without changing block membership.",
|
|
27190
27194
|
"requiresDocumentContext": true,
|
|
27191
27195
|
"docRequirement": "optional",
|
|
27192
27196
|
"responseEnvelopeKey": "result",
|
|
@@ -27446,6 +27450,25 @@ export const CONTRACT = {
|
|
|
27446
27450
|
"type": "boolean",
|
|
27447
27451
|
"flag": "include-text",
|
|
27448
27452
|
"description": "When true, includes the full flattened block text in each block entry."
|
|
27453
|
+
},
|
|
27454
|
+
{
|
|
27455
|
+
"name": "reviewMode",
|
|
27456
|
+
"kind": "flag",
|
|
27457
|
+
"type": "string",
|
|
27458
|
+
"flag": "review-mode",
|
|
27459
|
+
"schema": {
|
|
27460
|
+
"oneOf": [
|
|
27461
|
+
{
|
|
27462
|
+
"const": "final"
|
|
27463
|
+
},
|
|
27464
|
+
{
|
|
27465
|
+
"const": "original"
|
|
27466
|
+
},
|
|
27467
|
+
{
|
|
27468
|
+
"const": "redline"
|
|
27469
|
+
}
|
|
27470
|
+
]
|
|
27471
|
+
}
|
|
27449
27472
|
}
|
|
27450
27473
|
],
|
|
27451
27474
|
"constraints": null,
|
|
@@ -27489,6 +27512,9 @@ export const CONTRACT = {
|
|
|
27489
27512
|
"includeText": {
|
|
27490
27513
|
"type": "boolean",
|
|
27491
27514
|
"description": "When true, includes the full flattened block text in each block entry."
|
|
27515
|
+
},
|
|
27516
|
+
"reviewMode": {
|
|
27517
|
+
"$ref": "#/$defs/SDProjectionReviewMode"
|
|
27492
27518
|
}
|
|
27493
27519
|
},
|
|
27494
27520
|
"additionalProperties": false
|
|
@@ -27637,13 +27663,17 @@ export const CONTRACT = {
|
|
|
27637
27663
|
},
|
|
27638
27664
|
"revision": {
|
|
27639
27665
|
"type": "string"
|
|
27666
|
+
},
|
|
27667
|
+
"reviewMode": {
|
|
27668
|
+
"$ref": "#/$defs/SDProjectionReviewMode"
|
|
27640
27669
|
}
|
|
27641
27670
|
},
|
|
27642
27671
|
"additionalProperties": false,
|
|
27643
27672
|
"required": [
|
|
27644
27673
|
"total",
|
|
27645
27674
|
"blocks",
|
|
27646
|
-
"revision"
|
|
27675
|
+
"revision",
|
|
27676
|
+
"reviewMode"
|
|
27647
27677
|
]
|
|
27648
27678
|
},
|
|
27649
27679
|
"intentGroup": "get_content",
|
|
@@ -141276,7 +141306,7 @@ export const CONTRACT = {
|
|
|
141276
141306
|
"set-level-numbering"
|
|
141277
141307
|
],
|
|
141278
141308
|
"category": "lists",
|
|
141279
|
-
"description": "Advanced alias for lists.setLevelNumberStyle/setLevelText/setLevelStart. Set format, pattern, and
|
|
141309
|
+
"description": "Advanced alias for lists.setLevelNumberStyle/setLevelText/setLevelStart. Set format, pattern, start, and legal numbering in one call (abstract-scoped, no clone-on-write).",
|
|
141280
141310
|
"requiresDocumentContext": true,
|
|
141281
141311
|
"docRequirement": "optional",
|
|
141282
141312
|
"responseEnvelopeKey": "result",
|
|
@@ -141552,6 +141582,12 @@ export const CONTRACT = {
|
|
|
141552
141582
|
"kind": "flag",
|
|
141553
141583
|
"type": "number"
|
|
141554
141584
|
},
|
|
141585
|
+
{
|
|
141586
|
+
"name": "isLgl",
|
|
141587
|
+
"kind": "flag",
|
|
141588
|
+
"type": "boolean",
|
|
141589
|
+
"flag": "is-lgl"
|
|
141590
|
+
},
|
|
141555
141591
|
{
|
|
141556
141592
|
"name": "input",
|
|
141557
141593
|
"kind": "jsonFlag",
|
|
@@ -141584,6 +141620,9 @@ export const CONTRACT = {
|
|
|
141584
141620
|
},
|
|
141585
141621
|
"start": {
|
|
141586
141622
|
"type": "integer"
|
|
141623
|
+
},
|
|
141624
|
+
"isLgl": {
|
|
141625
|
+
"type": "boolean"
|
|
141587
141626
|
}
|
|
141588
141627
|
},
|
|
141589
141628
|
"additionalProperties": false,
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_crypto = require('node:crypto');
|
|
4
|
+
var errors = require('./errors.cjs');
|
|
5
|
+
|
|
6
|
+
const DOCUMENT_RPC_FEATURES = ['document.open', 'document.invoke', 'document.save', 'document.close'];
|
|
7
|
+
const DOCUMENT_RPC_V0_OPERATIONS = new Set(['doc.getText', 'doc.insert', 'doc.save', 'doc.close']);
|
|
8
|
+
const DOCUMENT_RPC_OPEN_FIELDS = new Set(['doc', 'sessionId', 'runtime']);
|
|
9
|
+
const DOCUMENT_RPC_INSERT_FIELDS = new Set([
|
|
10
|
+
'value',
|
|
11
|
+
'type',
|
|
12
|
+
'target',
|
|
13
|
+
'ref',
|
|
14
|
+
'in',
|
|
15
|
+
'placement',
|
|
16
|
+
'content',
|
|
17
|
+
'nestingPolicy',
|
|
18
|
+
]);
|
|
19
|
+
function unsupported(message, operationId) {
|
|
20
|
+
return new errors.SuperDocCliError(message, {
|
|
21
|
+
code: 'DOCUMENT_RPC_INPUT_UNSUPPORTED',
|
|
22
|
+
...(operationId === undefined ? {} : { details: { operationId } }),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function documentRpcEnabled(env) {
|
|
26
|
+
return (env?.SUPERDOC_SDK_DOCUMENT_RPC ?? process.env.SUPERDOC_SDK_DOCUMENT_RPC) === '1';
|
|
27
|
+
}
|
|
28
|
+
function supportsDocumentRpc(features) {
|
|
29
|
+
return DOCUMENT_RPC_FEATURES.every((feature) => features.has(feature));
|
|
30
|
+
}
|
|
31
|
+
function hasUnsupportedInvokeOptions(options) {
|
|
32
|
+
return (options.stdinBytes !== undefined ||
|
|
33
|
+
options.dryRun !== undefined ||
|
|
34
|
+
options.expectedRevision !== undefined ||
|
|
35
|
+
options.changeMode !== undefined);
|
|
36
|
+
}
|
|
37
|
+
function canOpenWithDocumentRpc(params, options) {
|
|
38
|
+
if (hasUnsupportedInvokeOptions(options))
|
|
39
|
+
return false;
|
|
40
|
+
if (typeof params.doc !== 'string' || params.doc.trim().length === 0 || params.doc === '-')
|
|
41
|
+
return false;
|
|
42
|
+
if (params.runtime !== undefined && params.runtime !== 'v2')
|
|
43
|
+
return false;
|
|
44
|
+
if (params.sessionId !== undefined && (typeof params.sessionId !== 'string' || params.sessionId.length === 0)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return Object.entries(params).every(([key, value]) => value === undefined || DOCUMENT_RPC_OPEN_FIELDS.has(key));
|
|
48
|
+
}
|
|
49
|
+
function buildDocumentOpenParams(params) {
|
|
50
|
+
const sessionId = typeof params.sessionId === 'string' && params.sessionId.length > 0 ? params.sessionId : node_crypto.randomUUID();
|
|
51
|
+
return {
|
|
52
|
+
sessionId,
|
|
53
|
+
params: { sessionId, path: params.doc },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function mapDocumentOpenResult(response, sessionId, path) {
|
|
57
|
+
if (typeof response !== 'object' || response == null || Array.isArray(response)) {
|
|
58
|
+
throw new errors.SuperDocCliError('Host returned invalid document.open result.', {
|
|
59
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
60
|
+
details: { result: response },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const record = response;
|
|
64
|
+
if (record.sessionId !== sessionId || typeof record.byteLength !== 'number') {
|
|
65
|
+
throw new errors.SuperDocCliError('Host returned invalid document.open session metadata.', {
|
|
66
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
67
|
+
details: { result: response },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
active: true,
|
|
72
|
+
contextId: sessionId,
|
|
73
|
+
runtime: 'v2',
|
|
74
|
+
sessionType: 'local',
|
|
75
|
+
document: { path, source: 'path', byteLength: record.byteLength, revision: 0 },
|
|
76
|
+
dirty: false,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function documentInvokeInput(operationId, params) {
|
|
80
|
+
const allowedFields = operationId === 'doc.getText' ? new Set(['in']) : DOCUMENT_RPC_INSERT_FIELDS;
|
|
81
|
+
const input = Object.fromEntries(Object.entries(params).filter(([key, value]) => value !== undefined && key !== 'doc' && key !== 'sessionId'));
|
|
82
|
+
const unsupportedField = Object.keys(input).find((key) => !allowedFields.has(key));
|
|
83
|
+
if (unsupportedField) {
|
|
84
|
+
throw unsupported(`Structured document RPC v0 does not support ${operationId} field ${unsupportedField}.`, operationId);
|
|
85
|
+
}
|
|
86
|
+
return input;
|
|
87
|
+
}
|
|
88
|
+
function buildDocumentInvokeParams(sessionId, operation, params, options) {
|
|
89
|
+
if (!DOCUMENT_RPC_V0_OPERATIONS.has(operation.operationId)) {
|
|
90
|
+
throw unsupported(`Structured document RPC does not support ${operation.operationId} in v0.`, operation.operationId);
|
|
91
|
+
}
|
|
92
|
+
if (hasUnsupportedInvokeOptions(options)) {
|
|
93
|
+
throw unsupported('Structured document RPC v0 does not support document mutation options.', operation.operationId);
|
|
94
|
+
}
|
|
95
|
+
if (operation.operationId === 'doc.save') {
|
|
96
|
+
if (params.inPlace === true || typeof params.out !== 'string' || params.out.length === 0) {
|
|
97
|
+
throw unsupported('Structured document RPC v0 requires doc.save({ out }) and does not support inPlace.', operation.operationId);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
method: 'document.save',
|
|
101
|
+
params: {
|
|
102
|
+
sessionId,
|
|
103
|
+
path: params.out,
|
|
104
|
+
overwrite: params.force === true,
|
|
105
|
+
...(params.mode === undefined ? {} : { mode: params.mode }),
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (operation.operationId === 'doc.close') {
|
|
110
|
+
return {
|
|
111
|
+
method: 'document.close',
|
|
112
|
+
params: {
|
|
113
|
+
sessionId,
|
|
114
|
+
...(params.discard === undefined ? {} : { discard: params.discard }),
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
method: 'document.invoke',
|
|
120
|
+
params: {
|
|
121
|
+
sessionId,
|
|
122
|
+
operationId: operation.operationId.slice('doc.'.length),
|
|
123
|
+
input: documentInvokeInput(operation.operationId, params),
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function mapDocumentLifecycleResult(operationId, response, sessionId) {
|
|
128
|
+
if (operationId !== 'doc.save' && operationId !== 'doc.close')
|
|
129
|
+
return response;
|
|
130
|
+
if (typeof response !== 'object' || response == null || Array.isArray(response)) {
|
|
131
|
+
throw new errors.SuperDocCliError(`Host returned invalid ${operationId.slice('doc.'.length)} result.`, {
|
|
132
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
133
|
+
details: { result: response },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const record = response;
|
|
137
|
+
if (record.sessionId !== sessionId) {
|
|
138
|
+
throw new errors.SuperDocCliError('Host returned a result for the wrong document session.', {
|
|
139
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
140
|
+
details: { expectedSessionId: sessionId, result: response },
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (operationId === 'doc.close') {
|
|
144
|
+
if (record.closed !== true || typeof record.discarded !== 'boolean') {
|
|
145
|
+
throw new errors.SuperDocCliError('Host returned invalid document.close result.', {
|
|
146
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
147
|
+
details: { result: response },
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
contextId: sessionId,
|
|
152
|
+
runtime: 'v2',
|
|
153
|
+
closed: true,
|
|
154
|
+
saved: false,
|
|
155
|
+
discarded: record.discarded,
|
|
156
|
+
defaultSessionCleared: false,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const output = record.output;
|
|
160
|
+
if (record.saved !== true ||
|
|
161
|
+
typeof output !== 'object' ||
|
|
162
|
+
output == null ||
|
|
163
|
+
Array.isArray(output) ||
|
|
164
|
+
typeof output.path !== 'string' ||
|
|
165
|
+
typeof output.byteLength !== 'number') {
|
|
166
|
+
throw new errors.SuperDocCliError('Host returned invalid document.save result.', {
|
|
167
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
168
|
+
details: { result: response },
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
contextId: sessionId,
|
|
173
|
+
runtime: 'v2',
|
|
174
|
+
saved: true,
|
|
175
|
+
inPlace: false,
|
|
176
|
+
mode: record.mode,
|
|
177
|
+
output,
|
|
178
|
+
report: record.report,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
exports.DOCUMENT_RPC_FEATURES = DOCUMENT_RPC_FEATURES;
|
|
183
|
+
exports.buildDocumentInvokeParams = buildDocumentInvokeParams;
|
|
184
|
+
exports.buildDocumentOpenParams = buildDocumentOpenParams;
|
|
185
|
+
exports.canOpenWithDocumentRpc = canOpenWithDocumentRpc;
|
|
186
|
+
exports.documentRpcEnabled = documentRpcEnabled;
|
|
187
|
+
exports.mapDocumentLifecycleResult = mapDocumentLifecycleResult;
|
|
188
|
+
exports.mapDocumentOpenResult = mapDocumentOpenResult;
|
|
189
|
+
exports.supportsDocumentRpc = supportsDocumentRpc;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { InvokeOptions, OperationSpec } from './transport-common.js';
|
|
2
|
+
export declare const DOCUMENT_RPC_FEATURES: readonly ["document.open", "document.invoke", "document.save", "document.close"];
|
|
3
|
+
export declare function documentRpcEnabled(env: Record<string, string | undefined> | undefined): boolean;
|
|
4
|
+
export declare function supportsDocumentRpc(features: ReadonlySet<string>): boolean;
|
|
5
|
+
export declare function canOpenWithDocumentRpc(params: Record<string, unknown>, options: InvokeOptions): boolean;
|
|
6
|
+
export declare function buildDocumentOpenParams(params: Record<string, unknown>): {
|
|
7
|
+
readonly sessionId: string;
|
|
8
|
+
readonly params: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
export declare function mapDocumentOpenResult(response: unknown, sessionId: string, path: string): Record<string, unknown>;
|
|
11
|
+
export declare function buildDocumentInvokeParams(sessionId: string, operation: OperationSpec, params: Record<string, unknown>, options: InvokeOptions): {
|
|
12
|
+
readonly method: string;
|
|
13
|
+
readonly params: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
export declare function mapDocumentLifecycleResult(operationId: string, response: unknown, sessionId: string): unknown;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { SuperDocCliError } from './errors.js';
|
|
3
|
+
export const DOCUMENT_RPC_FEATURES = ['document.open', 'document.invoke', 'document.save', 'document.close'];
|
|
4
|
+
const DOCUMENT_RPC_V0_OPERATIONS = new Set(['doc.getText', 'doc.insert', 'doc.save', 'doc.close']);
|
|
5
|
+
const DOCUMENT_RPC_OPEN_FIELDS = new Set(['doc', 'sessionId', 'runtime']);
|
|
6
|
+
const DOCUMENT_RPC_INSERT_FIELDS = new Set([
|
|
7
|
+
'value',
|
|
8
|
+
'type',
|
|
9
|
+
'target',
|
|
10
|
+
'ref',
|
|
11
|
+
'in',
|
|
12
|
+
'placement',
|
|
13
|
+
'content',
|
|
14
|
+
'nestingPolicy',
|
|
15
|
+
]);
|
|
16
|
+
function unsupported(message, operationId) {
|
|
17
|
+
return new SuperDocCliError(message, {
|
|
18
|
+
code: 'DOCUMENT_RPC_INPUT_UNSUPPORTED',
|
|
19
|
+
...(operationId === undefined ? {} : { details: { operationId } }),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function documentRpcEnabled(env) {
|
|
23
|
+
return (env?.SUPERDOC_SDK_DOCUMENT_RPC ?? process.env.SUPERDOC_SDK_DOCUMENT_RPC) === '1';
|
|
24
|
+
}
|
|
25
|
+
export function supportsDocumentRpc(features) {
|
|
26
|
+
return DOCUMENT_RPC_FEATURES.every((feature) => features.has(feature));
|
|
27
|
+
}
|
|
28
|
+
function hasUnsupportedInvokeOptions(options) {
|
|
29
|
+
return (options.stdinBytes !== undefined ||
|
|
30
|
+
options.dryRun !== undefined ||
|
|
31
|
+
options.expectedRevision !== undefined ||
|
|
32
|
+
options.changeMode !== undefined);
|
|
33
|
+
}
|
|
34
|
+
export function canOpenWithDocumentRpc(params, options) {
|
|
35
|
+
if (hasUnsupportedInvokeOptions(options))
|
|
36
|
+
return false;
|
|
37
|
+
if (typeof params.doc !== 'string' || params.doc.trim().length === 0 || params.doc === '-')
|
|
38
|
+
return false;
|
|
39
|
+
if (params.runtime !== undefined && params.runtime !== 'v2')
|
|
40
|
+
return false;
|
|
41
|
+
if (params.sessionId !== undefined && (typeof params.sessionId !== 'string' || params.sessionId.length === 0)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return Object.entries(params).every(([key, value]) => value === undefined || DOCUMENT_RPC_OPEN_FIELDS.has(key));
|
|
45
|
+
}
|
|
46
|
+
export function buildDocumentOpenParams(params) {
|
|
47
|
+
const sessionId = typeof params.sessionId === 'string' && params.sessionId.length > 0 ? params.sessionId : randomUUID();
|
|
48
|
+
return {
|
|
49
|
+
sessionId,
|
|
50
|
+
params: { sessionId, path: params.doc },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function mapDocumentOpenResult(response, sessionId, path) {
|
|
54
|
+
if (typeof response !== 'object' || response == null || Array.isArray(response)) {
|
|
55
|
+
throw new SuperDocCliError('Host returned invalid document.open result.', {
|
|
56
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
57
|
+
details: { result: response },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const record = response;
|
|
61
|
+
if (record.sessionId !== sessionId || typeof record.byteLength !== 'number') {
|
|
62
|
+
throw new SuperDocCliError('Host returned invalid document.open session metadata.', {
|
|
63
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
64
|
+
details: { result: response },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
active: true,
|
|
69
|
+
contextId: sessionId,
|
|
70
|
+
runtime: 'v2',
|
|
71
|
+
sessionType: 'local',
|
|
72
|
+
document: { path, source: 'path', byteLength: record.byteLength, revision: 0 },
|
|
73
|
+
dirty: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function documentInvokeInput(operationId, params) {
|
|
77
|
+
const allowedFields = operationId === 'doc.getText' ? new Set(['in']) : DOCUMENT_RPC_INSERT_FIELDS;
|
|
78
|
+
const input = Object.fromEntries(Object.entries(params).filter(([key, value]) => value !== undefined && key !== 'doc' && key !== 'sessionId'));
|
|
79
|
+
const unsupportedField = Object.keys(input).find((key) => !allowedFields.has(key));
|
|
80
|
+
if (unsupportedField) {
|
|
81
|
+
throw unsupported(`Structured document RPC v0 does not support ${operationId} field ${unsupportedField}.`, operationId);
|
|
82
|
+
}
|
|
83
|
+
return input;
|
|
84
|
+
}
|
|
85
|
+
export function buildDocumentInvokeParams(sessionId, operation, params, options) {
|
|
86
|
+
if (!DOCUMENT_RPC_V0_OPERATIONS.has(operation.operationId)) {
|
|
87
|
+
throw unsupported(`Structured document RPC does not support ${operation.operationId} in v0.`, operation.operationId);
|
|
88
|
+
}
|
|
89
|
+
if (hasUnsupportedInvokeOptions(options)) {
|
|
90
|
+
throw unsupported('Structured document RPC v0 does not support document mutation options.', operation.operationId);
|
|
91
|
+
}
|
|
92
|
+
if (operation.operationId === 'doc.save') {
|
|
93
|
+
if (params.inPlace === true || typeof params.out !== 'string' || params.out.length === 0) {
|
|
94
|
+
throw unsupported('Structured document RPC v0 requires doc.save({ out }) and does not support inPlace.', operation.operationId);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
method: 'document.save',
|
|
98
|
+
params: {
|
|
99
|
+
sessionId,
|
|
100
|
+
path: params.out,
|
|
101
|
+
overwrite: params.force === true,
|
|
102
|
+
...(params.mode === undefined ? {} : { mode: params.mode }),
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (operation.operationId === 'doc.close') {
|
|
107
|
+
return {
|
|
108
|
+
method: 'document.close',
|
|
109
|
+
params: {
|
|
110
|
+
sessionId,
|
|
111
|
+
...(params.discard === undefined ? {} : { discard: params.discard }),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
method: 'document.invoke',
|
|
117
|
+
params: {
|
|
118
|
+
sessionId,
|
|
119
|
+
operationId: operation.operationId.slice('doc.'.length),
|
|
120
|
+
input: documentInvokeInput(operation.operationId, params),
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function mapDocumentLifecycleResult(operationId, response, sessionId) {
|
|
125
|
+
if (operationId !== 'doc.save' && operationId !== 'doc.close')
|
|
126
|
+
return response;
|
|
127
|
+
if (typeof response !== 'object' || response == null || Array.isArray(response)) {
|
|
128
|
+
throw new SuperDocCliError(`Host returned invalid ${operationId.slice('doc.'.length)} result.`, {
|
|
129
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
130
|
+
details: { result: response },
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
const record = response;
|
|
134
|
+
if (record.sessionId !== sessionId) {
|
|
135
|
+
throw new SuperDocCliError('Host returned a result for the wrong document session.', {
|
|
136
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
137
|
+
details: { expectedSessionId: sessionId, result: response },
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (operationId === 'doc.close') {
|
|
141
|
+
if (record.closed !== true || typeof record.discarded !== 'boolean') {
|
|
142
|
+
throw new SuperDocCliError('Host returned invalid document.close result.', {
|
|
143
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
144
|
+
details: { result: response },
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
contextId: sessionId,
|
|
149
|
+
runtime: 'v2',
|
|
150
|
+
closed: true,
|
|
151
|
+
saved: false,
|
|
152
|
+
discarded: record.discarded,
|
|
153
|
+
defaultSessionCleared: false,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const output = record.output;
|
|
157
|
+
if (record.saved !== true ||
|
|
158
|
+
typeof output !== 'object' ||
|
|
159
|
+
output == null ||
|
|
160
|
+
Array.isArray(output) ||
|
|
161
|
+
typeof output.path !== 'string' ||
|
|
162
|
+
typeof output.byteLength !== 'number') {
|
|
163
|
+
throw new SuperDocCliError('Host returned invalid document.save result.', {
|
|
164
|
+
code: 'HOST_PROTOCOL_ERROR',
|
|
165
|
+
details: { result: response },
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
contextId: sessionId,
|
|
170
|
+
runtime: 'v2',
|
|
171
|
+
saved: true,
|
|
172
|
+
inPlace: false,
|
|
173
|
+
mode: record.mode,
|
|
174
|
+
output,
|
|
175
|
+
report: record.report,
|
|
176
|
+
};
|
|
177
|
+
}
|