@renderinc/sdk 0.3.0 → 0.4.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.
Files changed (38) hide show
  1. package/README.md +159 -42
  2. package/dist/experimental/experimental.d.ts +2 -2
  3. package/dist/experimental/experimental.d.ts.map +1 -1
  4. package/dist/experimental/experimental.js +4 -4
  5. package/dist/experimental/object/client.d.ts +10 -6
  6. package/dist/experimental/object/client.d.ts.map +1 -1
  7. package/dist/experimental/object/client.js +33 -9
  8. package/dist/experimental/object/e2e-helpers.d.ts +3 -0
  9. package/dist/experimental/object/e2e-helpers.d.ts.map +1 -0
  10. package/dist/experimental/object/e2e-helpers.js +70 -0
  11. package/dist/experimental/object/types.d.ts +1 -0
  12. package/dist/experimental/object/types.d.ts.map +1 -1
  13. package/dist/render.d.ts.map +1 -1
  14. package/dist/render.js +3 -1
  15. package/dist/workflows/client/client.d.ts +7 -3
  16. package/dist/workflows/client/client.d.ts.map +1 -1
  17. package/dist/workflows/client/client.js +96 -15
  18. package/dist/workflows/client/index.d.ts +2 -0
  19. package/dist/workflows/client/index.d.ts.map +1 -1
  20. package/dist/workflows/client/index.js +5 -1
  21. package/dist/workflows/client/sse.d.ts +0 -7
  22. package/dist/workflows/client/sse.d.ts.map +1 -1
  23. package/dist/workflows/client/sse.js +1 -71
  24. package/dist/workflows/client/task-run-promise.d.ts +12 -0
  25. package/dist/workflows/client/task-run-promise.d.ts.map +1 -0
  26. package/dist/workflows/client/task-run-promise.js +22 -0
  27. package/dist/workflows/client/task-run-result.d.ts +10 -0
  28. package/dist/workflows/client/task-run-result.d.ts.map +1 -0
  29. package/dist/workflows/client/task-run-result.js +18 -0
  30. package/dist/workflows/client/types.d.ts +2 -0
  31. package/dist/workflows/client/types.d.ts.map +1 -1
  32. package/dist/workflows/uds.d.ts +1 -0
  33. package/dist/workflows/uds.d.ts.map +1 -1
  34. package/dist/workflows/uds.js +27 -0
  35. package/dist/workflows/workflows.d.ts +19 -0
  36. package/dist/workflows/workflows.d.ts.map +1 -0
  37. package/dist/workflows/workflows.js +51 -0
  38. package/package.json +2 -1
package/README.md CHANGED
@@ -30,6 +30,12 @@ Or with pnpm:
30
30
  pnpm add @renderinc/sdk
31
31
  ```
32
32
 
33
+ Or with Bun:
34
+
35
+ ```bash
36
+ bun add @renderinc/sdk
37
+ ```
38
+
33
39
  ## Quick Start
34
40
 
35
41
  ### REST API Client
@@ -47,11 +53,13 @@ const result = await render.workflows.runTask('my-workflow/my-task', [42, 'hello
47
53
  console.log('Status:', result.status);
48
54
  console.log('Results:', result.results);
49
55
 
56
+ // Or start a task and decide when to await the result
57
+ const run = await render.workflows.startTask('my-workflow/my-task', [42, 'hello']);
58
+ console.log('Task run ID:', run.taskRunId);
59
+ const details = await run.get();
60
+
50
61
  // List recent task runs
51
62
  const taskRuns = await render.workflows.listTaskRuns({ limit: 10 });
52
-
53
- // Get specific task run
54
- const details = await render.workflows.getTaskRun(result.id);
55
63
  ```
56
64
 
57
65
  Alternatively, you can create a workflows client directly:
@@ -125,9 +133,12 @@ Creates a new Render SDK instance with access to all Render products.
125
133
  - `baseUrl?: string` - Base URL (defaults to `https://api.render.com`)
126
134
  - `useLocalDev?: boolean` - Use local development mode
127
135
  - `localDevUrl?: string` - Local development URL
136
+ - `ownerId?: string` - Default owner ID for object storage (falls back to `RENDER_WORKSPACE_ID` env var)
137
+ - `region?: string` - Default region for object storage (falls back to `RENDER_REGION` env var)
128
138
 
129
139
  **Properties:**
130
140
  - `workflows` - WorkflowsClient instance for managing workflow tasks
141
+ - `experimental` - ExperimentalClient instance for object storage and other experimental APIs
131
142
 
132
143
  **Example:**
133
144
  ```typescript
@@ -175,6 +186,56 @@ const result = await render.workflows.runTask('my-workflow/square', [5]);
175
186
  console.log('Results:', result.results);
176
187
  ```
177
188
 
189
+ #### `render.workflows.startTask(taskIdentifier, inputData, signal?)`
190
+
191
+ Starts a task run and returns a `TaskRunResult`. Results are not streamed until you call `.get()` on the returned result. Use this when you need the task run ID, want to defer awaiting, or want fire-and-forget.
192
+
193
+ **Parameters:**
194
+ - `taskIdentifier: string` - Task identifier in format "workflow-slug/task-name"
195
+ - `inputData: any[]` - Input data as array of parameters
196
+ - `signal?: AbortSignal` - Optional abort signal for cancellation
197
+
198
+ **Returns:** `Promise<TaskRunResult>`
199
+
200
+ **Example:**
201
+ ```typescript
202
+ const render = new Render();
203
+
204
+ // Start a task and grab its ID
205
+ const run = await render.workflows.startTask('my-workflow/square', [5]);
206
+ console.log('Task run ID:', run.taskRunId);
207
+
208
+ // Await the result when you're ready
209
+ const result = await run.get();
210
+ console.log('Results:', result.results);
211
+ ```
212
+
213
+ #### `render.workflows.taskRunEvents(taskRunIds, signal?)`
214
+
215
+ Streams task run events as an async iterable. Yields a `TaskRunDetails` for each terminal event (completed or failed) received on the stream.
216
+
217
+ **Parameters:**
218
+ - `taskRunIds: string[]` - One or more task run IDs to subscribe to
219
+ - `signal?: AbortSignal` - Optional abort signal for cancellation
220
+
221
+ **Returns:** `AsyncGenerator<TaskRunDetails>`
222
+
223
+ **Example:**
224
+ ```typescript
225
+ const render = new Render();
226
+
227
+ const run1 = await render.workflows.startTask('my-workflow/square', [3]);
228
+ const run2 = await render.workflows.startTask('my-workflow/square', [6]);
229
+
230
+ // The stream stays open until you break or abort.
231
+ const pending = new Set([run1.taskRunId, run2.taskRunId]);
232
+ for await (const event of render.workflows.taskRunEvents([...pending])) {
233
+ console.log('Event:', event.status, event.id, event.results);
234
+ pending.delete(event.id);
235
+ if (pending.size === 0) break;
236
+ }
237
+ ```
238
+
178
239
  #### `render.workflows.getTaskRun(taskRunId)`
179
240
 
180
241
  Gets task run details by ID.
@@ -190,6 +251,22 @@ const render = new Render();
190
251
  const details = await render.workflows.getTaskRun('task-run-id');
191
252
  ```
192
253
 
254
+ #### `render.workflows.cancelTaskRun(taskRunId)`
255
+
256
+ Cancels a running task.
257
+
258
+ **Parameters:**
259
+ - `taskRunId: string` - Task run ID to cancel
260
+
261
+ **Returns:** `Promise<void>`
262
+
263
+ **Example:**
264
+ ```typescript
265
+ const render = new Render();
266
+ const run = await render.workflows.startTask('my-workflow/square', [5]);
267
+ await render.workflows.cancelTaskRun(run.taskRunId);
268
+ ```
269
+
193
270
  #### `render.workflows.listTaskRuns(params)`
194
271
 
195
272
  Lists task runs with optional filters.
@@ -300,20 +377,36 @@ enum TaskRunStatus {
300
377
  ```typescript
301
378
  interface TaskRun {
302
379
  id: string;
380
+ taskId: string;
303
381
  status: TaskRunStatus;
304
- created_at: string;
305
- updated_at: string;
306
- task_identifier: string;
382
+ startedAt?: string;
383
+ completedAt?: string;
384
+ parentTaskRunId: string;
385
+ rootTaskRunId: string;
386
+ retries: number;
307
387
  }
308
388
  ```
309
389
 
310
390
  #### `TaskRunDetails`
311
391
 
312
392
  ```typescript
313
- interface TaskRunDetails extends TaskRun {
314
- completed_at?: string;
315
- results?: any[];
393
+ interface TaskRunDetails {
394
+ id: string;
395
+ taskId: string;
396
+ status: TaskRunStatus;
397
+ results?: any;
316
398
  error?: string;
399
+ startedAt?: string;
400
+ completedAt?: string;
401
+ }
402
+ ```
403
+
404
+ #### `TaskRunResult`
405
+
406
+ ```typescript
407
+ class TaskRunResult {
408
+ readonly taskRunId: string;
409
+ get(): Promise<TaskRunDetails>;
317
410
  }
318
411
  ```
319
412
 
@@ -340,6 +433,7 @@ The SDK provides several error classes:
340
433
  import { Render } from '@renderinc/sdk';
341
434
  import {
342
435
  RenderError,
436
+ TaskRunError,
343
437
  ClientError,
344
438
  ServerError,
345
439
  AbortError,
@@ -350,7 +444,9 @@ const render = new Render();
350
444
  try {
351
445
  const result = await render.workflows.runTask('my-workflow/task', [42]);
352
446
  } catch (error) {
353
- if (error instanceof ClientError) {
447
+ if (error instanceof TaskRunError) {
448
+ console.error('Task failed:', error.taskRunId, error.message);
449
+ } else if (error instanceof ClientError) {
354
450
  console.error('Client error:', error.statusCode, error.cause);
355
451
  } else if (error instanceof ServerError) {
356
452
  console.error('Server error:', error.statusCode, error.cause);
@@ -365,11 +461,36 @@ try {
365
461
  ## Environment Variables
366
462
 
367
463
  - `RENDER_API_KEY` - Your Render API key (required)
464
+ - `RENDER_WORKSPACE_ID` - Default owner ID for object storage (workspace team ID, e.g. `tea-xxxxx`)
465
+ - `RENDER_REGION` - Default region for object storage (e.g. `oregon`, `frankfurt`)
368
466
  - `RENDER_USE_LOCAL_DEV` - Enable local development mode (`true`/`false`)
369
467
  - `RENDER_LOCAL_DEV_URL` - Local development URL (default: `http://localhost:8120`)
370
468
  - `RENDER_SDK_MODE` - Task execution mode (`run` or `register`)
371
469
  - `RENDER_SDK_SOCKET_PATH` - Unix socket path for task communication
372
470
 
471
+ ### Object Storage
472
+
473
+ When running on Render, `RENDER_WORKSPACE_ID` and `RENDER_REGION` are set automatically. You can also pass them as constructor options:
474
+
475
+ ```typescript
476
+ import { Render } from '@renderinc/sdk';
477
+
478
+ const render = new Render(); // Uses env vars for auth + object storage defaults
479
+
480
+ // Upload (no need to pass ownerId/region when env vars are set)
481
+ await render.experimental.storage.objects.put({
482
+ key: 'path/to/file.png',
483
+ data: Buffer.from('binary content'),
484
+ contentType: 'image/png',
485
+ });
486
+
487
+ // Download
488
+ const obj = await render.experimental.storage.objects.get({ key: 'path/to/file.png' });
489
+
490
+ // List
491
+ const response = await render.experimental.storage.objects.list();
492
+ ```
493
+
373
494
  ## Examples
374
495
 
375
496
  ### Example 1: Running a Task
@@ -379,18 +500,14 @@ import { Render } from '@renderinc/sdk';
379
500
 
380
501
  const render = new Render();
381
502
 
382
- async function runSquareTask() {
383
- const result = await render.workflows.runTask('my-workflow/square', [5]);
384
- console.log('Square of 5 is:', result.results[0]); // 25
385
- }
386
-
387
- runSquareTask();
503
+ const result = await render.workflows.runTask('my-workflow/square', [5]);
504
+ console.log('Square of 5 is:', result.results[0]); // 25
388
505
  ```
389
506
 
390
507
  ### Example 2: Defining Tasks with Subtasks
391
508
 
392
509
  ```typescript
393
- import { task, startTaskServer } from '@renderinc/sdk/workflows';
510
+ import { task } from '@renderinc/sdk/workflows';
394
511
 
395
512
  const square = task(
396
513
  { name: 'square' },
@@ -407,8 +524,6 @@ task(
407
524
  return Math.sqrt(aSquared + bSquared);
408
525
  }
409
526
  );
410
-
411
- await startTaskServer();
412
527
  ```
413
528
 
414
529
  ### Example 3: Error Handling in Tasks
@@ -502,8 +617,7 @@ async function workflowExample() {
502
617
  console.log(`\nRecent task runs: ${recentRuns.length}`);
503
618
 
504
619
  for (const run of recentRuns) {
505
- const details = await render.workflows.getTaskRun(run.id);
506
- console.log(`- ${run.taskId}: ${details.status}`);
620
+ console.log(`- ${run.id}: ${run.status} (${run.taskId})`);
507
621
  }
508
622
  } catch (error) {
509
623
  console.error('Error:', error);
@@ -544,30 +658,33 @@ npm run format
544
658
  ```
545
659
  typescript/
546
660
  ├── src/
547
- │ ├── render.ts # Main Render SDK class
548
- │ ├── index.ts # Main exports
549
- └── workflows/ # Workflows functionality
550
- ├── client/ # REST API client
551
- ├── client.ts # WorkflowsClient class
552
- │ ├── workflows.ts # WorkflowsService
553
- │ ├── sse.ts # SSE client
554
- │ ├── types.ts # Type definitions
555
- │ ├── errors.ts # Error classes
556
- └── index.ts # Exports
557
- ├── task/ # Task execution SDK
558
- │ ├── task.ts # task() function
559
- │ ├── runner.ts # start() and run()
560
- │ ├── executor.ts # TaskExecutor
561
- │ ├── registry.ts # TaskRegistry
562
- │ ├── uds.ts # Unix socket client
563
- │ ├── types.ts # Type definitions
564
- │ └── index.ts # Exports
565
- └── index.ts # Workflows exports
661
+ │ ├── render.ts # Main Render SDK class
662
+ │ ├── errors.ts # Error classes
663
+ ├── index.ts # Main exports
664
+ ├── version.ts # SDK version and user-agent
665
+ │ ├── workflows/ # Workflows functionality
666
+ │ ├── task.ts # task() function
667
+ │ ├── runner.ts # startTaskServer() and run()
668
+ │ ├── executor.ts # TaskExecutor
669
+ │ ├── registry.ts # TaskRegistry
670
+ ├── uds.ts # Unix socket client
671
+ ├── types.ts # Type definitions
672
+ │ ├── client/ # REST API client
673
+ ├── client.ts # WorkflowsClient class
674
+ ├── create-client.ts # createWorkflowsClient() factory
675
+ ├── task-run-result.ts # TaskRunResult class
676
+ ├── sse.ts # SSE event types
677
+ ├── types.ts # Client type definitions
678
+ └── index.ts # Exports
679
+ └── index.ts # Workflows exports
680
+ │ ├── experimental/ # Experimental features
681
+ │ │ └── object/ # Object storage API
682
+ │ └── utils/ # Shared utilities
566
683
  ├── examples/
567
- │ ├── client/ # Client example
684
+ │ ├── client/ # Client example
568
685
  │ │ ├── main.ts
569
686
  │ │ └── package.json
570
- │ └── task/ # Task example
687
+ │ └── task/ # Task example
571
688
  │ ├── main.ts
572
689
  │ └── package.json
573
690
  ├── package.json
@@ -3,10 +3,10 @@ import type { paths } from "../generated/schema.js";
3
3
  import { ObjectClient } from "./object/client.js";
4
4
  export declare class StorageClient {
5
5
  readonly objects: ObjectClient;
6
- constructor(apiClient: Client<paths>);
6
+ constructor(apiClient: Client<paths>, defaultOwnerId?: string, defaultRegion?: string);
7
7
  }
8
8
  export declare class ExperimentalClient {
9
9
  readonly storage: StorageClient;
10
- constructor(apiClient: Client<paths>);
10
+ constructor(apiClient: Client<paths>, defaultOwnerId?: string, defaultRegion?: string);
11
11
  }
12
12
  //# sourceMappingURL=experimental.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"experimental.d.ts","sourceRoot":"","sources":["../../src/experimental/experimental.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAgBlD,qBAAa,aAAa;IAExB,SAAgB,OAAO,EAAE,YAAY,CAAC;gBAE1B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC;CAGrC;AAuBD,qBAAa,kBAAkB;IAE7B,SAAgB,OAAO,EAAE,aAAa,CAAC;gBAE3B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC;CAGrC"}
1
+ {"version":3,"file":"experimental.d.ts","sourceRoot":"","sources":["../../src/experimental/experimental.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAgBlD,qBAAa,aAAa;IAExB,SAAgB,OAAO,EAAE,YAAY,CAAC;gBAE1B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM;CAGtF;AAuBD,qBAAa,kBAAkB;IAE7B,SAAgB,OAAO,EAAE,aAAa,CAAC;gBAE3B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM;CAGtF"}
@@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ExperimentalClient = exports.StorageClient = void 0;
4
4
  const client_js_1 = require("./object/client.js");
5
5
  class StorageClient {
6
- constructor(apiClient) {
7
- this.objects = new client_js_1.ObjectClient(apiClient);
6
+ constructor(apiClient, defaultOwnerId, defaultRegion) {
7
+ this.objects = new client_js_1.ObjectClient(apiClient, defaultOwnerId, defaultRegion);
8
8
  }
9
9
  }
10
10
  exports.StorageClient = StorageClient;
11
11
  class ExperimentalClient {
12
- constructor(apiClient) {
13
- this.storage = new StorageClient(apiClient);
12
+ constructor(apiClient, defaultOwnerId, defaultRegion) {
13
+ this.storage = new StorageClient(apiClient, defaultOwnerId, defaultRegion);
14
14
  }
15
15
  }
16
16
  exports.ExperimentalClient = ExperimentalClient;
@@ -1,13 +1,17 @@
1
1
  import type { Client } from "openapi-fetch";
2
2
  import type { paths } from "../../generated/schema.js";
3
- import type { DeleteObjectInput, GetObjectInput, ListObjectsInput, ListObjectsResponse, ObjectData, ObjectScope, PutObjectInput, PutObjectResult, ScopedDeleteObjectInput, ScopedGetObjectInput, ScopedListObjectsInput, ScopedPutObjectInput } from "./types.js";
3
+ import type { DeleteObjectInput, GetObjectInput, ListObjectsInput, ListObjectsResponse, ObjectData, ObjectScope, OptionalScope, PutObjectInput, PutObjectResult, ScopedDeleteObjectInput, ScopedGetObjectInput, ScopedListObjectsInput, ScopedPutObjectInput } from "./types.js";
4
4
  export declare class ObjectClient {
5
5
  private readonly apiClient;
6
- constructor(apiClient: Client<paths>);
7
- put(input: PutObjectInput): Promise<PutObjectResult>;
8
- get(input: GetObjectInput): Promise<ObjectData>;
9
- delete(input: DeleteObjectInput): Promise<void>;
10
- list(input: ListObjectsInput): Promise<ListObjectsResponse>;
6
+ private readonly defaultOwnerId?;
7
+ private readonly defaultRegion?;
8
+ constructor(apiClient: Client<paths>, defaultOwnerId?: string, defaultRegion?: string);
9
+ private resolveOwnerId;
10
+ private resolveRegion;
11
+ put(input: OptionalScope<PutObjectInput>): Promise<PutObjectResult>;
12
+ get(input: OptionalScope<GetObjectInput>): Promise<ObjectData>;
13
+ delete(input: OptionalScope<DeleteObjectInput>): Promise<void>;
14
+ list(input: OptionalScope<ListObjectsInput>): Promise<ListObjectsResponse>;
11
15
  scoped(scope: ObjectScope): ScopedObjectClient;
12
16
  private resolveSize;
13
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/experimental/object/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,UAAU,EAEV,WAAW,EACX,cAAc,EACd,eAAe,EAEf,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AASpB,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC;IAoC/C,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAqFpD,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA+C/C,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IA6C/C,IAAI,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA8CjE,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,kBAAkB;IAU9C,OAAO,CAAC,WAAW;CA0BpB;AAQD,qBAAa,kBAAkB;IAK3B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAG1C,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,EACP,KAAK,EAAE,WAAW;IAqB/B,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC;IAmB1D,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBrD,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBrD,IAAI,CAAC,KAAK,GAAE,sBAA2B,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAM7E"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/experimental/object/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,UAAU,EAEV,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EAEf,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AASpB,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAkB;gBAG9B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,EACzC,cAAc,CAAC,EAAE,MAAM,EACvB,aAAa,CAAC,EAAE,MAAM;IAMxB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,aAAa;IA4Cf,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IAwFnE,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAkD9D,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgD9D,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiDhF,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,kBAAkB;IAU9C,OAAO,CAAC,WAAW;CA0BpB;AAQD,qBAAa,kBAAkB;IAK3B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAG1C,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,EACP,KAAK,EAAE,WAAW;IAqB/B,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC;IAmB1D,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBrD,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBrD,IAAI,CAAC,KAAK,GAAE,sBAA2B,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAM7E"}
@@ -4,16 +4,34 @@ exports.ScopedObjectClient = exports.ObjectClient = void 0;
4
4
  const node_stream_1 = require("node:stream");
5
5
  const errors_js_1 = require("../../errors.js");
6
6
  class ObjectClient {
7
- constructor(apiClient) {
7
+ constructor(apiClient, defaultOwnerId, defaultRegion) {
8
8
  this.apiClient = apiClient;
9
+ this.defaultOwnerId = defaultOwnerId;
10
+ this.defaultRegion = defaultRegion;
11
+ }
12
+ resolveOwnerId(ownerId) {
13
+ const resolved = ownerId || this.defaultOwnerId;
14
+ if (!resolved) {
15
+ throw new errors_js_1.RenderError("ownerId is required. Provide it as a parameter or set the RENDER_WORKSPACE_ID environment variable.");
16
+ }
17
+ return resolved;
18
+ }
19
+ resolveRegion(region) {
20
+ const resolved = region || this.defaultRegion;
21
+ if (!resolved) {
22
+ throw new errors_js_1.RenderError("region is required. Provide it as a parameter or set the RENDER_REGION environment variable.");
23
+ }
24
+ return resolved;
9
25
  }
10
26
  async put(input) {
27
+ const ownerId = this.resolveOwnerId(input.ownerId);
28
+ const region = this.resolveRegion(input.region);
11
29
  const size = this.resolveSize(input);
12
30
  const { data, error } = await this.apiClient.PUT("/objects/{ownerId}/{region}/{key}", {
13
31
  params: {
14
32
  path: {
15
- ownerId: input.ownerId,
16
- region: input.region,
33
+ ownerId,
34
+ region: region,
17
35
  key: input.key,
18
36
  },
19
37
  },
@@ -53,11 +71,13 @@ class ObjectClient {
53
71
  };
54
72
  }
55
73
  async get(input) {
74
+ const ownerId = this.resolveOwnerId(input.ownerId);
75
+ const region = this.resolveRegion(input.region);
56
76
  const { data, error } = await this.apiClient.GET("/objects/{ownerId}/{region}/{key}", {
57
77
  params: {
58
78
  path: {
59
- ownerId: input.ownerId,
60
- region: input.region,
79
+ ownerId,
80
+ region: region,
61
81
  key: input.key,
62
82
  },
63
83
  },
@@ -78,11 +98,13 @@ class ObjectClient {
78
98
  };
79
99
  }
80
100
  async delete(input) {
101
+ const ownerId = this.resolveOwnerId(input.ownerId);
102
+ const region = this.resolveRegion(input.region);
81
103
  const { error } = await this.apiClient.DELETE("/objects/{ownerId}/{region}/{key}", {
82
104
  params: {
83
105
  path: {
84
- ownerId: input.ownerId,
85
- region: input.region,
106
+ ownerId,
107
+ region: region,
86
108
  key: input.key,
87
109
  },
88
110
  },
@@ -92,11 +114,13 @@ class ObjectClient {
92
114
  }
93
115
  }
94
116
  async list(input) {
117
+ const ownerId = this.resolveOwnerId(input.ownerId);
118
+ const region = this.resolveRegion(input.region);
95
119
  const { data, error } = await this.apiClient.GET("/objects/{ownerId}/{region}", {
96
120
  params: {
97
121
  path: {
98
- ownerId: input.ownerId,
99
- region: input.region,
122
+ ownerId,
123
+ region: region,
100
124
  },
101
125
  query: {
102
126
  cursor: input.cursor,
@@ -0,0 +1,3 @@
1
+ import type { ObjectClient } from "./client.js";
2
+ export declare function objectStorageCrudCheck(client: ObjectClient, ownerId: `tea-${string}`, region: string): Promise<string>;
3
+ //# sourceMappingURL=e2e-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-helpers.d.ts","sourceRoot":"","sources":["../../../src/experimental/object/e2e-helpers.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAchD,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,MAAM,EAAE,EACxB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAsEjB"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.objectStorageCrudCheck = objectStorageCrudCheck;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const errors_js_1 = require("../../errors.js");
6
+ const RETRY_ATTEMPTS = 5;
7
+ const RETRY_INTERVAL_MS = 1000;
8
+ function sleep(ms) {
9
+ return new Promise((resolve) => setTimeout(resolve, ms));
10
+ }
11
+ async function objectStorageCrudCheck(client, ownerId, region) {
12
+ const key = `e2e-test/${(0, node_crypto_1.randomUUID)()}/crud-test.txt`;
13
+ const content = Buffer.from("hello from e2e");
14
+ try {
15
+ await client.put({
16
+ ownerId,
17
+ region,
18
+ key,
19
+ data: content,
20
+ });
21
+ let found = false;
22
+ for (let attempt = 1; attempt <= RETRY_ATTEMPTS; attempt++) {
23
+ const listResponse = await client.list({ ownerId, region });
24
+ const match = listResponse.objects.find((o) => o.key === key);
25
+ if (match) {
26
+ if (match.size !== content.byteLength) {
27
+ throw new Error(`LIST size mismatch: expected ${content.byteLength}, got ${match.size}`);
28
+ }
29
+ const age = Date.now() - match.lastModified.getTime();
30
+ if (age > 5 * 60 * 1000) {
31
+ throw new Error(`LIST lastModified too old: ${match.lastModified.toISOString()}`);
32
+ }
33
+ found = true;
34
+ break;
35
+ }
36
+ if (attempt < RETRY_ATTEMPTS) {
37
+ await sleep(RETRY_INTERVAL_MS);
38
+ }
39
+ }
40
+ if (!found) {
41
+ throw new Error(`Object ${key} not found in LIST after ${RETRY_ATTEMPTS} attempts`);
42
+ }
43
+ const obj = await client.get({ ownerId, region, key });
44
+ if (!obj.data.equals(content)) {
45
+ throw new Error("GET data does not match uploaded content");
46
+ }
47
+ if (obj.size !== content.byteLength) {
48
+ throw new Error(`GET size mismatch: expected ${content.byteLength}, got ${obj.size}`);
49
+ }
50
+ await client.delete({ ownerId, region, key });
51
+ try {
52
+ await client.get({ ownerId, region, key });
53
+ throw new Error("GET after DELETE should have thrown");
54
+ }
55
+ catch (err) {
56
+ if (!(err instanceof errors_js_1.RenderError)) {
57
+ throw err;
58
+ }
59
+ }
60
+ return key;
61
+ }
62
+ catch (err) {
63
+ try {
64
+ await client.delete({ ownerId, region, key });
65
+ }
66
+ catch {
67
+ }
68
+ throw err;
69
+ }
70
+ }
@@ -38,6 +38,7 @@ export interface ObjectData {
38
38
  export interface PutObjectResult {
39
39
  etag?: string;
40
40
  }
41
+ export type OptionalScope<T> = Omit<T, keyof ObjectScope> & Partial<ObjectScope>;
41
42
  export interface ObjectScope {
42
43
  ownerId: `tea-${string}`;
43
44
  region: Region | string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/experimental/object/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK5C,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;AAKhF,MAAM,WAAW,gBAAgB;IAE/B,OAAO,EAAE,OAAO,MAAM,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB,GAAG,EAAE,MAAM,CAAC;CACb;AAKD,UAAU,kBAAmB,SAAQ,gBAAgB;IAEnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAE9D,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IAEnC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAE9D,IAAI,EAAE,QAAQ,CAAC;IAEf,IAAI,EAAE,MAAM,CAAC;CACd;AAMD,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAKzE,MAAM,WAAW,cAAe,SAAQ,gBAAgB;CAAG;AAK3D,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;CAAG;AAK9D,MAAM,WAAW,kBAAkB;IAEjC,GAAG,EAAE,MAAM,CAAC;IAEZ,SAAS,EAAE,IAAI,CAAC;IAEhB,YAAY,EAAE,MAAM,CAAC;CACtB;AAKD,MAAM,WAAW,oBAAoB;IAEnC,GAAG,EAAE,MAAM,CAAC;IAEZ,SAAS,EAAE,IAAI,CAAC;CACjB;AAKD,MAAM,WAAW,UAAU;IAEzB,IAAI,EAAE,MAAM,CAAC;IAEb,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,MAAM,WAAW,eAAe;IAE9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD,MAAM,WAAW,WAAW;IAE1B,OAAO,EAAE,OAAO,MAAM,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAKD,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,WAAW,CAAC,CAAC;AAK3E,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,WAAW,CAAC,CAAC;AAK3E,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,WAAW,CAAC,CAAC;AAKjF,MAAM,WAAW,gBAAgB;IAE/B,OAAO,EAAE,OAAO,MAAM,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,WAAW,CAAC,CAAC;AAK/E,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,MAAM,CAAC;IAEZ,IAAI,EAAE,MAAM,CAAC;IAEb,YAAY,EAAE,IAAI,CAAC;CACpB;AAKD,MAAM,WAAW,mBAAmB;IAElC,OAAO,EAAE,cAAc,EAAE,CAAC;IAE1B,OAAO,EAAE,OAAO,CAAC;IAEjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/experimental/object/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK5C,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;AAKhF,MAAM,WAAW,gBAAgB;IAE/B,OAAO,EAAE,OAAO,MAAM,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB,GAAG,EAAE,MAAM,CAAC;CACb;AAKD,UAAU,kBAAmB,SAAQ,gBAAgB;IAEnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAE9D,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IAEnC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAE9D,IAAI,EAAE,QAAQ,CAAC;IAEf,IAAI,EAAE,MAAM,CAAC;CACd;AAMD,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAKzE,MAAM,WAAW,cAAe,SAAQ,gBAAgB;CAAG;AAK3D,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;CAAG;AAK9D,MAAM,WAAW,kBAAkB;IAEjC,GAAG,EAAE,MAAM,CAAC;IAEZ,SAAS,EAAE,IAAI,CAAC;IAEhB,YAAY,EAAE,MAAM,CAAC;CACtB;AAKD,MAAM,WAAW,oBAAoB;IAEnC,GAAG,EAAE,MAAM,CAAC;IAEZ,SAAS,EAAE,IAAI,CAAC;CACjB;AAKD,MAAM,WAAW,UAAU;IAEzB,IAAI,EAAE,MAAM,CAAC;IAEb,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,MAAM,WAAW,eAAe;IAE9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAKjF,MAAM,WAAW,WAAW;IAE1B,OAAO,EAAE,OAAO,MAAM,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAKD,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,WAAW,CAAC,CAAC;AAK3E,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,WAAW,CAAC,CAAC;AAK3E,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,WAAW,CAAC,CAAC;AAKjF,MAAM,WAAW,gBAAgB;IAE/B,OAAO,EAAE,OAAO,MAAM,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,WAAW,CAAC,CAAC;AAK/E,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,MAAM,CAAC;IAEZ,IAAI,EAAE,MAAM,CAAC;IAEb,YAAY,EAAE,IAAI,CAAC;CACpB;AAKD,MAAM,WAAW,mBAAmB;IAElC,OAAO,EAAE,cAAc,EAAE,CAAC;IAE1B,OAAO,EAAE,OAAO,CAAC;IAEjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAIpE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAKjE,qBAAa,MAAM;IACjB,SAAgB,SAAS,EAAE,eAAe,CAAC;IAC3C,SAAgB,YAAY,EAAE,kBAAkB,CAAC;IAEjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;gBAM9B,OAAO,CAAC,EAAE,aAAa;CAYpC"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAIpE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAKjE,qBAAa,MAAM;IACjB,SAAgB,SAAS,EAAE,eAAe,CAAC;IAC3C,SAAgB,YAAY,EAAE,kBAAkB,CAAC;IAEjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;gBAM9B,OAAO,CAAC,EAAE,aAAa;CAepC"}
package/dist/render.js CHANGED
@@ -15,7 +15,9 @@ class Render {
15
15
  const baseUrl = (0, get_base_url_js_1.getBaseUrl)(options);
16
16
  this.apiClient = (0, create_api_client_js_1.createApiClient)(baseUrl, token);
17
17
  this.workflows = new index_js_1.WorkflowsClient(this.apiClient, baseUrl, token);
18
- this.experimental = new experimental_js_1.ExperimentalClient(this.apiClient);
18
+ const defaultOwnerId = options?.ownerId || process.env.RENDER_WORKSPACE_ID || undefined;
19
+ const defaultRegion = options?.region || process.env.RENDER_REGION || undefined;
20
+ this.experimental = new experimental_js_1.ExperimentalClient(this.apiClient, defaultOwnerId, defaultRegion);
19
21
  }
20
22
  }
21
23
  exports.Render = Render;
@@ -1,14 +1,18 @@
1
1
  import type { Client as ApiClient } from "openapi-fetch";
2
2
  import type { paths } from "../../generated/schema.js";
3
+ import { TaskRunResult } from "./task-run-result.js";
3
4
  import type { ListTaskRunsParams, TaskData, TaskIdentifier, TaskRun, TaskRunDetails } from "./types.js";
4
5
  export declare class WorkflowsClient {
5
- private readonly sse;
6
6
  private readonly apiClient;
7
+ private readonly baseUrl;
8
+ private readonly token;
7
9
  constructor(apiClient: ApiClient<paths>, baseUrl: string, token: string);
10
+ taskRunEvents(taskRunIds: string[], signal?: AbortSignal): AsyncGenerator<TaskRunDetails>;
11
+ startTask(taskIdentifier: TaskIdentifier, inputData: TaskData, signal?: AbortSignal): Promise<TaskRunResult>;
8
12
  runTask(taskIdentifier: TaskIdentifier, inputData: TaskData, signal?: AbortSignal): Promise<TaskRunDetails>;
9
- private waitForTask;
10
13
  getTaskRun(taskRunId: string): Promise<TaskRunDetails>;
11
- private cancelTaskRun;
14
+ cancelTaskRun(taskRunId: string): Promise<void>;
12
15
  listTaskRuns(params: ListTaskRunsParams): Promise<TaskRun[]>;
16
+ private waitOnTaskRun;
13
17
  }
14
18
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAEvD,OAAO,KAAK,EACV,kBAAkB,EAClB,QAAQ,EACR,cAAc,EACd,OAAO,EACP,cAAc,EACf,MAAM,YAAY,CAAC;AAoBpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;gBAOjC,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAKjE,OAAO,CACX,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,QAAQ,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC;YA4CZ,WAAW;IAUnB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;YAe9C,aAAa;IAerB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CASnE"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAGvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EACV,kBAAkB,EAClB,QAAQ,EACR,cAAc,EACd,OAAO,EACP,cAAc,EACf,MAAM,YAAY,CAAC;AAoBpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAOnB,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAchE,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,cAAc,CAAC,cAAc,CAAC;IA0G1F,SAAS,CACb,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,QAAQ,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC;IA+BnB,OAAO,CACX,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,QAAQ,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC;IAWpB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IActD,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe/C,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YAcpD,aAAa;CAM5B"}
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WorkflowsClient = void 0;
4
+ const eventsource_1 = require("eventsource");
4
5
  const errors_js_1 = require("../../errors.js");
6
+ const version_js_1 = require("../../version.js");
5
7
  const sse_js_1 = require("./sse.js");
8
+ const task_run_result_js_1 = require("./task-run-result.js");
6
9
  function handleApiError(error, response, context) {
7
10
  const statusCode = response.status;
8
11
  const errorMessage = `${context}: ${error}`;
@@ -16,22 +19,97 @@ function handleApiError(error, response, context) {
16
19
  }
17
20
  class WorkflowsClient {
18
21
  constructor(apiClient, baseUrl, token) {
19
- this.sse = new sse_js_1.SSEClient(baseUrl, token);
20
22
  this.apiClient = apiClient;
23
+ this.baseUrl = baseUrl;
24
+ this.token = token;
21
25
  }
22
- async runTask(taskIdentifier, inputData, signal) {
26
+ async *taskRunEvents(taskRunIds, signal) {
23
27
  if (signal?.aborted) {
24
28
  throw new errors_js_1.AbortError();
25
29
  }
26
- let taskRunId = null;
27
- const abortHandler = async () => {
28
- if (taskRunId) {
29
- await this.cancelTaskRun(taskRunId);
30
- throw new errors_js_1.AbortError();
30
+ const queue = [];
31
+ let resolve = null;
32
+ let finished = false;
33
+ let streamError = null;
34
+ const push = (item) => {
35
+ queue.push(item);
36
+ if (resolve) {
37
+ resolve();
38
+ resolve = null;
39
+ }
40
+ };
41
+ const fail = (err) => {
42
+ streamError = err;
43
+ finished = true;
44
+ if (resolve) {
45
+ resolve();
46
+ resolve = null;
31
47
  }
32
48
  };
49
+ const url = new URL("/v1/task-runs/events", this.baseUrl);
50
+ url.searchParams.append("taskRunIds", taskRunIds.join(","));
51
+ const eventSource = new eventsource_1.EventSource(url.toString(), {
52
+ fetch: (input, init) => fetch(input, {
53
+ ...init,
54
+ headers: {
55
+ ...init?.headers,
56
+ Authorization: `Bearer ${this.token}`,
57
+ "User-Agent": (0, version_js_1.getUserAgent)(),
58
+ },
59
+ }),
60
+ });
61
+ const eventHandler = (event) => {
62
+ try {
63
+ const details = JSON.parse(event.data);
64
+ push(details);
65
+ }
66
+ catch (e) {
67
+ fail(new Error(`Failed to parse task run details: ${e}`));
68
+ }
69
+ };
70
+ const errorHandler = (error) => {
71
+ fail(new Error(`SSE connection error: ${error.message || "Unknown error"}`));
72
+ };
73
+ const abortHandler = () => {
74
+ cleanup();
75
+ fail(new errors_js_1.AbortError());
76
+ };
77
+ const cleanup = () => {
78
+ eventSource.removeEventListener(sse_js_1.TaskEventType.COMPLETED, eventHandler);
79
+ eventSource.removeEventListener(sse_js_1.TaskEventType.FAILED, eventHandler);
80
+ eventSource.removeEventListener("error", errorHandler);
81
+ eventSource.close();
82
+ signal?.removeEventListener("abort", abortHandler);
83
+ };
84
+ eventSource.addEventListener(sse_js_1.TaskEventType.COMPLETED, eventHandler);
85
+ eventSource.addEventListener(sse_js_1.TaskEventType.FAILED, eventHandler);
86
+ eventSource.addEventListener("error", errorHandler);
87
+ signal?.addEventListener("abort", abortHandler);
88
+ try {
89
+ while (true) {
90
+ while (queue.length > 0) {
91
+ yield queue.shift();
92
+ }
93
+ if (finished) {
94
+ break;
95
+ }
96
+ await new Promise((r) => {
97
+ resolve = r;
98
+ });
99
+ }
100
+ if (streamError) {
101
+ throw streamError;
102
+ }
103
+ }
104
+ finally {
105
+ cleanup();
106
+ }
107
+ }
108
+ async startTask(taskIdentifier, inputData, signal) {
109
+ if (signal?.aborted) {
110
+ throw new errors_js_1.AbortError();
111
+ }
33
112
  try {
34
- signal?.addEventListener("abort", abortHandler);
35
113
  const { data, error, response } = await this.apiClient.POST("/task-runs", {
36
114
  body: {
37
115
  task: taskIdentifier,
@@ -42,8 +120,7 @@ class WorkflowsClient {
42
120
  if (error) {
43
121
  handleApiError(error, response, "Failed to run task");
44
122
  }
45
- taskRunId = data.id;
46
- return await this.waitForTask(data.id, signal);
123
+ return new task_run_result_js_1.TaskRunResult((id, sig) => this.waitOnTaskRun(id, sig), data.id, signal);
47
124
  }
48
125
  catch (err) {
49
126
  if (err instanceof DOMException && err.name === "AbortError") {
@@ -51,12 +128,10 @@ class WorkflowsClient {
51
128
  }
52
129
  throw err;
53
130
  }
54
- finally {
55
- signal?.removeEventListener("abort", abortHandler);
56
- }
57
131
  }
58
- async waitForTask(taskRunId, signal) {
59
- return this.sse.waitOnTaskRun(taskRunId, signal);
132
+ async runTask(taskIdentifier, inputData, signal) {
133
+ const result = await this.startTask(taskIdentifier, inputData, signal);
134
+ return result.get();
60
135
  }
61
136
  async getTaskRun(taskRunId) {
62
137
  const { data, error, response } = await this.apiClient.GET("/task-runs/{taskRunId}", {
@@ -84,5 +159,11 @@ class WorkflowsClient {
84
159
  }
85
160
  return data;
86
161
  }
162
+ async waitOnTaskRun(taskRunId, signal) {
163
+ for await (const event of this.taskRunEvents([taskRunId], signal)) {
164
+ return event;
165
+ }
166
+ throw new Error(`SSE stream ended without receiving an event for task run ${taskRunId}`);
167
+ }
87
168
  }
88
169
  exports.WorkflowsClient = WorkflowsClient;
@@ -1,4 +1,6 @@
1
1
  export { WorkflowsClient } from "./client.js";
2
2
  export { createWorkflowsClient } from "./create-client.js";
3
+ export { TaskEventType } from "./sse.js";
4
+ export { TaskRunResult } from "./task-run-result.js";
3
5
  export * from "./types.js";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,cAAc,YAAY,CAAC"}
@@ -14,9 +14,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.createWorkflowsClient = exports.WorkflowsClient = void 0;
17
+ exports.TaskRunResult = exports.TaskEventType = exports.createWorkflowsClient = exports.WorkflowsClient = void 0;
18
18
  var client_js_1 = require("./client.js");
19
19
  Object.defineProperty(exports, "WorkflowsClient", { enumerable: true, get: function () { return client_js_1.WorkflowsClient; } });
20
20
  var create_client_js_1 = require("./create-client.js");
21
21
  Object.defineProperty(exports, "createWorkflowsClient", { enumerable: true, get: function () { return create_client_js_1.createWorkflowsClient; } });
22
+ var sse_js_1 = require("./sse.js");
23
+ Object.defineProperty(exports, "TaskEventType", { enumerable: true, get: function () { return sse_js_1.TaskEventType; } });
24
+ var task_run_result_js_1 = require("./task-run-result.js");
25
+ Object.defineProperty(exports, "TaskRunResult", { enumerable: true, get: function () { return task_run_result_js_1.TaskRunResult; } });
22
26
  __exportStar(require("./types.js"), exports);
@@ -1,14 +1,7 @@
1
- import type { TaskRunDetails } from "./types.js";
2
1
  export declare enum TaskEventType {
3
2
  COMPLETED = "task.completed",
4
3
  FAILED = "task.failed",
5
4
  RUNNING = "task.running",
6
5
  PENDING = "task.pending"
7
6
  }
8
- export declare class SSEClient {
9
- private readonly baseUrl;
10
- private readonly token;
11
- constructor(baseUrl: string, token: string);
12
- waitOnTaskRun(taskRunId: string, signal?: AbortSignal): Promise<TaskRunDetails>;
13
- }
14
7
  //# sourceMappingURL=sse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/sse.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,oBAAY,aAAa;IACvB,SAAS,mBAAmB;IAC5B,MAAM,gBAAgB;IACtB,OAAO,iBAAiB;IACxB,OAAO,iBAAiB;CACzB;AAKD,qBAAa,SAAS;IAElB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM;IAG1B,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC;CAsEtF"}
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/sse.ts"],"names":[],"mappings":"AAGA,oBAAY,aAAa;IACvB,SAAS,mBAAmB;IAC5B,MAAM,gBAAgB;IACtB,OAAO,iBAAiB;IACxB,OAAO,iBAAiB;CACzB"}
@@ -1,9 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SSEClient = exports.TaskEventType = void 0;
4
- const eventsource_1 = require("eventsource");
5
- const errors_js_1 = require("../../errors.js");
6
- const version_js_1 = require("../../version.js");
3
+ exports.TaskEventType = void 0;
7
4
  var TaskEventType;
8
5
  (function (TaskEventType) {
9
6
  TaskEventType["COMPLETED"] = "task.completed";
@@ -11,70 +8,3 @@ var TaskEventType;
11
8
  TaskEventType["RUNNING"] = "task.running";
12
9
  TaskEventType["PENDING"] = "task.pending";
13
10
  })(TaskEventType || (exports.TaskEventType = TaskEventType = {}));
14
- class SSEClient {
15
- constructor(baseUrl, token) {
16
- this.baseUrl = baseUrl;
17
- this.token = token;
18
- }
19
- async waitOnTaskRun(taskRunId, signal) {
20
- return new Promise((resolve, reject) => {
21
- let eventSource = null;
22
- const abortHandler = () => {
23
- cleanup();
24
- reject(new errors_js_1.AbortError());
25
- };
26
- const cleanup = () => {
27
- if (eventSource) {
28
- eventSource.removeEventListener(TaskEventType.COMPLETED, eventHandler);
29
- eventSource.removeEventListener(TaskEventType.FAILED, eventHandler);
30
- eventSource.removeEventListener("error", errorHandler);
31
- eventSource.close();
32
- eventSource = null;
33
- }
34
- signal?.removeEventListener("abort", abortHandler);
35
- };
36
- const eventHandler = (event) => {
37
- try {
38
- const details = JSON.parse(event.data);
39
- cleanup();
40
- resolve(details);
41
- }
42
- catch (e) {
43
- cleanup();
44
- reject(new Error(`Failed to parse task run details: ${e}`));
45
- }
46
- };
47
- const errorHandler = (error) => {
48
- cleanup();
49
- reject(new Error(`SSE connection error: ${error.message || "Unknown error"}`));
50
- };
51
- if (signal?.aborted) {
52
- reject(new errors_js_1.AbortError());
53
- return;
54
- }
55
- signal?.addEventListener("abort", abortHandler);
56
- try {
57
- const url = new URL("/v1/task-runs/events", this.baseUrl);
58
- url.searchParams.append("taskRunIds", taskRunId);
59
- eventSource = new eventsource_1.EventSource(url.toString(), {
60
- fetch: (input, init) => fetch(input, {
61
- ...init,
62
- headers: {
63
- ...init?.headers,
64
- Authorization: `Bearer ${this.token}`,
65
- "User-Agent": (0, version_js_1.getUserAgent)(),
66
- },
67
- }),
68
- });
69
- eventSource.addEventListener(TaskEventType.COMPLETED, eventHandler);
70
- eventSource.addEventListener(TaskEventType.FAILED, eventHandler);
71
- eventSource.addEventListener("error", errorHandler);
72
- }
73
- catch (e) {
74
- cleanup();
75
- reject(e);
76
- }
77
- });
78
- }
79
- }
80
- exports.SSEClient = SSEClient;
@@ -0,0 +1,12 @@
1
+ import type { SSEClient } from "./sse.js";
2
+ import type { TaskRunDetails } from "./types.js";
3
+ export declare class TaskRunPromise implements PromiseLike<TaskRunDetails> {
4
+ private readonly sseClient;
5
+ private readonly postPromise;
6
+ private readonly signal?;
7
+ private resultPromise;
8
+ constructor(sseClient: SSEClient, postPromise: Promise<string>, signal?: AbortSignal);
9
+ get taskRunId(): Promise<string>;
10
+ then<TResult1 = TaskRunDetails, TResult2 = never>(onfulfilled?: ((value: TaskRunDetails) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
11
+ }
12
+ //# sourceMappingURL=task-run-promise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-run-promise.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/task-run-promise.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAUjD,qBAAa,cAAe,YAAW,WAAW,CAAC,cAAc,CAAC;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAc;IACtC,OAAO,CAAC,aAAa,CAAwC;gBAEjD,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW;IAUpF,IAAI,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAE/B;IAED,IAAI,CAAC,QAAQ,GAAG,cAAc,EAAE,QAAQ,GAAG,KAAK,EAC9C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAClF,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GACtE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;CAShC"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskRunPromise = void 0;
4
+ class TaskRunPromise {
5
+ constructor(sseClient, postPromise, signal) {
6
+ this.resultPromise = null;
7
+ this.sseClient = sseClient;
8
+ this.postPromise = postPromise;
9
+ this.signal = signal;
10
+ this.postPromise.catch(() => { });
11
+ }
12
+ get taskRunId() {
13
+ return this.postPromise;
14
+ }
15
+ then(onfulfilled, onrejected) {
16
+ if (!this.resultPromise) {
17
+ this.resultPromise = this.postPromise.then((taskRunId) => this.sseClient.waitOnTaskRun(taskRunId, this.signal));
18
+ }
19
+ return this.resultPromise.then(onfulfilled, onrejected);
20
+ }
21
+ }
22
+ exports.TaskRunPromise = TaskRunPromise;
@@ -0,0 +1,10 @@
1
+ import type { TaskRunDetails } from "./types.js";
2
+ export declare class TaskRunResult {
3
+ readonly taskRunId: string;
4
+ private readonly waitOnTaskRun;
5
+ private readonly signal?;
6
+ private resultPromise;
7
+ constructor(waitOnTaskRun: (taskRunId: string, signal?: AbortSignal) => Promise<TaskRunDetails>, taskRunId: string, signal?: AbortSignal);
8
+ get(): Promise<TaskRunDetails>;
9
+ }
10
+ //# sourceMappingURL=task-run-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-run-result.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/task-run-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,aAAa;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAGD;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAc;IACtC,OAAO,CAAC,aAAa,CAAwC;gBAG3D,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,cAAc,CAAC,EACnF,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW;IAOtB,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;CAM/B"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskRunResult = void 0;
4
+ class TaskRunResult {
5
+ constructor(waitOnTaskRun, taskRunId, signal) {
6
+ this.resultPromise = null;
7
+ this.waitOnTaskRun = waitOnTaskRun;
8
+ this.taskRunId = taskRunId;
9
+ this.signal = signal;
10
+ }
11
+ get() {
12
+ if (!this.resultPromise) {
13
+ this.resultPromise = this.waitOnTaskRun(this.taskRunId, this.signal);
14
+ }
15
+ return this.resultPromise;
16
+ }
17
+ }
18
+ exports.TaskRunResult = TaskRunResult;
@@ -19,5 +19,7 @@ export interface ClientOptions {
19
19
  baseUrl?: string;
20
20
  useLocalDev?: boolean;
21
21
  localDevUrl?: string;
22
+ ownerId?: string;
23
+ region?: string;
22
24
  }
23
25
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAKhE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAKpC,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;AAKlC,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,SAAS,cAAc;IACvB,MAAM,WAAW;CAClB;AAMD,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC;AAMvD,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,gBAAgB,CAAC,CAAC;AAKrE,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC;AAKnF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAKD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/workflows/client/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAKhE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAKpC,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;AAKlC,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,SAAS,cAAc;IACvB,MAAM,WAAW;CAClB;AAMD,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC;AAMvD,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,gBAAgB,CAAC,CAAC;AAKrE,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC;AAKnF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAKD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -9,5 +9,6 @@ export declare class UDSClient {
9
9
  getSubtaskResult(subtaskId: string): Promise<GetSubtaskResultResponse>;
10
10
  registerTasks(tasks: TaskMetadata[]): Promise<void>;
11
11
  private request;
12
+ private requestOnce;
12
13
  }
13
14
  //# sourceMappingURL=uds.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uds.d.ts","sourceRoot":"","sources":["../../src/workflows/uds.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,gBAAgB,EAEhB,wBAAwB,EAIxB,YAAY,EACb,MAAM,YAAY,CAAC;AAKpB,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,MAAM;IAKzC,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAI3C,OAAO,CAAC,iBAAiB;IAyBnB,YAAY,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAa3D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAUtE,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAa3C,OAAO;CA4CtB"}
1
+ {"version":3,"file":"uds.d.ts","sourceRoot":"","sources":["../../src/workflows/uds.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,gBAAgB,EAEhB,wBAAwB,EAIxB,YAAY,EACb,MAAM,YAAY,CAAC;AAapB,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,MAAM;IAKzC,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAI3C,OAAO,CAAC,iBAAiB;IAyBnB,YAAY,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAa3D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAUtE,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAa3C,OAAO;YAmCP,WAAW;CA2C1B"}
@@ -6,6 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.UDSClient = void 0;
7
7
  const node_http_1 = __importDefault(require("node:http"));
8
8
  const version_js_1 = require("../version.js");
9
+ const UDS_MAX_RETRIES = 15;
10
+ const UDS_INITIAL_DELAY_MS = 250;
11
+ const UDS_BACKOFF_FACTOR = 2;
12
+ const UDS_MAX_DELAY_MS = 16000;
13
+ const CLIENT_ERROR_RE = /^HTTP 4\d{2}:/;
14
+ const RETRY_ERROR_RE = /^HTTP 429:/;
9
15
  class UDSClient {
10
16
  constructor(socketPath) {
11
17
  this.socketPath = socketPath;
@@ -61,6 +67,27 @@ class UDSClient {
61
67
  }
62
68
  async request(path, method, body) {
63
69
  const bodyString = body ? JSON.stringify(body) : "";
70
+ let lastError = new Error("UDS request failed");
71
+ for (let attempt = 0; attempt < UDS_MAX_RETRIES; attempt++) {
72
+ try {
73
+ return await this.requestOnce(path, method, bodyString);
74
+ }
75
+ catch (e) {
76
+ lastError = e instanceof Error ? e : new Error(String(e));
77
+ if (CLIENT_ERROR_RE.test(lastError.message) && !RETRY_ERROR_RE.test(lastError.message)) {
78
+ throw lastError;
79
+ }
80
+ if (attempt < UDS_MAX_RETRIES - 1) {
81
+ const delay = Math.min(UDS_INITIAL_DELAY_MS * UDS_BACKOFF_FACTOR ** attempt, UDS_MAX_DELAY_MS);
82
+ console.warn(`Request to Render failed (attempt ${attempt + 1}/${UDS_MAX_RETRIES}), ` +
83
+ `retrying in ${delay}ms: ${lastError.message}`);
84
+ await new Promise((resolve) => setTimeout(resolve, delay));
85
+ }
86
+ }
87
+ }
88
+ throw lastError;
89
+ }
90
+ async requestOnce(path, method, bodyString) {
64
91
  return new Promise((resolve, reject) => {
65
92
  const req = node_http_1.default.request({
66
93
  socketPath: this.socketPath,
@@ -0,0 +1,19 @@
1
+ import { TaskRegistry } from "./registry.js";
2
+ import type { RegisterTaskOptions, Retry, TaskFunction } from "./types.js";
3
+ export interface WorkflowsOptions {
4
+ defaultRetry?: Retry;
5
+ defaultTimeout?: number;
6
+ defaultPlan?: string;
7
+ }
8
+ export declare class Workflows {
9
+ private readonly _registry;
10
+ private readonly _defaultRetry?;
11
+ private readonly _defaultTimeout?;
12
+ private readonly _defaultPlan?;
13
+ constructor(options?: WorkflowsOptions);
14
+ get registry(): TaskRegistry;
15
+ task<TArgs extends any[], TResult>(options: RegisterTaskOptions, func: TaskFunction<TArgs, TResult>): TaskFunction<TArgs, TResult>;
16
+ start(): Promise<void>;
17
+ static fromWorkflows(apps: Workflows[], options?: WorkflowsOptions): Workflows;
18
+ }
19
+ //# sourceMappingURL=workflows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/workflows/workflows.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE3E,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAWD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;gBAE3B,OAAO,CAAC,EAAE,gBAAgB;IAUtC,IAAI,QAAQ,IAAI,YAAY,CAE3B;IAQD,IAAI,CAAC,KAAK,SAAS,GAAG,EAAE,EAAE,OAAO,EAC/B,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,GACjC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC;IAyBzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS;CAgB/E"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Workflows = void 0;
4
+ const errors_js_1 = require("../errors.js");
5
+ const registry_js_1 = require("./registry.js");
6
+ const runner_js_1 = require("./runner.js");
7
+ const task_js_1 = require("./task.js");
8
+ class Workflows {
9
+ constructor(options) {
10
+ this._registry = new registry_js_1.TaskRegistry();
11
+ this._defaultRetry = options?.defaultRetry;
12
+ this._defaultTimeout = options?.defaultTimeout;
13
+ this._defaultPlan = options?.defaultPlan;
14
+ }
15
+ get registry() {
16
+ return this._registry;
17
+ }
18
+ task(options, func) {
19
+ const mergedOptions = {
20
+ ...options,
21
+ retry: options.retry ?? this._defaultRetry,
22
+ timeoutSeconds: options.timeoutSeconds ?? this._defaultTimeout,
23
+ plan: options.plan ?? this._defaultPlan,
24
+ };
25
+ this._registry.register(func, mergedOptions);
26
+ return ((...args) => {
27
+ const context = (0, task_js_1.getCurrentContext)();
28
+ if (!context) {
29
+ return func(...args);
30
+ }
31
+ const result = context.executeTask(func, options.name, ...args);
32
+ return result.get();
33
+ });
34
+ }
35
+ async start() {
36
+ await (0, runner_js_1.startTaskServer)(this._registry);
37
+ }
38
+ static fromWorkflows(apps, options) {
39
+ const combined = new Workflows(options);
40
+ for (const app of apps) {
41
+ for (const task of app._registry.getAllTasks()) {
42
+ if (combined._registry.has(task.name)) {
43
+ throw new errors_js_1.RenderError(`Duplicate task name '${task.name}' when combining workflows`);
44
+ }
45
+ combined._registry.registerMetadata(task);
46
+ }
47
+ }
48
+ return combined;
49
+ }
50
+ }
51
+ exports.Workflows = Workflows;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@renderinc/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Render SDK for TypeScript",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,6 +10,7 @@
10
10
  "scripts": {
11
11
  "build": "tsc -p tsconfig.build.json",
12
12
  "test": "vitest",
13
+ "test:e2e": "vitest run --config vitest.config.e2e.ts",
13
14
  "typecheck": "tsc --noEmit",
14
15
  "lint": "biome lint",
15
16
  "lint:fix": "biome lint --write",