@verentis/sdk 0.2.6 → 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 +42 -9
- package/dist/index.cjs +527 -145
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +591 -124
- package/dist/index.d.ts +591 -124
- package/dist/index.js +521 -145
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -261,6 +261,7 @@ var ContextModule = class {
|
|
|
261
261
|
};
|
|
262
262
|
|
|
263
263
|
// src/modules/executions.ts
|
|
264
|
+
var SCRIPT_ARGUMENTS_SCHEMA = "verentis.io/script-arguments/v1";
|
|
264
265
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
265
266
|
"Completed",
|
|
266
267
|
"Failed",
|
|
@@ -291,7 +292,8 @@ var ExecutionsModule = class {
|
|
|
291
292
|
tool: options?.tool,
|
|
292
293
|
mode: options?.mode,
|
|
293
294
|
arguments: options?.arguments ?? [],
|
|
294
|
-
parameters: serializeParameters(options?.parameters)
|
|
295
|
+
parameters: serializeParameters(options?.parameters),
|
|
296
|
+
...options?.invocationKey ? { invocationKey: options.invocationKey } : {}
|
|
295
297
|
}),
|
|
296
298
|
headers: { "Content-Type": "application/json" }
|
|
297
299
|
});
|
|
@@ -316,10 +318,30 @@ var ExecutionsModule = class {
|
|
|
316
318
|
headers: { "Content-Type": "application/json" }
|
|
317
319
|
});
|
|
318
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Read the arguments a script declares (its exported `<script>.arguments.json`), e.g. to build a form
|
|
323
|
+
* before {@link run}. Returns `null` for scripts that declare none. Reading never runs the script.
|
|
324
|
+
*/
|
|
325
|
+
async getArguments(filePath, options) {
|
|
326
|
+
const path = `${filePath}.arguments.json`.replace(/\/+/g, "/").replace(/^\//, "");
|
|
327
|
+
const response = await this.http.requestRaw("GET", `/files/raw/${path}`, {
|
|
328
|
+
params: { branch: options?.branch ?? "main" },
|
|
329
|
+
headers: { ...this.workspaceId ? { "X-Workspace-Id": this.workspaceId } : {}, Accept: "application/json" }
|
|
330
|
+
});
|
|
331
|
+
if (response.status === 404) return null;
|
|
332
|
+
if (!response.ok) {
|
|
333
|
+
throw new Error(`Failed to read script arguments: ${response.status} ${response.statusText}`);
|
|
334
|
+
}
|
|
335
|
+
const descriptor = await response.json();
|
|
336
|
+
if (descriptor?.schema !== SCRIPT_ARGUMENTS_SCHEMA || !Array.isArray(descriptor.arguments)) {
|
|
337
|
+
throw new Error(`Unsupported script argument descriptor for ${filePath}`);
|
|
338
|
+
}
|
|
339
|
+
return descriptor;
|
|
340
|
+
}
|
|
319
341
|
/** Get an execution by id. */
|
|
320
|
-
async get(
|
|
342
|
+
async get(id2, options) {
|
|
321
343
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
322
|
-
return this.http.request("GET", `/executions/${encodeURIComponent(
|
|
344
|
+
return this.http.request("GET", `/executions/${encodeURIComponent(id2)}`, {
|
|
323
345
|
params: { workspaceId }
|
|
324
346
|
});
|
|
325
347
|
}
|
|
@@ -344,17 +366,17 @@ var ExecutionsModule = class {
|
|
|
344
366
|
});
|
|
345
367
|
}
|
|
346
368
|
/** Get the captured stdout/stderr of an execution. */
|
|
347
|
-
async logs(
|
|
369
|
+
async logs(id2, options) {
|
|
348
370
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
349
|
-
return this.http.request("GET", `/executions/${encodeURIComponent(
|
|
371
|
+
return this.http.request("GET", `/executions/${encodeURIComponent(id2)}/logs`, {
|
|
350
372
|
params: { workspaceId }
|
|
351
373
|
});
|
|
352
374
|
}
|
|
353
375
|
/** Cancel a pending or running execution. */
|
|
354
|
-
async cancel(
|
|
376
|
+
async cancel(id2, options) {
|
|
355
377
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
356
|
-
return this.http.request("POST", `/executions/${encodeURIComponent(
|
|
357
|
-
body: JSON.stringify({ id, workspaceId }),
|
|
378
|
+
return this.http.request("POST", `/executions/${encodeURIComponent(id2)}/cancel`, {
|
|
379
|
+
body: JSON.stringify({ id: id2, workspaceId }),
|
|
358
380
|
headers: { "Content-Type": "application/json" }
|
|
359
381
|
});
|
|
360
382
|
}
|
|
@@ -362,16 +384,16 @@ var ExecutionsModule = class {
|
|
|
362
384
|
* Poll an execution until it reaches a terminal status. Returns immediately if it is already
|
|
363
385
|
* terminal. Throws if `timeoutMs` elapses or the supplied signal aborts.
|
|
364
386
|
*/
|
|
365
|
-
async wait(
|
|
387
|
+
async wait(id2, options) {
|
|
366
388
|
const interval = options?.intervalMs ?? 1e3;
|
|
367
389
|
const deadline = options?.timeoutMs ? Date.now() + options.timeoutMs : void 0;
|
|
368
390
|
for (; ; ) {
|
|
369
|
-
const execution = await this.get(
|
|
391
|
+
const execution = await this.get(id2, { workspaceId: options?.workspaceId });
|
|
370
392
|
if (isTerminalStatus(execution.status)) {
|
|
371
393
|
return execution;
|
|
372
394
|
}
|
|
373
395
|
if (deadline !== void 0 && Date.now() >= deadline) {
|
|
374
|
-
throw new Error(`Timed out waiting for execution '${
|
|
396
|
+
throw new Error(`Timed out waiting for execution '${id2}' to complete`);
|
|
375
397
|
}
|
|
376
398
|
await delay(interval, options?.signal);
|
|
377
399
|
}
|
|
@@ -388,11 +410,11 @@ var ExecutionsModule = class {
|
|
|
388
410
|
return this.wait(execution.id, options);
|
|
389
411
|
}
|
|
390
412
|
requireWorkspaceId(override) {
|
|
391
|
-
const
|
|
392
|
-
if (!
|
|
413
|
+
const id2 = override ?? this.workspaceId;
|
|
414
|
+
if (!id2) {
|
|
393
415
|
throw new Error("workspaceId is required: provide it in options or when creating the client");
|
|
394
416
|
}
|
|
395
|
-
return
|
|
417
|
+
return id2;
|
|
396
418
|
}
|
|
397
419
|
};
|
|
398
420
|
function serializeParameters(parameters) {
|
|
@@ -433,8 +455,8 @@ var EnginesModule = class {
|
|
|
433
455
|
}
|
|
434
456
|
});
|
|
435
457
|
}
|
|
436
|
-
async get(
|
|
437
|
-
return this.http.request("GET", `/engines/${encodeURIComponent(
|
|
458
|
+
async get(id2, options) {
|
|
459
|
+
return this.http.request("GET", `/engines/${encodeURIComponent(id2)}`, {
|
|
438
460
|
params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) }
|
|
439
461
|
});
|
|
440
462
|
}
|
|
@@ -655,11 +677,11 @@ var FilesModule = class {
|
|
|
655
677
|
});
|
|
656
678
|
}
|
|
657
679
|
workspaceHeaders() {
|
|
658
|
-
const
|
|
680
|
+
const headers2 = {};
|
|
659
681
|
if (this.workspaceId) {
|
|
660
|
-
|
|
682
|
+
headers2["X-Workspace-Id"] = this.workspaceId;
|
|
661
683
|
}
|
|
662
|
-
return
|
|
684
|
+
return headers2;
|
|
663
685
|
}
|
|
664
686
|
};
|
|
665
687
|
function requireNonBlank(value, name) {
|
|
@@ -751,14 +773,14 @@ var InstallationsModule = class {
|
|
|
751
773
|
}
|
|
752
774
|
});
|
|
753
775
|
}
|
|
754
|
-
async update(
|
|
776
|
+
async update(id2, options) {
|
|
755
777
|
const workspaceId = this.requireWorkspaceId(options?.workspaceId);
|
|
756
778
|
return this.http.request(
|
|
757
779
|
"PUT",
|
|
758
|
-
`/installations/${encodeURIComponent(
|
|
780
|
+
`/installations/${encodeURIComponent(id2)}`,
|
|
759
781
|
{
|
|
760
782
|
body: JSON.stringify({
|
|
761
|
-
id,
|
|
783
|
+
id: id2,
|
|
762
784
|
workspaceId,
|
|
763
785
|
packageVersion: options?.packageVersion,
|
|
764
786
|
installMode: options?.installMode
|
|
@@ -767,8 +789,8 @@ var InstallationsModule = class {
|
|
|
767
789
|
}
|
|
768
790
|
);
|
|
769
791
|
}
|
|
770
|
-
async uninstall(
|
|
771
|
-
await this.http.request("DELETE", `/installations/${encodeURIComponent(
|
|
792
|
+
async uninstall(id2, options) {
|
|
793
|
+
await this.http.request("DELETE", `/installations/${encodeURIComponent(id2)}`, {
|
|
772
794
|
params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) }
|
|
773
795
|
});
|
|
774
796
|
}
|
|
@@ -794,10 +816,10 @@ var ResourcesModule = class {
|
|
|
794
816
|
params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) }
|
|
795
817
|
});
|
|
796
818
|
}
|
|
797
|
-
async get(
|
|
819
|
+
async get(id2, options) {
|
|
798
820
|
return this.http.request(
|
|
799
821
|
"GET",
|
|
800
|
-
`/resources/${encodeURIComponent(
|
|
822
|
+
`/resources/${encodeURIComponent(id2)}`,
|
|
801
823
|
{ params: { workspaceId: this.requireWorkspaceId(options?.workspaceId) } }
|
|
802
824
|
);
|
|
803
825
|
}
|
|
@@ -849,7 +871,7 @@ var SettingsModule = class {
|
|
|
849
871
|
}
|
|
850
872
|
});
|
|
851
873
|
}
|
|
852
|
-
/** Upsert a setting value by its full key. Requires the `
|
|
874
|
+
/** Upsert a setting value by its full key. Requires the `setting.write` scope. */
|
|
853
875
|
async set(key, value, options) {
|
|
854
876
|
await this.http.request("PUT", `/settings/${encodeURIComponent(key)}`, {
|
|
855
877
|
params: {
|
|
@@ -860,7 +882,7 @@ var SettingsModule = class {
|
|
|
860
882
|
headers: { "Content-Type": "application/json" }
|
|
861
883
|
});
|
|
862
884
|
}
|
|
863
|
-
/** Delete a stored value (reverting to the definition default). Requires `
|
|
885
|
+
/** Delete a stored value (reverting to the definition default). Requires `setting.delete`. */
|
|
864
886
|
async reset(key, options) {
|
|
865
887
|
await this.http.request("DELETE", `/settings/${encodeURIComponent(key)}`, {
|
|
866
888
|
params: {
|
|
@@ -907,104 +929,78 @@ var SettingsModule = class {
|
|
|
907
929
|
}
|
|
908
930
|
};
|
|
909
931
|
|
|
910
|
-
// src/
|
|
911
|
-
var
|
|
932
|
+
// src/types.ts
|
|
933
|
+
var ApiError = class extends Error {
|
|
934
|
+
constructor(status, detail, title, code, retryAfterMs) {
|
|
935
|
+
super(title ?? `API error ${status}: ${detail}`);
|
|
936
|
+
this.status = status;
|
|
937
|
+
this.detail = detail;
|
|
938
|
+
this.title = title;
|
|
939
|
+
this.code = code;
|
|
940
|
+
this.retryAfterMs = retryAfterMs;
|
|
941
|
+
this.name = "ApiError";
|
|
942
|
+
}
|
|
943
|
+
status;
|
|
944
|
+
detail;
|
|
945
|
+
title;
|
|
946
|
+
code;
|
|
947
|
+
retryAfterMs;
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
// src/modules/notifications.ts
|
|
951
|
+
var NotificationsModule = class {
|
|
912
952
|
constructor(http, workspaceId) {
|
|
913
953
|
this.http = http;
|
|
914
954
|
this.workspaceId = workspaceId;
|
|
915
955
|
}
|
|
916
956
|
http;
|
|
917
957
|
workspaceId;
|
|
918
|
-
async
|
|
919
|
-
|
|
920
|
-
params: { workspaceId: this.workspace(options) }
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
async consents(options) {
|
|
924
|
-
return this.http.request("GET", "/email/consents", { params: { workspaceId: this.workspace(options) } });
|
|
925
|
-
}
|
|
926
|
-
/** Approve exactly the reviewed signed candidate; tracking stays off unless explicitly opted in. */
|
|
927
|
-
async consent(preview, approval, options) {
|
|
928
|
-
if (approval !== true) throw new Error("Explicit email consent is required");
|
|
929
|
-
if (!options?.senderGrants?.length) throw new Error("Explicit purpose/sender grants are required");
|
|
930
|
-
return this.http.request("PUT", `/email/consents/${encodeURIComponent(preview.installationId)}`, {
|
|
931
|
-
params: { workspaceId: preview.workspaceId },
|
|
958
|
+
async send(options) {
|
|
959
|
+
const request = {
|
|
932
960
|
body: JSON.stringify({
|
|
933
|
-
|
|
934
|
-
enabled: true,
|
|
935
|
-
allowOpenTracking: options?.allowOpenTracking ?? false,
|
|
936
|
-
allowClickTracking: options?.allowClickTracking ?? false,
|
|
937
|
-
senderGrants: options.senderGrants.map((grant) => ({ purpose: grant.purpose, senderId: grant.senderId }))
|
|
938
|
-
}),
|
|
939
|
-
headers: { "Content-Type": "application/json" }
|
|
940
|
-
});
|
|
941
|
-
}
|
|
942
|
-
async revoke(consent, options) {
|
|
943
|
-
return this.http.request("PUT", `/email/consents/${encodeURIComponent(consent.installationId)}`, {
|
|
944
|
-
params: { workspaceId: this.workspace(options) },
|
|
945
|
-
body: JSON.stringify({ candidateDigest: consent.candidateDigest, enabled: false, allowOpenTracking: false, allowClickTracking: false }),
|
|
946
|
-
headers: { "Content-Type": "application/json" }
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
async senders(options) {
|
|
950
|
-
return this.http.request("GET", "/email/senders", { params: { workspaceId: this.workspace(options) } });
|
|
951
|
-
}
|
|
952
|
-
async invoicePdf(recordId, installationId, options) {
|
|
953
|
-
this.mainBranch(options);
|
|
954
|
-
return this.http.request("POST", "/email/artifacts/invoice", {
|
|
955
|
-
body: JSON.stringify({ workspaceId: this.workspace(options), recordId, installationId }),
|
|
956
|
-
headers: { "Content-Type": "application/json" }
|
|
957
|
-
});
|
|
958
|
-
}
|
|
959
|
-
/** Authenticated immutable bytes; no public URL. The caller owns any local object URL it creates. */
|
|
960
|
-
async artifactContent(artifactId, options) {
|
|
961
|
-
this.mainBranch(options);
|
|
962
|
-
return this.http.request("GET", `/email/artifacts/${encodeURIComponent(artifactId)}/content`, {
|
|
963
|
-
params: { workspaceId: this.workspace(options), branch: "main" }
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
/** A stable key binds this exact request. After a lost response inspect status; never automatically resend. */
|
|
967
|
-
async dispatch(options) {
|
|
968
|
-
this.mainBranch(options);
|
|
969
|
-
return this.http.request("POST", "/email/dispatches", {
|
|
970
|
-
body: JSON.stringify({
|
|
971
|
-
workspaceId: this.workspace(options),
|
|
961
|
+
workspaceId: this.requireWorkspaceId(options.workspaceId),
|
|
972
962
|
installationId: options.installationId,
|
|
973
|
-
|
|
974
|
-
purpose: options.purpose,
|
|
975
|
-
templateId: options.templateId,
|
|
976
|
-
senderId: options.senderId,
|
|
977
|
-
recipients: options.recipients,
|
|
978
|
-
artifactIds: options.artifactIds,
|
|
963
|
+
typeKey: options.typeKey,
|
|
979
964
|
idempotencyKey: options.idempotencyKey,
|
|
980
|
-
|
|
965
|
+
userIds: options.userIds,
|
|
966
|
+
audienceScope: options.audienceScope,
|
|
967
|
+
emailAddresses: options.emailAddresses,
|
|
968
|
+
parameters: options.parameters
|
|
981
969
|
}),
|
|
982
970
|
headers: { "Content-Type": "application/json" }
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
async status(id, options) {
|
|
998
|
-
return this.outcome(id, options);
|
|
971
|
+
};
|
|
972
|
+
const deadline = Date.now() + 1e4;
|
|
973
|
+
for (; ; ) {
|
|
974
|
+
try {
|
|
975
|
+
return await this.http.request("POST", "/notifications/send", request);
|
|
976
|
+
} catch (error) {
|
|
977
|
+
if (!(error instanceof ApiError) || error.status !== 409 || error.code !== "execution_not_ready") {
|
|
978
|
+
throw error;
|
|
979
|
+
}
|
|
980
|
+
const delay2 = Math.max(250, error.retryAfterMs ?? 1e3);
|
|
981
|
+
if (Date.now() + delay2 > deadline) throw error;
|
|
982
|
+
await new Promise((resolve) => setTimeout(resolve, delay2));
|
|
983
|
+
}
|
|
984
|
+
}
|
|
999
985
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
986
|
+
async request(id2, options) {
|
|
987
|
+
return this.http.request(
|
|
988
|
+
"GET",
|
|
989
|
+
`/notifications/requests/${encodeURIComponent(id2)}`,
|
|
990
|
+
{
|
|
991
|
+
params: {
|
|
992
|
+
workspaceId: this.requireWorkspaceId(options?.workspaceId),
|
|
993
|
+
installationId: options?.installationId
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
);
|
|
1004
997
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
998
|
+
requireWorkspaceId(override) {
|
|
999
|
+
const workspaceId = override ?? this.workspaceId;
|
|
1000
|
+
if (!workspaceId) {
|
|
1001
|
+
throw new Error("workspaceId is required: provide it in options or when creating the client");
|
|
1002
|
+
}
|
|
1003
|
+
return workspaceId;
|
|
1008
1004
|
}
|
|
1009
1005
|
};
|
|
1010
1006
|
|
|
@@ -1034,8 +1030,8 @@ var BusinessModule = class _BusinessModule {
|
|
|
1034
1030
|
body: JSON.stringify(command)
|
|
1035
1031
|
});
|
|
1036
1032
|
}
|
|
1037
|
-
async read(
|
|
1038
|
-
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() });
|
|
1039
1035
|
}
|
|
1040
1036
|
async list(kind) {
|
|
1041
1037
|
return this.http.request("GET", "/business/records", {
|
|
@@ -1077,6 +1073,201 @@ var BusinessModule = class _BusinessModule {
|
|
|
1077
1073
|
}
|
|
1078
1074
|
};
|
|
1079
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
|
+
|
|
1260
|
+
// src/transport/app-commands.ts
|
|
1261
|
+
var APP_COMMAND_BATCH_SIZE = 200;
|
|
1262
|
+
var APP_COMMANDS_CAPABILITY = "commands";
|
|
1263
|
+
var APP_COMMAND_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/#@-]{0,255}$/;
|
|
1264
|
+
function isAppCommand(value) {
|
|
1265
|
+
if (!value || typeof value !== "object") return false;
|
|
1266
|
+
const c = value;
|
|
1267
|
+
const optionalText = (key, max) => c[key] === void 0 || typeof c[key] === "string" && c[key].length <= max;
|
|
1268
|
+
return typeof c.id === "string" && APP_COMMAND_ID_PATTERN.test(c.id) && typeof c.label === "string" && c.label.trim().length > 0 && c.label.length <= 200 && optionalText("description", 500) && optionalText("group", 100) && optionalText("disabledReason", 200) && (c.icon === void 0 || typeof c.icon === "string" && /^lucide:[a-z0-9-]{1,64}$/.test(c.icon)) && (c.keywords === void 0 || Array.isArray(c.keywords) && c.keywords.length <= 16 && c.keywords.every((k) => typeof k === "string" && k.length <= 64)) && (c.variant === void 0 || ["default", "outline", "destructive"].includes(String(c.variant))) && ["enabled", "busy"].every((key) => c[key] === void 0 || typeof c[key] === "boolean");
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1080
1271
|
// src/transport/header-actions.ts
|
|
1081
1272
|
function isHeaderAction(value) {
|
|
1082
1273
|
if (!value || typeof value !== "object") return false;
|
|
@@ -1109,7 +1300,7 @@ function element(value) {
|
|
|
1109
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");
|
|
1110
1301
|
}
|
|
1111
1302
|
function files(value) {
|
|
1112
|
-
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)));
|
|
1113
1304
|
}
|
|
1114
1305
|
function isNativeSnapshot(value) {
|
|
1115
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)
|
|
@@ -1217,6 +1408,14 @@ var Bridge = class {
|
|
|
1217
1408
|
sessionId = null;
|
|
1218
1409
|
actions = /* @__PURE__ */ new Map();
|
|
1219
1410
|
requests = /* @__PURE__ */ new Set();
|
|
1411
|
+
commands = /* @__PURE__ */ new Map();
|
|
1412
|
+
commandUpserts = /* @__PURE__ */ new Set();
|
|
1413
|
+
commandRemovals = /* @__PURE__ */ new Set();
|
|
1414
|
+
commandReset = false;
|
|
1415
|
+
commandFlushScheduled = false;
|
|
1416
|
+
commandRequests = /* @__PURE__ */ new Set();
|
|
1417
|
+
_hostCapabilities = [];
|
|
1418
|
+
chatSubscribers = /* @__PURE__ */ new Set();
|
|
1220
1419
|
hostMessageHandlers = /* @__PURE__ */ new Map();
|
|
1221
1420
|
hostMessageRequests = /* @__PURE__ */ new Set();
|
|
1222
1421
|
wopiRequests = /* @__PURE__ */ new Map();
|
|
@@ -1245,6 +1444,17 @@ var Bridge = class {
|
|
|
1245
1444
|
get hostOrigin() {
|
|
1246
1445
|
return this._hostOrigin;
|
|
1247
1446
|
}
|
|
1447
|
+
/** Capabilities the host announced in `verentis:init`. */
|
|
1448
|
+
get hostCapabilities() {
|
|
1449
|
+
return this._hostCapabilities;
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Whether the host exports page commands to its command registry. Older hosts ignore registrations;
|
|
1453
|
+
* commands still run locally, they are just not discoverable in the workspace palette.
|
|
1454
|
+
*/
|
|
1455
|
+
get supportsCommands() {
|
|
1456
|
+
return this._hostCapabilities.includes(APP_COMMANDS_CAPABILITY);
|
|
1457
|
+
}
|
|
1248
1458
|
/** Send a message to the host */
|
|
1249
1459
|
postToHost(message) {
|
|
1250
1460
|
if (this._destroyed) throw new Error("Bridge has been destroyed.");
|
|
@@ -1383,6 +1593,113 @@ var Bridge = class {
|
|
|
1383
1593
|
}
|
|
1384
1594
|
};
|
|
1385
1595
|
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Export a page command to the workspace command registry while it is active. There is no count limit;
|
|
1598
|
+
* dispose the registration when the control unmounts. May be called before the init handshake.
|
|
1599
|
+
*/
|
|
1600
|
+
registerCommand(descriptor, handler) {
|
|
1601
|
+
if (this._destroyed) throw new Error("Bridge has been destroyed.");
|
|
1602
|
+
if (!isAppCommand(descriptor)) throw new Error("Invalid command.");
|
|
1603
|
+
if (this.commands.has(descriptor.id)) throw new Error(`Command '${descriptor.id}' is already registered.`);
|
|
1604
|
+
const command = { descriptor: cloneCommand(descriptor), handler, busy: false };
|
|
1605
|
+
this.commands.set(descriptor.id, command);
|
|
1606
|
+
this.queueCommand(descriptor.id, "upsert");
|
|
1607
|
+
return {
|
|
1608
|
+
update: (next) => {
|
|
1609
|
+
if (this.commands.get(descriptor.id) !== command) throw new Error("Command has been disposed.");
|
|
1610
|
+
if (!isAppCommand(next) || next.id !== descriptor.id) throw new Error("Invalid command update.");
|
|
1611
|
+
if (sameCommand(command.descriptor, next)) return;
|
|
1612
|
+
command.descriptor = cloneCommand(next);
|
|
1613
|
+
this.queueCommand(descriptor.id, "upsert");
|
|
1614
|
+
},
|
|
1615
|
+
dispose: () => {
|
|
1616
|
+
if (this.commands.get(descriptor.id) !== command) return;
|
|
1617
|
+
this.commands.delete(descriptor.id);
|
|
1618
|
+
this.queueCommand(descriptor.id, "remove");
|
|
1619
|
+
}
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
queueCommand(id2, change) {
|
|
1623
|
+
if (change === "upsert") {
|
|
1624
|
+
this.commandRemovals.delete(id2);
|
|
1625
|
+
this.commandUpserts.add(id2);
|
|
1626
|
+
} else {
|
|
1627
|
+
this.commandUpserts.delete(id2);
|
|
1628
|
+
this.commandRemovals.add(id2);
|
|
1629
|
+
}
|
|
1630
|
+
this.scheduleCommandFlush();
|
|
1631
|
+
}
|
|
1632
|
+
scheduleCommandFlush() {
|
|
1633
|
+
if (this.commandFlushScheduled) return;
|
|
1634
|
+
this.commandFlushScheduled = true;
|
|
1635
|
+
queueMicrotask(() => {
|
|
1636
|
+
this.commandFlushScheduled = false;
|
|
1637
|
+
this.flushCommands();
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
commandSnapshot(id2) {
|
|
1641
|
+
const command = this.commands.get(id2);
|
|
1642
|
+
if (!command) return null;
|
|
1643
|
+
return command.busy ? { ...command.descriptor, busy: true } : command.descriptor;
|
|
1644
|
+
}
|
|
1645
|
+
flushCommands() {
|
|
1646
|
+
if (!this.sessionId || !this._hostOrigin || this._destroyed) return;
|
|
1647
|
+
const upsert = [...this.commandUpserts].map((id2) => this.commandSnapshot(id2)).filter((c) => !!c);
|
|
1648
|
+
const remove = this.commandReset ? [] : [...this.commandRemovals];
|
|
1649
|
+
let reset = this.commandReset;
|
|
1650
|
+
this.commandUpserts.clear();
|
|
1651
|
+
this.commandRemovals.clear();
|
|
1652
|
+
this.commandReset = false;
|
|
1653
|
+
if (!reset && !upsert.length && !remove.length) return;
|
|
1654
|
+
let offset = 0;
|
|
1655
|
+
let removeOffset = 0;
|
|
1656
|
+
do {
|
|
1657
|
+
const batchUpsert = upsert.slice(offset, offset + APP_COMMAND_BATCH_SIZE);
|
|
1658
|
+
offset += batchUpsert.length;
|
|
1659
|
+
const room = APP_COMMAND_BATCH_SIZE - batchUpsert.length;
|
|
1660
|
+
const batchRemove = remove.slice(removeOffset, removeOffset + room);
|
|
1661
|
+
removeOffset += batchRemove.length;
|
|
1662
|
+
this.postToHost({
|
|
1663
|
+
type: "verentis:commands:update",
|
|
1664
|
+
version: 1,
|
|
1665
|
+
sessionId: this.sessionId,
|
|
1666
|
+
...reset ? { reset: true } : {},
|
|
1667
|
+
upsert: batchUpsert,
|
|
1668
|
+
remove: batchRemove
|
|
1669
|
+
});
|
|
1670
|
+
reset = false;
|
|
1671
|
+
} while (offset < upsert.length || removeOffset < remove.length);
|
|
1672
|
+
}
|
|
1673
|
+
async invokeCommand(message) {
|
|
1674
|
+
if (message.sessionId !== this.sessionId || typeof message.requestId !== "string" || message.requestId.length > 128 || !message.requestId || this.commandRequests.has(message.requestId) || typeof message.commandId !== "string") return;
|
|
1675
|
+
this.commandRequests.add(message.requestId);
|
|
1676
|
+
if (this.commandRequests.size > 1e3) this.commandRequests.delete(this.commandRequests.values().next().value);
|
|
1677
|
+
const command = this.commands.get(message.commandId);
|
|
1678
|
+
const reply = {
|
|
1679
|
+
type: "verentis:command:result",
|
|
1680
|
+
version: 1,
|
|
1681
|
+
sessionId: message.sessionId,
|
|
1682
|
+
requestId: message.requestId,
|
|
1683
|
+
commandId: message.commandId
|
|
1684
|
+
};
|
|
1685
|
+
if (!command || command.busy || command.descriptor.busy || command.descriptor.enabled === false) {
|
|
1686
|
+
this.postToHost({ ...reply, error: "Command is unavailable." });
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
command.busy = true;
|
|
1690
|
+
this.queueCommand(message.commandId, "upsert");
|
|
1691
|
+
try {
|
|
1692
|
+
await command.handler();
|
|
1693
|
+
if (!this._destroyed && this.sessionId === message.sessionId) this.postToHost(reply);
|
|
1694
|
+
} catch (error) {
|
|
1695
|
+
if (!this._destroyed && this.sessionId === message.sessionId) {
|
|
1696
|
+
this.postToHost({ ...reply, error: (error instanceof Error ? error.message : "Command failed.").slice(0, 500) || "Command failed." });
|
|
1697
|
+
}
|
|
1698
|
+
} finally {
|
|
1699
|
+
command.busy = false;
|
|
1700
|
+
if (this.commands.get(message.commandId) === command) this.queueCommand(message.commandId, "upsert");
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1386
1703
|
publishActions() {
|
|
1387
1704
|
if (!this.sessionId || this._destroyed) return;
|
|
1388
1705
|
this.postToHost({
|
|
@@ -1467,6 +1784,41 @@ var Bridge = class {
|
|
|
1467
1784
|
this.postToHost({ ...reply, error: "The reply could not be sent to the workspace." });
|
|
1468
1785
|
}
|
|
1469
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
|
+
}
|
|
1470
1822
|
/** Subscribe to a specific message type from the host */
|
|
1471
1823
|
on(type, listener) {
|
|
1472
1824
|
if (!this.listeners.has(type)) {
|
|
@@ -1485,8 +1837,13 @@ var Bridge = class {
|
|
|
1485
1837
|
if (!this._hostOrigin) this._initReject(new Error("Bridge has been destroyed."));
|
|
1486
1838
|
this.actions.clear();
|
|
1487
1839
|
this.requests.clear();
|
|
1840
|
+
this.commands.clear();
|
|
1841
|
+
this.commandUpserts.clear();
|
|
1842
|
+
this.commandRemovals.clear();
|
|
1843
|
+
this.commandRequests.clear();
|
|
1488
1844
|
this.hostMessageHandlers.clear();
|
|
1489
1845
|
this.hostMessageRequests.clear();
|
|
1846
|
+
this.chatSubscribers.clear();
|
|
1490
1847
|
this.listeners.clear();
|
|
1491
1848
|
for (const pending of this.wopiRequests.values()) {
|
|
1492
1849
|
clearTimeout(pending.timer);
|
|
@@ -1515,6 +1872,13 @@ var Bridge = class {
|
|
|
1515
1872
|
this._initTimer = void 0;
|
|
1516
1873
|
this._hostOrigin = event.origin;
|
|
1517
1874
|
this.sessionId = typeof data.sessionId === "string" ? data.sessionId : null;
|
|
1875
|
+
this._hostCapabilities = Array.isArray(data.capabilities) ? data.capabilities.filter((c) => typeof c === "string").slice(0, 64) : [];
|
|
1876
|
+
if (this.sessionId && this.commands.size > 0) {
|
|
1877
|
+
this.commandReset = true;
|
|
1878
|
+
this.commandRemovals.clear();
|
|
1879
|
+
for (const id2 of this.commands.keys()) this.commandUpserts.add(id2);
|
|
1880
|
+
this.scheduleCommandFlush();
|
|
1881
|
+
}
|
|
1518
1882
|
console.info("[Verentis SDK] Received verentis:init from host", {
|
|
1519
1883
|
origin: event.origin,
|
|
1520
1884
|
workspaceId: data.context.workspace.id,
|
|
@@ -1552,10 +1916,15 @@ var Bridge = class {
|
|
|
1552
1916
|
void this.invokeAction(data);
|
|
1553
1917
|
return;
|
|
1554
1918
|
}
|
|
1919
|
+
if (data.type === "verentis:command:invoke") {
|
|
1920
|
+
void this.invokeCommand(data);
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1555
1923
|
if (data.type === "verentis:host:message") {
|
|
1556
1924
|
void this.receiveHostMessage(data);
|
|
1557
1925
|
return;
|
|
1558
1926
|
}
|
|
1927
|
+
if (this.receiveChat(data)) return;
|
|
1559
1928
|
const typeListeners = this.listeners.get(data.type);
|
|
1560
1929
|
if (typeListeners) {
|
|
1561
1930
|
for (const listener of typeListeners) {
|
|
@@ -1564,22 +1933,18 @@ var Bridge = class {
|
|
|
1564
1933
|
}
|
|
1565
1934
|
}
|
|
1566
1935
|
};
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
detail;
|
|
1580
|
-
title;
|
|
1581
|
-
code;
|
|
1582
|
-
};
|
|
1936
|
+
function cloneCommand(command) {
|
|
1937
|
+
return { ...command, ...command.keywords ? { keywords: [...command.keywords] } : {} };
|
|
1938
|
+
}
|
|
1939
|
+
function sameCommand(a, b) {
|
|
1940
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
1941
|
+
for (const key of keys) {
|
|
1942
|
+
if (key === "keywords") {
|
|
1943
|
+
if ((a.keywords ?? []).join("\0") !== (b.keywords ?? []).join("\0")) return false;
|
|
1944
|
+
} else if (a[key] !== b[key]) return false;
|
|
1945
|
+
}
|
|
1946
|
+
return true;
|
|
1947
|
+
}
|
|
1583
1948
|
|
|
1584
1949
|
// src/transport/http.transport.ts
|
|
1585
1950
|
var HttpTransport = class {
|
|
@@ -1594,17 +1959,17 @@ var HttpTransport = class {
|
|
|
1594
1959
|
async request(method, path, options) {
|
|
1595
1960
|
const url = this.buildUrl(path, options?.params);
|
|
1596
1961
|
console.info("[Verentis SDK] Request started", { method, path, url });
|
|
1597
|
-
const
|
|
1962
|
+
const headers2 = {};
|
|
1598
1963
|
const authHeader = await this.auth.getAuthHeader();
|
|
1599
1964
|
if (authHeader) {
|
|
1600
|
-
|
|
1965
|
+
headers2["Authorization"] = authHeader;
|
|
1601
1966
|
}
|
|
1602
1967
|
if (options?.headers) {
|
|
1603
|
-
Object.assign(
|
|
1968
|
+
Object.assign(headers2, options.headers);
|
|
1604
1969
|
}
|
|
1605
1970
|
const response = await fetch(url, {
|
|
1606
1971
|
method,
|
|
1607
|
-
headers,
|
|
1972
|
+
headers: headers2,
|
|
1608
1973
|
body: options?.body
|
|
1609
1974
|
});
|
|
1610
1975
|
await this.ensureSuccess(response);
|
|
@@ -1623,15 +1988,15 @@ var HttpTransport = class {
|
|
|
1623
1988
|
async requestRaw(method, path, options) {
|
|
1624
1989
|
const url = this.buildUrl(path, options?.params);
|
|
1625
1990
|
console.info("[Verentis SDK] Raw request started", { method, path, url });
|
|
1626
|
-
const
|
|
1991
|
+
const headers2 = {};
|
|
1627
1992
|
const authHeader = await this.auth.getAuthHeader();
|
|
1628
1993
|
if (authHeader) {
|
|
1629
|
-
|
|
1994
|
+
headers2["Authorization"] = authHeader;
|
|
1630
1995
|
}
|
|
1631
1996
|
if (options?.headers) {
|
|
1632
|
-
Object.assign(
|
|
1997
|
+
Object.assign(headers2, options.headers);
|
|
1633
1998
|
}
|
|
1634
|
-
const response = await fetch(url, { method, headers, body: options?.body });
|
|
1999
|
+
const response = await fetch(url, { method, headers: headers2, body: options?.body });
|
|
1635
2000
|
console.info("[Verentis SDK] Raw request completed", {
|
|
1636
2001
|
method,
|
|
1637
2002
|
path,
|
|
@@ -1659,7 +2024,15 @@ var HttpTransport = class {
|
|
|
1659
2024
|
if (!(error instanceof SyntaxError)) throw error;
|
|
1660
2025
|
}
|
|
1661
2026
|
console.error("[Verentis SDK] Request failed", { status: response.status, code });
|
|
1662
|
-
|
|
2027
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
2028
|
+
const retryAfterMs = retryAfter === null ? void 0 : /^\d+$/.test(retryAfter) ? Number(retryAfter) * 1e3 : Date.parse(retryAfter) - Date.now();
|
|
2029
|
+
throw new ApiError(
|
|
2030
|
+
response.status,
|
|
2031
|
+
detail,
|
|
2032
|
+
title,
|
|
2033
|
+
code,
|
|
2034
|
+
retryAfterMs !== void 0 && Number.isFinite(retryAfterMs) ? Math.max(0, retryAfterMs) : void 0
|
|
2035
|
+
);
|
|
1663
2036
|
}
|
|
1664
2037
|
buildUrl(path, params) {
|
|
1665
2038
|
const base = `${this.baseUrl}/${this.apiVersion}${path}`;
|
|
@@ -1690,8 +2063,9 @@ var VerentisClient = class {
|
|
|
1690
2063
|
installations;
|
|
1691
2064
|
resources;
|
|
1692
2065
|
settings;
|
|
1693
|
-
|
|
2066
|
+
notifications;
|
|
1694
2067
|
business;
|
|
2068
|
+
chat;
|
|
1695
2069
|
context;
|
|
1696
2070
|
bridge;
|
|
1697
2071
|
collaboration;
|
|
@@ -1726,8 +2100,9 @@ var VerentisClient = class {
|
|
|
1726
2100
|
this.installations = new InstallationsModule(this._http, options?.workspaceId);
|
|
1727
2101
|
this.resources = new ResourcesModule(this._http, options?.workspaceId);
|
|
1728
2102
|
this.settings = new SettingsModule(this._http, options?.workspaceId);
|
|
1729
|
-
this.
|
|
2103
|
+
this.notifications = new NotificationsModule(this._http, options?.workspaceId);
|
|
1730
2104
|
this.business = new BusinessModule(this._http);
|
|
2105
|
+
this.chat = new ChatModule(this._http, null, this.executions);
|
|
1731
2106
|
this._ready = Promise.resolve();
|
|
1732
2107
|
return;
|
|
1733
2108
|
}
|
|
@@ -1776,8 +2151,9 @@ var VerentisClient = class {
|
|
|
1776
2151
|
this.installations = new InstallationsModule(http, context.workspace.id);
|
|
1777
2152
|
this.resources = new ResourcesModule(http, context.workspace.id);
|
|
1778
2153
|
this.settings = new SettingsModule(http, context.workspace.id);
|
|
1779
|
-
this.
|
|
2154
|
+
this.notifications = new NotificationsModule(http, context.workspace.id);
|
|
1780
2155
|
this.business = new BusinessModule(http);
|
|
2156
|
+
this.chat = new ChatModule(http, this.bridge, this.executions);
|
|
1781
2157
|
}
|
|
1782
2158
|
};
|
|
1783
2159
|
function detectEnvironment() {
|
|
@@ -1873,13 +2249,16 @@ function createVerentisClient(options) {
|
|
|
1873
2249
|
return new VerentisClient(options);
|
|
1874
2250
|
}
|
|
1875
2251
|
|
|
2252
|
+
exports.APP_COMMANDS_CAPABILITY = APP_COMMANDS_CAPABILITY;
|
|
2253
|
+
exports.APP_COMMAND_BATCH_SIZE = APP_COMMAND_BATCH_SIZE;
|
|
2254
|
+
exports.APP_COMMAND_ID_PATTERN = APP_COMMAND_ID_PATTERN;
|
|
1876
2255
|
exports.ApiError = ApiError;
|
|
1877
2256
|
exports.ApiKeyAuth = ApiKeyAuth;
|
|
1878
2257
|
exports.Bridge = Bridge;
|
|
1879
2258
|
exports.BridgeAuth = BridgeAuth;
|
|
1880
2259
|
exports.BusinessModule = BusinessModule;
|
|
2260
|
+
exports.ChatModule = ChatModule;
|
|
1881
2261
|
exports.ContextModule = ContextModule;
|
|
1882
|
-
exports.EmailModule = EmailModule;
|
|
1883
2262
|
exports.EnginesModule = EnginesModule;
|
|
1884
2263
|
exports.ExecutionsModule = ExecutionsModule;
|
|
1885
2264
|
exports.FilesModule = FilesModule;
|
|
@@ -1888,13 +2267,16 @@ exports.HttpTransport = HttpTransport;
|
|
|
1888
2267
|
exports.InstallationsModule = InstallationsModule;
|
|
1889
2268
|
exports.NativeCollaborationClient = NativeCollaborationClient;
|
|
1890
2269
|
exports.NativeCollaborationError = NativeCollaborationError;
|
|
2270
|
+
exports.NotificationsModule = NotificationsModule;
|
|
1891
2271
|
exports.ResourcesModule = ResourcesModule;
|
|
2272
|
+
exports.SCRIPT_ARGUMENTS_SCHEMA = SCRIPT_ARGUMENTS_SCHEMA;
|
|
1892
2273
|
exports.SettingsModule = SettingsModule;
|
|
1893
2274
|
exports.TokenAuth = TokenAuth;
|
|
1894
2275
|
exports.VerentisClient = VerentisClient;
|
|
1895
2276
|
exports.createVerentisClient = createVerentisClient;
|
|
1896
2277
|
exports.exactHttpsOrigin = exactHttpsOrigin;
|
|
1897
2278
|
exports.findBestMatch = findBestMatch;
|
|
2279
|
+
exports.isAppCommand = isAppCommand;
|
|
1898
2280
|
exports.isDurableSaveConfirmed = isDurableSaveConfirmed;
|
|
1899
2281
|
exports.isHeaderAction = isHeaderAction;
|
|
1900
2282
|
exports.isNativeSaveResult = isNativeSaveResult;
|