@meistrari/tela-sdk-js 1.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +976 -82
- package/dist/index.cjs +1352 -118
- package/dist/index.d.cts +1207 -422
- package/dist/index.d.mts +1207 -422
- package/dist/index.d.ts +1207 -422
- package/dist/index.mjs +1325 -119
- package/package.json +43 -32
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const changeCase = require('change-case');
|
|
4
4
|
const minimatch = require('minimatch');
|
|
5
|
+
const z = require('zod');
|
|
6
|
+
const Emittery = require('emittery');
|
|
7
|
+
|
|
8
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
5
9
|
|
|
6
10
|
function _interopNamespaceCompat(e) {
|
|
7
11
|
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
@@ -16,13 +20,16 @@ function _interopNamespaceCompat(e) {
|
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
const changeCase__namespace = /*#__PURE__*/_interopNamespaceCompat(changeCase);
|
|
23
|
+
const z__default = /*#__PURE__*/_interopDefaultCompat(z);
|
|
24
|
+
const z__namespace = /*#__PURE__*/_interopNamespaceCompat(z);
|
|
25
|
+
const Emittery__default = /*#__PURE__*/_interopDefaultCompat(Emittery);
|
|
19
26
|
|
|
20
|
-
const version = "1.0
|
|
27
|
+
const version = "2.1.0";
|
|
21
28
|
|
|
22
|
-
var __defProp$
|
|
23
|
-
var __defNormalProp$
|
|
24
|
-
var __publicField$
|
|
25
|
-
__defNormalProp$
|
|
29
|
+
var __defProp$7 = Object.defineProperty;
|
|
30
|
+
var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
31
|
+
var __publicField$7 = (obj, key, value) => {
|
|
32
|
+
__defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
26
33
|
return value;
|
|
27
34
|
};
|
|
28
35
|
class TelaError extends Error {
|
|
@@ -48,16 +55,35 @@ class InvalidFileURL extends TelaError {
|
|
|
48
55
|
}
|
|
49
56
|
}
|
|
50
57
|
class FileUploadError extends TelaError {
|
|
58
|
+
constructor(message, statusCode) {
|
|
59
|
+
super(`Failed to upload file: ${message} (Status code: ${statusCode})`);
|
|
60
|
+
__publicField$7(this, "statusCode");
|
|
61
|
+
this.statusCode = statusCode;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
class ExecutionNotStartedError extends TelaError {
|
|
65
|
+
constructor() {
|
|
66
|
+
super("Execution has not started yet");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
class InvalidExecutionModeError extends TelaError {
|
|
51
70
|
constructor(message) {
|
|
52
|
-
super(
|
|
71
|
+
super(message);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
class ExecutionFailedError extends TelaError {
|
|
75
|
+
constructor(rawOutput) {
|
|
76
|
+
super(`Execution failed: ${JSON.stringify(rawOutput)}`);
|
|
77
|
+
__publicField$7(this, "rawOutput");
|
|
78
|
+
this.rawOutput = rawOutput;
|
|
53
79
|
}
|
|
54
80
|
}
|
|
55
81
|
class APIError extends TelaError {
|
|
56
82
|
constructor(statusCode, error, _message) {
|
|
57
83
|
const message = error?.message ? typeof error.message === "string" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : _message;
|
|
58
84
|
super(message);
|
|
59
|
-
__publicField$
|
|
60
|
-
__publicField$
|
|
85
|
+
__publicField$7(this, "statusCode");
|
|
86
|
+
__publicField$7(this, "error");
|
|
61
87
|
this.statusCode = statusCode;
|
|
62
88
|
this.error = error;
|
|
63
89
|
}
|
|
@@ -99,7 +125,7 @@ class APIError extends TelaError {
|
|
|
99
125
|
class UserAbortError extends APIError {
|
|
100
126
|
constructor({ message } = {}) {
|
|
101
127
|
super(void 0, void 0, message || "User aborted.");
|
|
102
|
-
__publicField$
|
|
128
|
+
__publicField$7(this, "statusCode");
|
|
103
129
|
}
|
|
104
130
|
}
|
|
105
131
|
class ConnectionError extends APIError {
|
|
@@ -108,7 +134,7 @@ class ConnectionError extends APIError {
|
|
|
108
134
|
cause
|
|
109
135
|
}) {
|
|
110
136
|
super(void 0, void 0, message || "Connection error.");
|
|
111
|
-
__publicField$
|
|
137
|
+
__publicField$7(this, "statusCode");
|
|
112
138
|
if (cause)
|
|
113
139
|
this.cause = cause;
|
|
114
140
|
}
|
|
@@ -118,57 +144,57 @@ class ConnectionTimeout extends APIError {
|
|
|
118
144
|
message
|
|
119
145
|
} = {}) {
|
|
120
146
|
super(void 0, void 0, message || "Request timed out.");
|
|
121
|
-
__publicField$
|
|
147
|
+
__publicField$7(this, "statusCode");
|
|
122
148
|
}
|
|
123
149
|
}
|
|
124
150
|
class BadRequestError extends APIError {
|
|
125
151
|
constructor() {
|
|
126
152
|
super(...arguments);
|
|
127
|
-
__publicField$
|
|
153
|
+
__publicField$7(this, "statusCode", 400);
|
|
128
154
|
}
|
|
129
155
|
// todo: handle validation errors from zod/typebox
|
|
130
156
|
}
|
|
131
157
|
class AuthenticationError extends APIError {
|
|
132
158
|
constructor() {
|
|
133
159
|
super(...arguments);
|
|
134
|
-
__publicField$
|
|
160
|
+
__publicField$7(this, "statusCode", 401);
|
|
135
161
|
}
|
|
136
162
|
}
|
|
137
163
|
class AuthorizationError extends APIError {
|
|
138
164
|
constructor() {
|
|
139
165
|
super(...arguments);
|
|
140
|
-
__publicField$
|
|
166
|
+
__publicField$7(this, "statusCode", 403);
|
|
141
167
|
}
|
|
142
168
|
}
|
|
143
169
|
class NotFoundError extends APIError {
|
|
144
170
|
constructor() {
|
|
145
171
|
super(...arguments);
|
|
146
|
-
__publicField$
|
|
172
|
+
__publicField$7(this, "statusCode", 404);
|
|
147
173
|
}
|
|
148
174
|
}
|
|
149
175
|
class ConflictError extends APIError {
|
|
150
176
|
constructor() {
|
|
151
177
|
super(...arguments);
|
|
152
|
-
__publicField$
|
|
178
|
+
__publicField$7(this, "statusCode", 409);
|
|
153
179
|
}
|
|
154
180
|
}
|
|
155
181
|
class UnprocessableEntityError extends APIError {
|
|
156
182
|
constructor() {
|
|
157
183
|
super(...arguments);
|
|
158
184
|
// todo: check if tela returns 400 or 422 for zod errors
|
|
159
|
-
__publicField$
|
|
185
|
+
__publicField$7(this, "statusCode", 422);
|
|
160
186
|
}
|
|
161
187
|
}
|
|
162
188
|
class RateLimitError extends APIError {
|
|
163
189
|
constructor() {
|
|
164
190
|
super(...arguments);
|
|
165
|
-
__publicField$
|
|
191
|
+
__publicField$7(this, "statusCode", 429);
|
|
166
192
|
}
|
|
167
193
|
}
|
|
168
194
|
class InternalServerError extends APIError {
|
|
169
195
|
constructor() {
|
|
170
196
|
super(...arguments);
|
|
171
|
-
__publicField$
|
|
197
|
+
__publicField$7(this, "statusCode", 500);
|
|
172
198
|
}
|
|
173
199
|
}
|
|
174
200
|
function toError(err) {
|
|
@@ -280,10 +306,10 @@ function transformObjectFromSnakeCaseToCamelCase(obj, exclusions = []) {
|
|
|
280
306
|
return result;
|
|
281
307
|
}
|
|
282
308
|
|
|
283
|
-
var __defProp$
|
|
284
|
-
var __defNormalProp$
|
|
285
|
-
var __publicField$
|
|
286
|
-
__defNormalProp$
|
|
309
|
+
var __defProp$6 = Object.defineProperty;
|
|
310
|
+
var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
311
|
+
var __publicField$6 = (obj, key, value) => {
|
|
312
|
+
__defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
287
313
|
return value;
|
|
288
314
|
};
|
|
289
315
|
class Stream {
|
|
@@ -298,7 +324,7 @@ class Stream {
|
|
|
298
324
|
/**
|
|
299
325
|
* The AbortController associated with this stream.
|
|
300
326
|
*/
|
|
301
|
-
__publicField$
|
|
327
|
+
__publicField$6(this, "controller");
|
|
302
328
|
this.controller = controller;
|
|
303
329
|
}
|
|
304
330
|
/**
|
|
@@ -339,6 +365,10 @@ class Stream {
|
|
|
339
365
|
if (data && data.error) {
|
|
340
366
|
throw new APIError(void 0, data.error, void 0);
|
|
341
367
|
}
|
|
368
|
+
data = data.message.content;
|
|
369
|
+
if (!data) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
342
372
|
yield data;
|
|
343
373
|
} else {
|
|
344
374
|
let data;
|
|
@@ -352,6 +382,10 @@ class Stream {
|
|
|
352
382
|
if (sse.event === "error") {
|
|
353
383
|
throw new APIError(void 0, data.error, data.message);
|
|
354
384
|
}
|
|
385
|
+
data = data.message.content;
|
|
386
|
+
if (!data) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
355
389
|
yield { event: sse.event, data };
|
|
356
390
|
}
|
|
357
391
|
}
|
|
@@ -541,9 +575,9 @@ function findDoubleNewlineIndex(buffer) {
|
|
|
541
575
|
}
|
|
542
576
|
class SSEDecoder {
|
|
543
577
|
constructor() {
|
|
544
|
-
__publicField$
|
|
545
|
-
__publicField$
|
|
546
|
-
__publicField$
|
|
578
|
+
__publicField$6(this, "data");
|
|
579
|
+
__publicField$6(this, "event");
|
|
580
|
+
__publicField$6(this, "chunks");
|
|
547
581
|
this.event = null;
|
|
548
582
|
this.data = [];
|
|
549
583
|
this.chunks = [];
|
|
@@ -584,9 +618,9 @@ class SSEDecoder {
|
|
|
584
618
|
const _LineDecoder = class _LineDecoder {
|
|
585
619
|
// TextDecoder found in browsers; not typed to avoid pulling in either "dom" or "node" types.
|
|
586
620
|
constructor() {
|
|
587
|
-
__publicField$
|
|
588
|
-
__publicField$
|
|
589
|
-
__publicField$
|
|
621
|
+
__publicField$6(this, "buffer");
|
|
622
|
+
__publicField$6(this, "trailingCR");
|
|
623
|
+
__publicField$6(this, "textDecoder");
|
|
590
624
|
this.buffer = [];
|
|
591
625
|
this.trailingCR = false;
|
|
592
626
|
}
|
|
@@ -661,8 +695,8 @@ const _LineDecoder = class _LineDecoder {
|
|
|
661
695
|
}
|
|
662
696
|
};
|
|
663
697
|
// prettier-ignore
|
|
664
|
-
__publicField$
|
|
665
|
-
__publicField$
|
|
698
|
+
__publicField$6(_LineDecoder, "NEWLINE_CHARS", /* @__PURE__ */ new Set(["\n", "\r"]));
|
|
699
|
+
__publicField$6(_LineDecoder, "NEWLINE_REGEXP", /\r\n|[\n\r]/g);
|
|
666
700
|
let LineDecoder = _LineDecoder;
|
|
667
701
|
function partition(str, delimiter) {
|
|
668
702
|
const index = str.indexOf(delimiter);
|
|
@@ -699,10 +733,10 @@ function readableStreamAsyncIterable(stream) {
|
|
|
699
733
|
};
|
|
700
734
|
}
|
|
701
735
|
|
|
702
|
-
var __defProp$
|
|
703
|
-
var __defNormalProp$
|
|
704
|
-
var __publicField$
|
|
705
|
-
__defNormalProp$
|
|
736
|
+
var __defProp$5 = Object.defineProperty;
|
|
737
|
+
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
738
|
+
var __publicField$5 = (obj, key, value) => {
|
|
739
|
+
__defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
706
740
|
return value;
|
|
707
741
|
};
|
|
708
742
|
async function defaultParseResponse(props) {
|
|
@@ -727,10 +761,10 @@ async function defaultParseResponse(props) {
|
|
|
727
761
|
}
|
|
728
762
|
class BaseClient {
|
|
729
763
|
constructor({ baseURL, maxRetries = 5, timeout = 0 }) {
|
|
730
|
-
__publicField$
|
|
731
|
-
__publicField$
|
|
732
|
-
__publicField$
|
|
733
|
-
__publicField$
|
|
764
|
+
__publicField$5(this, "baseURL");
|
|
765
|
+
__publicField$5(this, "maxRetries");
|
|
766
|
+
__publicField$5(this, "timeout");
|
|
767
|
+
__publicField$5(this, "fetch");
|
|
734
768
|
this.baseURL = baseURL;
|
|
735
769
|
this.maxRetries = validateMaxRetries(maxRetries);
|
|
736
770
|
this.timeout = validateTimeout(timeout);
|
|
@@ -752,9 +786,6 @@ class BaseClient {
|
|
|
752
786
|
getUserAgent() {
|
|
753
787
|
return `tela-sdk-node/${version}`;
|
|
754
788
|
}
|
|
755
|
-
getAuthHeaders() {
|
|
756
|
-
return {};
|
|
757
|
-
}
|
|
758
789
|
get(path, opts) {
|
|
759
790
|
return this.methodRequest("GET", path, opts);
|
|
760
791
|
}
|
|
@@ -1007,29 +1038,41 @@ async function getStreamSize(stream) {
|
|
|
1007
1038
|
return size;
|
|
1008
1039
|
}
|
|
1009
1040
|
|
|
1010
|
-
var __defProp$
|
|
1011
|
-
var __defNormalProp$
|
|
1012
|
-
var __publicField$
|
|
1013
|
-
__defNormalProp$
|
|
1041
|
+
var __defProp$4 = Object.defineProperty;
|
|
1042
|
+
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1043
|
+
var __publicField$4 = (obj, key, value) => {
|
|
1044
|
+
__defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1014
1045
|
return value;
|
|
1015
1046
|
};
|
|
1047
|
+
function TelaFileSchema() {
|
|
1048
|
+
return z__default.custom((value) => value instanceof TelaFile, { message: "Value must be an instance of TelaFile" }).meta({ isTelaFile: true });
|
|
1049
|
+
}
|
|
1016
1050
|
class TelaFile {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
* @throws {EmptyFileError} If the provided file is empty.
|
|
1024
|
-
*/
|
|
1025
|
-
constructor(file, options) {
|
|
1026
|
-
__publicField$2(this, "_file");
|
|
1027
|
-
__publicField$2(this, "_options");
|
|
1028
|
-
__publicField$2(this, "_size", null);
|
|
1051
|
+
constructor(file, options = {}) {
|
|
1052
|
+
__publicField$4(this, "_file");
|
|
1053
|
+
__publicField$4(this, "_options");
|
|
1054
|
+
__publicField$4(this, "_size", null);
|
|
1055
|
+
__publicField$4(this, "_mimeType");
|
|
1056
|
+
__publicField$4(this, "_name");
|
|
1029
1057
|
this._file = file;
|
|
1058
|
+
if (file instanceof File || file instanceof Blob) {
|
|
1059
|
+
this._size = file.size;
|
|
1060
|
+
}
|
|
1061
|
+
if (file instanceof File || file instanceof Blob) {
|
|
1062
|
+
this._mimeType = file.type;
|
|
1063
|
+
}
|
|
1064
|
+
if ("name" in options) {
|
|
1065
|
+
this._name = options.name;
|
|
1066
|
+
}
|
|
1067
|
+
if ("mimeType" in options) {
|
|
1068
|
+
this._mimeType = options.mimeType;
|
|
1069
|
+
}
|
|
1030
1070
|
this._options = options;
|
|
1031
1071
|
this.validateFile();
|
|
1032
1072
|
}
|
|
1073
|
+
static create(file, options) {
|
|
1074
|
+
return new TelaFile(file, options);
|
|
1075
|
+
}
|
|
1033
1076
|
/**
|
|
1034
1077
|
* Retrieves the options provided during instantiation.
|
|
1035
1078
|
*
|
|
@@ -1044,7 +1087,15 @@ class TelaFile {
|
|
|
1044
1087
|
* @returns `true` if the file source is a valid URL string, otherwise `false`.
|
|
1045
1088
|
*/
|
|
1046
1089
|
get isURL() {
|
|
1047
|
-
return
|
|
1090
|
+
return this.isValidURL(this._file);
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Determines whether the file source is a valid Vault reference.
|
|
1094
|
+
*
|
|
1095
|
+
* @returns `true` if the file source is a valid Vault reference, otherwise `false`.
|
|
1096
|
+
*/
|
|
1097
|
+
get isVaultReference() {
|
|
1098
|
+
return this.isValidVaultReference(this._file);
|
|
1048
1099
|
}
|
|
1049
1100
|
/**
|
|
1050
1101
|
* Gets the size of the file in bytes.
|
|
@@ -1054,6 +1105,22 @@ class TelaFile {
|
|
|
1054
1105
|
get size() {
|
|
1055
1106
|
return this._size;
|
|
1056
1107
|
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Gets the name of the file.
|
|
1110
|
+
*
|
|
1111
|
+
* @returns The name of the file if available, otherwise `null`.
|
|
1112
|
+
*/
|
|
1113
|
+
get name() {
|
|
1114
|
+
return this._name ?? null;
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Gets the type of the file.
|
|
1118
|
+
*
|
|
1119
|
+
* @returns The type of the file if available, otherwise `null`.
|
|
1120
|
+
*/
|
|
1121
|
+
get type() {
|
|
1122
|
+
return this._mimeType ?? null;
|
|
1123
|
+
}
|
|
1057
1124
|
/**
|
|
1058
1125
|
* Retrieves the content of the file in a format suitable for uploading.
|
|
1059
1126
|
*
|
|
@@ -1064,11 +1131,11 @@ class TelaFile {
|
|
|
1064
1131
|
* @returns A promise that resolves to the uploadable content.
|
|
1065
1132
|
*/
|
|
1066
1133
|
async getUploadableContent() {
|
|
1067
|
-
if (this.
|
|
1134
|
+
if (this.isValidURL(this._file) || this.isValidVaultReference(this._file)) {
|
|
1068
1135
|
return this._file;
|
|
1069
1136
|
}
|
|
1070
1137
|
if (this._file instanceof Uint8Array) {
|
|
1071
|
-
return new File([this._file], "file", {
|
|
1138
|
+
return new File([this._file.buffer], "file", {
|
|
1072
1139
|
type: "application/octet-stream"
|
|
1073
1140
|
});
|
|
1074
1141
|
}
|
|
@@ -1109,6 +1176,9 @@ class TelaFile {
|
|
|
1109
1176
|
* @returns `true` if the URL is valid, otherwise `false`.
|
|
1110
1177
|
*/
|
|
1111
1178
|
isValidURL(url) {
|
|
1179
|
+
if (typeof url !== "string") {
|
|
1180
|
+
return false;
|
|
1181
|
+
}
|
|
1112
1182
|
try {
|
|
1113
1183
|
new URL(url);
|
|
1114
1184
|
return true;
|
|
@@ -1116,43 +1186,858 @@ class TelaFile {
|
|
|
1116
1186
|
return false;
|
|
1117
1187
|
}
|
|
1118
1188
|
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Checks if the provided string is a valid Vault reference.
|
|
1191
|
+
*
|
|
1192
|
+
* @param url - The Vault reference string to validate.
|
|
1193
|
+
* @returns `true` if the Vault reference is valid, otherwise `false`.
|
|
1194
|
+
*/
|
|
1195
|
+
isValidVaultReference(url) {
|
|
1196
|
+
if (typeof url !== "string") {
|
|
1197
|
+
return false;
|
|
1198
|
+
}
|
|
1199
|
+
return url.startsWith("vault://");
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
function compareSchemas(clientSchema, serverSchema, path = "$") {
|
|
1204
|
+
const mismatches = [];
|
|
1205
|
+
if (clientSchema.type !== serverSchema.type) {
|
|
1206
|
+
mismatches.push({
|
|
1207
|
+
path,
|
|
1208
|
+
issue: `Type mismatch: client has "${clientSchema.type}", server has "${serverSchema.type}"`
|
|
1209
|
+
});
|
|
1210
|
+
return mismatches;
|
|
1211
|
+
}
|
|
1212
|
+
if (clientSchema.type === "object") {
|
|
1213
|
+
const clientProps = clientSchema.properties || {};
|
|
1214
|
+
const serverProps = serverSchema.properties || {};
|
|
1215
|
+
const clientRequired = clientSchema.required || [];
|
|
1216
|
+
const serverRequired = serverSchema.required || [];
|
|
1217
|
+
for (const reqProp of serverRequired) {
|
|
1218
|
+
if (!clientProps[reqProp]) {
|
|
1219
|
+
mismatches.push({
|
|
1220
|
+
path: `${path}.${reqProp}`,
|
|
1221
|
+
issue: `Property is required on server but missing on client`
|
|
1222
|
+
});
|
|
1223
|
+
continue;
|
|
1224
|
+
}
|
|
1225
|
+
if (!clientRequired.includes(reqProp)) {
|
|
1226
|
+
mismatches.push({
|
|
1227
|
+
path: `${path}.${reqProp}`,
|
|
1228
|
+
issue: `Property is required on server but optional on client`
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
for (const clientProp of Object.keys(clientProps)) {
|
|
1233
|
+
if (!serverProps[clientProp]) {
|
|
1234
|
+
mismatches.push({
|
|
1235
|
+
path: `${path}.${clientProp}`,
|
|
1236
|
+
issue: `Extra property not expected by server`
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
for (const prop of Object.keys(serverProps)) {
|
|
1241
|
+
if (!clientProps[prop]) {
|
|
1242
|
+
continue;
|
|
1243
|
+
}
|
|
1244
|
+
const nestedMismatches = compareSchemas(
|
|
1245
|
+
clientProps[prop],
|
|
1246
|
+
serverProps[prop],
|
|
1247
|
+
`${path}.${prop}`
|
|
1248
|
+
);
|
|
1249
|
+
mismatches.push(...nestedMismatches);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
if (clientSchema.type === "array") {
|
|
1253
|
+
const clientItems = clientSchema.items;
|
|
1254
|
+
const serverItems = serverSchema.items;
|
|
1255
|
+
if (!clientItems || !serverItems) {
|
|
1256
|
+
if (clientItems !== serverItems) {
|
|
1257
|
+
mismatches.push({
|
|
1258
|
+
path: `${path}[]`,
|
|
1259
|
+
issue: `Array items schema mismatch: one side has items definition, other doesn't`
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
return mismatches;
|
|
1263
|
+
}
|
|
1264
|
+
const itemMismatches = compareSchemas(
|
|
1265
|
+
clientItems,
|
|
1266
|
+
serverItems,
|
|
1267
|
+
`${path}[]`
|
|
1268
|
+
);
|
|
1269
|
+
mismatches.push(...itemMismatches);
|
|
1270
|
+
}
|
|
1271
|
+
return mismatches;
|
|
1119
1272
|
}
|
|
1120
|
-
function
|
|
1121
|
-
|
|
1273
|
+
function mapServerTypeToJsonSchemaType(serverType) {
|
|
1274
|
+
const typeMap = {
|
|
1275
|
+
text: "string",
|
|
1276
|
+
number: "number",
|
|
1277
|
+
boolean: "boolean",
|
|
1278
|
+
file: "string",
|
|
1279
|
+
// z.file() generates type: "string" with format: "binary", contentEncoding: "binary"
|
|
1280
|
+
array: "array",
|
|
1281
|
+
object: "object"
|
|
1282
|
+
};
|
|
1283
|
+
return typeMap[serverType.toLowerCase()] || null;
|
|
1284
|
+
}
|
|
1285
|
+
function validateInputSchema(clientSchema, serverVariables) {
|
|
1286
|
+
const mismatches = [];
|
|
1287
|
+
const clientProps = clientSchema.properties || {};
|
|
1288
|
+
const clientRequired = clientSchema.required || [];
|
|
1289
|
+
for (const serverVar of serverVariables) {
|
|
1290
|
+
if (serverVar.required) {
|
|
1291
|
+
if (!clientProps[serverVar.name]) {
|
|
1292
|
+
mismatches.push({
|
|
1293
|
+
path: `$.${serverVar.name}`,
|
|
1294
|
+
issue: `Property is required on server but missing on client`
|
|
1295
|
+
});
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
if (!clientRequired.includes(serverVar.name)) {
|
|
1299
|
+
mismatches.push({
|
|
1300
|
+
path: `$.${serverVar.name}`,
|
|
1301
|
+
issue: `Variable is required on server but optional on client`
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
if (!clientProps[serverVar.name]) {
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
{
|
|
1309
|
+
const clientProp = clientProps[serverVar.name];
|
|
1310
|
+
const clientType = clientProp.type;
|
|
1311
|
+
const expectedType = mapServerTypeToJsonSchemaType(serverVar.type);
|
|
1312
|
+
if (serverVar.type.toLowerCase() === "file") {
|
|
1313
|
+
const isFileSchema = clientProp.isTelaFile;
|
|
1314
|
+
if (isFileSchema) {
|
|
1315
|
+
continue;
|
|
1316
|
+
}
|
|
1317
|
+
if (clientProp.format === "binary") {
|
|
1318
|
+
mismatches.push({
|
|
1319
|
+
path: `$.${serverVar.name}`,
|
|
1320
|
+
issue: `Type mismatch: file is expected to be a \`telaFile()\` but is a regular file instead.`
|
|
1321
|
+
});
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
if (clientType === "string" && !clientProp.format && !clientProp.contentEncoding) {
|
|
1325
|
+
mismatches.push({
|
|
1326
|
+
path: `$.${serverVar.name}`,
|
|
1327
|
+
issue: `Type mismatch: server expects file, client has plain string. Did you mean to use \`telaFile()\`?`
|
|
1328
|
+
});
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
mismatches.push({
|
|
1332
|
+
path: `$.${serverVar.name}`,
|
|
1333
|
+
issue: `Type mismatch: server expects file, client has "${clientType}"`
|
|
1334
|
+
});
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1337
|
+
if (expectedType && clientType !== expectedType) {
|
|
1338
|
+
mismatches.push({
|
|
1339
|
+
path: `$.${serverVar.name}`,
|
|
1340
|
+
issue: `Type mismatch: server expects "${serverVar.type}", client has "${clientType}"`
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
const serverVarNames = serverVariables.map((v) => v.name);
|
|
1346
|
+
for (const clientProp of Object.keys(clientProps)) {
|
|
1347
|
+
if (!serverVarNames.includes(clientProp)) {
|
|
1348
|
+
mismatches.push({
|
|
1349
|
+
path: `$.${clientProp}`,
|
|
1350
|
+
issue: `Extra property not expected by server`
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
return mismatches;
|
|
1355
|
+
}
|
|
1356
|
+
function validateOutputSchema(clientSchema, serverSchema) {
|
|
1357
|
+
return compareSchemas(clientSchema, serverSchema);
|
|
1122
1358
|
}
|
|
1123
1359
|
|
|
1124
|
-
var __defProp$
|
|
1125
|
-
var __defNormalProp$
|
|
1126
|
-
var __publicField$
|
|
1127
|
-
__defNormalProp$
|
|
1360
|
+
var __defProp$3 = Object.defineProperty;
|
|
1361
|
+
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1362
|
+
var __publicField$3 = (obj, key, value) => {
|
|
1363
|
+
__defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1128
1364
|
return value;
|
|
1129
1365
|
};
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1366
|
+
function timeout(ms, signal) {
|
|
1367
|
+
return new Promise((resolve, reject) => {
|
|
1368
|
+
const timer = setTimeout(resolve, ms);
|
|
1369
|
+
if (signal) {
|
|
1370
|
+
signal.addEventListener("abort", () => {
|
|
1371
|
+
clearTimeout(timer);
|
|
1372
|
+
reject(signal.reason);
|
|
1373
|
+
}, { once: true });
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
class Poller {
|
|
1378
|
+
constructor({ interval, timeout: timeout2, abortSignal }) {
|
|
1379
|
+
__publicField$3(this, "_interval");
|
|
1380
|
+
__publicField$3(this, "_timeout");
|
|
1381
|
+
__publicField$3(this, "_abortSignal");
|
|
1382
|
+
__publicField$3(this, "_internalAbortController");
|
|
1383
|
+
if (interval <= 0) {
|
|
1384
|
+
throw new TelaError("Interval must be greater than 0");
|
|
1385
|
+
}
|
|
1386
|
+
if (timeout2 <= 0) {
|
|
1387
|
+
throw new TelaError("Timeout must be greater than 0");
|
|
1388
|
+
}
|
|
1389
|
+
this._interval = interval;
|
|
1390
|
+
this._timeout = timeout2;
|
|
1391
|
+
this._abortSignal = abortSignal ?? new AbortController().signal;
|
|
1392
|
+
this._internalAbortController = new AbortController();
|
|
1393
|
+
}
|
|
1394
|
+
async startTimeout() {
|
|
1395
|
+
await timeout(this._timeout, this._internalAbortController.signal);
|
|
1396
|
+
throw new ConnectionTimeout({
|
|
1397
|
+
message: `Reached timeout of ${this._timeout}ms when polling`
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Starts the polling operation, repeatedly calling the callback until completion.
|
|
1402
|
+
* The callback is invoked at the configured interval and must return a PollerResult
|
|
1403
|
+
* indicating whether polling should continue or if the final value is ready.
|
|
1404
|
+
*
|
|
1405
|
+
* @param callback - Function called on each polling iteration.
|
|
1406
|
+
* @returns A promise resolving to the final result value.
|
|
1407
|
+
* @throws {Error} If the polling operation times out.
|
|
1408
|
+
* @throws {Error} If the operation is aborted via the AbortSignal.
|
|
1409
|
+
* @throws Any error thrown by the callback function.
|
|
1410
|
+
*
|
|
1411
|
+
* @example
|
|
1412
|
+
* ```typescript
|
|
1413
|
+
* const result = await poller.start(async (signal) => {
|
|
1414
|
+
* const response = await fetch('/api/status', { signal });
|
|
1415
|
+
* const data = await response.json();
|
|
1416
|
+
*
|
|
1417
|
+
* if (data.status === 'completed') {
|
|
1418
|
+
* return { done: true, value: data.result };
|
|
1419
|
+
* }
|
|
1420
|
+
* return { done: false };
|
|
1421
|
+
* });
|
|
1422
|
+
* ```
|
|
1423
|
+
*/
|
|
1424
|
+
start(callback) {
|
|
1425
|
+
const resultPromise = async () => {
|
|
1426
|
+
try {
|
|
1427
|
+
while (!this._abortSignal.aborted) {
|
|
1428
|
+
const result = await callback(this._abortSignal);
|
|
1429
|
+
if (result.done) {
|
|
1430
|
+
return result.value;
|
|
1431
|
+
}
|
|
1432
|
+
await timeout(this._interval, this._abortSignal);
|
|
1433
|
+
}
|
|
1434
|
+
throw new UserAbortError({ message: "Polling aborted" });
|
|
1435
|
+
} finally {
|
|
1436
|
+
this._internalAbortController.abort();
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
return Promise.race([this.startTimeout(), resultPromise()]);
|
|
1134
1440
|
}
|
|
1135
1441
|
}
|
|
1136
1442
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1443
|
+
async function calculateSha256sum(content) {
|
|
1444
|
+
const stream = content instanceof File || content instanceof Blob ? content.stream() : content;
|
|
1445
|
+
const reader = stream.getReader();
|
|
1446
|
+
try {
|
|
1447
|
+
const { createHash } = await import('node:crypto');
|
|
1448
|
+
const hash = createHash("sha256");
|
|
1449
|
+
while (true) {
|
|
1450
|
+
const { done, value } = await reader.read();
|
|
1451
|
+
if (done)
|
|
1452
|
+
break;
|
|
1453
|
+
hash.update(value);
|
|
1454
|
+
}
|
|
1455
|
+
return hash.digest("hex");
|
|
1456
|
+
} catch {
|
|
1457
|
+
const chunks = [];
|
|
1458
|
+
while (true) {
|
|
1459
|
+
const { done, value } = await reader.read();
|
|
1460
|
+
if (done)
|
|
1461
|
+
break;
|
|
1462
|
+
chunks.push(value);
|
|
1463
|
+
}
|
|
1464
|
+
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
1465
|
+
const buffer = new Uint8Array(totalLength);
|
|
1466
|
+
let offset = 0;
|
|
1467
|
+
for (const chunk of chunks) {
|
|
1468
|
+
buffer.set(chunk, offset);
|
|
1469
|
+
offset += chunk.length;
|
|
1470
|
+
}
|
|
1471
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
1472
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
1473
|
+
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1474
|
+
return hashHex;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
var __defProp$2 = Object.defineProperty;
|
|
1479
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1480
|
+
var __publicField$2 = (obj, key, value) => {
|
|
1481
|
+
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1482
|
+
return value;
|
|
1483
|
+
};
|
|
1484
|
+
function isTelaFile(obj) {
|
|
1485
|
+
return obj instanceof TelaFile;
|
|
1486
|
+
}
|
|
1487
|
+
function isTelaFileArray(obj) {
|
|
1488
|
+
return Array.isArray(obj) && obj.length > 0 && obj.every(isTelaFile);
|
|
1489
|
+
}
|
|
1490
|
+
function isUUID(str) {
|
|
1491
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1492
|
+
return uuidRegex.test(str);
|
|
1493
|
+
}
|
|
1494
|
+
class CanvasExecution extends Emittery__default {
|
|
1495
|
+
/**
|
|
1496
|
+
* Creates a new canvas execution instance.
|
|
1497
|
+
*
|
|
1498
|
+
* @param variables - Input variables to be passed to the canvas template.
|
|
1499
|
+
* @param params - Execution parameters controlling sync/async/stream behavior.
|
|
1500
|
+
* @param outputSchema - Zod schema or object schema for validating/parsing output.
|
|
1501
|
+
* @param client - HTTP client instance for making API requests.
|
|
1502
|
+
*/
|
|
1503
|
+
constructor(variables, params = { async: false }, outputSchema, client) {
|
|
1504
|
+
super();
|
|
1505
|
+
__publicField$2(this, "_id");
|
|
1506
|
+
__publicField$2(this, "_status");
|
|
1507
|
+
__publicField$2(this, "_variables");
|
|
1508
|
+
__publicField$2(this, "_params");
|
|
1509
|
+
__publicField$2(this, "_client");
|
|
1510
|
+
__publicField$2(this, "_outputSchema");
|
|
1511
|
+
__publicField$2(this, "_skipResultValidation");
|
|
1512
|
+
__publicField$2(this, "_abortController");
|
|
1513
|
+
__publicField$2(this, "_resultPromise");
|
|
1514
|
+
__publicField$2(this, "_stream");
|
|
1515
|
+
__publicField$2(this, "_rawResultValue");
|
|
1516
|
+
this._variables = variables;
|
|
1517
|
+
this._params = params;
|
|
1518
|
+
this._outputSchema = outputSchema;
|
|
1519
|
+
this._skipResultValidation = params.skipResultValidation ?? false;
|
|
1520
|
+
this._client = client;
|
|
1521
|
+
this._abortController = new AbortController();
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Fetches an existing asynchronous execution by its ID.
|
|
1525
|
+
*
|
|
1526
|
+
* This method retrieves the current state of an async execution and creates a new
|
|
1527
|
+
* CanvasExecution instance with the fetched data. Only async executions can be
|
|
1528
|
+
* fetched, as they are the only ones with persistent UUIDs on the server.
|
|
1529
|
+
*
|
|
1530
|
+
* @param id - The UUID of the async execution to fetch.
|
|
1531
|
+
* @param outputSchema - Zod schema or object schema for validating/parsing output.
|
|
1532
|
+
* @param client - HTTP client instance for making API requests.
|
|
1533
|
+
* @param options - Optional configuration for polling behavior.
|
|
1534
|
+
* @param options.pollingInterval - Time in milliseconds between polling attempts (default: 1000).
|
|
1535
|
+
* @param options.pollingTimeout - Maximum time in milliseconds to wait for completion (default: 60000).
|
|
1536
|
+
* @throws {InvalidExecutionModeError} If the provided ID is not a valid UUID.
|
|
1537
|
+
* @returns A promise resolving to a CanvasExecution instance with the fetched state.
|
|
1538
|
+
*
|
|
1539
|
+
* @example
|
|
1540
|
+
* ```typescript
|
|
1541
|
+
* const execution = await CanvasExecution.fetch(
|
|
1542
|
+
* 'execution-uuid',
|
|
1543
|
+
* z.object({ result: z.string() }),
|
|
1544
|
+
* client,
|
|
1545
|
+
* { pollingInterval: 2000, pollingTimeout: 120000 }
|
|
1546
|
+
* )
|
|
1547
|
+
* console.log(execution.status) // 'running' or 'succeeded' or 'failed'
|
|
1548
|
+
* ```
|
|
1549
|
+
*/
|
|
1550
|
+
static async fetch(id, outputSchema, client, options) {
|
|
1551
|
+
if (!isUUID(id)) {
|
|
1552
|
+
throw new InvalidExecutionModeError(
|
|
1553
|
+
"Only async executions can be fetched by ID. The provided ID is not a valid UUID."
|
|
1554
|
+
);
|
|
1555
|
+
}
|
|
1556
|
+
const response = await client.get(
|
|
1557
|
+
`/v2/chat/completions/${id}`
|
|
1558
|
+
);
|
|
1559
|
+
const params = {
|
|
1560
|
+
async: true,
|
|
1561
|
+
pollingInterval: options?.pollingInterval,
|
|
1562
|
+
pollingTimeout: options?.pollingTimeout
|
|
1563
|
+
};
|
|
1564
|
+
const execution = new CanvasExecution(
|
|
1565
|
+
{},
|
|
1566
|
+
// No variables needed for fetched execution
|
|
1567
|
+
params,
|
|
1568
|
+
outputSchema,
|
|
1569
|
+
client
|
|
1570
|
+
);
|
|
1571
|
+
execution._id = response.id;
|
|
1572
|
+
execution.status = response.status;
|
|
1573
|
+
if (response.status === "succeeded") {
|
|
1574
|
+
execution._rawResultValue = response;
|
|
1575
|
+
const content = response.outputContent.content;
|
|
1576
|
+
try {
|
|
1577
|
+
const validatedContent = execution._skipResultValidation || !(outputSchema instanceof z__default.ZodType) ? content : outputSchema.parse(content);
|
|
1578
|
+
execution._resultPromise = Promise.resolve(validatedContent);
|
|
1579
|
+
} catch (error) {
|
|
1580
|
+
execution._resultPromise = Promise.reject(error);
|
|
1581
|
+
execution._resultPromise.catch(() => {
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
} else if (response.status === "failed") {
|
|
1585
|
+
execution._rawResultValue = response;
|
|
1586
|
+
const error = new ExecutionFailedError(response.rawOutput);
|
|
1587
|
+
execution._resultPromise = Promise.reject(error);
|
|
1588
|
+
execution._resultPromise.catch(() => {
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
return execution;
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Gets the unique execution ID assigned by the server.
|
|
1595
|
+
*
|
|
1596
|
+
* Note: Streaming executions do not have an ID as they don't create a tracked execution on the server.
|
|
1597
|
+
*
|
|
1598
|
+
* @throws {ExecutionNotStartedError} If the execution has not been started yet.
|
|
1599
|
+
* @throws {InvalidExecutionModeError} If called on a streaming execution (streams don't have IDs).
|
|
1600
|
+
* @returns The execution ID.
|
|
1601
|
+
*/
|
|
1602
|
+
get id() {
|
|
1603
|
+
if (this.isStream) {
|
|
1604
|
+
throw new InvalidExecutionModeError("Streaming executions do not have an execution ID");
|
|
1605
|
+
}
|
|
1606
|
+
if (!this._id) {
|
|
1607
|
+
throw new ExecutionNotStartedError();
|
|
1608
|
+
}
|
|
1609
|
+
return this._id;
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Gets the latest known status of the execution.
|
|
1613
|
+
*
|
|
1614
|
+
* Status values and transitions:
|
|
1615
|
+
* - **Sync**: `succeeded` (after validation) or `failed` (on any error)
|
|
1616
|
+
* - **Async**: `created` → `running` → `succeeded` or `failed`
|
|
1617
|
+
* - **Stream**: `streaming` (once started)
|
|
1618
|
+
*
|
|
1619
|
+
* **Important:** Status is set to `succeeded` only after successful validation.
|
|
1620
|
+
* If validation fails, status will be `failed` even if the API request succeeded.
|
|
1621
|
+
*
|
|
1622
|
+
* Use the `statusChange` event to track status transitions in real-time.
|
|
1623
|
+
*
|
|
1624
|
+
* @throws {ExecutionNotStartedError} If the execution has not been started yet.
|
|
1625
|
+
* @returns The current status of the execution.
|
|
1626
|
+
*
|
|
1627
|
+
* @example
|
|
1628
|
+
* ```typescript
|
|
1629
|
+
* const execution = await canvas.execute({ query: 'test' }, { async: true })
|
|
1630
|
+
* console.log(execution.status) // 'created'
|
|
1631
|
+
*
|
|
1632
|
+
* await execution.result
|
|
1633
|
+
* console.log(execution.status) // 'succeeded' or 'failed'
|
|
1634
|
+
* ```
|
|
1635
|
+
*/
|
|
1636
|
+
get status() {
|
|
1637
|
+
if (!this._status) {
|
|
1638
|
+
throw new ExecutionNotStartedError();
|
|
1639
|
+
}
|
|
1640
|
+
return this._status;
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Sets the status of the execution.
|
|
1644
|
+
*
|
|
1645
|
+
* @param status - The new status of the execution.
|
|
1646
|
+
* @private
|
|
1647
|
+
*/
|
|
1648
|
+
set status(status) {
|
|
1649
|
+
const changed = this._status !== status;
|
|
1650
|
+
this._status = status;
|
|
1651
|
+
if (changed) {
|
|
1652
|
+
this.emit("statusChange", status);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
/**
|
|
1656
|
+
* Gets the input variables provided to this execution.
|
|
1657
|
+
*
|
|
1658
|
+
* @returns The variables object.
|
|
1659
|
+
*/
|
|
1660
|
+
get variables() {
|
|
1661
|
+
return this._variables;
|
|
1662
|
+
}
|
|
1663
|
+
/**
|
|
1664
|
+
* Gets the execution parameters configured for this instance.
|
|
1665
|
+
*
|
|
1666
|
+
* @returns The execution parameters or undefined.
|
|
1667
|
+
*/
|
|
1668
|
+
get params() {
|
|
1669
|
+
return this._params;
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Checks if this execution is configured for asynchronous processing.
|
|
1673
|
+
*
|
|
1674
|
+
* @returns True if async mode is enabled.
|
|
1675
|
+
*/
|
|
1676
|
+
get isAsync() {
|
|
1677
|
+
return this._isAsync(this._params);
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* Checks if this execution is configured for synchronous processing.
|
|
1681
|
+
*
|
|
1682
|
+
* @returns True if sync mode is enabled (not async).
|
|
1683
|
+
*/
|
|
1684
|
+
get isSync() {
|
|
1685
|
+
return !this._isAsync(this._params) && !this.isStream;
|
|
1686
|
+
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Checks if this execution is configured for streaming responses.
|
|
1689
|
+
*
|
|
1690
|
+
* @returns True if stream mode is enabled.
|
|
1691
|
+
*/
|
|
1692
|
+
get isStream() {
|
|
1693
|
+
return Boolean(this._params.stream);
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Gets the raw API response without any processing or validation.
|
|
1697
|
+
* Automatically starts execution and waits for completion (including polling for async executions).
|
|
1698
|
+
*
|
|
1699
|
+
* For sync executions, returns the complete API response.
|
|
1700
|
+
* For async executions, returns the polling response with status and output.
|
|
1701
|
+
*
|
|
1702
|
+
* @throws {InvalidExecutionModeError} If called on a streaming execution.
|
|
1703
|
+
* @returns A promise resolving to the raw API result.
|
|
1704
|
+
*/
|
|
1705
|
+
get rawResult() {
|
|
1706
|
+
if (this.isStream) {
|
|
1707
|
+
throw new InvalidExecutionModeError("rawResult is not available for streaming executions");
|
|
1708
|
+
}
|
|
1709
|
+
if (this.isSync) {
|
|
1710
|
+
if (!this._resultPromise) {
|
|
1711
|
+
throw new ExecutionNotStartedError();
|
|
1712
|
+
}
|
|
1713
|
+
return this._resultPromise.then(() => this._rawResultValue);
|
|
1714
|
+
}
|
|
1715
|
+
if (!this._resultPromise) {
|
|
1716
|
+
this._resultPromise = this.startPolling();
|
|
1717
|
+
}
|
|
1718
|
+
return this._resultPromise.then(() => this._rawResultValue);
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Type guard to check if params indicate async execution.
|
|
1722
|
+
*
|
|
1723
|
+
* @param params - Execution parameters to check.
|
|
1724
|
+
* @returns True if params indicate async mode.
|
|
1725
|
+
*/
|
|
1726
|
+
_isAsync(params) {
|
|
1727
|
+
return Boolean(params.async);
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Starts the execution based on configured parameters.
|
|
1731
|
+
* Routes to the appropriate execution method (sync, async, or stream).
|
|
1732
|
+
*
|
|
1733
|
+
* @returns A promise or async generator depending on execution mode.
|
|
1734
|
+
*/
|
|
1735
|
+
start() {
|
|
1736
|
+
if (this._resultPromise || this._stream) {
|
|
1737
|
+
return this._resultPromise ?? this._stream;
|
|
1738
|
+
}
|
|
1739
|
+
if (this._params.stream) {
|
|
1740
|
+
return this.startStream();
|
|
1741
|
+
}
|
|
1742
|
+
if (this.isSync) {
|
|
1743
|
+
return this.startSync();
|
|
1744
|
+
}
|
|
1745
|
+
return this.startAsync();
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Gets the execution result. For async executions, automatically starts polling.
|
|
1749
|
+
* For sync executions, returns the result promise. For streams, returns the generator.
|
|
1750
|
+
*
|
|
1751
|
+
* @returns The execution result as a promise or async generator.
|
|
1752
|
+
*/
|
|
1753
|
+
get result() {
|
|
1754
|
+
if (this.isSync) {
|
|
1755
|
+
if (!this._resultPromise) {
|
|
1756
|
+
throw new ExecutionNotStartedError();
|
|
1757
|
+
}
|
|
1758
|
+
return this._resultPromise;
|
|
1759
|
+
}
|
|
1760
|
+
if (this.isStream) {
|
|
1761
|
+
if (!this._stream) {
|
|
1762
|
+
throw new ExecutionNotStartedError();
|
|
1763
|
+
}
|
|
1764
|
+
return this._stream;
|
|
1765
|
+
}
|
|
1766
|
+
if (this._resultPromise) {
|
|
1767
|
+
return this._resultPromise;
|
|
1768
|
+
}
|
|
1769
|
+
this._resultPromise = this.startPolling();
|
|
1770
|
+
return this._resultPromise;
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* Cancels the ongoing execution by aborting all active requests and polling operations.
|
|
1774
|
+
*/
|
|
1775
|
+
cancel() {
|
|
1776
|
+
this._abortController.abort();
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Starts polling for the execution result without waiting for the promise to resolve.
|
|
1780
|
+
* This allows users to track execution progress via events rather than awaiting a promise.
|
|
1781
|
+
*
|
|
1782
|
+
* The following events will be emitted during polling:
|
|
1783
|
+
* - `statusChange`: Emitted when the execution status changes (e.g., 'created' → 'running' → 'succeeded')
|
|
1784
|
+
* - `poll`: Emitted on each polling attempt with the server response
|
|
1785
|
+
* - `success`: Emitted when the execution completes successfully with the final result
|
|
1786
|
+
* - `error`: Emitted if the execution fails
|
|
1787
|
+
*
|
|
1788
|
+
* **Important:** Events are only emitted while polling is active. You must either call `poll()` or
|
|
1789
|
+
* await `execution.result` to start polling. Simply setting up event listeners without starting
|
|
1790
|
+
* polling will not trigger any events.
|
|
1791
|
+
*
|
|
1792
|
+
* **Note:** If the execution has already completed (succeeded or failed) when fetched, the `success`
|
|
1793
|
+
* and `error` events will not fire since no polling is needed. Check the `status` property and
|
|
1794
|
+
* access the `result` directly for already-completed executions.
|
|
1795
|
+
*
|
|
1796
|
+
* @throws {InvalidExecutionModeError} If called on a non-async execution (sync or stream).
|
|
1797
|
+
* @throws {ExecutionNotStartedError} If the execution has not been started yet (no ID assigned).
|
|
1798
|
+
*
|
|
1799
|
+
* @example
|
|
1800
|
+
* ```typescript
|
|
1801
|
+
* const execution = await canvas.getExecution('execution-id')
|
|
1802
|
+
*
|
|
1803
|
+
* // Check if already completed
|
|
1804
|
+
* if (execution.status === 'succeeded' || execution.status === 'failed') {
|
|
1805
|
+
* // Access result directly - events won't fire
|
|
1806
|
+
* const result = await execution.result
|
|
1807
|
+
* console.log('Already completed:', result)
|
|
1808
|
+
* } else {
|
|
1809
|
+
* // Still running - set up events and start polling
|
|
1810
|
+
* execution.on('statusChange', (status) => {
|
|
1811
|
+
* console.log('Status:', status)
|
|
1812
|
+
* })
|
|
1813
|
+
*
|
|
1814
|
+
* execution.on('success', (result) => {
|
|
1815
|
+
* console.log('Completed:', result)
|
|
1816
|
+
* })
|
|
1817
|
+
*
|
|
1818
|
+
* execution.on('error', (error) => {
|
|
1819
|
+
* console.error('Failed:', error)
|
|
1820
|
+
* })
|
|
1821
|
+
*
|
|
1822
|
+
* // Start polling without waiting
|
|
1823
|
+
* execution.poll()
|
|
1824
|
+
* }
|
|
1825
|
+
* ```
|
|
1826
|
+
*/
|
|
1827
|
+
poll() {
|
|
1828
|
+
if (!this.isAsync) {
|
|
1829
|
+
throw new InvalidExecutionModeError("Polling is only supported for async executions");
|
|
1830
|
+
}
|
|
1831
|
+
if (!this._id) {
|
|
1832
|
+
throw new ExecutionNotStartedError();
|
|
1833
|
+
}
|
|
1834
|
+
if (this._resultPromise) {
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
this._resultPromise = this.startPolling();
|
|
1838
|
+
this._resultPromise.catch(() => {
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
/**
|
|
1842
|
+
* Builds the base request body shared across all execution types.
|
|
1843
|
+
* Includes messages, overrides, tags, label, and structured output configuration.
|
|
1844
|
+
*
|
|
1845
|
+
* @returns The base request body object.
|
|
1846
|
+
*/
|
|
1847
|
+
get baseBody() {
|
|
1848
|
+
if (this._params.label && !this._params.applicationId) {
|
|
1849
|
+
console.warn(
|
|
1850
|
+
'[Tela SDK - WARNING] The "label" field is only applicable when using applicationId. It will be ignored since no applicationId is provided.'
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
const body = {
|
|
1854
|
+
canvasId: this._params.canvasId,
|
|
1855
|
+
applicationId: this._params.applicationId,
|
|
1856
|
+
versionId: this._params.versionId,
|
|
1857
|
+
messages: this._params.messages,
|
|
1858
|
+
tags: this._params.tags,
|
|
1859
|
+
label: this._params.label
|
|
1860
|
+
};
|
|
1861
|
+
if (this._params.override && this._outputSchema instanceof z__default.ZodType) {
|
|
1862
|
+
return {
|
|
1863
|
+
...body,
|
|
1864
|
+
override: {
|
|
1865
|
+
...this._params.override,
|
|
1866
|
+
structured_output: z__default.toJSONSchema(this._outputSchema)
|
|
1148
1867
|
}
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
return body;
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Processes variables and uploads any TelaFile instances to the server.
|
|
1874
|
+
* Replaces TelaFile objects with their uploaded URLs while preserving other values.
|
|
1875
|
+
*
|
|
1876
|
+
* @returns A promise resolving to the processed variables object.
|
|
1877
|
+
*/
|
|
1878
|
+
async resolveVariables() {
|
|
1879
|
+
const variables = {};
|
|
1880
|
+
for (const [key, value] of Object.entries(this._variables)) {
|
|
1881
|
+
if (isTelaFileArray(value)) {
|
|
1882
|
+
variables[key] = await this.uploadFiles(value);
|
|
1883
|
+
continue;
|
|
1884
|
+
}
|
|
1885
|
+
if (isTelaFile(value)) {
|
|
1886
|
+
variables[key] = await this.uploadFile(value);
|
|
1887
|
+
continue;
|
|
1149
1888
|
}
|
|
1150
|
-
|
|
1889
|
+
variables[key] = value;
|
|
1151
1890
|
}
|
|
1152
|
-
return
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1891
|
+
return variables;
|
|
1892
|
+
}
|
|
1893
|
+
/**
|
|
1894
|
+
* Initiates a synchronous execution that waits for the complete result.
|
|
1895
|
+
* The result is validated against the output schema if provided.
|
|
1896
|
+
*
|
|
1897
|
+
* @returns A promise resolving to the parsed execution result.
|
|
1898
|
+
*/
|
|
1899
|
+
async startSync() {
|
|
1900
|
+
const resolvedVariables = await this.resolveVariables();
|
|
1901
|
+
const body = {
|
|
1902
|
+
async: this._params.async ?? false,
|
|
1903
|
+
stream: false,
|
|
1904
|
+
...this.baseBody,
|
|
1905
|
+
variables: resolvedVariables
|
|
1906
|
+
};
|
|
1907
|
+
this._resultPromise = this._client.post("/v2/chat/completions", {
|
|
1908
|
+
body,
|
|
1909
|
+
stream: false,
|
|
1910
|
+
signal: this._abortController.signal
|
|
1911
|
+
}).then((response) => {
|
|
1912
|
+
this._id = response.id;
|
|
1913
|
+
this._rawResultValue = response;
|
|
1914
|
+
return response.choices?.[0]?.message?.content;
|
|
1915
|
+
}).then((content) => {
|
|
1916
|
+
const validatedContent = this._skipResultValidation || !(this._outputSchema instanceof z__default.ZodType) ? content : this._outputSchema.parse(content);
|
|
1917
|
+
this.status = "succeeded";
|
|
1918
|
+
this.emit("success", validatedContent);
|
|
1919
|
+
return validatedContent;
|
|
1920
|
+
}).catch((error) => {
|
|
1921
|
+
this.status = "failed";
|
|
1922
|
+
if (this.listenerCount("error") > 0) {
|
|
1923
|
+
this.emit("error", error);
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
throw error;
|
|
1927
|
+
});
|
|
1928
|
+
return this._resultPromise;
|
|
1929
|
+
}
|
|
1930
|
+
/**
|
|
1931
|
+
* Initiates an asynchronous execution that returns immediately with an execution ID.
|
|
1932
|
+
* Results must be retrieved separately via polling using the `result` getter.
|
|
1933
|
+
*
|
|
1934
|
+
* @returns A promise that resolves when the execution is queued.
|
|
1935
|
+
*/
|
|
1936
|
+
async startAsync() {
|
|
1937
|
+
const resolvedVariables = await this.resolveVariables();
|
|
1938
|
+
const body = {
|
|
1939
|
+
async: true,
|
|
1940
|
+
stream: false,
|
|
1941
|
+
...this.baseBody,
|
|
1942
|
+
variables: resolvedVariables
|
|
1943
|
+
};
|
|
1944
|
+
return await this._client.post("/v2/chat/completions", {
|
|
1945
|
+
body,
|
|
1946
|
+
stream: false,
|
|
1947
|
+
signal: this._abortController.signal
|
|
1948
|
+
}).then((response) => {
|
|
1949
|
+
this._id = response.id;
|
|
1950
|
+
this.status = response.status;
|
|
1951
|
+
this.emit("poll", {
|
|
1952
|
+
id: response.id,
|
|
1953
|
+
status: response.status,
|
|
1954
|
+
outputContent: response.output_content,
|
|
1955
|
+
rawOutput: response.raw_output
|
|
1956
|
+
});
|
|
1957
|
+
return response;
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
/**
|
|
1961
|
+
* Initiates a streaming execution that returns results incrementally as they're generated.
|
|
1962
|
+
*
|
|
1963
|
+
* @returns A promise resolving to an async generator yielding result chunks.
|
|
1964
|
+
*/
|
|
1965
|
+
async startStream() {
|
|
1966
|
+
const resolvedVariables = await this.resolveVariables();
|
|
1967
|
+
const body = {
|
|
1968
|
+
...this.baseBody,
|
|
1969
|
+
stream: true,
|
|
1970
|
+
variables: resolvedVariables
|
|
1971
|
+
};
|
|
1972
|
+
this._stream = await this._client.post("/v2/chat/completions", {
|
|
1973
|
+
body,
|
|
1974
|
+
stream: true,
|
|
1975
|
+
signal: this._abortController.signal
|
|
1976
|
+
});
|
|
1977
|
+
this.status = "streaming";
|
|
1978
|
+
return this._stream;
|
|
1979
|
+
}
|
|
1980
|
+
/**
|
|
1981
|
+
* Polls the server for async execution results at regular intervals.
|
|
1982
|
+
* Continues polling until the execution completes or the timeout is reached.
|
|
1983
|
+
*
|
|
1984
|
+
* @throws {Error} If called on a non-async execution.
|
|
1985
|
+
* @throws {Error} If the execution fails on the server.
|
|
1986
|
+
* @throws {Error} If the polling operation times out.
|
|
1987
|
+
* @returns A promise resolving to the final execution result.
|
|
1988
|
+
*/
|
|
1989
|
+
async startPolling() {
|
|
1990
|
+
if (!this._isAsync(this._params)) {
|
|
1991
|
+
throw new InvalidExecutionModeError("Polling is only supported for async executions");
|
|
1992
|
+
}
|
|
1993
|
+
return new Poller({
|
|
1994
|
+
interval: this._params.pollingInterval ?? 1e3,
|
|
1995
|
+
// 1 second
|
|
1996
|
+
timeout: this._params.pollingTimeout ?? 6e4,
|
|
1997
|
+
// 1 minute
|
|
1998
|
+
abortSignal: this._abortController.signal
|
|
1999
|
+
}).start(async (signal) => {
|
|
2000
|
+
const response = await this._client.get(
|
|
2001
|
+
`/v2/chat/completions/${this.id}`,
|
|
2002
|
+
{
|
|
2003
|
+
signal
|
|
2004
|
+
}
|
|
2005
|
+
);
|
|
2006
|
+
this.status = response.status;
|
|
2007
|
+
this.emit("poll", response);
|
|
2008
|
+
if (response.status === "failed") {
|
|
2009
|
+
const error = new ExecutionFailedError(response.rawOutput);
|
|
2010
|
+
this.emit("error", error);
|
|
2011
|
+
throw error;
|
|
2012
|
+
}
|
|
2013
|
+
if (response.status !== "succeeded") {
|
|
2014
|
+
return {
|
|
2015
|
+
done: false,
|
|
2016
|
+
value: void 0
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
this._rawResultValue = response;
|
|
2020
|
+
this.emit("success", response.outputContent.content);
|
|
2021
|
+
return {
|
|
2022
|
+
done: response.status === "succeeded",
|
|
2023
|
+
value: response.outputContent.content
|
|
2024
|
+
};
|
|
2025
|
+
}).then((value) => {
|
|
2026
|
+
if (this._skipResultValidation || !(this._outputSchema instanceof z__default.ZodType)) {
|
|
2027
|
+
return value;
|
|
2028
|
+
}
|
|
2029
|
+
return this._outputSchema.parse(value);
|
|
2030
|
+
}).catch((error) => {
|
|
2031
|
+
if (this._status !== "failed") {
|
|
2032
|
+
this.status = "failed";
|
|
2033
|
+
}
|
|
2034
|
+
if (this.listenerCount("error") > 0) {
|
|
2035
|
+
if (!(error instanceof ExecutionFailedError)) {
|
|
2036
|
+
this.emit("error", error);
|
|
2037
|
+
}
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
throw error;
|
|
1156
2041
|
});
|
|
1157
2042
|
}
|
|
1158
2043
|
/**
|
|
@@ -1168,36 +2053,334 @@ class ChatCompletions extends Resource {
|
|
|
1168
2053
|
* ```typescript
|
|
1169
2054
|
* const file = new TelaFile({ /* file options *\/ });
|
|
1170
2055
|
* const uploadedFile = await this.uploadFile(file);
|
|
1171
|
-
* console.log(uploadedFile.
|
|
2056
|
+
* console.log(uploadedFile.fileUrl);
|
|
1172
2057
|
* ```
|
|
1173
2058
|
*/
|
|
1174
2059
|
async uploadFile(file) {
|
|
1175
|
-
|
|
1176
|
-
|
|
2060
|
+
let content = await file.getUploadableContent();
|
|
2061
|
+
let sha256sumStream;
|
|
2062
|
+
if (typeof content === "string") {
|
|
1177
2063
|
return { fileUrl: content, options: file.options };
|
|
1178
2064
|
}
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
2065
|
+
const filename = file.name ?? void 0;
|
|
2066
|
+
const fileType = file.type ?? void 0;
|
|
2067
|
+
const contentLength = file.size ?? void 0;
|
|
2068
|
+
if (content instanceof ReadableStream) {
|
|
2069
|
+
const [hashStream, contentStream] = content.tee();
|
|
2070
|
+
content = contentStream;
|
|
2071
|
+
sha256sumStream = hashStream;
|
|
2072
|
+
}
|
|
2073
|
+
const sha256sum = await calculateSha256sum(sha256sumStream ?? content);
|
|
2074
|
+
const { id, uploadUrl } = await this._client.post("/_services/vault/files", {
|
|
2075
|
+
body: {
|
|
2076
|
+
fileName: filename,
|
|
2077
|
+
mimeType: fileType,
|
|
2078
|
+
size: contentLength ?? void 0,
|
|
2079
|
+
sha256sum
|
|
2080
|
+
}
|
|
2081
|
+
});
|
|
2082
|
+
if (content instanceof ReadableStream && typeof Bun !== "undefined") {
|
|
2083
|
+
console.warn(
|
|
2084
|
+
"[Tela SDK - WARNING] Buffering file upload due to Bun fetch implementation. Large files may cause memory issues. Consider using Node.js for streaming uploads.",
|
|
2085
|
+
{ fileName: filename, fileSize: contentLength }
|
|
2086
|
+
);
|
|
2087
|
+
const chunks = [];
|
|
2088
|
+
const reader = content.getReader();
|
|
2089
|
+
while (true) {
|
|
2090
|
+
const { done, value } = await reader.read();
|
|
2091
|
+
if (done)
|
|
2092
|
+
break;
|
|
2093
|
+
chunks.push(value);
|
|
2094
|
+
}
|
|
2095
|
+
content = new Blob(chunks, { type: fileType ?? "application/octet-stream" });
|
|
1186
2096
|
}
|
|
1187
|
-
const
|
|
2097
|
+
const request = new Request(uploadUrl, {
|
|
1188
2098
|
method: "PUT",
|
|
1189
2099
|
body: content,
|
|
1190
2100
|
headers: {
|
|
1191
|
-
"Content-Type":
|
|
2101
|
+
"Content-Type": fileType ?? "application/octet-stream",
|
|
1192
2102
|
...file.size ? { "Content-Length": file.size.toString() } : {}
|
|
1193
|
-
}
|
|
1194
|
-
// duplex is not supported
|
|
1195
|
-
duplex: "half"
|
|
2103
|
+
}
|
|
1196
2104
|
});
|
|
2105
|
+
const uploadResponse = await fetch(request);
|
|
1197
2106
|
if (!uploadResponse.ok) {
|
|
1198
|
-
throw new FileUploadError(await uploadResponse.text());
|
|
2107
|
+
throw new FileUploadError(await uploadResponse.text(), uploadResponse.status);
|
|
1199
2108
|
}
|
|
1200
|
-
return { fileUrl:
|
|
2109
|
+
return { fileUrl: `vault://${id}`, options: file.options };
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Uploads multiple files and returns their URLs and options.
|
|
2113
|
+
*
|
|
2114
|
+
* This is used internally to handle multiple file uploads associated with chat completions.
|
|
2115
|
+
*
|
|
2116
|
+
* @param files - An array of TelaFile instances to be uploaded.
|
|
2117
|
+
* @returns A Promise that resolves to an array of objects containing file URLs and options.
|
|
2118
|
+
* @throws {FileUploadError} If any file upload fails.
|
|
2119
|
+
*/
|
|
2120
|
+
async uploadFiles(files) {
|
|
2121
|
+
const uploadPromises = files.map((file) => this.uploadFile(file));
|
|
2122
|
+
return Promise.all(uploadPromises);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
var __defProp$1 = Object.defineProperty;
|
|
2127
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
2128
|
+
var __publicField$1 = (obj, key, value) => {
|
|
2129
|
+
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
2130
|
+
return value;
|
|
2131
|
+
};
|
|
2132
|
+
const zod = {
|
|
2133
|
+
...z__namespace,
|
|
2134
|
+
file: TelaFileSchema
|
|
2135
|
+
};
|
|
2136
|
+
function fetchById(id, client) {
|
|
2137
|
+
return client.get(`/prompt/${id}/promoted-version`);
|
|
2138
|
+
}
|
|
2139
|
+
function fetchByVersionId(versionId, client) {
|
|
2140
|
+
return client.get(`/prompt-version/${versionId}`);
|
|
2141
|
+
}
|
|
2142
|
+
function fetchByApplicationId(applicationId, client) {
|
|
2143
|
+
return client.get(`/prompt-application/${applicationId}/targetPromptVersion`);
|
|
2144
|
+
}
|
|
2145
|
+
function fetchByAny({ id, versionId, applicationId, client }) {
|
|
2146
|
+
if (applicationId) {
|
|
2147
|
+
return fetchByApplicationId(applicationId, client);
|
|
2148
|
+
}
|
|
2149
|
+
if (versionId) {
|
|
2150
|
+
return fetchByVersionId(versionId, client);
|
|
2151
|
+
}
|
|
2152
|
+
if (id) {
|
|
2153
|
+
return fetchById(id, client);
|
|
2154
|
+
}
|
|
2155
|
+
throw new Error("Either id, versionId, or applicationId must be provided");
|
|
2156
|
+
}
|
|
2157
|
+
function validateSchemas(input, output, promptVersion) {
|
|
2158
|
+
const canvasIdentifier = `${promptVersion.title} (${promptVersion.promptId})`;
|
|
2159
|
+
if (input instanceof z.z.ZodType) {
|
|
2160
|
+
try {
|
|
2161
|
+
const inputSchema = z.z.toJSONSchema(input, { unrepresentable: "any" });
|
|
2162
|
+
const mismatches = validateInputSchema(inputSchema, promptVersion.variables);
|
|
2163
|
+
if (mismatches.length === 0) {
|
|
2164
|
+
return;
|
|
2165
|
+
}
|
|
2166
|
+
console.warn(
|
|
2167
|
+
`[Tela SDK - Canvas Input Validation] Input schema mismatches for canvas "${canvasIdentifier}":`
|
|
2168
|
+
);
|
|
2169
|
+
for (const mismatch of mismatches) {
|
|
2170
|
+
console.warn(` - ${mismatch.path}: ${mismatch.issue}`);
|
|
2171
|
+
}
|
|
2172
|
+
} catch (error) {
|
|
2173
|
+
console.warn(
|
|
2174
|
+
`[Tela SDK - Canvas Input Validation] Failed to validate input schema for canvas "${canvasIdentifier}":`,
|
|
2175
|
+
error
|
|
2176
|
+
);
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
if (output instanceof z.z.ZodType) {
|
|
2180
|
+
try {
|
|
2181
|
+
const outputSchema = z.z.toJSONSchema(output);
|
|
2182
|
+
const serverOutput = promptVersion.configuration.structuredOutput;
|
|
2183
|
+
if (!serverOutput.enabled) {
|
|
2184
|
+
console.warn(
|
|
2185
|
+
`[Tela SDK - Canvas Output Validation] Output schema provided for canvas "${canvasIdentifier}", but structured output is not enabled on the server. The schema may not be enforced.`
|
|
2186
|
+
);
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
const mismatches = validateOutputSchema(outputSchema, serverOutput.schema);
|
|
2190
|
+
if (mismatches.length === 0) {
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
console.warn(
|
|
2194
|
+
`[Tela SDK - Canvas Output Validation] Output schema mismatches for canvas "${canvasIdentifier}":`
|
|
2195
|
+
);
|
|
2196
|
+
for (const mismatch of mismatches) {
|
|
2197
|
+
console.warn(` - ${mismatch.path}: ${mismatch.issue}`);
|
|
2198
|
+
}
|
|
2199
|
+
} catch (error) {
|
|
2200
|
+
console.warn(
|
|
2201
|
+
`[Tela SDK - Canvas Output Validation] Failed to validate output schema for canvas "${canvasIdentifier}":`,
|
|
2202
|
+
error
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
class Canvas {
|
|
2208
|
+
/**
|
|
2209
|
+
* Creates a new instance of the Canvas class. Usage of this constructor is not recommended.
|
|
2210
|
+
* Use the `tela.getCanvas` method instead.
|
|
2211
|
+
*
|
|
2212
|
+
* @private
|
|
2213
|
+
*/
|
|
2214
|
+
constructor({ id, applicationId, name, versionId, input, output, client, variables }) {
|
|
2215
|
+
__publicField$1(this, "_id");
|
|
2216
|
+
__publicField$1(this, "_versionId");
|
|
2217
|
+
__publicField$1(this, "_applicationId");
|
|
2218
|
+
__publicField$1(this, "_name");
|
|
2219
|
+
__publicField$1(this, "_input");
|
|
2220
|
+
__publicField$1(this, "_output");
|
|
2221
|
+
__publicField$1(this, "_client");
|
|
2222
|
+
__publicField$1(this, "_variables");
|
|
2223
|
+
this._id = id;
|
|
2224
|
+
this._applicationId = applicationId;
|
|
2225
|
+
this._name = name;
|
|
2226
|
+
this._versionId = versionId;
|
|
2227
|
+
this._input = input && input(zod);
|
|
2228
|
+
this._output = output && output(zod);
|
|
2229
|
+
this._client = client;
|
|
2230
|
+
this._variables = variables;
|
|
2231
|
+
}
|
|
2232
|
+
/**
|
|
2233
|
+
* Gets a canvas by its ID.
|
|
2234
|
+
*
|
|
2235
|
+
* @param options - The options to use to get the canvas.
|
|
2236
|
+
* @param options.id - The ID of the canvas to get.
|
|
2237
|
+
* @param options.versionId - The version ID of the canvas to get.
|
|
2238
|
+
* @param options.applicationId - The application ID of the canvas to get.
|
|
2239
|
+
* @param options.client - The client to use to make the request.
|
|
2240
|
+
* @param options.input - The input schema of the canvas to get.
|
|
2241
|
+
* @param options.output - The output schema of the canvas to get.
|
|
2242
|
+
* @returns The canvas.
|
|
2243
|
+
*/
|
|
2244
|
+
static async get(options) {
|
|
2245
|
+
const { id, versionId, applicationId, client, input, output, skipSchemaValidation = false } = options;
|
|
2246
|
+
const promptVersion = await fetchByAny({ id, versionId, applicationId, client });
|
|
2247
|
+
const inputSchema = input && input(zod);
|
|
2248
|
+
const outputSchema = output && output(zod);
|
|
2249
|
+
if (!skipSchemaValidation) {
|
|
2250
|
+
validateSchemas(inputSchema, outputSchema, promptVersion);
|
|
2251
|
+
}
|
|
2252
|
+
return new Canvas({
|
|
2253
|
+
id: promptVersion.promptId,
|
|
2254
|
+
name: promptVersion.title,
|
|
2255
|
+
versionId: promptVersion.id,
|
|
2256
|
+
input,
|
|
2257
|
+
output,
|
|
2258
|
+
client,
|
|
2259
|
+
variables: promptVersion.variables
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
/**
|
|
2263
|
+
* Gets the unique identifier of this canvas.
|
|
2264
|
+
*
|
|
2265
|
+
* @returns The canvas ID.
|
|
2266
|
+
*/
|
|
2267
|
+
get id() {
|
|
2268
|
+
if (!this._id) {
|
|
2269
|
+
throw new Error("Canvas ID is not set");
|
|
2270
|
+
}
|
|
2271
|
+
return this._id;
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Gets the name of this canvas, if provided.
|
|
2275
|
+
*
|
|
2276
|
+
* @returns The canvas name or undefined.
|
|
2277
|
+
*/
|
|
2278
|
+
get name() {
|
|
2279
|
+
if (!this._name) {
|
|
2280
|
+
throw new Error("Canvas name is not set");
|
|
2281
|
+
}
|
|
2282
|
+
return this._name;
|
|
2283
|
+
}
|
|
2284
|
+
/**
|
|
2285
|
+
* Gets the version identifier of this canvas, if specified.
|
|
2286
|
+
* When undefined, the latest promoted version is used.
|
|
2287
|
+
*
|
|
2288
|
+
* @returns The version ID or undefined.
|
|
2289
|
+
*/
|
|
2290
|
+
get versionId() {
|
|
2291
|
+
if (!this._versionId) {
|
|
2292
|
+
throw new Error("Canvas version ID is not set");
|
|
2293
|
+
}
|
|
2294
|
+
return this._versionId;
|
|
2295
|
+
}
|
|
2296
|
+
get applicationId() {
|
|
2297
|
+
if (!this._applicationId) {
|
|
2298
|
+
throw new Error("Canvas application ID is not set");
|
|
2299
|
+
}
|
|
2300
|
+
return this._applicationId;
|
|
2301
|
+
}
|
|
2302
|
+
/**
|
|
2303
|
+
* Gets the variables of this canvas.
|
|
2304
|
+
*
|
|
2305
|
+
* @returns The variables of the canvas.
|
|
2306
|
+
*/
|
|
2307
|
+
get variables() {
|
|
2308
|
+
return this._variables;
|
|
2309
|
+
}
|
|
2310
|
+
/**
|
|
2311
|
+
* Validates and parses input variables using the canvas input schema.
|
|
2312
|
+
*
|
|
2313
|
+
* @param variables - Raw input variables to validate.
|
|
2314
|
+
* @returns Parsed and validated variables.
|
|
2315
|
+
* @throws {ZodError} If validation fails when a Zod schema is configured.
|
|
2316
|
+
*/
|
|
2317
|
+
parseVariables(variables) {
|
|
2318
|
+
try {
|
|
2319
|
+
if (this._input instanceof z.z.ZodType) {
|
|
2320
|
+
return this._input.parse(variables);
|
|
2321
|
+
}
|
|
2322
|
+
return variables;
|
|
2323
|
+
} catch (error) {
|
|
2324
|
+
if (!(error instanceof z.ZodError)) {
|
|
2325
|
+
throw error;
|
|
2326
|
+
}
|
|
2327
|
+
throw new Error(z.z.prettifyError(error));
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
execute(variables, params) {
|
|
2331
|
+
const parsedInput = this.parseVariables(variables);
|
|
2332
|
+
const fullParams = {
|
|
2333
|
+
...params ?? { async: false },
|
|
2334
|
+
versionId: this._versionId,
|
|
2335
|
+
canvasId: this._id,
|
|
2336
|
+
applicationId: this._applicationId
|
|
2337
|
+
};
|
|
2338
|
+
const execution = new CanvasExecution(parsedInput, fullParams, this._output, this._client);
|
|
2339
|
+
return {
|
|
2340
|
+
then(onfulfilled, onrejected) {
|
|
2341
|
+
return Promise.resolve(execution.start()).then(() => onfulfilled?.(execution) ?? execution).catch(onrejected);
|
|
2342
|
+
},
|
|
2343
|
+
get result() {
|
|
2344
|
+
return Promise.resolve(execution.start()).then(() => execution.result);
|
|
2345
|
+
}
|
|
2346
|
+
};
|
|
2347
|
+
}
|
|
2348
|
+
/**
|
|
2349
|
+
* Fetches an existing async execution by its ID.
|
|
2350
|
+
*
|
|
2351
|
+
* This method retrieves the current state of an async execution that was previously
|
|
2352
|
+
* started on this canvas. Only async executions can be fetched, as they are the only
|
|
2353
|
+
* ones with persistent UUIDs on the server.
|
|
2354
|
+
*
|
|
2355
|
+
* @param id - The UUID of the async execution to fetch.
|
|
2356
|
+
* @param options - Optional configuration for polling behavior.
|
|
2357
|
+
* @param options.pollingInterval - Time in milliseconds between polling attempts (default: 1000).
|
|
2358
|
+
* @param options.pollingTimeout - Maximum time in milliseconds to wait for completion (default: 60000).
|
|
2359
|
+
* @throws {InvalidExecutionModeError} If the provided ID is not a valid UUID.
|
|
2360
|
+
* @returns A promise resolving to a CanvasExecution instance with the fetched state.
|
|
2361
|
+
*
|
|
2362
|
+
* @example
|
|
2363
|
+
* ```typescript
|
|
2364
|
+
* // Start an async execution
|
|
2365
|
+
* const execution = await canvas.execute({ query: 'test' }, { async: true })
|
|
2366
|
+
* const executionId = execution.id
|
|
2367
|
+
*
|
|
2368
|
+
* // Later, fetch the execution by ID
|
|
2369
|
+
* const fetched = await canvas.getExecution(executionId)
|
|
2370
|
+
* console.log(fetched.status) // 'running', 'succeeded', or 'failed'
|
|
2371
|
+
*
|
|
2372
|
+
* // Use poll() for event-driven progress tracking
|
|
2373
|
+
* fetched.on('statusChange', (status) => console.log('Status:', status))
|
|
2374
|
+
* fetched.poll()
|
|
2375
|
+
* ```
|
|
2376
|
+
*/
|
|
2377
|
+
async getExecution(id, options) {
|
|
2378
|
+
return CanvasExecution.fetch(
|
|
2379
|
+
id,
|
|
2380
|
+
this._output,
|
|
2381
|
+
this._client,
|
|
2382
|
+
options
|
|
2383
|
+
);
|
|
1201
2384
|
}
|
|
1202
2385
|
}
|
|
1203
2386
|
|
|
@@ -1218,31 +2401,58 @@ const _TelaSDK = class _TelaSDK extends BaseClient {
|
|
|
1218
2401
|
__publicField(this, "apiKey");
|
|
1219
2402
|
__publicField(this, "jwt");
|
|
1220
2403
|
/**
|
|
1221
|
-
*
|
|
2404
|
+
* Creates a new `TelaFile` instance from the provided file input.
|
|
1222
2405
|
*
|
|
1223
|
-
*
|
|
2406
|
+
* @param file - The file input to create a `TelaFile` instance from.
|
|
2407
|
+
* @returns A new `TelaFile` instance.
|
|
2408
|
+
*/
|
|
2409
|
+
__publicField(this, "createFile", TelaFile.create.bind(this));
|
|
2410
|
+
/**
|
|
2411
|
+
* Retrieves a canvas by its ID, version ID, or application ID.
|
|
2412
|
+
* Validates input and output schemas if provided via schema builder functions.
|
|
2413
|
+
*
|
|
2414
|
+
* @param options - Options for retrieving the canvas.
|
|
2415
|
+
* @returns A promise resolving to a Canvas instance.
|
|
1224
2416
|
*
|
|
1225
2417
|
* @example
|
|
1226
2418
|
* ```typescript
|
|
1227
|
-
*
|
|
1228
|
-
*
|
|
1229
|
-
*
|
|
2419
|
+
* // Get canvas by ID with schemas
|
|
2420
|
+
* const canvas = await tela.canvas.get({
|
|
2421
|
+
* id: 'canvas-id',
|
|
2422
|
+
* input: schema => schema.object({
|
|
2423
|
+
* query: schema.string()
|
|
2424
|
+
* }),
|
|
2425
|
+
* output: schema => schema.object({
|
|
2426
|
+
* response: schema.string()
|
|
2427
|
+
* })
|
|
1230
2428
|
* });
|
|
1231
|
-
* ```
|
|
1232
|
-
*/
|
|
1233
|
-
__publicField(this, "completions", new ChatCompletions(this));
|
|
1234
|
-
/**
|
|
1235
|
-
* Creates a new `TelaFile` instance from the provided file input.
|
|
1236
2429
|
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
2430
|
+
* // Get canvas by application ID
|
|
2431
|
+
* const canvas = await tela.canvas.get({
|
|
2432
|
+
* applicationId: 'app-id'
|
|
2433
|
+
* });
|
|
2434
|
+
*
|
|
2435
|
+
* // Execute the canvas
|
|
2436
|
+
* const execution = await canvas.execute({ query: 'Hello' });
|
|
2437
|
+
* const result = await execution.result;
|
|
2438
|
+
* ```
|
|
1239
2439
|
*/
|
|
1240
|
-
__publicField(this, "
|
|
2440
|
+
__publicField(this, "canvas", {
|
|
2441
|
+
get: async (options) => {
|
|
2442
|
+
return Canvas.get({
|
|
2443
|
+
...options,
|
|
2444
|
+
client: this
|
|
2445
|
+
});
|
|
2446
|
+
}
|
|
2447
|
+
});
|
|
1241
2448
|
this.opts = { baseURL, ...rest };
|
|
1242
2449
|
this.apiKey = apiKey;
|
|
1243
2450
|
this.jwt = jwt;
|
|
1244
2451
|
this.validateAuth();
|
|
1245
2452
|
}
|
|
2453
|
+
get authToken() {
|
|
2454
|
+
return this.apiKey || this.jwt;
|
|
2455
|
+
}
|
|
1246
2456
|
validateAuth() {
|
|
1247
2457
|
if (!this.apiKey && !this.jwt) {
|
|
1248
2458
|
throw new MissingApiKeyOrJWTError();
|
|
@@ -1299,6 +2509,30 @@ function createTelaClient(opts) {
|
|
|
1299
2509
|
return new TelaSDK(opts);
|
|
1300
2510
|
}
|
|
1301
2511
|
|
|
2512
|
+
exports.APIError = APIError;
|
|
2513
|
+
exports.AuthenticationError = AuthenticationError;
|
|
2514
|
+
exports.AuthorizationError = AuthorizationError;
|
|
2515
|
+
exports.BadRequestError = BadRequestError;
|
|
2516
|
+
exports.BaseClient = BaseClient;
|
|
2517
|
+
exports.ConflictApiKeyAndJWTError = ConflictApiKeyAndJWTError;
|
|
2518
|
+
exports.ConflictError = ConflictError;
|
|
2519
|
+
exports.ConnectionError = ConnectionError;
|
|
2520
|
+
exports.ConnectionTimeout = ConnectionTimeout;
|
|
2521
|
+
exports.EmptyFileError = EmptyFileError;
|
|
2522
|
+
exports.ExecutionFailedError = ExecutionFailedError;
|
|
2523
|
+
exports.ExecutionNotStartedError = ExecutionNotStartedError;
|
|
2524
|
+
exports.FileUploadError = FileUploadError;
|
|
2525
|
+
exports.InternalServerError = InternalServerError;
|
|
2526
|
+
exports.InvalidExecutionModeError = InvalidExecutionModeError;
|
|
2527
|
+
exports.InvalidFileURL = InvalidFileURL;
|
|
2528
|
+
exports.MissingApiKeyOrJWTError = MissingApiKeyOrJWTError;
|
|
2529
|
+
exports.NotFoundError = NotFoundError;
|
|
2530
|
+
exports.RateLimitError = RateLimitError;
|
|
2531
|
+
exports.TelaError = TelaError;
|
|
1302
2532
|
exports.TelaFile = TelaFile;
|
|
2533
|
+
exports.TelaFileSchema = TelaFileSchema;
|
|
1303
2534
|
exports.TelaSDK = TelaSDK;
|
|
2535
|
+
exports.UnprocessableEntityError = UnprocessableEntityError;
|
|
2536
|
+
exports.UserAbortError = UserAbortError;
|
|
1304
2537
|
exports.createTelaClient = createTelaClient;
|
|
2538
|
+
exports.toError = toError;
|