@meistrari/tela-sdk-js 2.9.4 → 2.11.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 CHANGED
@@ -17,6 +17,8 @@ The Tela SDK for JavaScript provides a simple and powerful way to interact with
17
17
  - [Webhook Notifications](#webhook-notifications)
18
18
  - [Execution Tags](#execution-tags)
19
19
  - [File Handling](#file-handling)
20
+ - [Tasks API](#tasks-api)
21
+ - [Vault API](#vault-api)
20
22
  - [Migration Guide from v1.x to v2](#migration-guide-from-v1x-to-v2)
21
23
  - [Breaking Changes](#breaking-changes)
22
24
  - [Migration Checklist](#migration-checklist)
@@ -608,6 +610,111 @@ const fileWithRange = TelaFile.create(
608
610
  )
609
611
  ```
610
612
 
613
+ ### Tasks API
614
+
615
+ The Tasks API exposes the persistent task records that workstation (application) canvases create. Use it to fetch, list, update, approve, edit, re-run, or delete tasks without dropping down to raw HTTP.
616
+
617
+ ```typescript
618
+ import { TelaSDK, extractTaskOutput, normalizeTaskStatus } from '@meistrari/tela-sdk-js'
619
+
620
+ const tela = new TelaSDK({ apiKey: 'your-api-key' })
621
+
622
+ // Fetch a task by id
623
+ const task = await tela.tasks.get('task-id')
624
+
625
+ // Read the parsed output (handles canvas vs workflow shape automatically)
626
+ const output = await tela.tasks.getOutput<MyOutput>('task-id')
627
+ // or, if you already have the task in hand:
628
+ const sameOutput = extractTaskOutput<MyOutput>(task)
629
+
630
+ // List input files attached to the task (e.g. uploaded PDFs)
631
+ const files = await tela.tasks.getInputFiles('task-id')
632
+
633
+ // List tasks with filters
634
+ const { data, meta } = await tela.tasks.list({
635
+ promptApplicationId: 'app-id',
636
+ status: ['validating', 'completed'],
637
+ tags: 'product:my-app',
638
+ createdAtSince: new Date('2024-01-01'),
639
+ excludeInputOutputColumns: true, // omit raw input/input content/original output
640
+ orderBy: ['createdAt'],
641
+ order: 'desc',
642
+ limit: 50,
643
+ })
644
+
645
+ // Lean list rows still include outputContent and flattened inputFiles.
646
+ // Fetch a single task when you need raw input or original output payloads.
647
+ const fullTask = await tela.tasks.get(data[0].id)
648
+
649
+ // Mutations
650
+ await tela.tasks.rename('task-id', 'New name')
651
+ await tela.tasks.approve('task-id') // sets status: 'completed'
652
+ await tela.tasks.setTags('task-id', ['reviewed', 'q2'])
653
+
654
+ // ─── Updating output content ────────────────────────────────────
655
+ // The server uses *deep-merge* semantics on outputContent.content.
656
+ // Keys you do not provide are left untouched. There is no way to
657
+ // delete a field through this API. Three methods cover different
658
+ // use-cases:
659
+
660
+ // 1. Top-level partial patch (single PATCH, no fetch)
661
+ await tela.tasks.patchOutputContent('task-id', { reviewedBy: 'me' })
662
+
663
+ // 2. Single-field shortcut for nested *object* paths
664
+ // Do NOT use this for array indices — use updateOutputContent below.
665
+ await tela.tasks.patchOutputField('task-id', 'profile.email', 'b@x.com')
666
+
667
+ // 3. Read-modify-write — safe for arrays, multiple edits, and any
668
+ // change that needs the previous value. SDK fetches current,
669
+ // runs your updater, then sends the full content via patchOutputContent.
670
+ await tela.tasks.updateOutputContent<MenuOutput>('task-id', (current) => {
671
+ current.menu.items[2].price = 9.99 // mutate in place
672
+ current.menu.items.push({ name: 'New', price: 5 }) // grow arrays
673
+ })
674
+ // Updaters can also return a new value:
675
+ await tela.tasks.updateOutputContent('task-id', current => ({ ...current, reviewed: true }))
676
+
677
+ // Re-run a task (only allowed when status === 'failed')
678
+ const rerun = await tela.tasks.rerun('task-id')
679
+ console.log(rerun.executionRunId)
680
+
681
+ // Delete
682
+ await tela.tasks.delete('task-id') // → { success: true }
683
+ await tela.tasks.deleteBulk(['id1', 'id2']) // → { deleted: 2, deletedIds: [...] }
684
+ await tela.tasks.undoApprovalBulk(['id1', 'id2']) // → { undoApproval: 2, undoApprovalIds: [...] }
685
+
686
+ // Map server statuses to coarse client-friendly buckets
687
+ const uiStatus = normalizeTaskStatus(task.status)
688
+ // 'created' | 'running' → 'running'
689
+ // 'validating' → 'pending'
690
+ // 'completed' → 'succeeded'
691
+ // 'failed' | 'cancelled' → 'failed'
692
+ ```
693
+
694
+ The full `Task`, `TaskListItem`, `TaskInputFile`, `TaskListQuery`, `TaskUpdatePayload`, and `TaskStatus` types are exported from the package root, so you don't need to type any task-related responses by hand.
695
+
696
+ ### Vault API
697
+
698
+ The Vault API resolves and downloads files stored in the Tela vault. It accepts both `vault://<id>` references and bare ids, and passes through plain `https://` URLs unchanged.
699
+
700
+ ```typescript
701
+ const tela = new TelaSDK({ apiKey: 'your-api-key' })
702
+
703
+ // Get a temporary signed URL
704
+ const signedUrl = await tela.vault.getSignedUrl('vault://abc-123')
705
+
706
+ // Resolve any reference (vault:// or https://) to a downloadable URL
707
+ const downloadUrl = await tela.vault.resolve(file.url)
708
+
709
+ // Download as a Blob
710
+ const blob = await tela.vault.download('vault://abc-123')
711
+
712
+ // Stream the file
713
+ const stream = await tela.vault.stream('vault://abc-123')
714
+ ```
715
+
716
+ This is particularly useful when reading task input files: `tela.tasks.getInputFiles(id)` returns the file references, and `tela.vault.download(file.url)` downloads them in one call.
717
+
611
718
  ## Migration Guide from v1.x to v2
612
719
 
613
720
  Version 2.0 of the Tela SDK introduces significant improvements to type safety, schema validation, and API design. This guide will help you migrate your code from v1.x to v2.
@@ -1097,5 +1204,6 @@ When you execute a canvas using `applicationId`, it creates a task in the applic
1097
1204
 
1098
1205
  If you encounter issues during migration, please:
1099
1206
  - Check the [examples](./examples/) directory for updated usage patterns
1100
- - Review the [API documentation](./docs/)
1207
+ - Review the [API documentation](https://sdk-js.tela.tools/)
1208
+ - Generate the API reference locally with `bun run docs` when checking changes
1101
1209
  - Open an issue at [GitHub Issues](https://github.com/meistrari/tela-sdk-js/issues)
package/dist/index.cjs CHANGED
@@ -23,7 +23,7 @@ const changeCase__namespace = /*#__PURE__*/_interopNamespaceCompat(changeCase);
23
23
  const z__default = /*#__PURE__*/_interopDefaultCompat(z);
24
24
  const Emittery__default = /*#__PURE__*/_interopDefaultCompat(Emittery);
25
25
 
26
- const version = "2.9.4";
26
+ const version = "2.11.0";
27
27
 
28
28
  var __defProp$a = Object.defineProperty;
29
29
  var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -1761,7 +1761,11 @@ async function uploadFiles(files, client) {
1761
1761
  async function downloadFile(vaultReference, client) {
1762
1762
  const vaultId = vaultReference.replace("vault://", "");
1763
1763
  const response = await client.get(`/_services/vault/files/${vaultId}`);
1764
- return fetch(response.url).then((res) => res.blob());
1764
+ const res = await fetch(response.url);
1765
+ if (!res.ok) {
1766
+ throw new Error(`Failed to download file: ${res.status} ${res.statusText}`);
1767
+ }
1768
+ return res.blob();
1765
1769
  }
1766
1770
  async function streamFile(vaultReference, client) {
1767
1771
  const vaultId = vaultReference.replace("vault://", "");
@@ -3933,6 +3937,7 @@ const TaskListFilters = z__default.looseObject({
3933
3937
  const TaskListOptions = z__default.looseObject({
3934
3938
  limit: z__default.number().optional(),
3935
3939
  offset: z__default.number().optional(),
3940
+ excludeInputOutputColumns: z__default.boolean().optional(),
3936
3941
  order: z__default.object({
3937
3942
  by: z__default.enum(["createdAt", "updatedAt", "approvedAt", "status", "reference", "name"]),
3938
3943
  direction: z__default.enum(["asc", "desc"])
@@ -4235,6 +4240,7 @@ class Workstation {
4235
4240
  async *iterateTasks({ filters, options }) {
4236
4241
  let rawQuery;
4237
4242
  let hasMore = true;
4243
+ const validatedOptions = TaskListOptions.optional().parse(options);
4238
4244
  while (hasMore) {
4239
4245
  const { tasks, meta } = await this.listTasks({
4240
4246
  filters,
@@ -4247,7 +4253,8 @@ class Workstation {
4247
4253
  if (meta.links.next !== null) {
4248
4254
  rawQuery = {
4249
4255
  ...meta.links.next,
4250
- objectLinks: true
4256
+ objectLinks: true,
4257
+ ...validatedOptions?.excludeInputOutputColumns !== void 0 ? { excludeInputOutputColumns: validatedOptions.excludeInputOutputColumns } : {}
4251
4258
  };
4252
4259
  } else {
4253
4260
  hasMore = false;
@@ -4256,6 +4263,393 @@ class Workstation {
4256
4263
  }
4257
4264
  }
4258
4265
 
4266
+ function extractTaskOutput(task) {
4267
+ const oc = task.outputContent;
4268
+ if (!oc)
4269
+ return null;
4270
+ if (oc.output && typeof oc.output === "object" && "output" in oc.output) {
4271
+ return oc.output.output ?? null;
4272
+ }
4273
+ if ("content" in oc && oc.content !== void 0) {
4274
+ return oc.content ?? null;
4275
+ }
4276
+ return null;
4277
+ }
4278
+ function normalizeTaskStatus(status) {
4279
+ switch (status) {
4280
+ case "created":
4281
+ case "running":
4282
+ return "running";
4283
+ case "validating":
4284
+ return "pending";
4285
+ case "completed":
4286
+ return "succeeded";
4287
+ case "failed":
4288
+ case "cancelled":
4289
+ return "failed";
4290
+ }
4291
+ }
4292
+
4293
+ const NO_TRANSFORM = { transformCase: false };
4294
+ class Tasks {
4295
+ constructor(client) {
4296
+ this.client = client;
4297
+ }
4298
+ /**
4299
+ * Fetches a task by id.
4300
+ *
4301
+ * @param id - The task id.
4302
+ * @param options - Optional flags.
4303
+ * @param options.includeAnalytics - Include analytics data on the task.
4304
+ */
4305
+ async get(id, options) {
4306
+ return this.client.get(`/task/${id}`, {
4307
+ query: options?.includeAnalytics ? { includeAnalytics: "true" } : void 0,
4308
+ ...NO_TRANSFORM
4309
+ });
4310
+ }
4311
+ async list(query = {}) {
4312
+ const serialized = serializeTaskListQuery(query);
4313
+ return this.client.get("/task", {
4314
+ query: serialized,
4315
+ // The list endpoint expects pre-serialized array fields (JSON strings),
4316
+ // so disable automatic case transformation of the query payload.
4317
+ transformCase: false
4318
+ });
4319
+ }
4320
+ /**
4321
+ * Updates one or more fields of a task.
4322
+ *
4323
+ * Only `name`, `status`, `tags`, and `outputContent` may be updated.
4324
+ */
4325
+ async update(id, payload) {
4326
+ return this.client.patch(`/task/${id}`, {
4327
+ body: payload,
4328
+ ...NO_TRANSFORM
4329
+ });
4330
+ }
4331
+ /**
4332
+ * Renames a task. Convenience wrapper around {@link update}.
4333
+ */
4334
+ async rename(id, name) {
4335
+ return this.update(id, { name });
4336
+ }
4337
+ /**
4338
+ * Approves a task by setting its status to `completed`.
4339
+ * Convenience wrapper around {@link update}.
4340
+ */
4341
+ async approve(id) {
4342
+ return this.update(id, { status: "completed" });
4343
+ }
4344
+ /**
4345
+ * Patches a task's output content with a **deep merge** against the existing
4346
+ * content.
4347
+ *
4348
+ * ⚠️ **Merge semantics, not replace.** The server iterates the keys of the
4349
+ * provided payload and overlays them onto the current `outputContent.content`:
4350
+ *
4351
+ * - Keys you provide overwrite the existing values at the same path.
4352
+ * - Nested objects are merged recursively.
4353
+ * - Arrays of objects are merged positionally by index.
4354
+ * - **Keys you do not provide are left untouched** — there is no way to
4355
+ * delete a field through this API.
4356
+ *
4357
+ * If you only need to update a single (possibly nested) field, prefer
4358
+ * {@link patchOutputField} which handles building the nested payload for you.
4359
+ *
4360
+ * @example Top-level patch
4361
+ * ```typescript
4362
+ * // Existing content: { name: 'foo', price: 10 }
4363
+ * await tela.tasks.patchOutputContent(id, { price: 12 })
4364
+ * // Result: { name: 'foo', price: 12 }
4365
+ * ```
4366
+ *
4367
+ * @example Nested patch
4368
+ * ```typescript
4369
+ * // Existing content: { menu: { items: [{ name: 'A', price: 5 }] } }
4370
+ * await tela.tasks.patchOutputContent(id, { menu: { items: [{ price: 6 }] } })
4371
+ * // Result: { menu: { items: [{ name: 'A', price: 6 }] } }
4372
+ * ```
4373
+ */
4374
+ async patchOutputContent(id, content) {
4375
+ return this.update(id, { outputContent: { content } });
4376
+ }
4377
+ /**
4378
+ * Patches a single field of a task's output content using a dot-notation path.
4379
+ *
4380
+ * Internally builds a nested object that mirrors the path and submits it via
4381
+ * {@link patchOutputContent}, relying on the server's deep-merge to leave
4382
+ * sibling fields untouched.
4383
+ *
4384
+ * Path syntax:
4385
+ * - `foo.bar.baz` — nested object keys
4386
+ * - `items.0.price` — numeric segments are treated as array indices
4387
+ *
4388
+ * ⚠️ **Use {@link updateOutputContent} for any change inside arrays.** The
4389
+ * server's deep-merge replaces an entire array whenever the patched array's
4390
+ * length differs from the current one. This method only sends a sparse
4391
+ * single-element array (e.g. `[{ price: 7 }]`), so an array index path will
4392
+ * truncate the rest of the items. It is safe for **object paths only**
4393
+ * (e.g. `profile.email`).
4394
+ *
4395
+ * @example Nested object update — safe
4396
+ * ```typescript
4397
+ * // Existing: { profile: { name: 'A', email: 'a@x' } }
4398
+ * await tela.tasks.patchOutputField(id, 'profile.email', 'b@x')
4399
+ * // Result: { profile: { name: 'A', email: 'b@x' } }
4400
+ * ```
4401
+ *
4402
+ * @example Array element update — UNSAFE, prefer updateOutputContent
4403
+ * ```typescript
4404
+ * // ❌ Do NOT use patchOutputField for array indices:
4405
+ * // await tela.tasks.patchOutputField(id, 'items.0.price', 7)
4406
+ * // → server replaces items[] with the single-element sparse array.
4407
+ *
4408
+ * // ✅ Use updateOutputContent instead:
4409
+ * await tela.tasks.updateOutputContent(id, (current) => {
4410
+ * current.items[0].price = 7
4411
+ * })
4412
+ * ```
4413
+ */
4414
+ async patchOutputField(id, path, value) {
4415
+ if (path.length === 0) {
4416
+ throw new Error("tasks.patchOutputField: path cannot be empty");
4417
+ }
4418
+ const payload = buildNestedPayload(path, value);
4419
+ return this.patchOutputContent(id, payload);
4420
+ }
4421
+ /**
4422
+ * Read-modify-write helper for safely updating any part of a task's output
4423
+ * content — including array elements.
4424
+ *
4425
+ * Fetches the current output, hands you a deep clone via the `updater`
4426
+ * callback (which can mutate it in place or return a new value), then
4427
+ * submits the full updated content via {@link patchOutputContent}. Because
4428
+ * the entire arrays are sent back, the server's "replace on length mismatch"
4429
+ * array behavior never triggers — array element edits, additions, removals,
4430
+ * and reorders all work correctly.
4431
+ *
4432
+ * Use this whenever:
4433
+ * - You're modifying anything inside an array
4434
+ * - You need the previous value to compute the new one
4435
+ * - You're making multiple field changes in one logical operation
4436
+ *
4437
+ * For simple top-level patches without needing the current value, prefer
4438
+ * {@link patchOutputContent}.
4439
+ *
4440
+ * @example Update one menu item's price
4441
+ * ```typescript
4442
+ * await tela.tasks.updateOutputContent<MenuOutput>(id, (current) => {
4443
+ * current.menu.items[2].price = 9.99
4444
+ * })
4445
+ * ```
4446
+ *
4447
+ * @example Add a new array item
4448
+ * ```typescript
4449
+ * await tela.tasks.updateOutputContent<TodoOutput>(id, (current) => {
4450
+ * current.todos.push({ text: 'new task', done: false })
4451
+ * })
4452
+ * ```
4453
+ *
4454
+ * @example Return a brand-new value
4455
+ * ```typescript
4456
+ * await tela.tasks.updateOutputContent(id, (current) => ({
4457
+ * ...current,
4458
+ * reviewed: true,
4459
+ * }))
4460
+ * ```
4461
+ *
4462
+ * @throws If the task has no output content yet (still running).
4463
+ */
4464
+ async updateOutputContent(id, updater) {
4465
+ const task = await this.get(id);
4466
+ const current = extractTaskOutput(task);
4467
+ if (current === null || current === void 0) {
4468
+ throw new Error(`tasks.updateOutputContent: task ${id} has no output content yet`);
4469
+ }
4470
+ const draft = structuredClone(current);
4471
+ const result = updater(draft);
4472
+ const next = result === void 0 ? draft : result;
4473
+ return this.patchOutputContent(id, next);
4474
+ }
4475
+ /**
4476
+ * Replaces a task's tags. Convenience wrapper around {@link update}.
4477
+ */
4478
+ async setTags(id, tags) {
4479
+ return this.update(id, { tags });
4480
+ }
4481
+ /**
4482
+ * Soft-deletes a task.
4483
+ */
4484
+ async delete(id) {
4485
+ return this.client.delete(`/task/${id}`, NO_TRANSFORM);
4486
+ }
4487
+ /**
4488
+ * Bulk soft-deletes multiple tasks.
4489
+ *
4490
+ * @throws If `ids` is empty.
4491
+ */
4492
+ async deleteBulk(ids) {
4493
+ if (ids.length === 0) {
4494
+ throw new Error("tasks.deleteBulk: ids array cannot be empty");
4495
+ }
4496
+ return this.client.delete("/task/bulk", {
4497
+ body: ids,
4498
+ ...NO_TRANSFORM
4499
+ });
4500
+ }
4501
+ /**
4502
+ * Reverts approval on multiple tasks (sets them back to `validating`).
4503
+ * Only tasks currently in `completed` status are eligible.
4504
+ *
4505
+ * @throws If `ids` is empty.
4506
+ */
4507
+ async undoApprovalBulk(ids) {
4508
+ if (ids.length === 0) {
4509
+ throw new Error("tasks.undoApprovalBulk: ids array cannot be empty");
4510
+ }
4511
+ return this.client.post("/task/bulk/undo-approval", {
4512
+ body: ids,
4513
+ ...NO_TRANSFORM
4514
+ });
4515
+ }
4516
+ /**
4517
+ * Re-runs a task. Returns the new execution metadata.
4518
+ *
4519
+ * Note: the server only allows re-running tasks in `failed` status. Calling
4520
+ * this on a task in any other state will result in a 400 response.
4521
+ */
4522
+ async rerun(id) {
4523
+ return this.client.post(`/task/${id}/rerun`, NO_TRANSFORM);
4524
+ }
4525
+ /**
4526
+ * Returns the input files attached to a task.
4527
+ *
4528
+ * Convenience helper around {@link get} that extracts and normalizes the
4529
+ * `inputContent.files[]` array.
4530
+ */
4531
+ async getInputFiles(id) {
4532
+ const task = await this.get(id);
4533
+ return task.inputContent?.files ?? [];
4534
+ }
4535
+ /**
4536
+ * Returns the parsed output of a task regardless of whether it came from a
4537
+ * canvas execution or a workflow execution.
4538
+ *
4539
+ * Returns `null` if the task has no output yet.
4540
+ */
4541
+ async getOutput(id) {
4542
+ const task = await this.get(id);
4543
+ return extractTaskOutput(task);
4544
+ }
4545
+ }
4546
+ function buildNestedPayload(path, value) {
4547
+ const segments = path.split(".");
4548
+ let current = value;
4549
+ for (let i = segments.length - 1; i >= 0; i--) {
4550
+ const seg = segments[i];
4551
+ if (/^\d+$/.test(seg)) {
4552
+ const arr = [];
4553
+ arr[Number(seg)] = current;
4554
+ current = arr;
4555
+ } else {
4556
+ current = { [seg]: current };
4557
+ }
4558
+ }
4559
+ return current;
4560
+ }
4561
+ function serializeTaskListQuery(query) {
4562
+ const out = {};
4563
+ for (const [key, value] of Object.entries(query)) {
4564
+ if (value === void 0)
4565
+ continue;
4566
+ if (key === "ids" || key === "status" || key === "approvedBy" || key === "createdBy") {
4567
+ out[key] = JSON.stringify(value);
4568
+ continue;
4569
+ }
4570
+ if (key === "orderBy") {
4571
+ out[key] = Array.isArray(value) ? JSON.stringify(value) : value;
4572
+ continue;
4573
+ }
4574
+ if (value instanceof Date) {
4575
+ out[key] = value.toISOString();
4576
+ continue;
4577
+ }
4578
+ out[key] = value;
4579
+ }
4580
+ return out;
4581
+ }
4582
+
4583
+ function toVaultId(ref) {
4584
+ if (ref.startsWith("vault://"))
4585
+ return ref.slice("vault://".length);
4586
+ if (/^https?:\/\//i.test(ref))
4587
+ return null;
4588
+ return ref;
4589
+ }
4590
+ class Vault {
4591
+ constructor(client) {
4592
+ this.client = client;
4593
+ }
4594
+ /**
4595
+ * Returns a temporary signed URL for a vault file.
4596
+ *
4597
+ * @param ref - A `vault://<id>` reference or a bare vault id.
4598
+ * @throws If `ref` is an `https://` URL (already resolved). Use {@link resolve} for that case.
4599
+ */
4600
+ async getSignedUrl(ref) {
4601
+ const id = toVaultId(ref);
4602
+ if (id === null) {
4603
+ throw new Error(`vault.getSignedUrl: '${ref}' is already an http(s) URL; use vault.resolve() instead`);
4604
+ }
4605
+ const response = await this.client.get(`/_services/vault/files/${id}`);
4606
+ return response.url;
4607
+ }
4608
+ /**
4609
+ * Resolves any file reference to a downloadable URL.
4610
+ *
4611
+ * - `vault://<id>` and bare ids are resolved through the vault service.
4612
+ * - `https://` / `http://` URLs are returned as-is.
4613
+ */
4614
+ async resolve(ref) {
4615
+ if (toVaultId(ref) === null)
4616
+ return ref;
4617
+ return this.getSignedUrl(ref);
4618
+ }
4619
+ /**
4620
+ * Downloads a vault file as a Blob.
4621
+ *
4622
+ * @param ref - A `vault://<id>` reference or a bare vault id.
4623
+ */
4624
+ async download(ref) {
4625
+ const id = toVaultId(ref);
4626
+ if (id === null) {
4627
+ const res = await fetch(ref);
4628
+ if (!res.ok) {
4629
+ throw new Error(`vault.download: failed to fetch ${ref}: ${res.status} ${res.statusText}`);
4630
+ }
4631
+ return res.blob();
4632
+ }
4633
+ return downloadFile(`vault://${id}`, this.client);
4634
+ }
4635
+ /**
4636
+ * Streams a vault file as a `ReadableStream`.
4637
+ *
4638
+ * @param ref - A `vault://<id>` reference or a bare vault id.
4639
+ */
4640
+ async stream(ref) {
4641
+ const id = toVaultId(ref);
4642
+ if (id === null) {
4643
+ const res = await fetch(ref);
4644
+ if (!res.ok || !res.body) {
4645
+ throw new Error(`vault.stream: failed to fetch ${ref}: ${res.status} ${res.statusText}`);
4646
+ }
4647
+ return res.body;
4648
+ }
4649
+ return streamFile(`vault://${id}`, this.client);
4650
+ }
4651
+ }
4652
+
4259
4653
  var __defProp = Object.defineProperty;
4260
4654
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4261
4655
  var __publicField = (obj, key, value) => {
@@ -4318,6 +4712,30 @@ const _TelaSDK = class _TelaSDK extends BaseClient {
4318
4712
  });
4319
4713
  }
4320
4714
  });
4715
+ /**
4716
+ * Tasks API resource for managing workstation tasks (fetch, list, update,
4717
+ * approve, rename, edit output, re-run, etc.).
4718
+ *
4719
+ * @example
4720
+ * ```typescript
4721
+ * const task = await tela.tasks.get('task-id')
4722
+ * await tela.tasks.approve('task-id')
4723
+ * await tela.tasks.rename('task-id', 'New name')
4724
+ * const files = await tela.tasks.getInputFiles('task-id')
4725
+ * ```
4726
+ */
4727
+ __publicField(this, "tasks", new Tasks(this));
4728
+ /**
4729
+ * Vault API resource for resolving, downloading, and streaming files
4730
+ * stored in the Tela vault.
4731
+ *
4732
+ * @example
4733
+ * ```typescript
4734
+ * const url = await tela.vault.getSignedUrl('vault://abc-123')
4735
+ * const blob = await tela.vault.download('vault://abc-123')
4736
+ * ```
4737
+ */
4738
+ __publicField(this, "vault", new Vault(this));
4321
4739
  __publicField(this, "workstation", {
4322
4740
  get: async (options) => {
4323
4741
  return Workstation.get({
@@ -4437,13 +4855,17 @@ exports.MissingAuthError = MissingAuthError;
4437
4855
  exports.NotFoundError = NotFoundError;
4438
4856
  exports.RateLimitError = RateLimitError;
4439
4857
  exports.TaskFailedError = TaskFailedError;
4858
+ exports.Tasks = Tasks;
4440
4859
  exports.TelaError = TelaError;
4441
4860
  exports.TelaFile = TelaFile;
4442
4861
  exports.TelaFileSchema = TelaFileSchema;
4443
4862
  exports.TelaSDK = TelaSDK;
4444
4863
  exports.UnprocessableEntityError = UnprocessableEntityError;
4445
4864
  exports.UserAbortError = UserAbortError;
4865
+ exports.Vault = Vault;
4446
4866
  exports.createTelaClient = createTelaClient;
4867
+ exports.extractTaskOutput = extractTaskOutput;
4447
4868
  exports.isTelaFile = isTelaFile;
4448
4869
  exports.isTelaFileArray = isTelaFileArray;
4870
+ exports.normalizeTaskStatus = normalizeTaskStatus;
4449
4871
  exports.toError = toError;