@verentis/sdk 1.0.0 → 1.0.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 +31 -0
- package/dist/index.cjs +275 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +413 -4
- package/dist/index.d.ts +413 -4
- package/dist/index.js +275 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -295,6 +295,37 @@ contracts must not assume a locally present feature-branch API is already deploy
|
|
|
295
295
|
| `BridgeAuth` | Auth strategy that receives tokens via the bridge |
|
|
296
296
|
| `matchMimeType` / `findBestMatch` | MIME type matching utilities |
|
|
297
297
|
|
|
298
|
+
### Chat
|
|
299
|
+
|
|
300
|
+
`client.chat` is the documented workspace chat API (`/v1/chat`). The caller and workspace always come from the
|
|
301
|
+
token; message content is untrusted Markdown that readers render without raw HTML.
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
const conversation = await client.chat.openDirect({ kind: 'user', id: colleagueId })
|
|
305
|
+
await client.chat.sendText(conversation.id, 'Hi **there**', { idempotencyKey: crypto.randomUUID() })
|
|
306
|
+
|
|
307
|
+
// Inside the workspace (needs the approved `chat.read` permission): identifier-only live hints over the
|
|
308
|
+
// host's realtime connection. Hints can be lost or repeated, so catch up from durable events.
|
|
309
|
+
const stop = client.chat.subscribeChanges({
|
|
310
|
+
onChange: async (hint) => {
|
|
311
|
+
const page = await client.chat.events(hint.conversationId, { afterSeq: lastAppliedSeq })
|
|
312
|
+
// apply page.items; if page.resetRequired, reload the conversation and its history
|
|
313
|
+
},
|
|
314
|
+
onConnection: (status) => { if (status === 'connected') void reconcile() },
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
// From an installed app's script: post as the app's bot (declared in `spec.chat.bots`). A command script receives
|
|
318
|
+
// chat_conversation_id and chat_invocation_key with its arguments; reusing the key makes a retried run reply once.
|
|
319
|
+
await client.chat.postAsBot({
|
|
320
|
+
conversationId: params.chat_conversation_id,
|
|
321
|
+
parts: [{ type: 'text', data: { markdown: 'Invoice 42 needs approval' } }],
|
|
322
|
+
idempotencyKey: params.chat_invocation_key,
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
// Run an installed app's slash command as the current user.
|
|
326
|
+
await client.chat.runCommand(conversationId, 'invoicing/approve-invoice', { invoice: 'INV-42' })
|
|
327
|
+
```
|
|
328
|
+
|
|
298
329
|
### Workspace settings
|
|
299
330
|
|
|
300
331
|
Apps whose manifest declares `spec.settings[]` get workspace setting definitions auto-registered
|
package/dist/index.cjs
CHANGED
|
@@ -292,7 +292,8 @@ var ExecutionsModule = class {
|
|
|
292
292
|
tool: options?.tool,
|
|
293
293
|
mode: options?.mode,
|
|
294
294
|
arguments: options?.arguments ?? [],
|
|
295
|
-
parameters: serializeParameters(options?.parameters)
|
|
295
|
+
parameters: serializeParameters(options?.parameters),
|
|
296
|
+
...options?.invocationKey ? { invocationKey: options.invocationKey } : {}
|
|
296
297
|
}),
|
|
297
298
|
headers: { "Content-Type": "application/json" }
|
|
298
299
|
});
|
|
@@ -338,9 +339,9 @@ var ExecutionsModule = class {
|
|
|
338
339
|
return descriptor;
|
|
339
340
|
}
|
|
340
341
|
/** Get an execution by id. */
|
|
341
|
-
async get(
|
|
342
|
+
async get(id2, options) {
|
|
342
343
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
343
|
-
return this.http.request("GET", `/executions/${encodeURIComponent(
|
|
344
|
+
return this.http.request("GET", `/executions/${encodeURIComponent(id2)}`, {
|
|
344
345
|
params: { workspaceId }
|
|
345
346
|
});
|
|
346
347
|
}
|
|
@@ -365,17 +366,17 @@ var ExecutionsModule = class {
|
|
|
365
366
|
});
|
|
366
367
|
}
|
|
367
368
|
/** Get the captured stdout/stderr of an execution. */
|
|
368
|
-
async logs(
|
|
369
|
+
async logs(id2, options) {
|
|
369
370
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
370
|
-
return this.http.request("GET", `/executions/${encodeURIComponent(
|
|
371
|
+
return this.http.request("GET", `/executions/${encodeURIComponent(id2)}/logs`, {
|
|
371
372
|
params: { workspaceId }
|
|
372
373
|
});
|
|
373
374
|
}
|
|
374
375
|
/** Cancel a pending or running execution. */
|
|
375
|
-
async cancel(
|
|
376
|
+
async cancel(id2, options) {
|
|
376
377
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
377
|
-
return this.http.request("POST", `/executions/${encodeURIComponent(
|
|
378
|
-
body: JSON.stringify({ id, workspaceId }),
|
|
378
|
+
return this.http.request("POST", `/executions/${encodeURIComponent(id2)}/cancel`, {
|
|
379
|
+
body: JSON.stringify({ id: id2, workspaceId }),
|
|
379
380
|
headers: { "Content-Type": "application/json" }
|
|
380
381
|
});
|
|
381
382
|
}
|
|
@@ -383,16 +384,16 @@ var ExecutionsModule = class {
|
|
|
383
384
|
* Poll an execution until it reaches a terminal status. Returns immediately if it is already
|
|
384
385
|
* terminal. Throws if `timeoutMs` elapses or the supplied signal aborts.
|
|
385
386
|
*/
|
|
386
|
-
async wait(
|
|
387
|
+
async wait(id2, options) {
|
|
387
388
|
const interval = options?.intervalMs ?? 1e3;
|
|
388
389
|
const deadline = options?.timeoutMs ? Date.now() + options.timeoutMs : void 0;
|
|
389
390
|
for (; ; ) {
|
|
390
|
-
const execution = await this.get(
|
|
391
|
+
const execution = await this.get(id2, { workspaceId: options?.workspaceId });
|
|
391
392
|
if (isTerminalStatus(execution.status)) {
|
|
392
393
|
return execution;
|
|
393
394
|
}
|
|
394
395
|
if (deadline !== void 0 && Date.now() >= deadline) {
|
|
395
|
-
throw new Error(`Timed out waiting for execution '${
|
|
396
|
+
throw new Error(`Timed out waiting for execution '${id2}' to complete`);
|
|
396
397
|
}
|
|
397
398
|
await delay(interval, options?.signal);
|
|
398
399
|
}
|
|
@@ -409,11 +410,11 @@ var ExecutionsModule = class {
|
|
|
409
410
|
return this.wait(execution.id, options);
|
|
410
411
|
}
|
|
411
412
|
requireWorkspaceId(override) {
|
|
412
|
-
const
|
|
413
|
-
if (!
|
|
413
|
+
const id2 = override ?? this.workspaceId;
|
|
414
|
+
if (!id2) {
|
|
414
415
|
throw new Error("workspaceId is required: provide it in options or when creating the client");
|
|
415
416
|
}
|
|
416
|
-
return
|
|
417
|
+
return id2;
|
|
417
418
|
}
|
|
418
419
|
};
|
|
419
420
|
function serializeParameters(parameters) {
|
|
@@ -454,8 +455,8 @@ var EnginesModule = class {
|
|
|
454
455
|
}
|
|
455
456
|
});
|
|
456
457
|
}
|
|
457
|
-
async get(
|
|
458
|
-
return this.http.request("GET", `/engines/${encodeURIComponent(
|
|
458
|
+
async get(id2, options) {
|
|
459
|
+
return this.http.request("GET", `/engines/${encodeURIComponent(id2)}`, {
|
|
459
460
|
params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) }
|
|
460
461
|
});
|
|
461
462
|
}
|
|
@@ -676,11 +677,11 @@ var FilesModule = class {
|
|
|
676
677
|
});
|
|
677
678
|
}
|
|
678
679
|
workspaceHeaders() {
|
|
679
|
-
const
|
|
680
|
+
const headers2 = {};
|
|
680
681
|
if (this.workspaceId) {
|
|
681
|
-
|
|
682
|
+
headers2["X-Workspace-Id"] = this.workspaceId;
|
|
682
683
|
}
|
|
683
|
-
return
|
|
684
|
+
return headers2;
|
|
684
685
|
}
|
|
685
686
|
};
|
|
686
687
|
function requireNonBlank(value, name) {
|
|
@@ -772,14 +773,14 @@ var InstallationsModule = class {
|
|
|
772
773
|
}
|
|
773
774
|
});
|
|
774
775
|
}
|
|
775
|
-
async update(
|
|
776
|
+
async update(id2, options) {
|
|
776
777
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
777
778
|
return this.http.request(
|
|
778
779
|
"PUT",
|
|
779
|
-
`/installations/${encodeURIComponent(
|
|
780
|
+
`/installations/${encodeURIComponent(id2)}`,
|
|
780
781
|
{
|
|
781
782
|
body: JSON.stringify({
|
|
782
|
-
id,
|
|
783
|
+
id: id2,
|
|
783
784
|
workspaceId,
|
|
784
785
|
packageVersion: options?.packageVersion,
|
|
785
786
|
installMode: options?.installMode
|
|
@@ -788,8 +789,8 @@ var InstallationsModule = class {
|
|
|
788
789
|
}
|
|
789
790
|
);
|
|
790
791
|
}
|
|
791
|
-
async uninstall(
|
|
792
|
-
await this.http.request("DELETE", `/installations/${encodeURIComponent(
|
|
792
|
+
async uninstall(id2, options) {
|
|
793
|
+
await this.http.request("DELETE", `/installations/${encodeURIComponent(id2)}`, {
|
|
793
794
|
params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) }
|
|
794
795
|
});
|
|
795
796
|
}
|
|
@@ -815,10 +816,10 @@ var ResourcesModule = class {
|
|
|
815
816
|
params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) }
|
|
816
817
|
});
|
|
817
818
|
}
|
|
818
|
-
async get(
|
|
819
|
+
async get(id2, options) {
|
|
819
820
|
return this.http.request(
|
|
820
821
|
"GET",
|
|
821
|
-
`/resources/${encodeURIComponent(
|
|
822
|
+
`/resources/${encodeURIComponent(id2)}`,
|
|
822
823
|
{ params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) } }
|
|
823
824
|
);
|
|
824
825
|
}
|
|
@@ -982,10 +983,10 @@ var NotificationsModule = class {
|
|
|
982
983
|
}
|
|
983
984
|
}
|
|
984
985
|
}
|
|
985
|
-
async request(
|
|
986
|
+
async request(id2, options) {
|
|
986
987
|
return this.http.request(
|
|
987
988
|
"GET",
|
|
988
|
-
`/notifications/requests/${encodeURIComponent(
|
|
989
|
+
`/notifications/requests/${encodeURIComponent(id2)}`,
|
|
989
990
|
{
|
|
990
991
|
params: {
|
|
991
992
|
workspaceId: this.requireWorkspaceId(options?.workspaceId),
|
|
@@ -1029,8 +1030,8 @@ var BusinessModule = class _BusinessModule {
|
|
|
1029
1030
|
body: JSON.stringify(command)
|
|
1030
1031
|
});
|
|
1031
1032
|
}
|
|
1032
|
-
async read(
|
|
1033
|
-
return this.http.request("GET", `/business/records/${encodeURIComponent(
|
|
1033
|
+
async read(id2) {
|
|
1034
|
+
return this.http.request("GET", `/business/records/${encodeURIComponent(id2)}`, { headers: this.headers() });
|
|
1034
1035
|
}
|
|
1035
1036
|
async list(kind) {
|
|
1036
1037
|
return this.http.request("GET", "/business/records", {
|
|
@@ -1072,6 +1073,190 @@ var BusinessModule = class _BusinessModule {
|
|
|
1072
1073
|
}
|
|
1073
1074
|
};
|
|
1074
1075
|
|
|
1076
|
+
// src/modules/chat.ts
|
|
1077
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
1078
|
+
var ChatModule = class {
|
|
1079
|
+
constructor(http, bridge = null, executions) {
|
|
1080
|
+
this.http = http;
|
|
1081
|
+
this.bridge = bridge;
|
|
1082
|
+
this.executions = executions;
|
|
1083
|
+
}
|
|
1084
|
+
http;
|
|
1085
|
+
bridge;
|
|
1086
|
+
executions;
|
|
1087
|
+
// ── Conversations ─────────────────────────────────────────────────
|
|
1088
|
+
listConversations(options) {
|
|
1089
|
+
return this.http.request("GET", "/chat/conversations", { params: page(options) });
|
|
1090
|
+
}
|
|
1091
|
+
createConversation(options) {
|
|
1092
|
+
const { idempotencyKey, ...body } = options;
|
|
1093
|
+
return this.http.request("POST", "/chat/conversations", { body: JSON.stringify(body), headers: headers(idempotencyKey) });
|
|
1094
|
+
}
|
|
1095
|
+
/** Opens (or returns the existing) direct conversation with one participant. */
|
|
1096
|
+
openDirect(participant) {
|
|
1097
|
+
return this.createConversation({ kind: "direct", participants: [participant] });
|
|
1098
|
+
}
|
|
1099
|
+
getConversation(conversationId) {
|
|
1100
|
+
return this.http.request("GET", `/chat/conversations/${id(conversationId)}`);
|
|
1101
|
+
}
|
|
1102
|
+
updateConversation(conversationId, changes) {
|
|
1103
|
+
return this.http.request("PATCH", `/chat/conversations/${id(conversationId)}`, { body: JSON.stringify(changes), headers: JSON_HEADERS });
|
|
1104
|
+
}
|
|
1105
|
+
join(conversationId) {
|
|
1106
|
+
return this.http.request("POST", `/chat/conversations/${id(conversationId)}/join`, { body: "{}", headers: JSON_HEADERS });
|
|
1107
|
+
}
|
|
1108
|
+
listPublicChannels(options) {
|
|
1109
|
+
return this.http.request("GET", "/chat/channels", { params: { ...page(options), query: options?.query } });
|
|
1110
|
+
}
|
|
1111
|
+
// ── Members ───────────────────────────────────────────────────────
|
|
1112
|
+
listMembers(conversationId) {
|
|
1113
|
+
return this.http.request("GET", `/chat/conversations/${id(conversationId)}/members`);
|
|
1114
|
+
}
|
|
1115
|
+
addMembers(conversationId, participants, role) {
|
|
1116
|
+
return this.http.request("POST", `/chat/conversations/${id(conversationId)}/members`, {
|
|
1117
|
+
body: JSON.stringify({ participants, role }),
|
|
1118
|
+
headers: JSON_HEADERS
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
/** Removes a member; pass yourself to leave. */
|
|
1122
|
+
async removeMember(conversationId, participant) {
|
|
1123
|
+
await this.http.request("DELETE", `/chat/conversations/${id(conversationId)}/members/${participant.kind}/${id(participant.id)}`);
|
|
1124
|
+
}
|
|
1125
|
+
changeRole(conversationId, participant, role) {
|
|
1126
|
+
return this.http.request("PUT", `/chat/conversations/${id(conversationId)}/members/${participant.kind}/${id(participant.id)}/role`, {
|
|
1127
|
+
body: JSON.stringify({ role }),
|
|
1128
|
+
headers: JSON_HEADERS
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
// ── Messages ──────────────────────────────────────────────────────
|
|
1132
|
+
listMessages(conversationId, options) {
|
|
1133
|
+
return this.http.request("GET", `/chat/conversations/${id(conversationId)}/messages`, {
|
|
1134
|
+
params: { before: options?.before, limit: options?.limit }
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
getMessage(conversationId, messageId) {
|
|
1138
|
+
return this.http.request("GET", `/chat/conversations/${id(conversationId)}/messages/${id(messageId)}`);
|
|
1139
|
+
}
|
|
1140
|
+
send(conversationId, parts, options) {
|
|
1141
|
+
return this.http.request("POST", `/chat/conversations/${id(conversationId)}/messages`, {
|
|
1142
|
+
body: JSON.stringify({ parts, replyTo: options?.replyTo }),
|
|
1143
|
+
headers: headers(options?.idempotencyKey)
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
/** Sends Markdown text (rendered without raw HTML by every reader). */
|
|
1147
|
+
sendText(conversationId, markdown, options) {
|
|
1148
|
+
return this.send(conversationId, [{ type: "text", data: { markdown } }], options);
|
|
1149
|
+
}
|
|
1150
|
+
/** Edits your own message; pass the revision you saw to reject a concurrent edit. */
|
|
1151
|
+
edit(conversationId, messageId, parts, options) {
|
|
1152
|
+
return this.http.request("PATCH", `/chat/conversations/${id(conversationId)}/messages/${id(messageId)}`, {
|
|
1153
|
+
body: JSON.stringify({ parts }),
|
|
1154
|
+
headers: { ...JSON_HEADERS, ...options?.revision ? { "If-Match": `"${options.revision}"` } : {} }
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
delete(conversationId, messageId) {
|
|
1158
|
+
return this.http.request("DELETE", `/chat/conversations/${id(conversationId)}/messages/${id(messageId)}`);
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Durable changes after a position: `afterSeq` is a snapshot's `highWatermark` (or the last sequence you applied);
|
|
1162
|
+
* `after` is the `next` cursor of a previous page.
|
|
1163
|
+
*/
|
|
1164
|
+
events(conversationId, options) {
|
|
1165
|
+
return this.http.request("GET", `/chat/conversations/${id(conversationId)}/events`, {
|
|
1166
|
+
params: { after: options?.after, afterSeq: options?.afterSeq, limit: options?.limit }
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
// ── Read state and preferences ────────────────────────────────────
|
|
1170
|
+
/** Marks messages read through a sequence; never moves back and never past what the server has. */
|
|
1171
|
+
markRead(conversationId, readThroughSeq) {
|
|
1172
|
+
return this.http.request("PUT", `/chat/conversations/${id(conversationId)}/read-state`, {
|
|
1173
|
+
body: JSON.stringify({ readThroughSeq }),
|
|
1174
|
+
headers: JSON_HEADERS
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
setPreferences(conversationId, preferences) {
|
|
1178
|
+
return this.http.request("PUT", `/chat/conversations/${id(conversationId)}/preferences`, {
|
|
1179
|
+
body: JSON.stringify(preferences),
|
|
1180
|
+
headers: JSON_HEADERS
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
// ── People, bots and commands ─────────────────────────────────────
|
|
1184
|
+
/** People in your workspace (name and avatar only). */
|
|
1185
|
+
searchPeople(options) {
|
|
1186
|
+
return this.http.request("GET", "/chat/people", { params: { ...page(options), query: options?.query } });
|
|
1187
|
+
}
|
|
1188
|
+
listBots() {
|
|
1189
|
+
return this.http.request("GET", "/chat/bots");
|
|
1190
|
+
}
|
|
1191
|
+
/** Workspace managers (`chat.manage`) decide whether a bot may message people directly. */
|
|
1192
|
+
updateBotSettings(botId, settings) {
|
|
1193
|
+
return this.http.request("PUT", `/chat/bots/${id(botId)}/settings`, { body: JSON.stringify(settings), headers: JSON_HEADERS });
|
|
1194
|
+
}
|
|
1195
|
+
listCommands() {
|
|
1196
|
+
return this.http.request("GET", "/chat/commands");
|
|
1197
|
+
}
|
|
1198
|
+
/** Validates and records a command invocation, returning the Execution request to run as you. */
|
|
1199
|
+
invokeCommand(conversationId, command, args, options) {
|
|
1200
|
+
return this.http.request("POST", `/chat/conversations/${id(conversationId)}/commands`, {
|
|
1201
|
+
body: JSON.stringify({ command, arguments: args ?? {} }),
|
|
1202
|
+
headers: headers(options?.idempotencyKey)
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Invokes an installed app's command and runs its script with your own authorisation. Retrying with the same
|
|
1207
|
+
* idempotency key reuses the invocation key, so Execution never runs it twice.
|
|
1208
|
+
*/
|
|
1209
|
+
async runCommand(conversationId, command, args, options) {
|
|
1210
|
+
if (!this.executions) throw new Error("Running commands needs the executions module.");
|
|
1211
|
+
const invocation = await this.invokeCommand(conversationId, command, args, options);
|
|
1212
|
+
const execution = await this.executions.run(invocation.filePath, {
|
|
1213
|
+
workspaceId: invocation.workspaceId,
|
|
1214
|
+
branch: invocation.branch,
|
|
1215
|
+
parameters: JSON.parse(invocation.parameters),
|
|
1216
|
+
invocationKey: invocation.invocationKey
|
|
1217
|
+
});
|
|
1218
|
+
return { invocation, execution };
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Posts as the installed app's bot from a running script. The bot is derived from the script's execution; the
|
|
1222
|
+
* conversation must have added the bot (or, for `userId`, the workspace must allow it to message people).
|
|
1223
|
+
* Retries briefly while Execution's start event is still on its way.
|
|
1224
|
+
*/
|
|
1225
|
+
async postAsBot(options) {
|
|
1226
|
+
const { idempotencyKey, ...body } = options;
|
|
1227
|
+
const request = { body: JSON.stringify(body), headers: headers(idempotencyKey ?? globalThis.crypto?.randomUUID?.()) };
|
|
1228
|
+
const deadline = Date.now() + 1e4;
|
|
1229
|
+
for (; ; ) {
|
|
1230
|
+
try {
|
|
1231
|
+
return await this.http.request("POST", "/chat/bot-messages", request);
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
if (!(error instanceof ApiError) || error.status !== 409 || error.code !== "execution_not_ready") throw error;
|
|
1234
|
+
const delay2 = Math.max(250, error.retryAfterMs ?? 1e3);
|
|
1235
|
+
if (Date.now() + delay2 > deadline) throw error;
|
|
1236
|
+
await new Promise((resolve) => setTimeout(resolve, delay2));
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
// ── Live hints ────────────────────────────────────────────────────
|
|
1241
|
+
/**
|
|
1242
|
+
* Subscribes to live change hints through the host (installed apps only). Returns an unsubscribe function.
|
|
1243
|
+
* Hints carry ids only; duplicates and reordering are normal, and hints are lost while disconnected.
|
|
1244
|
+
*/
|
|
1245
|
+
subscribeChanges(handlers) {
|
|
1246
|
+
if (!this.bridge) throw new Error("Live chat hints are only available to apps running inside the workspace.");
|
|
1247
|
+
return this.bridge.subscribeChat(handlers);
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
function id(value) {
|
|
1251
|
+
return encodeURIComponent(value);
|
|
1252
|
+
}
|
|
1253
|
+
function page(options) {
|
|
1254
|
+
return { cursor: options?.cursor, limit: options?.limit };
|
|
1255
|
+
}
|
|
1256
|
+
function headers(idempotencyKey) {
|
|
1257
|
+
return idempotencyKey ? { ...JSON_HEADERS, "Idempotency-Key": idempotencyKey } : JSON_HEADERS;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1075
1260
|
// src/transport/app-commands.ts
|
|
1076
1261
|
var APP_COMMAND_BATCH_SIZE = 200;
|
|
1077
1262
|
var APP_COMMANDS_CAPABILITY = "commands";
|
|
@@ -1115,7 +1300,7 @@ function element(value) {
|
|
|
1115
1300
|
return record(value) && identifier(value.id) && natural(value.version) && (value.versionNonce === void 0 || natural(value.versionNonce)) && (value.isDeleted === void 0 || typeof value.isDeleted === "boolean");
|
|
1116
1301
|
}
|
|
1117
1302
|
function files(value) {
|
|
1118
|
-
return record(value) && Object.keys(value).length <= 1e4 && Object.entries(value).every(([
|
|
1303
|
+
return record(value) && Object.keys(value).length <= 1e4 && Object.entries(value).every(([id2, file]) => record(file) && identifier(id2) && file.id === id2 && typeof file.dataURL === "string" && file.dataURL.length <= 10 * 1024 * 1024 && typeof file.mimeType === "string" && file.mimeType.length > 0 && file.mimeType.length <= 128 && natural(file.created) && (file.lastRetrieved === void 0 || natural(file.lastRetrieved)));
|
|
1119
1304
|
}
|
|
1120
1305
|
function isNativeSnapshot(value) {
|
|
1121
1306
|
if (!record(value) || !natural(value.sequence) || !natural(value.savedSequence) || value.savedSequence > value.sequence || typeof value.revision !== "string" || !value.revision || value.revision.length > 1024 || typeof value.readOnly !== "boolean" || !record(value.scene) || !Array.isArray(value.scene.elements) || value.scene.elements.length > 1e4 || !value.scene.elements.every(element) || !files(value.scene.files) || !record(value.scene.appState) || !Array.isArray(value.participants) || value.participants.length > 20)
|
|
@@ -1230,6 +1415,7 @@ var Bridge = class {
|
|
|
1230
1415
|
commandFlushScheduled = false;
|
|
1231
1416
|
commandRequests = /* @__PURE__ */ new Set();
|
|
1232
1417
|
_hostCapabilities = [];
|
|
1418
|
+
chatSubscribers = /* @__PURE__ */ new Set();
|
|
1233
1419
|
hostMessageHandlers = /* @__PURE__ */ new Map();
|
|
1234
1420
|
hostMessageRequests = /* @__PURE__ */ new Set();
|
|
1235
1421
|
wopiRequests = /* @__PURE__ */ new Map();
|
|
@@ -1433,13 +1619,13 @@ var Bridge = class {
|
|
|
1433
1619
|
}
|
|
1434
1620
|
};
|
|
1435
1621
|
}
|
|
1436
|
-
queueCommand(
|
|
1622
|
+
queueCommand(id2, change) {
|
|
1437
1623
|
if (change === "upsert") {
|
|
1438
|
-
this.commandRemovals.delete(
|
|
1439
|
-
this.commandUpserts.add(
|
|
1624
|
+
this.commandRemovals.delete(id2);
|
|
1625
|
+
this.commandUpserts.add(id2);
|
|
1440
1626
|
} else {
|
|
1441
|
-
this.commandUpserts.delete(
|
|
1442
|
-
this.commandRemovals.add(
|
|
1627
|
+
this.commandUpserts.delete(id2);
|
|
1628
|
+
this.commandRemovals.add(id2);
|
|
1443
1629
|
}
|
|
1444
1630
|
this.scheduleCommandFlush();
|
|
1445
1631
|
}
|
|
@@ -1451,14 +1637,14 @@ var Bridge = class {
|
|
|
1451
1637
|
this.flushCommands();
|
|
1452
1638
|
});
|
|
1453
1639
|
}
|
|
1454
|
-
commandSnapshot(
|
|
1455
|
-
const command = this.commands.get(
|
|
1640
|
+
commandSnapshot(id2) {
|
|
1641
|
+
const command = this.commands.get(id2);
|
|
1456
1642
|
if (!command) return null;
|
|
1457
1643
|
return command.busy ? { ...command.descriptor, busy: true } : command.descriptor;
|
|
1458
1644
|
}
|
|
1459
1645
|
flushCommands() {
|
|
1460
1646
|
if (!this.sessionId || !this._hostOrigin || this._destroyed) return;
|
|
1461
|
-
const upsert = [...this.commandUpserts].map((
|
|
1647
|
+
const upsert = [...this.commandUpserts].map((id2) => this.commandSnapshot(id2)).filter((c) => !!c);
|
|
1462
1648
|
const remove = this.commandReset ? [] : [...this.commandRemovals];
|
|
1463
1649
|
let reset = this.commandReset;
|
|
1464
1650
|
this.commandUpserts.clear();
|
|
@@ -1598,6 +1784,41 @@ var Bridge = class {
|
|
|
1598
1784
|
this.postToHost({ ...reply, error: "The reply could not be sent to the workspace." });
|
|
1599
1785
|
}
|
|
1600
1786
|
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Subscribes to the host's chat live hints (see `ChatModule.subscribeChanges`). The first subscriber asks the host
|
|
1789
|
+
* to relay; the last one to leave stops it. Messages from another session are ignored.
|
|
1790
|
+
*/
|
|
1791
|
+
subscribeChat(handlers) {
|
|
1792
|
+
if (this._destroyed) throw new Error("Bridge has been destroyed.");
|
|
1793
|
+
this.chatSubscribers.add(handlers);
|
|
1794
|
+
const subscribe = () => {
|
|
1795
|
+
if (this.sessionId && this._hostOrigin && this.chatSubscribers.size > 0)
|
|
1796
|
+
this.postToHost({ type: "verentis:chat:subscribe", version: 1, sessionId: this.sessionId });
|
|
1797
|
+
};
|
|
1798
|
+
if (this.chatSubscribers.size === 1) {
|
|
1799
|
+
if (this._hostOrigin) subscribe();
|
|
1800
|
+
else void this._initPromise.then(subscribe, () => void 0);
|
|
1801
|
+
}
|
|
1802
|
+
return () => {
|
|
1803
|
+
if (!this.chatSubscribers.delete(handlers) || this.chatSubscribers.size > 0) return;
|
|
1804
|
+
if (!this._destroyed && this.sessionId && this._hostOrigin)
|
|
1805
|
+
this.postToHost({ type: "verentis:chat:unsubscribe", version: 1, sessionId: this.sessionId });
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1808
|
+
receiveChat(data) {
|
|
1809
|
+
if (data.type !== "verentis:chat:changed" && data.type !== "verentis:chat:connection" && data.type !== "verentis:chat:subscribed" && data.type !== "verentis:chat:error") return false;
|
|
1810
|
+
if (!this._hostOrigin || data.sessionId !== this.sessionId) return true;
|
|
1811
|
+
for (const subscriber of [...this.chatSubscribers]) {
|
|
1812
|
+
try {
|
|
1813
|
+
if (data.type === "verentis:chat:changed") subscriber.onChange(data.hint);
|
|
1814
|
+
else if (data.type === "verentis:chat:error") subscriber.onError?.(String(data.reason).slice(0, 500));
|
|
1815
|
+
else subscriber.onConnection?.(data.status);
|
|
1816
|
+
} catch (error) {
|
|
1817
|
+
console.error("[Verentis SDK] Chat subscriber failed", error);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
return true;
|
|
1821
|
+
}
|
|
1601
1822
|
/** Subscribe to a specific message type from the host */
|
|
1602
1823
|
on(type, listener) {
|
|
1603
1824
|
if (!this.listeners.has(type)) {
|
|
@@ -1622,6 +1843,7 @@ var Bridge = class {
|
|
|
1622
1843
|
this.commandRequests.clear();
|
|
1623
1844
|
this.hostMessageHandlers.clear();
|
|
1624
1845
|
this.hostMessageRequests.clear();
|
|
1846
|
+
this.chatSubscribers.clear();
|
|
1625
1847
|
this.listeners.clear();
|
|
1626
1848
|
for (const pending of this.wopiRequests.values()) {
|
|
1627
1849
|
clearTimeout(pending.timer);
|
|
@@ -1654,7 +1876,7 @@ var Bridge = class {
|
|
|
1654
1876
|
if (this.sessionId && this.commands.size > 0) {
|
|
1655
1877
|
this.commandReset = true;
|
|
1656
1878
|
this.commandRemovals.clear();
|
|
1657
|
-
for (const
|
|
1879
|
+
for (const id2 of this.commands.keys()) this.commandUpserts.add(id2);
|
|
1658
1880
|
this.scheduleCommandFlush();
|
|
1659
1881
|
}
|
|
1660
1882
|
console.info("[Verentis SDK] Received verentis:init from host", {
|
|
@@ -1702,6 +1924,7 @@ var Bridge = class {
|
|
|
1702
1924
|
void this.receiveHostMessage(data);
|
|
1703
1925
|
return;
|
|
1704
1926
|
}
|
|
1927
|
+
if (this.receiveChat(data)) return;
|
|
1705
1928
|
const typeListeners = this.listeners.get(data.type);
|
|
1706
1929
|
if (typeListeners) {
|
|
1707
1930
|
for (const listener of typeListeners) {
|
|
@@ -1736,17 +1959,17 @@ var HttpTransport = class {
|
|
|
1736
1959
|
async request(method, path, options) {
|
|
1737
1960
|
const url = this.buildUrl(path, options?.params);
|
|
1738
1961
|
console.info("[Verentis SDK] Request started", { method, path, url });
|
|
1739
|
-
const
|
|
1962
|
+
const headers2 = {};
|
|
1740
1963
|
const authHeader = await this.auth.getAuthHeader();
|
|
1741
1964
|
if (authHeader) {
|
|
1742
|
-
|
|
1965
|
+
headers2["Authorization"] = authHeader;
|
|
1743
1966
|
}
|
|
1744
1967
|
if (options?.headers) {
|
|
1745
|
-
Object.assign(
|
|
1968
|
+
Object.assign(headers2, options.headers);
|
|
1746
1969
|
}
|
|
1747
1970
|
const response = await fetch(url, {
|
|
1748
1971
|
method,
|
|
1749
|
-
headers,
|
|
1972
|
+
headers: headers2,
|
|
1750
1973
|
body: options?.body
|
|
1751
1974
|
});
|
|
1752
1975
|
await this.ensureSuccess(response);
|
|
@@ -1765,15 +1988,15 @@ var HttpTransport = class {
|
|
|
1765
1988
|
async requestRaw(method, path, options) {
|
|
1766
1989
|
const url = this.buildUrl(path, options?.params);
|
|
1767
1990
|
console.info("[Verentis SDK] Raw request started", { method, path, url });
|
|
1768
|
-
const
|
|
1991
|
+
const headers2 = {};
|
|
1769
1992
|
const authHeader = await this.auth.getAuthHeader();
|
|
1770
1993
|
if (authHeader) {
|
|
1771
|
-
|
|
1994
|
+
headers2["Authorization"] = authHeader;
|
|
1772
1995
|
}
|
|
1773
1996
|
if (options?.headers) {
|
|
1774
|
-
Object.assign(
|
|
1997
|
+
Object.assign(headers2, options.headers);
|
|
1775
1998
|
}
|
|
1776
|
-
const response = await fetch(url, { method, headers, body: options?.body });
|
|
1999
|
+
const response = await fetch(url, { method, headers: headers2, body: options?.body });
|
|
1777
2000
|
console.info("[Verentis SDK] Raw request completed", {
|
|
1778
2001
|
method,
|
|
1779
2002
|
path,
|
|
@@ -1842,6 +2065,7 @@ var VerentisClient = class {
|
|
|
1842
2065
|
settings;
|
|
1843
2066
|
notifications;
|
|
1844
2067
|
business;
|
|
2068
|
+
chat;
|
|
1845
2069
|
context;
|
|
1846
2070
|
bridge;
|
|
1847
2071
|
collaboration;
|
|
@@ -1878,6 +2102,7 @@ var VerentisClient = class {
|
|
|
1878
2102
|
this.settings = new SettingsModule(this._http, options?.workspaceId);
|
|
1879
2103
|
this.notifications = new NotificationsModule(this._http, options?.workspaceId);
|
|
1880
2104
|
this.business = new BusinessModule(this._http);
|
|
2105
|
+
this.chat = new ChatModule(this._http, null, this.executions);
|
|
1881
2106
|
this._ready = Promise.resolve();
|
|
1882
2107
|
return;
|
|
1883
2108
|
}
|
|
@@ -1928,6 +2153,7 @@ var VerentisClient = class {
|
|
|
1928
2153
|
this.settings = new SettingsModule(http, context.workspace.id);
|
|
1929
2154
|
this.notifications = new NotificationsModule(http, context.workspace.id);
|
|
1930
2155
|
this.business = new BusinessModule(http);
|
|
2156
|
+
this.chat = new ChatModule(http, this.bridge, this.executions);
|
|
1931
2157
|
}
|
|
1932
2158
|
};
|
|
1933
2159
|
function detectEnvironment() {
|
|
@@ -2031,6 +2257,7 @@ exports.ApiKeyAuth = ApiKeyAuth;
|
|
|
2031
2257
|
exports.Bridge = Bridge;
|
|
2032
2258
|
exports.BridgeAuth = BridgeAuth;
|
|
2033
2259
|
exports.BusinessModule = BusinessModule;
|
|
2260
|
+
exports.ChatModule = ChatModule;
|
|
2034
2261
|
exports.ContextModule = ContextModule;
|
|
2035
2262
|
exports.EnginesModule = EnginesModule;
|
|
2036
2263
|
exports.ExecutionsModule = ExecutionsModule;
|