@superdoc/sdk 2.26.0-next.1 → 2.26.0-next.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,333 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { SuperDocCliError } from './errors.js';
3
- import { SDK_POLICY } from './sdk-policy.js';
4
- import { operationAcceptsTrackedMode } from './tracked-support.js';
5
- import { applyOperationParamAliases, captureMutationPlanAuthor, } from './transport-common.js';
6
- export const DOCUMENT_RPC_FEATURES = SDK_POLICY.documentRpcFeatures;
7
- export const DOCUMENT_RPC_REPLACE_FILE_FEATURE = SDK_POLICY.features.replaceFile;
8
- export const DOCUMENT_RPC_DEFAULT_CHANGE_MODE_FEATURE = SDK_POLICY.features.defaultChangeMode;
9
- export const DOCUMENT_RPC_SOURCE_SAVE_FEATURE = SDK_POLICY.features.sourceSave;
10
- export const DOCUMENT_RPC_REQUEST_TIMEOUT_FEATURE = SDK_POLICY.features.requestTimeout;
11
- const DOCUMENT_RPC_OPEN_FIELDS = new Set(SDK_POLICY.documentOpenFields);
12
- const DOCUMENT_RPC_SAVE_FIELDS = new Set(SDK_POLICY.documentSaveFields);
13
- const DOCUMENT_API_OPTION_FIELDS = new Set(SDK_POLICY.documentOptionFields);
14
- const DOCUMENT_API_REVISION_PREFLIGHT_OPERATIONS = new Set(SDK_POLICY.revisionPreflightOperations);
15
- function unsupported(message, operationId) {
16
- return new SuperDocCliError(message, {
17
- code: 'DOCUMENT_RPC_INPUT_UNSUPPORTED',
18
- ...(operationId === undefined ? {} : { details: { operationId } }),
19
- });
20
- }
21
- function buildDocumentAuthor(user) {
22
- if (user === undefined)
23
- return undefined;
24
- if (typeof user !== 'object' || user === null || Array.isArray(user)) {
25
- throw new SuperDocCliError('user must be an object with a non-empty name.', {
26
- code: 'INVALID_ARGUMENT',
27
- });
28
- }
29
- const record = user;
30
- if (typeof record.name !== 'string' || record.name.trim().length === 0) {
31
- throw new SuperDocCliError('user.name must be a non-empty string.', {
32
- code: 'INVALID_ARGUMENT',
33
- });
34
- }
35
- if (record.email !== undefined && typeof record.email !== 'string') {
36
- throw new SuperDocCliError('user.email must be a string.', {
37
- code: 'INVALID_ARGUMENT',
38
- });
39
- }
40
- return {
41
- name: record.name,
42
- ...(record.email === undefined ? {} : { email: record.email }),
43
- };
44
- }
45
- export function documentRpcEnabled(env) {
46
- return (env?.SUPERDOC_SDK_DOCUMENT_RPC ?? process.env.SUPERDOC_SDK_DOCUMENT_RPC) === '1';
47
- }
48
- export function supportsDocumentRpc(features) {
49
- return DOCUMENT_RPC_FEATURES.every((feature) => features.has(feature));
50
- }
51
- export function canOpenWithDocumentRpc(params, options) {
52
- if (options.stdinBytes !== undefined)
53
- return false;
54
- if (options.dryRun !== undefined || options.expectedRevision !== undefined || options.changeMode !== undefined) {
55
- return false;
56
- }
57
- if (typeof params.doc !== 'string' || params.doc.trim().length === 0 || params.doc === '-')
58
- return false;
59
- if (params.runtime !== undefined && params.runtime !== 'v2')
60
- return false;
61
- if (params.sessionId !== undefined && (typeof params.sessionId !== 'string' || params.sessionId.length === 0)) {
62
- return false;
63
- }
64
- return Object.entries(params).every(([key, value]) => value === undefined || DOCUMENT_RPC_OPEN_FIELDS.has(key));
65
- }
66
- export function buildDocumentOpenParams(params, user, defaultChangeMode) {
67
- const sessionId = typeof params.sessionId === 'string' && params.sessionId.length > 0 ? params.sessionId : randomUUID();
68
- const author = buildDocumentAuthor(user);
69
- return {
70
- sessionId,
71
- params: {
72
- sessionId,
73
- path: params.doc,
74
- ...(author === undefined ? {} : { author }),
75
- ...(defaultChangeMode == null ? {} : { defaultChangeMode }),
76
- },
77
- };
78
- }
79
- export function mapDocumentOpenResult(response, sessionId, path) {
80
- if (typeof response !== 'object' || response == null || Array.isArray(response)) {
81
- throw new SuperDocCliError('Host returned invalid document.open result.', {
82
- code: 'HOST_PROTOCOL_ERROR',
83
- details: { result: response },
84
- });
85
- }
86
- const record = response;
87
- if (record.sessionId !== sessionId || typeof record.byteLength !== 'number') {
88
- throw new SuperDocCliError('Host returned invalid document.open session metadata.', {
89
- code: 'HOST_PROTOCOL_ERROR',
90
- details: { result: response },
91
- });
92
- }
93
- return {
94
- active: true,
95
- contextId: sessionId,
96
- runtime: 'v2',
97
- sessionType: 'local',
98
- document: { path, source: 'path', byteLength: record.byteLength, revision: 0 },
99
- dirty: false,
100
- };
101
- }
102
- export function mapDocumentReplaceFileResult(response, sessionId) {
103
- if (typeof response !== 'object' || response == null || Array.isArray(response)) {
104
- throw new SuperDocCliError('Host returned invalid document.replaceFile result.', {
105
- code: 'HOST_PROTOCOL_ERROR',
106
- details: { result: response },
107
- });
108
- }
109
- const record = response;
110
- if (record.sessionId !== sessionId ||
111
- record.replaced !== true ||
112
- typeof record.byteLength !== 'number' ||
113
- typeof record.revision !== 'string') {
114
- throw new SuperDocCliError('Host returned invalid document.replaceFile session metadata.', {
115
- code: 'HOST_PROTOCOL_ERROR',
116
- details: { expectedSessionId: sessionId, result: response },
117
- });
118
- }
119
- return {
120
- contextId: sessionId,
121
- runtime: 'v2',
122
- replaced: true,
123
- document: { byteLength: record.byteLength, revision: record.revision },
124
- };
125
- }
126
- function documentInvokePayload(operation, params, invokeOptions) {
127
- params = captureMutationPlanAuthor(operation.operationId, params, invokeOptions);
128
- const normalizedParams = applyOperationParamAliases(operation, params);
129
- if (invokeOptions.stdinBytes !== undefined) {
130
- throw unsupported('Structured document RPC does not support stdinBytes.', operation.operationId);
131
- }
132
- if (typeof normalizedParams.out === 'string' && normalizedParams.out.length > 0) {
133
- throw unsupported('Structured document RPC does not support per-operation output paths.', operation.operationId);
134
- }
135
- if (normalizedParams.force === true) {
136
- throw unsupported('Structured document RPC does not support per-operation force.', operation.operationId);
137
- }
138
- const input = {};
139
- const options = {};
140
- const paramsByName = new Map(operation.params.map((param) => [param.name, param]));
141
- for (const [name, value] of Object.entries(normalizedParams)) {
142
- if (value === undefined || name === 'doc' || name === 'sessionId' || name === 'out' || name === 'force')
143
- continue;
144
- const param = paramsByName.get(name);
145
- if (!param) {
146
- throw unsupported(`Structured document RPC does not support ${operation.operationId} field ${name}.`, operation.operationId);
147
- }
148
- if (typeof param.documentApiInputName === 'string' && param.documentApiInputName.length > 0) {
149
- input[param.documentApiInputName] = value;
150
- continue;
151
- }
152
- if (DOCUMENT_API_OPTION_FIELDS.has(name)) {
153
- options[name] = value;
154
- continue;
155
- }
156
- throw unsupported(`Structured document RPC does not support ${operation.operationId} field ${name}.`, operation.operationId);
157
- }
158
- for (const name of ['expectedRevision', 'changeMode', 'dryRun']) {
159
- const value = invokeOptions[name];
160
- if (value === undefined || normalizedParams[name] !== undefined)
161
- continue;
162
- const projectedValue = name === 'expectedRevision' ? String(value) : value;
163
- const param = paramsByName.get(name);
164
- if (typeof param?.documentApiInputName === 'string' && param.documentApiInputName.length > 0) {
165
- input[param.documentApiInputName] = projectedValue;
166
- }
167
- else {
168
- options[name] = projectedValue;
169
- }
170
- }
171
- if (options.changeMode !== undefined && !operationAcceptsTrackedMode(operation)) {
172
- if (options.changeMode === 'tracked') {
173
- throw unsupported(`Structured document RPC does not support tracked mode for ${operation.operationId}.`, operation.operationId);
174
- }
175
- if (options.changeMode !== 'direct') {
176
- throw unsupported(`Structured document RPC received an invalid change mode for ${operation.operationId}.`, operation.operationId);
177
- }
178
- delete options.changeMode;
179
- }
180
- if (options.dryRun !== undefined && operation.supportsDryRun !== true) {
181
- if (options.dryRun === true) {
182
- throw unsupported(`Structured document RPC does not support dry run for ${operation.operationId}.`, operation.operationId);
183
- }
184
- delete options.dryRun;
185
- }
186
- if (options.expectedRevision !== undefined && DOCUMENT_API_REVISION_PREFLIGHT_OPERATIONS.has(operation.operationId)) {
187
- throw unsupported(`Structured document RPC does not yet support expectedRevision for ${operation.operationId}.`, operation.operationId);
188
- }
189
- if (options.expectedRevision !== undefined && operation.mutates !== true) {
190
- throw unsupported(`Structured document RPC does not support expectedRevision for ${operation.operationId}.`, operation.operationId);
191
- }
192
- return {
193
- input,
194
- ...(Object.keys(options).length === 0 ? {} : { options }),
195
- };
196
- }
197
- export function buildDocumentInvokeParams(sessionId, operation, params, options, hostFeatures) {
198
- if (operation.operationId === 'doc.save') {
199
- if (options.stdinBytes !== undefined ||
200
- options.dryRun !== undefined ||
201
- options.expectedRevision !== undefined ||
202
- options.changeMode !== undefined) {
203
- throw unsupported('Structured document RPC does not support document.save invoke options.', operation.operationId);
204
- }
205
- const unknownField = Object.entries(params).find(([name, value]) => value !== undefined && !DOCUMENT_RPC_SAVE_FIELDS.has(name))?.[0];
206
- if (unknownField !== undefined) {
207
- throw unsupported(`Structured document RPC does not support doc.save field ${unknownField}.`, operation.operationId);
208
- }
209
- if (params.inPlace !== undefined && typeof params.inPlace !== 'boolean') {
210
- throw unsupported('Structured document RPC requires inPlace to be a boolean.', operation.operationId);
211
- }
212
- if (params.inPlace === true && params.out !== undefined) {
213
- throw unsupported('Structured document RPC requires either inPlace or out, not both.', operation.operationId);
214
- }
215
- if (params.out !== undefined && (typeof params.out !== 'string' || params.out.length === 0)) {
216
- throw unsupported('Structured document RPC requires out to be a non-empty path.', operation.operationId);
217
- }
218
- if (params.out === undefined && hostFeatures?.has(DOCUMENT_RPC_SOURCE_SAVE_FEATURE) !== true) {
219
- throw unsupported('Structured document RPC host does not support source saves.', operation.operationId);
220
- }
221
- return {
222
- method: 'document.save',
223
- params: {
224
- sessionId,
225
- ...(params.out === undefined ? {} : { path: params.out }),
226
- ...(params.force === true ? { overwrite: true } : {}),
227
- ...(params.mode === undefined ? {} : { mode: params.mode }),
228
- },
229
- };
230
- }
231
- if (operation.operationId === 'doc.close') {
232
- if (options.stdinBytes !== undefined ||
233
- options.dryRun !== undefined ||
234
- options.expectedRevision !== undefined ||
235
- options.changeMode !== undefined) {
236
- throw unsupported('Structured document RPC does not support document.close invoke options.', operation.operationId);
237
- }
238
- return {
239
- method: 'document.close',
240
- params: {
241
- sessionId,
242
- ...(params.discard === undefined ? {} : { discard: params.discard }),
243
- },
244
- };
245
- }
246
- const documentOperation = operation;
247
- if (typeof documentOperation.documentApiOperationId !== 'string' ||
248
- documentOperation.documentApiOperationId.length === 0) {
249
- throw unsupported(`Structured document RPC does not support ${operation.operationId}.`, operation.operationId);
250
- }
251
- const payload = documentInvokePayload(documentOperation, params, options);
252
- return {
253
- method: 'document.invoke',
254
- params: {
255
- sessionId,
256
- operationId: documentOperation.documentApiOperationId,
257
- input: payload.input,
258
- ...(payload.options === undefined ? {} : { options: payload.options }),
259
- },
260
- };
261
- }
262
- export function documentRpcRequestSupportsResponseTimeout(operation, request) {
263
- if (request.method === 'document.save')
264
- return false;
265
- if (request.method !== 'document.invoke')
266
- return true;
267
- const documentOperation = operation;
268
- const requestOptions = typeof request.params.options === 'object' &&
269
- request.params.options !== null &&
270
- !Array.isArray(request.params.options)
271
- ? request.params.options
272
- : undefined;
273
- if (requestOptions?.dryRun === true)
274
- return true;
275
- if (documentOperation.mutates === false)
276
- return true;
277
- return documentOperation.idempotency === 'idempotent';
278
- }
279
- export function mapDocumentLifecycleResult(operationId, response, sessionId, expectedInPlace) {
280
- if (operationId !== 'doc.save' && operationId !== 'doc.close')
281
- return response;
282
- if (typeof response !== 'object' || response == null || Array.isArray(response)) {
283
- throw new SuperDocCliError(`Host returned invalid ${operationId.slice('doc.'.length)} result.`, {
284
- code: 'HOST_PROTOCOL_ERROR',
285
- details: { result: response },
286
- });
287
- }
288
- const record = response;
289
- if (record.sessionId !== sessionId) {
290
- throw new SuperDocCliError('Host returned a result for the wrong document session.', {
291
- code: 'HOST_PROTOCOL_ERROR',
292
- details: { expectedSessionId: sessionId, result: response },
293
- });
294
- }
295
- if (operationId === 'doc.close') {
296
- if (record.closed !== true || typeof record.discarded !== 'boolean') {
297
- throw new SuperDocCliError('Host returned invalid document.close result.', {
298
- code: 'HOST_PROTOCOL_ERROR',
299
- details: { result: response },
300
- });
301
- }
302
- return {
303
- contextId: sessionId,
304
- runtime: 'v2',
305
- closed: true,
306
- saved: false,
307
- discarded: record.discarded,
308
- defaultSessionCleared: false,
309
- };
310
- }
311
- const output = record.output;
312
- if (record.saved !== true ||
313
- (typeof record.inPlace !== 'boolean' && !(record.inPlace === undefined && expectedInPlace === false)) ||
314
- typeof output !== 'object' ||
315
- output == null ||
316
- Array.isArray(output) ||
317
- typeof output.path !== 'string' ||
318
- typeof output.byteLength !== 'number') {
319
- throw new SuperDocCliError('Host returned invalid document.save result.', {
320
- code: 'HOST_PROTOCOL_ERROR',
321
- details: { result: response },
322
- });
323
- }
324
- return {
325
- contextId: sessionId,
326
- runtime: 'v2',
327
- saved: true,
328
- inPlace: record.inPlace ?? false,
329
- mode: record.mode,
330
- output,
331
- report: record.report,
332
- };
333
- }
@@ -1,28 +0,0 @@
1
- 'use strict';
2
-
3
- var embeddedPlatform = require('./embedded-platform.cjs');
4
- var errors = require('./errors.cjs');
5
-
6
- function binaryNameForTarget(target) {
7
- return target === 'windows-x64' ? 'superdoc-document-host.exe' : 'superdoc-document-host';
8
- }
9
- function resolveEmbeddedDocumentHostBinary() {
10
- const target = embeddedPlatform.resolveEmbeddedTarget();
11
- if (!target) {
12
- throw new errors.SuperDocCliError('No embedded SuperDoc document host is available for this platform.', {
13
- code: 'UNSUPPORTED_PLATFORM',
14
- details: { platform: process.platform, arch: process.arch },
15
- });
16
- }
17
- const resolvedPath = embeddedPlatform.resolveEmbeddedPlatformBinary(target, binaryNameForTarget(target));
18
- if (!resolvedPath) {
19
- throw new errors.SuperDocCliError('Embedded SuperDoc document host is missing for this platform.', {
20
- code: 'DOCUMENT_HOST_BINARY_MISSING',
21
- details: { target, packageName: embeddedPlatform.embeddedPlatformPackage(target) },
22
- });
23
- }
24
- embeddedPlatform.ensureEmbeddedExecutable(resolvedPath);
25
- return resolvedPath;
26
- }
27
-
28
- exports.resolveEmbeddedDocumentHostBinary = resolveEmbeddedDocumentHostBinary;
@@ -1 +0,0 @@
1
- export declare function resolveEmbeddedDocumentHostBinary(): string;
@@ -1,23 +0,0 @@
1
- import { embeddedPlatformPackage, ensureEmbeddedExecutable, resolveEmbeddedPlatformBinary, resolveEmbeddedTarget, } from './embedded-platform.js';
2
- import { SuperDocCliError } from './errors.js';
3
- function binaryNameForTarget(target) {
4
- return target === 'windows-x64' ? 'superdoc-document-host.exe' : 'superdoc-document-host';
5
- }
6
- export function resolveEmbeddedDocumentHostBinary() {
7
- const target = resolveEmbeddedTarget();
8
- if (!target) {
9
- throw new SuperDocCliError('No embedded SuperDoc document host is available for this platform.', {
10
- code: 'UNSUPPORTED_PLATFORM',
11
- details: { platform: process.platform, arch: process.arch },
12
- });
13
- }
14
- const resolvedPath = resolveEmbeddedPlatformBinary(target, binaryNameForTarget(target));
15
- if (!resolvedPath) {
16
- throw new SuperDocCliError('Embedded SuperDoc document host is missing for this platform.', {
17
- code: 'DOCUMENT_HOST_BINARY_MISSING',
18
- details: { target, packageName: embeddedPlatformPackage(target) },
19
- });
20
- }
21
- ensureEmbeddedExecutable(resolvedPath);
22
- return resolvedPath;
23
- }