@superdoc/sdk 2.26.0 → 2.27.0-next.4
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 +202 -29
- package/dist/agent/catalog.d.ts +0 -4
- package/dist/agent/catalog.js +0 -4
- package/dist/generated/client.cjs +14 -1
- package/dist/generated/client.d.ts +1496 -215
- package/dist/generated/client.js +14 -1
- package/dist/generated/contract.cjs +1 -2
- package/dist/generated/contract.d.ts +1 -0
- package/dist/generated/contract.js +1 -2
- package/dist/index.cjs +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/runtime/host.cjs +36 -3
- package/dist/runtime/host.d.ts +5 -0
- package/dist/runtime/host.js +36 -4
- package/dist/runtime/notifications.cjs +124 -0
- package/dist/runtime/notifications.d.ts +35 -0
- package/dist/runtime/notifications.js +116 -0
- package/dist/runtime/process.cjs +4 -1
- package/dist/runtime/process.d.ts +2 -0
- package/dist/runtime/process.js +4 -1
- package/dist/runtime/sdk-policy.d.ts +1 -0
- 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 +9 -1
- package/dist/runtime/transport-common.d.ts +3 -0
- package/dist/runtime/transport-common.js +8 -1
- package/package.json +7 -7
- package/tools/generation-receipt.json +51 -13
- package/tools/tools-policy.json +1 -1
package/dist/index.cjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
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
2
|
import { SuperDocRuntime, type SuperDocClientOptions, type DocOpenOptions, type InvokeOptions, type OperationSpec, type ReplaceFileOptions, type ReplaceFileResult, type ReplaceFileSource, type RuntimeInvoker } from './runtime/process.js';
|
|
3
|
+
import type { HostNotifications, SubscribeOptions } from './runtime/notifications.js';
|
|
3
4
|
/**
|
|
4
5
|
* Wraps a raw runtime and injects a fixed sessionId into every invoke call.
|
|
5
6
|
* Implements RuntimeInvoker so generated code can use it directly.
|
|
@@ -73,6 +74,7 @@ export declare class SuperDocClient {
|
|
|
73
74
|
private readonly pendingSessionIds;
|
|
74
75
|
constructor(options?: SuperDocClientOptions);
|
|
75
76
|
connect(): Promise<void>;
|
|
77
|
+
subscribe(options?: SubscribeOptions): HostNotifications;
|
|
76
78
|
/**
|
|
77
79
|
* Open a document and return a bound document handle.
|
|
78
80
|
*
|
|
@@ -104,6 +106,7 @@ export type { AgentToolkit, CreateAgentToolkitInput } from './tools.js';
|
|
|
104
106
|
export { defineAction } from './actions/define.js';
|
|
105
107
|
export type { ActionSpec, ActionStep, DefineActionInput, JSONSchemaObject } from './actions/define.js';
|
|
106
108
|
export { SuperDocCliError } from './runtime/errors.js';
|
|
109
|
+
export type { HostNotification, HostNotifications, SubscribeOptions } from './runtime/notifications.js';
|
|
107
110
|
export { runTrackedComparisonReview } from './tracked-review-route.js';
|
|
108
111
|
export type { TrackedReviewSession, TrackedComparisonReviewInput } from './tracked-review-route.js';
|
|
109
112
|
export type { CollaborationAuth, DocOpenOptions, InvokeOptions, OperationSpec, OperationParamSpec, RuntimeInvoker, SuperDocClientOptions, } from './runtime/process.js';
|
package/dist/index.js
CHANGED
package/dist/runtime/host.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var node_child_process = require('node:child_process');
|
|
|
4
4
|
var transportCommon = require('./transport-common.cjs');
|
|
5
5
|
var errors = require('./errors.cjs');
|
|
6
6
|
var stateDirectory = require('./state-directory.cjs');
|
|
7
|
+
var notifications = require('./notifications.cjs');
|
|
7
8
|
var documentEvidence = require('./document-evidence.cjs');
|
|
8
9
|
var contract = require('../generated/contract.cjs');
|
|
9
10
|
var sdkPolicy = require('./sdk-policy.cjs');
|
|
@@ -11,6 +12,7 @@ var sdkPolicy = require('./sdk-policy.cjs');
|
|
|
11
12
|
const HOST_PROTOCOL_VERSION = sdkPolicy.SDK_POLICY.protocolVersion;
|
|
12
13
|
const CLI_HOST_REQUIRED_FEATURES = sdkPolicy.SDK_POLICY.cliRequiredFeatures;
|
|
13
14
|
const COLLABORATION_AUTH_PER_OPEN_FEATURE = sdkPolicy.SDK_POLICY.features.collaborationAuthPerOpen;
|
|
15
|
+
const IDENTITY_CLAIM_PER_OPEN_FEATURE = sdkPolicy.SDK_POLICY.features.identityClaimPerOpen;
|
|
14
16
|
const HOST_REQUEST_TIMEOUT_FEATURE = sdkPolicy.SDK_POLICY.features.requestTimeout;
|
|
15
17
|
const CHANGE_MODES = ['direct', 'tracked'];
|
|
16
18
|
const FORWARD_HOST_STDERR = typeof process !== 'undefined' && typeof process.env?.SUPERDOC_DEBUG_TEXT_REWRITE === 'string'
|
|
@@ -125,6 +127,7 @@ class HostTransport {
|
|
|
125
127
|
activeCalls = new Set();
|
|
126
128
|
hostFeatures = new Set();
|
|
127
129
|
cliLocalSessions = new Set();
|
|
130
|
+
notifications = new notifications.HostNotificationHub();
|
|
128
131
|
constructor(options) {
|
|
129
132
|
this.stateDirectory = new stateDirectory.SdkStateDirectory(options.stateDir);
|
|
130
133
|
this.hostBin = options.hostBin;
|
|
@@ -146,6 +149,9 @@ class HostTransport {
|
|
|
146
149
|
async connect() {
|
|
147
150
|
await this.runWhileActive(() => this.ensureConnected());
|
|
148
151
|
}
|
|
152
|
+
subscribe(options = {}) {
|
|
153
|
+
return this.notifications.subscribe(options);
|
|
154
|
+
}
|
|
149
155
|
supportsDocumentFacts(sessionId) {
|
|
150
156
|
return this.usesCliDocumentFacts(sessionId);
|
|
151
157
|
}
|
|
@@ -171,14 +177,18 @@ class HostTransport {
|
|
|
171
177
|
async dispose() {
|
|
172
178
|
if (this.disposePromise)
|
|
173
179
|
return this.disposePromise;
|
|
174
|
-
if (this.terminalDisposalError)
|
|
180
|
+
if (this.terminalDisposalError) {
|
|
181
|
+
this.notifications.close();
|
|
175
182
|
throw this.terminalDisposalError;
|
|
183
|
+
}
|
|
176
184
|
if (!this.child &&
|
|
177
185
|
!this.connecting &&
|
|
178
186
|
this.activeCalls.size === 0 &&
|
|
179
187
|
!this.stateDirectory.ownsRoot &&
|
|
180
|
-
this.stoppedChildren.size === 0)
|
|
188
|
+
this.stoppedChildren.size === 0) {
|
|
189
|
+
this.notifications.close();
|
|
181
190
|
return;
|
|
191
|
+
}
|
|
182
192
|
this.stopping = true;
|
|
183
193
|
const disposal = this.disposeAfterActiveCalls();
|
|
184
194
|
this.disposePromise = disposal;
|
|
@@ -192,6 +202,14 @@ class HostTransport {
|
|
|
192
202
|
}
|
|
193
203
|
}
|
|
194
204
|
async disposeAfterActiveCalls() {
|
|
205
|
+
try {
|
|
206
|
+
await this.shutdownAfterActiveCalls();
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
this.notifications.close();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async shutdownAfterActiveCalls() {
|
|
195
213
|
await Promise.allSettled(Array.from(this.activeCalls));
|
|
196
214
|
if (this.terminalDisposalError)
|
|
197
215
|
throw this.terminalDisposalError;
|
|
@@ -244,6 +262,12 @@ class HostTransport {
|
|
|
244
262
|
});
|
|
245
263
|
}
|
|
246
264
|
}
|
|
265
|
+
const identityClaim = options.identityClaim === undefined ? undefined : transportCommon.normalizeIdentityClaim(options.identityClaim);
|
|
266
|
+
if (identityClaim !== undefined && operation.operationId !== 'doc.open') {
|
|
267
|
+
throw new errors.SuperDocCliError('identityClaim is supported only for doc.open requests.', {
|
|
268
|
+
code: 'INVALID_ARGUMENT',
|
|
269
|
+
});
|
|
270
|
+
}
|
|
247
271
|
await this.ensureConnected();
|
|
248
272
|
if (collaborationAuth !== undefined && !this.hostFeatures.has(COLLABORATION_AUTH_PER_OPEN_FEATURE)) {
|
|
249
273
|
throw new errors.SuperDocCliError('The connected CLI host does not support per-open collaboration authentication.', {
|
|
@@ -251,6 +275,12 @@ class HostTransport {
|
|
|
251
275
|
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
252
276
|
});
|
|
253
277
|
}
|
|
278
|
+
if (identityClaim !== undefined && !this.hostFeatures.has(IDENTITY_CLAIM_PER_OPEN_FEATURE)) {
|
|
279
|
+
throw new errors.SuperDocCliError('The connected CLI host does not support a per-open identity claim.', {
|
|
280
|
+
code: 'CAPABILITY_UNSUPPORTED',
|
|
281
|
+
details: { feature: IDENTITY_CLAIM_PER_OPEN_FEATURE },
|
|
282
|
+
});
|
|
283
|
+
}
|
|
254
284
|
const sessionId = typeof params.sessionId === 'string' ? params.sessionId : undefined;
|
|
255
285
|
const supportsRequestTimeoutMetadata = this.hostFeatures.has(HOST_REQUEST_TIMEOUT_FEATURE);
|
|
256
286
|
const cliHostRequestTimeoutMs = this.requestTimeoutMs ?? HOST_DEFAULT_REQUEST_TIMEOUT_MS;
|
|
@@ -288,6 +318,7 @@ class HostTransport {
|
|
|
288
318
|
}),
|
|
289
319
|
...(includeRevision ? { includeRevision: true } : {}),
|
|
290
320
|
...(collaborationAuth === undefined ? {} : { collaborationAuth }),
|
|
321
|
+
...(identityClaim === undefined ? {} : { identityClaim }),
|
|
291
322
|
}, watchdogTimeout, {
|
|
292
323
|
requestTimeoutMs: supportsRequestTimeoutMetadata ? options.timeoutMs : undefined,
|
|
293
324
|
});
|
|
@@ -511,8 +542,8 @@ class HostTransport {
|
|
|
511
542
|
if (record.jsonrpc !== '2.0') {
|
|
512
543
|
return;
|
|
513
544
|
}
|
|
514
|
-
// Notification (no id) — reserved for future eventing
|
|
515
545
|
if ('method' in record && !('id' in record)) {
|
|
546
|
+
this.notifications.publish(record);
|
|
516
547
|
return;
|
|
517
548
|
}
|
|
518
549
|
const idRaw = record.id;
|
|
@@ -616,6 +647,7 @@ class HostTransport {
|
|
|
616
647
|
}
|
|
617
648
|
handleDisconnect(error) {
|
|
618
649
|
this.cleanupProcess(error);
|
|
650
|
+
this.notifications.disconnect(error);
|
|
619
651
|
}
|
|
620
652
|
cleanupProcess(error) {
|
|
621
653
|
this.hostFeatures.clear();
|
|
@@ -644,6 +676,7 @@ class HostTransport {
|
|
|
644
676
|
|
|
645
677
|
exports.COLLABORATION_AUTH_PER_OPEN_FEATURE = COLLABORATION_AUTH_PER_OPEN_FEATURE;
|
|
646
678
|
exports.HostTransport = HostTransport;
|
|
679
|
+
exports.IDENTITY_CLAIM_PER_OPEN_FEATURE = IDENTITY_CLAIM_PER_OPEN_FEATURE;
|
|
647
680
|
exports.buildHostSpawnArgs = buildHostSpawnArgs;
|
|
648
681
|
exports.mapCliInvocationResult = mapCliInvocationResult;
|
|
649
682
|
exports.mapDocumentReplaceFileResult = mapDocumentReplaceFileResult;
|
package/dist/runtime/host.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type OperationSpec, type SuperDocClientOptions, type TransportInvokeOptions } from './transport-common.js';
|
|
2
|
+
import { type HostNotifications, type SubscribeOptions } from './notifications.js';
|
|
2
3
|
export declare const COLLABORATION_AUTH_PER_OPEN_FEATURE: string;
|
|
4
|
+
export declare const IDENTITY_CLAIM_PER_OPEN_FEATURE: string;
|
|
3
5
|
export declare function mapCliInvocationResult(operation: OperationSpec, value: unknown): unknown;
|
|
4
6
|
export declare function mapDocumentReplaceFileResult(response: unknown, sessionId: string): Record<string, unknown>;
|
|
5
7
|
/**
|
|
@@ -53,15 +55,18 @@ export declare class HostTransport {
|
|
|
53
55
|
private readonly activeCalls;
|
|
54
56
|
private readonly hostFeatures;
|
|
55
57
|
private readonly cliLocalSessions;
|
|
58
|
+
private readonly notifications;
|
|
56
59
|
constructor(options: {
|
|
57
60
|
hostBin: string;
|
|
58
61
|
} & SuperDocClientOptions);
|
|
59
62
|
connect(): Promise<void>;
|
|
63
|
+
subscribe(options?: SubscribeOptions): HostNotifications;
|
|
60
64
|
supportsDocumentFacts(sessionId: string): boolean;
|
|
61
65
|
usesCliDocumentFacts(sessionId: string): boolean;
|
|
62
66
|
readDocumentRevision(sessionId: string): Promise<string | undefined>;
|
|
63
67
|
dispose(): Promise<void>;
|
|
64
68
|
private disposeAfterActiveCalls;
|
|
69
|
+
private shutdownAfterActiveCalls;
|
|
65
70
|
invoke<TData = unknown>(operation: OperationSpec, params?: Record<string, unknown>, options?: TransportInvokeOptions): Promise<TData>;
|
|
66
71
|
replaceFile(sessionId: string, path: string, options?: TransportInvokeOptions): Promise<Record<string, unknown>>;
|
|
67
72
|
private invokeWhileActive;
|
package/dist/runtime/host.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { buildOperationArgv, captureMutationPlanAuthor, buildStructuredReadInput, normalizeCollaborationAuth, resolveInvocation, } from './transport-common.js';
|
|
2
|
+
import { buildOperationArgv, captureMutationPlanAuthor, buildStructuredReadInput, normalizeCollaborationAuth, normalizeIdentityClaim, resolveInvocation, } from './transport-common.js';
|
|
3
3
|
import { SuperDocCliError } from './errors.js';
|
|
4
4
|
import { SdkStateDirectory } from './state-directory.js';
|
|
5
|
+
import { HostNotificationHub } from './notifications.js';
|
|
5
6
|
import { registerMutationRevision } from './document-evidence.js';
|
|
6
7
|
import { CONTRACT } from '../generated/contract.js';
|
|
7
8
|
import { SDK_POLICY } from './sdk-policy.js';
|
|
8
9
|
const HOST_PROTOCOL_VERSION = SDK_POLICY.protocolVersion;
|
|
9
10
|
const CLI_HOST_REQUIRED_FEATURES = SDK_POLICY.cliRequiredFeatures;
|
|
10
11
|
export const COLLABORATION_AUTH_PER_OPEN_FEATURE = SDK_POLICY.features.collaborationAuthPerOpen;
|
|
12
|
+
export const IDENTITY_CLAIM_PER_OPEN_FEATURE = SDK_POLICY.features.identityClaimPerOpen;
|
|
11
13
|
const HOST_REQUEST_TIMEOUT_FEATURE = SDK_POLICY.features.requestTimeout;
|
|
12
14
|
const CHANGE_MODES = ['direct', 'tracked'];
|
|
13
15
|
const FORWARD_HOST_STDERR = typeof process !== 'undefined' && typeof process.env?.SUPERDOC_DEBUG_TEXT_REWRITE === 'string'
|
|
@@ -122,6 +124,7 @@ export class HostTransport {
|
|
|
122
124
|
activeCalls = new Set();
|
|
123
125
|
hostFeatures = new Set();
|
|
124
126
|
cliLocalSessions = new Set();
|
|
127
|
+
notifications = new HostNotificationHub();
|
|
125
128
|
constructor(options) {
|
|
126
129
|
this.stateDirectory = new SdkStateDirectory(options.stateDir);
|
|
127
130
|
this.hostBin = options.hostBin;
|
|
@@ -143,6 +146,9 @@ export class HostTransport {
|
|
|
143
146
|
async connect() {
|
|
144
147
|
await this.runWhileActive(() => this.ensureConnected());
|
|
145
148
|
}
|
|
149
|
+
subscribe(options = {}) {
|
|
150
|
+
return this.notifications.subscribe(options);
|
|
151
|
+
}
|
|
146
152
|
supportsDocumentFacts(sessionId) {
|
|
147
153
|
return this.usesCliDocumentFacts(sessionId);
|
|
148
154
|
}
|
|
@@ -168,14 +174,18 @@ export class HostTransport {
|
|
|
168
174
|
async dispose() {
|
|
169
175
|
if (this.disposePromise)
|
|
170
176
|
return this.disposePromise;
|
|
171
|
-
if (this.terminalDisposalError)
|
|
177
|
+
if (this.terminalDisposalError) {
|
|
178
|
+
this.notifications.close();
|
|
172
179
|
throw this.terminalDisposalError;
|
|
180
|
+
}
|
|
173
181
|
if (!this.child &&
|
|
174
182
|
!this.connecting &&
|
|
175
183
|
this.activeCalls.size === 0 &&
|
|
176
184
|
!this.stateDirectory.ownsRoot &&
|
|
177
|
-
this.stoppedChildren.size === 0)
|
|
185
|
+
this.stoppedChildren.size === 0) {
|
|
186
|
+
this.notifications.close();
|
|
178
187
|
return;
|
|
188
|
+
}
|
|
179
189
|
this.stopping = true;
|
|
180
190
|
const disposal = this.disposeAfterActiveCalls();
|
|
181
191
|
this.disposePromise = disposal;
|
|
@@ -189,6 +199,14 @@ export class HostTransport {
|
|
|
189
199
|
}
|
|
190
200
|
}
|
|
191
201
|
async disposeAfterActiveCalls() {
|
|
202
|
+
try {
|
|
203
|
+
await this.shutdownAfterActiveCalls();
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
this.notifications.close();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async shutdownAfterActiveCalls() {
|
|
192
210
|
await Promise.allSettled(Array.from(this.activeCalls));
|
|
193
211
|
if (this.terminalDisposalError)
|
|
194
212
|
throw this.terminalDisposalError;
|
|
@@ -241,6 +259,12 @@ export class HostTransport {
|
|
|
241
259
|
});
|
|
242
260
|
}
|
|
243
261
|
}
|
|
262
|
+
const identityClaim = options.identityClaim === undefined ? undefined : normalizeIdentityClaim(options.identityClaim);
|
|
263
|
+
if (identityClaim !== undefined && operation.operationId !== 'doc.open') {
|
|
264
|
+
throw new SuperDocCliError('identityClaim is supported only for doc.open requests.', {
|
|
265
|
+
code: 'INVALID_ARGUMENT',
|
|
266
|
+
});
|
|
267
|
+
}
|
|
244
268
|
await this.ensureConnected();
|
|
245
269
|
if (collaborationAuth !== undefined && !this.hostFeatures.has(COLLABORATION_AUTH_PER_OPEN_FEATURE)) {
|
|
246
270
|
throw new SuperDocCliError('The connected CLI host does not support per-open collaboration authentication.', {
|
|
@@ -248,6 +272,12 @@ export class HostTransport {
|
|
|
248
272
|
details: { feature: COLLABORATION_AUTH_PER_OPEN_FEATURE },
|
|
249
273
|
});
|
|
250
274
|
}
|
|
275
|
+
if (identityClaim !== undefined && !this.hostFeatures.has(IDENTITY_CLAIM_PER_OPEN_FEATURE)) {
|
|
276
|
+
throw new SuperDocCliError('The connected CLI host does not support a per-open identity claim.', {
|
|
277
|
+
code: 'CAPABILITY_UNSUPPORTED',
|
|
278
|
+
details: { feature: IDENTITY_CLAIM_PER_OPEN_FEATURE },
|
|
279
|
+
});
|
|
280
|
+
}
|
|
251
281
|
const sessionId = typeof params.sessionId === 'string' ? params.sessionId : undefined;
|
|
252
282
|
const supportsRequestTimeoutMetadata = this.hostFeatures.has(HOST_REQUEST_TIMEOUT_FEATURE);
|
|
253
283
|
const cliHostRequestTimeoutMs = this.requestTimeoutMs ?? HOST_DEFAULT_REQUEST_TIMEOUT_MS;
|
|
@@ -285,6 +315,7 @@ export class HostTransport {
|
|
|
285
315
|
}),
|
|
286
316
|
...(includeRevision ? { includeRevision: true } : {}),
|
|
287
317
|
...(collaborationAuth === undefined ? {} : { collaborationAuth }),
|
|
318
|
+
...(identityClaim === undefined ? {} : { identityClaim }),
|
|
288
319
|
}, watchdogTimeout, {
|
|
289
320
|
requestTimeoutMs: supportsRequestTimeoutMetadata ? options.timeoutMs : undefined,
|
|
290
321
|
});
|
|
@@ -508,8 +539,8 @@ export class HostTransport {
|
|
|
508
539
|
if (record.jsonrpc !== '2.0') {
|
|
509
540
|
return;
|
|
510
541
|
}
|
|
511
|
-
// Notification (no id) — reserved for future eventing
|
|
512
542
|
if ('method' in record && !('id' in record)) {
|
|
543
|
+
this.notifications.publish(record);
|
|
513
544
|
return;
|
|
514
545
|
}
|
|
515
546
|
const idRaw = record.id;
|
|
@@ -613,6 +644,7 @@ export class HostTransport {
|
|
|
613
644
|
}
|
|
614
645
|
handleDisconnect(error) {
|
|
615
646
|
this.cleanupProcess(error);
|
|
647
|
+
this.notifications.disconnect(error);
|
|
616
648
|
}
|
|
617
649
|
cleanupProcess(error) {
|
|
618
650
|
this.hostFeatures.clear();
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('./errors.cjs');
|
|
4
|
+
|
|
5
|
+
const NOTIFICATIONS_LAGGED = 'NOTIFICATIONS_LAGGED';
|
|
6
|
+
const DEFAULT_NOTIFICATION_CAPACITY = 64;
|
|
7
|
+
const LAGGED_MESSAGE = 'resynchronize document state before using notification-derived caches';
|
|
8
|
+
const RESYNC_HINT = 'Call changes.list with the cursor of the last change record you processed.';
|
|
9
|
+
class HostNotifications {
|
|
10
|
+
capacity;
|
|
11
|
+
detach;
|
|
12
|
+
queue = [];
|
|
13
|
+
waiters = [];
|
|
14
|
+
skipped = 0;
|
|
15
|
+
failure = null;
|
|
16
|
+
closed = false;
|
|
17
|
+
constructor(capacity, detach) {
|
|
18
|
+
this.capacity = capacity;
|
|
19
|
+
this.detach = detach;
|
|
20
|
+
}
|
|
21
|
+
next() {
|
|
22
|
+
if (this.skipped > 0) {
|
|
23
|
+
const skipped = this.skipped;
|
|
24
|
+
this.skipped = 0;
|
|
25
|
+
return Promise.reject(new errors.SuperDocCliError(LAGGED_MESSAGE, {
|
|
26
|
+
code: NOTIFICATIONS_LAGGED,
|
|
27
|
+
details: { skipped, resync: RESYNC_HINT },
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
const notification = this.queue.shift();
|
|
31
|
+
if (notification)
|
|
32
|
+
return Promise.resolve({ done: false, value: notification });
|
|
33
|
+
if (this.failure) {
|
|
34
|
+
const failure = this.failure;
|
|
35
|
+
this.failure = null;
|
|
36
|
+
return Promise.reject(failure);
|
|
37
|
+
}
|
|
38
|
+
if (this.closed)
|
|
39
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
40
|
+
return new Promise((resolve, reject) => this.waiters.push({ resolve, reject }));
|
|
41
|
+
}
|
|
42
|
+
return() {
|
|
43
|
+
this.close();
|
|
44
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
45
|
+
}
|
|
46
|
+
close() {
|
|
47
|
+
if (this.closed)
|
|
48
|
+
return;
|
|
49
|
+
this.closed = true;
|
|
50
|
+
this.queue.length = 0;
|
|
51
|
+
this.skipped = 0;
|
|
52
|
+
this.failure = null;
|
|
53
|
+
this.detach(this);
|
|
54
|
+
for (const waiter of this.waiters.splice(0))
|
|
55
|
+
waiter.resolve({ done: true, value: undefined });
|
|
56
|
+
}
|
|
57
|
+
[Symbol.asyncIterator]() {
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
get isClosed() {
|
|
61
|
+
return this.closed;
|
|
62
|
+
}
|
|
63
|
+
deliver(notification) {
|
|
64
|
+
if (this.closed)
|
|
65
|
+
return;
|
|
66
|
+
const waiter = this.waiters.shift();
|
|
67
|
+
if (waiter) {
|
|
68
|
+
waiter.resolve({ done: false, value: notification });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (this.queue.length >= this.capacity) {
|
|
72
|
+
this.queue.shift();
|
|
73
|
+
this.skipped += 1;
|
|
74
|
+
}
|
|
75
|
+
this.queue.push(notification);
|
|
76
|
+
}
|
|
77
|
+
fail(error) {
|
|
78
|
+
if (this.closed)
|
|
79
|
+
return;
|
|
80
|
+
const waiter = this.waiters.shift();
|
|
81
|
+
if (waiter) {
|
|
82
|
+
waiter.reject(error);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.failure = error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
class HostNotificationHub {
|
|
89
|
+
subscriptions = new Set();
|
|
90
|
+
subscribe(options = {}) {
|
|
91
|
+
const capacity = options.capacity ?? DEFAULT_NOTIFICATION_CAPACITY;
|
|
92
|
+
if (!Number.isSafeInteger(capacity) || capacity < 1) {
|
|
93
|
+
throw new errors.SuperDocCliError('Notification capacity must be a positive integer.', {
|
|
94
|
+
code: 'INVALID_ARGUMENT',
|
|
95
|
+
details: { capacity },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const subscription = new HostNotifications(capacity, (closed) => this.subscriptions.delete(closed));
|
|
99
|
+
this.subscriptions.add(subscription);
|
|
100
|
+
return subscription;
|
|
101
|
+
}
|
|
102
|
+
publish(frame) {
|
|
103
|
+
if (this.subscriptions.size === 0 || typeof frame.method !== 'string')
|
|
104
|
+
return;
|
|
105
|
+
const notification = frame.params === undefined
|
|
106
|
+
? { jsonrpc: '2.0', method: frame.method }
|
|
107
|
+
: { jsonrpc: '2.0', method: frame.method, params: frame.params };
|
|
108
|
+
for (const subscription of this.subscriptions)
|
|
109
|
+
subscription.deliver(notification);
|
|
110
|
+
}
|
|
111
|
+
disconnect(error) {
|
|
112
|
+
for (const subscription of this.subscriptions)
|
|
113
|
+
subscription.fail(error);
|
|
114
|
+
}
|
|
115
|
+
close() {
|
|
116
|
+
for (const subscription of [...this.subscriptions])
|
|
117
|
+
subscription.close();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
exports.DEFAULT_NOTIFICATION_CAPACITY = DEFAULT_NOTIFICATION_CAPACITY;
|
|
122
|
+
exports.HostNotificationHub = HostNotificationHub;
|
|
123
|
+
exports.HostNotifications = HostNotifications;
|
|
124
|
+
exports.NOTIFICATIONS_LAGGED = NOTIFICATIONS_LAGGED;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SuperDocCliError } from './errors.js';
|
|
2
|
+
export declare const NOTIFICATIONS_LAGGED = "NOTIFICATIONS_LAGGED";
|
|
3
|
+
export declare const DEFAULT_NOTIFICATION_CAPACITY = 64;
|
|
4
|
+
export interface HostNotification {
|
|
5
|
+
readonly jsonrpc: '2.0';
|
|
6
|
+
readonly method: string;
|
|
7
|
+
readonly params?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface SubscribeOptions {
|
|
10
|
+
readonly capacity?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class HostNotifications implements AsyncIterableIterator<HostNotification> {
|
|
13
|
+
private readonly capacity;
|
|
14
|
+
private readonly detach;
|
|
15
|
+
private readonly queue;
|
|
16
|
+
private readonly waiters;
|
|
17
|
+
private skipped;
|
|
18
|
+
private failure;
|
|
19
|
+
private closed;
|
|
20
|
+
constructor(capacity: number, detach: (subscription: HostNotifications) => void);
|
|
21
|
+
next(): Promise<IteratorResult<HostNotification, undefined>>;
|
|
22
|
+
return(): Promise<IteratorResult<HostNotification, undefined>>;
|
|
23
|
+
close(): void;
|
|
24
|
+
[Symbol.asyncIterator](): this;
|
|
25
|
+
get isClosed(): boolean;
|
|
26
|
+
deliver(notification: HostNotification): void;
|
|
27
|
+
fail(error: SuperDocCliError): void;
|
|
28
|
+
}
|
|
29
|
+
export declare class HostNotificationHub {
|
|
30
|
+
private readonly subscriptions;
|
|
31
|
+
subscribe(options?: SubscribeOptions): HostNotifications;
|
|
32
|
+
publish(frame: Record<string, unknown>): void;
|
|
33
|
+
disconnect(error: SuperDocCliError): void;
|
|
34
|
+
close(): void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { SuperDocCliError } from './errors.js';
|
|
2
|
+
export const NOTIFICATIONS_LAGGED = 'NOTIFICATIONS_LAGGED';
|
|
3
|
+
export const DEFAULT_NOTIFICATION_CAPACITY = 64;
|
|
4
|
+
const LAGGED_MESSAGE = 'resynchronize document state before using notification-derived caches';
|
|
5
|
+
const RESYNC_HINT = 'Call changes.list with the cursor of the last change record you processed.';
|
|
6
|
+
export class HostNotifications {
|
|
7
|
+
capacity;
|
|
8
|
+
detach;
|
|
9
|
+
queue = [];
|
|
10
|
+
waiters = [];
|
|
11
|
+
skipped = 0;
|
|
12
|
+
failure = null;
|
|
13
|
+
closed = false;
|
|
14
|
+
constructor(capacity, detach) {
|
|
15
|
+
this.capacity = capacity;
|
|
16
|
+
this.detach = detach;
|
|
17
|
+
}
|
|
18
|
+
next() {
|
|
19
|
+
if (this.skipped > 0) {
|
|
20
|
+
const skipped = this.skipped;
|
|
21
|
+
this.skipped = 0;
|
|
22
|
+
return Promise.reject(new SuperDocCliError(LAGGED_MESSAGE, {
|
|
23
|
+
code: NOTIFICATIONS_LAGGED,
|
|
24
|
+
details: { skipped, resync: RESYNC_HINT },
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
const notification = this.queue.shift();
|
|
28
|
+
if (notification)
|
|
29
|
+
return Promise.resolve({ done: false, value: notification });
|
|
30
|
+
if (this.failure) {
|
|
31
|
+
const failure = this.failure;
|
|
32
|
+
this.failure = null;
|
|
33
|
+
return Promise.reject(failure);
|
|
34
|
+
}
|
|
35
|
+
if (this.closed)
|
|
36
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
37
|
+
return new Promise((resolve, reject) => this.waiters.push({ resolve, reject }));
|
|
38
|
+
}
|
|
39
|
+
return() {
|
|
40
|
+
this.close();
|
|
41
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
42
|
+
}
|
|
43
|
+
close() {
|
|
44
|
+
if (this.closed)
|
|
45
|
+
return;
|
|
46
|
+
this.closed = true;
|
|
47
|
+
this.queue.length = 0;
|
|
48
|
+
this.skipped = 0;
|
|
49
|
+
this.failure = null;
|
|
50
|
+
this.detach(this);
|
|
51
|
+
for (const waiter of this.waiters.splice(0))
|
|
52
|
+
waiter.resolve({ done: true, value: undefined });
|
|
53
|
+
}
|
|
54
|
+
[Symbol.asyncIterator]() {
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
get isClosed() {
|
|
58
|
+
return this.closed;
|
|
59
|
+
}
|
|
60
|
+
deliver(notification) {
|
|
61
|
+
if (this.closed)
|
|
62
|
+
return;
|
|
63
|
+
const waiter = this.waiters.shift();
|
|
64
|
+
if (waiter) {
|
|
65
|
+
waiter.resolve({ done: false, value: notification });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (this.queue.length >= this.capacity) {
|
|
69
|
+
this.queue.shift();
|
|
70
|
+
this.skipped += 1;
|
|
71
|
+
}
|
|
72
|
+
this.queue.push(notification);
|
|
73
|
+
}
|
|
74
|
+
fail(error) {
|
|
75
|
+
if (this.closed)
|
|
76
|
+
return;
|
|
77
|
+
const waiter = this.waiters.shift();
|
|
78
|
+
if (waiter) {
|
|
79
|
+
waiter.reject(error);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.failure = error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export class HostNotificationHub {
|
|
86
|
+
subscriptions = new Set();
|
|
87
|
+
subscribe(options = {}) {
|
|
88
|
+
const capacity = options.capacity ?? DEFAULT_NOTIFICATION_CAPACITY;
|
|
89
|
+
if (!Number.isSafeInteger(capacity) || capacity < 1) {
|
|
90
|
+
throw new SuperDocCliError('Notification capacity must be a positive integer.', {
|
|
91
|
+
code: 'INVALID_ARGUMENT',
|
|
92
|
+
details: { capacity },
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const subscription = new HostNotifications(capacity, (closed) => this.subscriptions.delete(closed));
|
|
96
|
+
this.subscriptions.add(subscription);
|
|
97
|
+
return subscription;
|
|
98
|
+
}
|
|
99
|
+
publish(frame) {
|
|
100
|
+
if (this.subscriptions.size === 0 || typeof frame.method !== 'string')
|
|
101
|
+
return;
|
|
102
|
+
const notification = frame.params === undefined
|
|
103
|
+
? { jsonrpc: '2.0', method: frame.method }
|
|
104
|
+
: { jsonrpc: '2.0', method: frame.method, params: frame.params };
|
|
105
|
+
for (const subscription of this.subscriptions)
|
|
106
|
+
subscription.deliver(notification);
|
|
107
|
+
}
|
|
108
|
+
disconnect(error) {
|
|
109
|
+
for (const subscription of this.subscriptions)
|
|
110
|
+
subscription.fail(error);
|
|
111
|
+
}
|
|
112
|
+
close() {
|
|
113
|
+
for (const subscription of [...this.subscriptions])
|
|
114
|
+
subscription.close();
|
|
115
|
+
}
|
|
116
|
+
}
|
package/dist/runtime/process.cjs
CHANGED
|
@@ -16,7 +16,7 @@ function resolveRuntimeProcess(options = {}, embedded = {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
function toSafeInvokeTraceOptions(options) {
|
|
19
|
-
const { collaborationAuth: _collaborationAuth, ...traceOptions } = options;
|
|
19
|
+
const { collaborationAuth: _collaborationAuth, identityClaim: _identityClaim, ...traceOptions } = options;
|
|
20
20
|
return traceOptions;
|
|
21
21
|
}
|
|
22
22
|
class SuperDocRuntime {
|
|
@@ -31,6 +31,9 @@ class SuperDocRuntime {
|
|
|
31
31
|
async connect() {
|
|
32
32
|
await this.transport.connect();
|
|
33
33
|
}
|
|
34
|
+
subscribe(options = {}) {
|
|
35
|
+
return this.transport.subscribe(options);
|
|
36
|
+
}
|
|
34
37
|
supportsDocumentFacts(sessionId) {
|
|
35
38
|
return this.transport.supportsDocumentFacts(sessionId);
|
|
36
39
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HostNotifications, SubscribeOptions } from './notifications.js';
|
|
1
2
|
import type { CollaborationAuth, DocumentRuntimeKind, DocOpenOptions, InvokeOptions, TransportInvokeOptions, OperationParamSpec, OperationSpec, RuntimeInvoker, SuperDocClientOptions } from './transport-common.js';
|
|
2
3
|
type RuntimeProcessResolution = {
|
|
3
4
|
hostBin: string;
|
|
@@ -24,6 +25,7 @@ export declare class SuperDocRuntime {
|
|
|
24
25
|
private readonly transport;
|
|
25
26
|
constructor(options?: SuperDocClientOptions);
|
|
26
27
|
connect(): Promise<void>;
|
|
28
|
+
subscribe(options?: SubscribeOptions): HostNotifications;
|
|
27
29
|
supportsDocumentFacts(sessionId: string): boolean;
|
|
28
30
|
usesCliDocumentFacts(sessionId: string): boolean;
|
|
29
31
|
readDocumentRevision(sessionId: string): Promise<string | undefined>;
|
package/dist/runtime/process.js
CHANGED
|
@@ -13,7 +13,7 @@ export function resolveRuntimeProcess(options = {}, embedded = {
|
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
export function toSafeInvokeTraceOptions(options) {
|
|
16
|
-
const { collaborationAuth: _collaborationAuth, ...traceOptions } = options;
|
|
16
|
+
const { collaborationAuth: _collaborationAuth, identityClaim: _identityClaim, ...traceOptions } = options;
|
|
17
17
|
return traceOptions;
|
|
18
18
|
}
|
|
19
19
|
export class SuperDocRuntime {
|
|
@@ -28,6 +28,9 @@ export class SuperDocRuntime {
|
|
|
28
28
|
async connect() {
|
|
29
29
|
await this.transport.connect();
|
|
30
30
|
}
|
|
31
|
+
subscribe(options = {}) {
|
|
32
|
+
return this.transport.subscribe(options);
|
|
33
|
+
}
|
|
31
34
|
supportsDocumentFacts(sessionId) {
|
|
32
35
|
return this.transport.supportsDocumentFacts(sessionId);
|
|
33
36
|
}
|
|
@@ -5,6 +5,7 @@ export declare const SDK_POLICY: {
|
|
|
5
5
|
replaceFile: string;
|
|
6
6
|
requestTimeout: string;
|
|
7
7
|
collaborationAuthPerOpen: string;
|
|
8
|
+
identityClaimPerOpen: string;
|
|
8
9
|
};
|
|
9
10
|
operationParamAliases: Record<string, Readonly<Record<string, readonly string[]>>>;
|
|
10
11
|
notifications: readonly string[];
|
|
@@ -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.27.0-next.4';
|
|
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.27.0-next.4";
|
|
@@ -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.27.0-next.4';
|