@transloadit/node 4.1.9 → 4.3.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 (105) hide show
  1. package/README.md +81 -1
  2. package/dist/Transloadit.d.ts +36 -5
  3. package/dist/Transloadit.d.ts.map +1 -1
  4. package/dist/Transloadit.js +228 -39
  5. package/dist/Transloadit.js.map +1 -1
  6. package/dist/alphalib/assembly-linter.d.ts +123 -0
  7. package/dist/alphalib/assembly-linter.d.ts.map +1 -0
  8. package/dist/alphalib/assembly-linter.js +1142 -0
  9. package/dist/alphalib/assembly-linter.js.map +1 -0
  10. package/dist/alphalib/assembly-linter.lang.en.d.ts +87 -0
  11. package/dist/alphalib/assembly-linter.lang.en.d.ts.map +1 -0
  12. package/dist/alphalib/assembly-linter.lang.en.js +326 -0
  13. package/dist/alphalib/assembly-linter.lang.en.js.map +1 -0
  14. package/dist/alphalib/mcache.d.ts.map +1 -1
  15. package/dist/alphalib/mcache.js +22 -7
  16. package/dist/alphalib/mcache.js.map +1 -1
  17. package/dist/alphalib/object.d.ts +20 -0
  18. package/dist/alphalib/object.d.ts.map +1 -0
  19. package/dist/alphalib/object.js +23 -0
  20. package/dist/alphalib/object.js.map +1 -0
  21. package/dist/alphalib/stepParsing.d.ts +93 -0
  22. package/dist/alphalib/stepParsing.d.ts.map +1 -0
  23. package/dist/alphalib/stepParsing.js +1154 -0
  24. package/dist/alphalib/stepParsing.js.map +1 -0
  25. package/dist/alphalib/templateMerge.d.ts +4 -0
  26. package/dist/alphalib/templateMerge.d.ts.map +1 -0
  27. package/dist/alphalib/templateMerge.js +22 -0
  28. package/dist/alphalib/templateMerge.js.map +1 -0
  29. package/dist/alphalib/types/assemblyReplay.d.ts +56 -0
  30. package/dist/alphalib/types/assemblyReplay.d.ts.map +1 -1
  31. package/dist/alphalib/types/assemblyReplayNotification.d.ts +56 -0
  32. package/dist/alphalib/types/assemblyReplayNotification.d.ts.map +1 -1
  33. package/dist/alphalib/types/assemblyStatus.d.ts +63 -57
  34. package/dist/alphalib/types/assemblyStatus.d.ts.map +1 -1
  35. package/dist/alphalib/types/assemblyStatus.js +9 -1
  36. package/dist/alphalib/types/assemblyStatus.js.map +1 -1
  37. package/dist/alphalib/types/assemblyUrls.d.ts +1 -1
  38. package/dist/alphalib/types/assemblyUrls.d.ts.map +1 -1
  39. package/dist/alphalib/types/assemblyUrls.js.map +1 -1
  40. package/dist/alphalib/types/robots/_index.d.ts +608 -81
  41. package/dist/alphalib/types/robots/_index.d.ts.map +1 -1
  42. package/dist/alphalib/types/robots/_index.js +4 -0
  43. package/dist/alphalib/types/robots/_index.js.map +1 -1
  44. package/dist/alphalib/types/robots/_instructions-primitives.d.ts +4 -4
  45. package/dist/alphalib/types/robots/_instructions-primitives.d.ts.map +1 -1
  46. package/dist/alphalib/types/robots/_instructions-primitives.js +1 -0
  47. package/dist/alphalib/types/robots/_instructions-primitives.js.map +1 -1
  48. package/dist/alphalib/types/robots/document-optimize.d.ts +489 -0
  49. package/dist/alphalib/types/robots/document-optimize.d.ts.map +1 -0
  50. package/dist/alphalib/types/robots/document-optimize.js +151 -0
  51. package/dist/alphalib/types/robots/document-optimize.js.map +1 -0
  52. package/dist/alphalib/types/template.d.ts +1050 -174
  53. package/dist/alphalib/types/template.d.ts.map +1 -1
  54. package/dist/cli/commands/assemblies.d.ts +20 -1
  55. package/dist/cli/commands/assemblies.d.ts.map +1 -1
  56. package/dist/cli/commands/assemblies.js +137 -2
  57. package/dist/cli/commands/assemblies.js.map +1 -1
  58. package/dist/cli/commands/auth.d.ts.map +1 -1
  59. package/dist/cli/commands/auth.js +19 -19
  60. package/dist/cli/commands/auth.js.map +1 -1
  61. package/dist/cli/commands/index.d.ts.map +1 -1
  62. package/dist/cli/commands/index.js +2 -1
  63. package/dist/cli/commands/index.js.map +1 -1
  64. package/dist/cli/docs/assemblyLintingExamples.d.ts +2 -0
  65. package/dist/cli/docs/assemblyLintingExamples.d.ts.map +1 -0
  66. package/dist/cli/docs/assemblyLintingExamples.js +10 -0
  67. package/dist/cli/docs/assemblyLintingExamples.js.map +1 -0
  68. package/dist/cli/helpers.d.ts +11 -0
  69. package/dist/cli/helpers.d.ts.map +1 -1
  70. package/dist/cli/helpers.js +29 -0
  71. package/dist/cli/helpers.js.map +1 -1
  72. package/dist/lintAssemblyInput.d.ts +10 -0
  73. package/dist/lintAssemblyInput.d.ts.map +1 -0
  74. package/dist/lintAssemblyInput.js +73 -0
  75. package/dist/lintAssemblyInput.js.map +1 -0
  76. package/dist/lintAssemblyInstructions.d.ts +29 -0
  77. package/dist/lintAssemblyInstructions.d.ts.map +1 -0
  78. package/dist/lintAssemblyInstructions.js +33 -0
  79. package/dist/lintAssemblyInstructions.js.map +1 -0
  80. package/dist/tus.d.ts +2 -1
  81. package/dist/tus.d.ts.map +1 -1
  82. package/dist/tus.js +2 -1
  83. package/dist/tus.js.map +1 -1
  84. package/package.json +5 -2
  85. package/src/Transloadit.ts +318 -49
  86. package/src/alphalib/assembly-linter.lang.en.ts +393 -0
  87. package/src/alphalib/assembly-linter.ts +1475 -0
  88. package/src/alphalib/mcache.ts +26 -7
  89. package/src/alphalib/object.ts +27 -0
  90. package/src/alphalib/stepParsing.ts +1465 -0
  91. package/src/alphalib/templateMerge.ts +32 -0
  92. package/src/alphalib/types/assemblyStatus.ts +9 -1
  93. package/src/alphalib/types/assemblyUrls.ts +2 -5
  94. package/src/alphalib/types/robots/_index.ts +14 -0
  95. package/src/alphalib/types/robots/_instructions-primitives.ts +1 -0
  96. package/src/alphalib/types/robots/document-optimize.ts +180 -0
  97. package/src/alphalib/typings/json-to-ast.d.ts +34 -0
  98. package/src/cli/commands/assemblies.ts +161 -2
  99. package/src/cli/commands/auth.ts +19 -22
  100. package/src/cli/commands/index.ts +2 -0
  101. package/src/cli/docs/assemblyLintingExamples.ts +9 -0
  102. package/src/cli/helpers.ts +50 -0
  103. package/src/lintAssemblyInput.ts +89 -0
  104. package/src/lintAssemblyInstructions.ts +72 -0
  105. package/src/tus.ts +3 -0
package/README.md CHANGED
@@ -112,6 +112,28 @@ npx transloadit assemblies replay --steps new-steps.json ASSEMBLY_ID
112
112
  npx transloadit assemblies replay --reparse-template ASSEMBLY_ID
113
113
  ```
114
114
 
115
+ ### Linting Assembly Instructions
116
+
117
+ Lint Assembly Instructions locally using the same linter as the API.
118
+
119
+ ```bash
120
+ # From a JSON file (full instructions or steps-only)
121
+ npx transloadit assemblies lint --steps steps.json
122
+
123
+ # From stdin
124
+ cat steps.json | npx transloadit assemblies lint
125
+
126
+ # Merge template content before linting
127
+ npx transloadit assemblies lint --template TEMPLATE_ID --steps steps.json
128
+
129
+ # Treat warnings as fatal; apply fixes (overwrites files / stdout for stdin)
130
+ npx transloadit assemblies lint --fatal warning --fix --steps steps.json
131
+ ```
132
+
133
+ When both `--template` and steps input are provided, Transloadit merges the template content with
134
+ the provided steps before linting, matching the API's runtime behavior. If the template sets
135
+ `allow_steps_override=false`, providing steps will fail with `TEMPLATE_DENIES_STEPS_OVERRIDE`.
136
+
115
137
  ### Managing Templates
116
138
 
117
139
  ```bash
@@ -260,6 +282,28 @@ try {
260
282
 
261
283
  You can find [details about your executed Assemblies here](https://transloadit.com/assemblies).
262
284
 
285
+ ### Resuming interrupted uploads
286
+
287
+ If an upload was interrupted, you can resume it by providing the original `assemblyUrl` and the
288
+ same input mapping. Resume relies on matching `fieldname`, `filename`, and `size`, so keep input
289
+ names stable and pass the same files. Only path-based inputs resume; Buffer/string/stream uploads
290
+ start a new tus upload automatically.
291
+
292
+ You can pass the same upload and progress options as `createAssembly` (such as `chunkSize`,
293
+ `uploadConcurrency`, `waitForCompletion`, `timeout`, `onUploadProgress`, and `onAssemblyProgress`).
294
+ When `waitForCompletion` is `true`, the SDK will poll and resolve once the Assembly is finished.
295
+
296
+ ```javascript
297
+ const status = await transloadit.resumeAssemblyUploads({
298
+ assemblyUrl: 'https://api2.transloadit.com/assemblies/ASSEMBLY_ID',
299
+ files: {
300
+ file1: '/PATH/TO/FILE.jpg',
301
+ file2: '/PATH/TO/FILE2.jpg',
302
+ },
303
+ uploadConcurrency: 2,
304
+ })
305
+ ```
306
+
263
307
  ## Examples
264
308
 
265
309
  - [Upload and resize image](https://github.com/transloadit/node-sdk/blob/main/examples/resize_an_image.ts)
@@ -394,6 +438,42 @@ See also:
394
438
  - [API documentation](https://transloadit.com/docs/api/assemblies-post/)
395
439
  - Error codes and retry logic below
396
440
 
441
+ #### async lintAssemblyInstructions(options)
442
+
443
+ Lint Assembly Instructions locally using the same linter as the API.
444
+ If you provide a `templateId`, the template content is fetched and merged with your instructions
445
+ before linting (matching the API's runtime merge behavior). If the template sets
446
+ `allow_steps_override=false`, providing steps will throw `TEMPLATE_DENIES_STEPS_OVERRIDE`.
447
+
448
+ The `options` object accepts:
449
+
450
+ - `assemblyInstructions` - Assembly Instructions as a JSON string, a full instructions object, or a steps-only object.
451
+ If no `steps` property is present, the object is treated as steps.
452
+ - `templateId` - Optional template ID to merge before linting.
453
+ - `fatal` - `'error' | 'warning'` (default: `'error'`). When set to `'warning'`, warnings are treated as fatal.
454
+ - `fix` - Apply auto-fixes where possible. If `true`, the result includes `fixedInstructions`.
455
+
456
+ The method returns:
457
+
458
+ - `success` - `true` when no fatal issues are found.
459
+ - `issues` - Array of lint issues (each includes `code`, `type`, `row`, `column`, and `desc`).
460
+ - `fixedInstructions` - The fixed JSON string when `fix` is `true` (steps-only inputs return steps-only JSON).
461
+
462
+ Example:
463
+
464
+ ```js
465
+ const result = await transloadit.lintAssemblyInstructions({
466
+ assemblyInstructions: {
467
+ resize: { robot: '/image/resize', use: ':original', width: 100, height: 100 },
468
+ },
469
+ fatal: 'warning',
470
+ })
471
+
472
+ if (!result.success) {
473
+ console.log(result.issues)
474
+ }
475
+ ```
476
+
397
477
  #### async listAssemblies(params)
398
478
 
399
479
  Retrieve Assemblies according to the given `params`.
@@ -677,7 +757,7 @@ If you want to retry on other errors, please see the [retry example code](exampl
677
757
  This project uses [debug](https://github.com/visionmedia/debug) so you can run node with the `DEBUG=transloadit` evironment variable to enable verbose logging. Example:
678
758
 
679
759
  ```bash
680
- DEBUG=transloadit* npx tsx examples/template_api.ts
760
+ DEBUG=transloadit* node examples/template_api.ts
681
761
  ```
682
762
 
683
763
  ## Maintainers
@@ -5,18 +5,19 @@ import { ApiError } from './ApiError.ts';
5
5
  import type { AssemblyIndexItem, AssemblyStatus } from './alphalib/types/assemblyStatus.ts';
6
6
  import type { BaseResponse, BillResponse, CreateAssemblyParams, CreateTemplateCredentialParams, CreateTemplateParams, EditTemplateParams, ListAssembliesParams, ListedTemplate, ListTemplateCredentialsParams, ListTemplatesParams, OptionalAuthParams, PaginationListWithCount, ReplayAssemblyNotificationParams, ReplayAssemblyNotificationResponse, ReplayAssemblyParams, ReplayAssemblyResponse, TemplateCredentialResponse, TemplateCredentialsResponse, TemplateResponse } from './apiTypes.ts';
7
7
  import InconsistentResponseError from './InconsistentResponseError.ts';
8
+ import type { LintAssemblyInstructionsInput, LintAssemblyInstructionsResult } from './lintAssemblyInstructions.ts';
8
9
  import PaginationStream from './PaginationStream.ts';
9
10
  export { HTTPError, MaxRedirectsError, ParseError, ReadError, RequestError, TimeoutError, UploadError, } from 'got';
10
11
  export type { AssemblyStatus } from './alphalib/types/assemblyStatus.ts';
11
12
  export * from './apiTypes.ts';
12
13
  export { InconsistentResponseError, ApiError };
14
+ export type { LintAssemblyInstructionsResult, LintFatalLevel } from './lintAssemblyInstructions.ts';
13
15
  export interface UploadProgress {
14
16
  uploadedBytes?: number | undefined;
15
17
  totalBytes?: number | undefined;
16
18
  }
17
19
  export type AssemblyProgress = (assembly: AssemblyStatus) => void;
18
- export interface CreateAssemblyOptions {
19
- params?: CreateAssemblyParams;
20
+ interface AssemblyUploadOptions {
20
21
  files?: {
21
22
  [name: string]: string;
22
23
  };
@@ -29,18 +30,29 @@ export interface CreateAssemblyOptions {
29
30
  timeout?: number;
30
31
  onUploadProgress?: (uploadProgress: UploadProgress) => void;
31
32
  onAssemblyProgress?: AssemblyProgress;
32
- assemblyId?: string;
33
33
  /**
34
- * Optional AbortSignal to cancel the assembly creation and upload.
34
+ * Optional AbortSignal to cancel the upload and any follow-up polling.
35
35
  * When aborted, any in-flight HTTP requests and TUS uploads will be cancelled.
36
36
  */
37
37
  signal?: AbortSignal;
38
38
  }
39
+ export interface CreateAssemblyOptions extends AssemblyUploadOptions {
40
+ params?: CreateAssemblyParams;
41
+ assemblyId?: string;
42
+ }
43
+ export interface ResumeAssemblyUploadsOptions extends AssemblyUploadOptions {
44
+ assemblyUrl: string;
45
+ }
39
46
  export interface AwaitAssemblyCompletionOptions {
40
47
  onAssemblyProgress?: AssemblyProgress;
41
48
  timeout?: number;
42
49
  interval?: number;
43
50
  startTimeMs?: number;
51
+ /**
52
+ * Optional assembly URL to poll instead of the configured client endpoint.
53
+ * Useful when resuming an Assembly created on a different host/region.
54
+ */
55
+ assemblyUrl?: string;
44
56
  /**
45
57
  * Optional AbortSignal to cancel polling.
46
58
  * When aborted, the polling loop will stop and throw an AbortError.
@@ -53,6 +65,12 @@ export interface AwaitAssemblyCompletionOptions {
53
65
  */
54
66
  onPoll?: () => boolean | undefined;
55
67
  }
68
+ export interface LintAssemblyInstructionsOptions extends Omit<LintAssemblyInstructionsInput, 'template'> {
69
+ /**
70
+ * Template ID to merge with the provided instructions before linting.
71
+ */
72
+ templateId?: string;
73
+ }
56
74
  export interface SmartCDNUrlOptions {
57
75
  /**
58
76
  * Workspace slug
@@ -107,7 +125,19 @@ export declare class Transloadit {
107
125
  * @param opts assembly options
108
126
  */
109
127
  createAssembly(opts?: CreateAssemblyOptions): CreateAssemblyPromise;
110
- awaitAssemblyCompletion(assemblyId: string, { onAssemblyProgress, timeout, startTimeMs, interval, signal, onPoll, }?: AwaitAssemblyCompletionOptions): Promise<AssemblyStatus>;
128
+ /**
129
+ * Lint Assembly Instructions locally.
130
+ *
131
+ * If a templateId is provided, the template content is merged with the instructions,
132
+ * just like the API. When a template sets `allow_steps_override=false`, providing
133
+ * `steps` will throw a TEMPLATE_DENIES_STEPS_OVERRIDE error.
134
+ *
135
+ * The `assemblyInstructions` input may be a JSON string, a full instructions object,
136
+ * or a steps-only object (missing the `steps` property).
137
+ */
138
+ lintAssemblyInstructions(options: LintAssemblyInstructionsOptions): Promise<LintAssemblyInstructionsResult>;
139
+ resumeAssemblyUploads(opts: ResumeAssemblyUploadsOptions): Promise<AssemblyStatus>;
140
+ awaitAssemblyCompletion(assemblyId: string, { onAssemblyProgress, timeout, startTimeMs, interval, assemblyUrl, signal, onPoll, }?: AwaitAssemblyCompletionOptions): Promise<AssemblyStatus>;
111
141
  maybeThrowInconsistentResponseError(message: string): void;
112
142
  /**
113
143
  * Cancel the assembly
@@ -150,6 +180,7 @@ export declare class Transloadit {
150
180
  getAssembly(assemblyId: string, options?: {
151
181
  signal?: AbortSignal;
152
182
  }): Promise<AssemblyStatus>;
183
+ private _fetchAssemblyStatus;
153
184
  /**
154
185
  * Create a Credential
155
186
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Transloadit.d.ts","sourceRoot":"","sources":["../src/Transloadit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Transloadit.d.ts","sourceRoot":"","sources":["../src/Transloadit.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import * as assert from 'node:assert';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { constants, createReadStream } from 'node:fs';
4
- import { access } from 'node:fs/promises';
4
+ import { access, stat } from 'node:fs/promises';
5
+ import { basename } from 'node:path';
5
6
  import { setTimeout as delay } from 'node:timers/promises';
6
7
  import { getSignedSmartCdnUrl, signParamsSync } from '@transloadit/utils/node';
7
8
  import debug from 'debug';
@@ -15,6 +16,7 @@ import { ApiError } from "./ApiError.js";
15
16
  import { assemblyIndexSchema, assemblyStatusSchema } from "./alphalib/types/assemblyStatus.js";
16
17
  import { zodParseWithContext } from "./alphalib/zodParseWithContext.js";
17
18
  import InconsistentResponseError from "./InconsistentResponseError.js";
19
+ import { lintAssemblyInstructions as lintAssemblyInstructionsInternal } from "./lintAssemblyInstructions.js";
18
20
  import PaginationStream from "./PaginationStream.js";
19
21
  import PollingTimeoutError from "./PollingTimeoutError.js";
20
22
  import { sendTusRequest } from "./tus.js";
@@ -26,6 +28,55 @@ export { InconsistentResponseError, ApiError };
26
28
  const log = debug('transloadit');
27
29
  const logWarn = debug('transloadit:warn');
28
30
  const { version } = packageJson;
31
+ const getUploadKey = (fieldname, filename, size) => {
32
+ if (!fieldname || !filename || size == null)
33
+ return null;
34
+ return JSON.stringify([fieldname, filename, size]);
35
+ };
36
+ const getSizeFromValue = (value) => {
37
+ if (typeof value === 'string')
38
+ return Buffer.byteLength(value);
39
+ if (Buffer.isBuffer(value))
40
+ return value.length;
41
+ if (value instanceof ArrayBuffer)
42
+ return value.byteLength;
43
+ if (ArrayBuffer.isView(value))
44
+ return value.byteLength;
45
+ return undefined;
46
+ };
47
+ const toReadableUpload = (label, value) => {
48
+ const readable = isReadableStream(value);
49
+ if (!readable && isStream(value)) {
50
+ throw new Error(`Upload named "${label}" is not a Readable stream`);
51
+ }
52
+ return readable ? value : intoStream(value);
53
+ };
54
+ const buildStreamsMap = (descriptors) => Object.fromEntries(descriptors.map((descriptor) => {
55
+ if (descriptor.path) {
56
+ const stream = createReadStream(descriptor.path);
57
+ return [descriptor.label, { stream, path: descriptor.path }];
58
+ }
59
+ const value = descriptor.value;
60
+ if (value == null) {
61
+ throw new Error(`Upload named "${descriptor.label}" has no data`);
62
+ }
63
+ const stream = toReadableUpload(descriptor.label, value);
64
+ return [descriptor.label, { stream }];
65
+ }));
66
+ const pauseStreams = (streamsMap) => {
67
+ for (const { stream } of Object.values(streamsMap)) {
68
+ stream.pause();
69
+ }
70
+ };
71
+ const createStreamErrorPromise = (streamsMap) => {
72
+ const promise = new Promise((_resolve, reject) => {
73
+ for (const { stream } of Object.values(streamsMap)) {
74
+ stream.on('error', reject);
75
+ }
76
+ });
77
+ promise.catch(() => { });
78
+ return promise;
79
+ };
29
80
  // Not sure if this is still a problem with the API, but throw a special error type so the user can retry if needed
30
81
  function checkAssemblyUrls(result) {
31
82
  if (result.assembly_url == null || result.assembly_ssl_url == null) {
@@ -35,6 +86,13 @@ function checkAssemblyUrls(result) {
35
86
  function getHrTimeMs() {
36
87
  return Number(process.hrtime.bigint() / 1000000n);
37
88
  }
89
+ function getAssemblyIdFromUrl(assemblyUrl) {
90
+ const match = assemblyUrl.match(/\/assemblies\/([^/?#]+)/);
91
+ if (!match) {
92
+ throw new Error(`Invalid assembly URL: ${assemblyUrl}`);
93
+ }
94
+ return match[1] ?? '';
95
+ }
38
96
  function checkResult(result) {
39
97
  // In case server returned a successful HTTP status code, but an `error` in the JSON object
40
98
  // This happens sometimes, for example when createAssembly with an invalid file (IMPORT_FILE_ERROR)
@@ -105,39 +163,29 @@ export class Transloadit {
105
163
  const promise = (async () => {
106
164
  this._lastUsedAssemblyUrl = `${this._endpoint}${urlSuffix}`;
107
165
  await pMap(Object.entries(files), async ([, path]) => access(path, constants.F_OK | constants.R_OK), { concurrency: 5 });
108
- // Convert uploads to streams
109
- const streamsMap = Object.fromEntries(Object.entries(uploads).map(([label, value]) => {
110
- const isReadable = isReadableStream(value);
111
- if (!isReadable && isStream(value)) {
112
- // https://github.com/transloadit/node-sdk/issues/92
113
- throw new Error(`Upload named "${label}" is not a Readable stream`);
114
- }
115
- return [label, isReadableStream(value) ? value : intoStream(value)];
116
- }));
117
- // Wrap in object structure (so we can store whether it's a pathless stream or not)
118
- const allStreamsMap = Object.fromEntries(Object.entries(streamsMap).map(([label, stream]) => [label, { stream }]));
119
- // Create streams from files too
120
- for (const [label, path] of Object.entries(files)) {
121
- const stream = createReadStream(path);
122
- allStreamsMap[label] = { stream, path }; // File streams have path
123
- }
166
+ const descriptors = [
167
+ ...Object.entries(files).map(([label, path]) => ({
168
+ label,
169
+ path,
170
+ filename: basename(path),
171
+ })),
172
+ ...Object.entries(uploads).map(([label, value]) => ({
173
+ label,
174
+ filename: label,
175
+ value,
176
+ })),
177
+ ];
178
+ const allStreamsMap = buildStreamsMap(descriptors);
124
179
  const allStreams = Object.values(allStreamsMap);
125
180
  // Pause all streams
126
- for (const { stream } of allStreams) {
127
- stream.pause();
128
- }
181
+ pauseStreams(allStreamsMap);
129
182
  // If any stream emits error, we want to handle this and exit with error.
130
183
  // This promise races against createAssemblyAndUpload() below via Promise.race().
131
184
  // When createAssemblyAndUpload wins the race, this promise becomes "orphaned" -
132
185
  // it's no longer awaited, but stream error handlers remain attached.
133
186
  // The no-op catch prevents Node's unhandled rejection warning if a stream
134
187
  // errors after the race is already won.
135
- const streamErrorPromise = new Promise((_resolve, reject) => {
136
- for (const { stream } of allStreams) {
137
- stream.on('error', reject);
138
- }
139
- });
140
- streamErrorPromise.catch(() => { });
188
+ const streamErrorPromise = createStreamErrorPromise(allStreamsMap);
141
189
  const createAssemblyAndUpload = async () => {
142
190
  const result = await this._remoteJson({
143
191
  urlSuffix,
@@ -179,9 +227,130 @@ export class Transloadit {
179
227
  // This allows the user to use or log the assemblyId even before it has been created for easier debugging
180
228
  return Object.assign(promise, { assemblyId: effectiveAssemblyId });
181
229
  }
182
- async awaitAssemblyCompletion(assemblyId, { onAssemblyProgress = () => { }, timeout, startTimeMs = getHrTimeMs(), interval = 1000, signal, onPoll, } = {}) {
230
+ /**
231
+ * Lint Assembly Instructions locally.
232
+ *
233
+ * If a templateId is provided, the template content is merged with the instructions,
234
+ * just like the API. When a template sets `allow_steps_override=false`, providing
235
+ * `steps` will throw a TEMPLATE_DENIES_STEPS_OVERRIDE error.
236
+ *
237
+ * The `assemblyInstructions` input may be a JSON string, a full instructions object,
238
+ * or a steps-only object (missing the `steps` property).
239
+ */
240
+ async lintAssemblyInstructions(options) {
241
+ const { templateId, ...rest } = options;
242
+ if (!templateId) {
243
+ return await lintAssemblyInstructionsInternal(rest);
244
+ }
245
+ const template = await this.getTemplate(templateId);
246
+ return await lintAssemblyInstructionsInternal({
247
+ ...rest,
248
+ template: template.content,
249
+ });
250
+ }
251
+ async resumeAssemblyUploads(opts) {
252
+ const { assemblyUrl, files = {}, uploads = {}, chunkSize: requestedChunkSize = Number.POSITIVE_INFINITY, uploadConcurrency = 10, timeout = 24 * 60 * 60 * 1000, // 1 day
253
+ waitForCompletion = false, onUploadProgress = () => { }, onAssemblyProgress = () => { }, signal, } = opts;
254
+ const startTimeMs = getHrTimeMs();
255
+ getAssemblyIdFromUrl(assemblyUrl);
256
+ const assembly = await this._fetchAssemblyStatus({ url: assemblyUrl, signal });
257
+ const statusUrl = assembly.assembly_ssl_url ?? assembly.assembly_url ?? assemblyUrl;
258
+ const finishedKeys = new Set();
259
+ for (const upload of assembly.uploads ?? []) {
260
+ const key = getUploadKey(upload.field ?? null, upload.basename ?? null, upload.size);
261
+ if (key)
262
+ finishedKeys.add(key);
263
+ }
264
+ for (const upload of assembly.tus_uploads ?? []) {
265
+ if (!upload.finished)
266
+ continue;
267
+ const key = getUploadKey(upload.fieldname, upload.filename, upload.size);
268
+ if (key)
269
+ finishedKeys.add(key);
270
+ }
271
+ const resumeUrls = new Map();
272
+ for (const upload of assembly.tus_uploads ?? []) {
273
+ if (upload.finished)
274
+ continue;
275
+ if (!upload.upload_url)
276
+ continue;
277
+ const key = getUploadKey(upload.fieldname, upload.filename, upload.size);
278
+ if (key)
279
+ resumeUrls.set(key, upload.upload_url);
280
+ }
281
+ const descriptors = [];
282
+ await pMap(Object.entries(files), async ([label, path]) => {
283
+ await access(path, constants.F_OK | constants.R_OK);
284
+ const info = await stat(path);
285
+ descriptors.push({
286
+ label,
287
+ path,
288
+ filename: basename(path),
289
+ size: info.size,
290
+ });
291
+ }, { concurrency: 5 });
292
+ for (const [label, value] of Object.entries(uploads)) {
293
+ descriptors.push({
294
+ label,
295
+ filename: label,
296
+ size: isReadableStream(value) ? undefined : getSizeFromValue(value),
297
+ value,
298
+ });
299
+ }
300
+ const descriptorsToUpload = descriptors.filter((descriptor) => {
301
+ const key = getUploadKey(descriptor.label, descriptor.filename, descriptor.size ?? null);
302
+ return key ? !finishedKeys.has(key) : true;
303
+ });
304
+ const uploadUrlsByLabel = {};
305
+ for (const descriptor of descriptorsToUpload) {
306
+ if (!descriptor.path)
307
+ continue;
308
+ const key = getUploadKey(descriptor.label, descriptor.filename, descriptor.size ?? null);
309
+ if (!key)
310
+ continue;
311
+ const uploadUrl = resumeUrls.get(key);
312
+ if (uploadUrl)
313
+ uploadUrlsByLabel[descriptor.label] = uploadUrl;
314
+ }
315
+ const streamsMap = buildStreamsMap(descriptorsToUpload);
316
+ pauseStreams(streamsMap);
317
+ if (Object.keys(streamsMap).length > 0) {
318
+ const streamErrorPromise = createStreamErrorPromise(streamsMap);
319
+ const uploadPromise = sendTusRequest({
320
+ streamsMap,
321
+ assembly,
322
+ requestedChunkSize,
323
+ uploadConcurrency,
324
+ onProgress: onUploadProgress,
325
+ signal,
326
+ uploadUrls: uploadUrlsByLabel,
327
+ });
328
+ await Promise.race([uploadPromise, streamErrorPromise]);
329
+ }
330
+ const latestAssembly = await this._fetchAssemblyStatus({ url: statusUrl, signal });
331
+ if (!waitForCompletion)
332
+ return latestAssembly;
333
+ if (latestAssembly.assembly_id == null) {
334
+ throw new InconsistentResponseError('Server returned an assembly response without an assembly_id after resuming uploads');
335
+ }
336
+ const awaitResult = await this.awaitAssemblyCompletion(latestAssembly.assembly_id, {
337
+ timeout,
338
+ onAssemblyProgress,
339
+ startTimeMs,
340
+ assemblyUrl: statusUrl,
341
+ signal,
342
+ });
343
+ checkResult(awaitResult);
344
+ return awaitResult;
345
+ }
346
+ async awaitAssemblyCompletion(assemblyId, { onAssemblyProgress = () => { }, timeout, startTimeMs = getHrTimeMs(), interval = 1000, assemblyUrl, signal, onPoll, } = {}) {
183
347
  assert.ok(assemblyId);
184
348
  let lastResult;
349
+ const fetchAssemblyStatus = () => {
350
+ return assemblyUrl
351
+ ? this._fetchAssemblyStatus({ url: assemblyUrl, signal })
352
+ : this.getAssembly(assemblyId, { signal });
353
+ };
185
354
  while (true) {
186
355
  // Check if caller wants to stop polling early
187
356
  if (onPoll?.() === false && lastResult) {
@@ -191,7 +360,7 @@ export class Transloadit {
191
360
  if (signal?.aborted) {
192
361
  throw signal.reason ?? new DOMException('Aborted', 'AbortError');
193
362
  }
194
- const result = await this.getAssembly(assemblyId, { signal });
363
+ const result = await fetchAssemblyStatus();
195
364
  lastResult = result;
196
365
  // If 'ok' is not in result, it implies a terminal state (e.g., error, completed, canceled).
197
366
  // If 'ok' is present, then we check if it's one of the non-terminal polling states.
@@ -327,13 +496,21 @@ export class Transloadit {
327
496
  * @returns the retrieved Assembly
328
497
  */
329
498
  async getAssembly(assemblyId, options) {
330
- const rawResult = await this._remoteJson({
331
- urlSuffix: `/assemblies/${assemblyId}`,
499
+ return await this._fetchAssemblyStatus({
500
+ assemblyId,
332
501
  signal: options?.signal,
333
502
  });
503
+ }
504
+ async _fetchAssemblyStatus({ assemblyId, url, signal, }) {
505
+ const rawResult = await this._remoteJson({
506
+ url,
507
+ urlSuffix: url ? undefined : `/assemblies/${assemblyId}`,
508
+ signal,
509
+ });
334
510
  const parsedResult = zodParseWithContext(assemblyStatusSchema, rawResult);
335
511
  if (!parsedResult.success) {
336
- this.maybeThrowInconsistentResponseError(`The API responded with data that does not match the expected schema while getting Assembly: ${assemblyId}.\n${parsedResult.humanReadable}`);
512
+ const label = assemblyId ?? url ?? 'unknown';
513
+ this.maybeThrowInconsistentResponseError(`The API responded with data that does not match the expected schema while getting Assembly: ${label}.\n${parsedResult.humanReadable}`);
337
514
  }
338
515
  checkAssemblyUrls(rawResult);
339
516
  return rawResult;
@@ -597,21 +774,33 @@ export class Transloadit {
597
774
  logWarn('HTTP error', statusCode, body);
598
775
  // check whether we should retry
599
776
  // https://transloadit.com/blog/2012/04/introducing-rate-limiting/
600
- if (typeof body === 'object' &&
777
+ const retryAfterHeader = err.response?.headers?.['retry-after'];
778
+ const retryAfterSeconds = typeof retryAfterHeader === 'string' ? Number(retryAfterHeader) : undefined;
779
+ const retryInFromInfo = typeof body === 'object' &&
601
780
  body != null &&
602
- 'error' in body &&
603
781
  'info' in body &&
604
782
  typeof body.info === 'object' &&
605
783
  body.info != null &&
606
784
  'retryIn' in body.info &&
607
785
  typeof body.info.retryIn === 'number' &&
608
- Boolean(body.info.retryIn) &&
609
- retryCount < this._maxRetries && // 413 taken from https://transloadit.com/blog/2012/04/introducing-rate-limiting/
786
+ body.info.retryIn > 0
787
+ ? body.info.retryIn
788
+ : undefined;
789
+ const retryInSec = retryInFromInfo ??
790
+ (typeof retryAfterSeconds === 'number' && retryAfterSeconds > 0
791
+ ? retryAfterSeconds
792
+ : undefined);
793
+ const shouldRetry = retryCount < this._maxRetries && // 413 taken from https://transloadit.com/blog/2012/04/introducing-rate-limiting/
610
794
  // todo can 413 be removed?
611
- ((statusCode === 413 && body.error === 'RATE_LIMIT_REACHED') || statusCode === 429)) {
612
- const { retryIn: retryInSec } = body.info;
613
- logWarn(`Rate limit reached, retrying request in approximately ${retryInSec} seconds.`);
614
- const retryInMs = 1000 * (retryInSec * (1 + 0.1 * Math.random()));
795
+ ((statusCode === 413 &&
796
+ body &&
797
+ typeof body === 'object' &&
798
+ body.error === 'RATE_LIMIT_REACHED') ||
799
+ statusCode === 429);
800
+ if (shouldRetry) {
801
+ const retryDelaySec = retryInSec ?? 1;
802
+ logWarn(`Rate limit reached, retrying request in approximately ${retryDelaySec} seconds.`);
803
+ const retryInMs = 1000 * (retryDelaySec * (1 + 0.1 * Math.random()));
615
804
  await delay(retryInMs);
616
805
  // Retry
617
806
  }