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