@transloadit/node 4.2.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -4
- package/dist/Transloadit.d.ts +45 -4
- package/dist/Transloadit.d.ts.map +1 -1
- package/dist/Transloadit.js +104 -21
- package/dist/Transloadit.js.map +1 -1
- package/dist/alphalib/assembly-linter.d.ts +123 -0
- package/dist/alphalib/assembly-linter.d.ts.map +1 -0
- package/dist/alphalib/assembly-linter.js +1142 -0
- package/dist/alphalib/assembly-linter.js.map +1 -0
- package/dist/alphalib/assembly-linter.lang.en.d.ts +87 -0
- package/dist/alphalib/assembly-linter.lang.en.d.ts.map +1 -0
- package/dist/alphalib/assembly-linter.lang.en.js +326 -0
- package/dist/alphalib/assembly-linter.lang.en.js.map +1 -0
- package/dist/alphalib/goldenTemplates.d.ts +52 -0
- package/dist/alphalib/goldenTemplates.d.ts.map +1 -0
- package/dist/alphalib/goldenTemplates.js +46 -0
- package/dist/alphalib/goldenTemplates.js.map +1 -0
- package/dist/alphalib/object.d.ts +20 -0
- package/dist/alphalib/object.d.ts.map +1 -0
- package/dist/alphalib/object.js +23 -0
- package/dist/alphalib/object.js.map +1 -0
- package/dist/alphalib/stepParsing.d.ts +93 -0
- package/dist/alphalib/stepParsing.d.ts.map +1 -0
- package/dist/alphalib/stepParsing.js +1154 -0
- package/dist/alphalib/stepParsing.js.map +1 -0
- package/dist/alphalib/templateMerge.d.ts +4 -0
- package/dist/alphalib/templateMerge.d.ts.map +1 -0
- package/dist/alphalib/templateMerge.js +22 -0
- package/dist/alphalib/templateMerge.js.map +1 -0
- package/dist/cli/commands/assemblies.d.ts +20 -1
- package/dist/cli/commands/assemblies.d.ts.map +1 -1
- package/dist/cli/commands/assemblies.js +137 -2
- package/dist/cli/commands/assemblies.js.map +1 -1
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +19 -19
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +2 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/docs/assemblyLintingExamples.d.ts +2 -0
- package/dist/cli/docs/assemblyLintingExamples.d.ts.map +1 -0
- package/dist/cli/docs/assemblyLintingExamples.js +10 -0
- package/dist/cli/docs/assemblyLintingExamples.js.map +1 -0
- package/dist/cli/helpers.d.ts +11 -0
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/helpers.js +29 -0
- package/dist/cli/helpers.js.map +1 -1
- package/dist/inputFiles.d.ts +41 -0
- package/dist/inputFiles.d.ts.map +1 -0
- package/dist/inputFiles.js +214 -0
- package/dist/inputFiles.js.map +1 -0
- package/dist/lintAssemblyInput.d.ts +10 -0
- package/dist/lintAssemblyInput.d.ts.map +1 -0
- package/dist/lintAssemblyInput.js +73 -0
- package/dist/lintAssemblyInput.js.map +1 -0
- package/dist/lintAssemblyInstructions.d.ts +29 -0
- package/dist/lintAssemblyInstructions.d.ts.map +1 -0
- package/dist/lintAssemblyInstructions.js +33 -0
- package/dist/lintAssemblyInstructions.js.map +1 -0
- package/dist/robots.d.ts +38 -0
- package/dist/robots.d.ts.map +1 -0
- package/dist/robots.js +230 -0
- package/dist/robots.js.map +1 -0
- package/dist/tus.d.ts +5 -1
- package/dist/tus.d.ts.map +1 -1
- package/dist/tus.js +80 -6
- package/dist/tus.js.map +1 -1
- package/package.json +5 -2
- package/src/Transloadit.ts +170 -26
- package/src/alphalib/assembly-linter.lang.en.ts +393 -0
- package/src/alphalib/assembly-linter.ts +1475 -0
- package/src/alphalib/goldenTemplates.ts +53 -0
- package/src/alphalib/object.ts +27 -0
- package/src/alphalib/stepParsing.ts +1465 -0
- package/src/alphalib/templateMerge.ts +32 -0
- package/src/alphalib/typings/json-to-ast.d.ts +34 -0
- package/src/cli/commands/assemblies.ts +161 -2
- package/src/cli/commands/auth.ts +19 -22
- package/src/cli/commands/index.ts +2 -0
- package/src/cli/docs/assemblyLintingExamples.ts +9 -0
- package/src/cli/helpers.ts +50 -0
- package/src/inputFiles.ts +278 -0
- package/src/lintAssemblyInput.ts +89 -0
- package/src/lintAssemblyInstructions.ts +72 -0
- package/src/robots.ts +317 -0
- package/src/tus.ts +91 -5
package/src/robots.ts
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import type { z } from 'zod'
|
|
2
|
+
import { robotsMeta, robotsSchema } from './alphalib/types/robots/_index.ts'
|
|
3
|
+
|
|
4
|
+
export type RobotListOptions = {
|
|
5
|
+
category?: string
|
|
6
|
+
search?: string
|
|
7
|
+
limit?: number
|
|
8
|
+
cursor?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type RobotListItem = {
|
|
12
|
+
name: string
|
|
13
|
+
title?: string
|
|
14
|
+
summary: string
|
|
15
|
+
category?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type RobotListResult = {
|
|
19
|
+
robots: RobotListItem[]
|
|
20
|
+
nextCursor?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type RobotParamHelp = {
|
|
24
|
+
name: string
|
|
25
|
+
type: string
|
|
26
|
+
description?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type RobotHelp = {
|
|
30
|
+
name: string
|
|
31
|
+
summary: string
|
|
32
|
+
requiredParams: RobotParamHelp[]
|
|
33
|
+
optionalParams: RobotParamHelp[]
|
|
34
|
+
examples?: Array<{ description: string; snippet: Record<string, unknown> }>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type RobotHelpOptions = {
|
|
38
|
+
robotName: string
|
|
39
|
+
detailLevel?: 'summary' | 'params' | 'examples'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type RobotsMetaMap = typeof robotsMeta
|
|
43
|
+
type RobotMeta = RobotsMetaMap[keyof RobotsMetaMap]
|
|
44
|
+
|
|
45
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
46
|
+
typeof value === 'object' && value !== null
|
|
47
|
+
|
|
48
|
+
const getDef = (schema: z.ZodTypeAny): Record<string, unknown> =>
|
|
49
|
+
(schema as unknown as { _def?: Record<string, unknown>; def?: Record<string, unknown> })._def ??
|
|
50
|
+
(schema as unknown as { def?: Record<string, unknown> }).def ??
|
|
51
|
+
{}
|
|
52
|
+
|
|
53
|
+
const getDefType = (def: Record<string, unknown>): string | undefined =>
|
|
54
|
+
(def.type as string | undefined) ?? (def.typeName as string | undefined)
|
|
55
|
+
|
|
56
|
+
const robotNameToPath = (name: string): string => {
|
|
57
|
+
const base = name.replace(/Robot$/, '')
|
|
58
|
+
const spaced = base
|
|
59
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
60
|
+
.replace(/([A-Z]+)([A-Z][a-z0-9])/g, '$1 $2')
|
|
61
|
+
const parts = spaced.split(/\s+/).filter(Boolean)
|
|
62
|
+
return `/${parts.map((part) => part.toLowerCase()).join('/')}`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const selectSummary = (meta: RobotMeta): string =>
|
|
66
|
+
meta.purpose_sentence ?? meta.purpose_words ?? meta.purpose_word ?? meta.title ?? meta.name
|
|
67
|
+
|
|
68
|
+
const resolveRobotPath = (robotName: string): string =>
|
|
69
|
+
robotName.startsWith('/') ? robotName : robotNameToPath(robotName)
|
|
70
|
+
|
|
71
|
+
const unwrapSchema = (schema: z.ZodTypeAny): { base: z.ZodTypeAny; optional: boolean } => {
|
|
72
|
+
let base = schema
|
|
73
|
+
let optional = typeof base.isOptional === 'function' ? base.isOptional() : false
|
|
74
|
+
|
|
75
|
+
while (true) {
|
|
76
|
+
const def = getDef(base)
|
|
77
|
+
const defType = getDefType(def)
|
|
78
|
+
if (
|
|
79
|
+
defType === 'optional' ||
|
|
80
|
+
defType === 'default' ||
|
|
81
|
+
defType === 'nullable' ||
|
|
82
|
+
defType === 'catch' ||
|
|
83
|
+
defType === 'ZodOptional' ||
|
|
84
|
+
defType === 'ZodDefault' ||
|
|
85
|
+
defType === 'ZodNullable' ||
|
|
86
|
+
defType === 'ZodCatch'
|
|
87
|
+
) {
|
|
88
|
+
const inner = def.innerType as z.ZodTypeAny | undefined
|
|
89
|
+
if (inner) {
|
|
90
|
+
base = inner
|
|
91
|
+
if (defType !== 'nullable' && defType !== 'ZodNullable') {
|
|
92
|
+
optional = true
|
|
93
|
+
}
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
break
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { base, optional }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const describeSchemaType = (schema: z.ZodTypeAny): string => {
|
|
104
|
+
const { base } = unwrapSchema(schema)
|
|
105
|
+
const def = getDef(base)
|
|
106
|
+
const defType = getDefType(def)
|
|
107
|
+
|
|
108
|
+
switch (defType) {
|
|
109
|
+
case 'string':
|
|
110
|
+
case 'ZodString':
|
|
111
|
+
return 'string'
|
|
112
|
+
case 'number':
|
|
113
|
+
case 'ZodNumber':
|
|
114
|
+
return 'number'
|
|
115
|
+
case 'boolean':
|
|
116
|
+
case 'ZodBoolean':
|
|
117
|
+
return 'boolean'
|
|
118
|
+
case 'bigint':
|
|
119
|
+
case 'ZodBigInt':
|
|
120
|
+
return 'bigint'
|
|
121
|
+
case 'literal':
|
|
122
|
+
case 'ZodLiteral': {
|
|
123
|
+
const value = (def.values as unknown[] | undefined)?.[0] ?? def.value
|
|
124
|
+
return value === undefined ? 'literal' : JSON.stringify(value)
|
|
125
|
+
}
|
|
126
|
+
case 'enum':
|
|
127
|
+
case 'ZodEnum': {
|
|
128
|
+
const values = Array.isArray(def.values) ? def.values : []
|
|
129
|
+
return values.length ? `enum(${values.join(' | ')})` : 'enum'
|
|
130
|
+
}
|
|
131
|
+
case 'array':
|
|
132
|
+
case 'ZodArray': {
|
|
133
|
+
const element = def.element as z.ZodTypeAny | undefined
|
|
134
|
+
const inner = element ? describeSchemaType(element) : 'unknown'
|
|
135
|
+
return `array<${inner}>`
|
|
136
|
+
}
|
|
137
|
+
case 'object':
|
|
138
|
+
case 'ZodObject':
|
|
139
|
+
return 'object'
|
|
140
|
+
case 'record':
|
|
141
|
+
case 'ZodRecord':
|
|
142
|
+
return 'record'
|
|
143
|
+
case 'union':
|
|
144
|
+
case 'ZodUnion': {
|
|
145
|
+
const options = Array.isArray(def.options) ? def.options : []
|
|
146
|
+
const rendered = options
|
|
147
|
+
.map((option) => describeSchemaType(option as z.ZodTypeAny))
|
|
148
|
+
.join(' | ')
|
|
149
|
+
return rendered ? `union<${rendered}>` : 'union'
|
|
150
|
+
}
|
|
151
|
+
case 'ZodDiscriminatedUnion':
|
|
152
|
+
return 'object'
|
|
153
|
+
default:
|
|
154
|
+
return defType ?? 'unknown'
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const getParamDescription = (schema: z.ZodTypeAny): string | undefined => {
|
|
159
|
+
if (schema.description?.trim()) {
|
|
160
|
+
return schema.description.trim()
|
|
161
|
+
}
|
|
162
|
+
const inner = unwrapSchema(schema).base
|
|
163
|
+
return inner.description?.trim()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const getShape = (schema: z.ZodTypeAny): Record<string, z.ZodTypeAny> => {
|
|
167
|
+
const { base } = unwrapSchema(schema)
|
|
168
|
+
const def = getDef(base)
|
|
169
|
+
const shape = def.shape as
|
|
170
|
+
| Record<string, z.ZodTypeAny>
|
|
171
|
+
| (() => Record<string, z.ZodTypeAny>)
|
|
172
|
+
| undefined
|
|
173
|
+
if (typeof shape === 'function') {
|
|
174
|
+
return shape()
|
|
175
|
+
}
|
|
176
|
+
return shape ?? {}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const getRobotParams = (
|
|
180
|
+
schema: z.ZodTypeAny,
|
|
181
|
+
): { required: RobotParamHelp[]; optional: RobotParamHelp[] } => {
|
|
182
|
+
const shape = getShape(schema)
|
|
183
|
+
const required: RobotParamHelp[] = []
|
|
184
|
+
const optional: RobotParamHelp[] = []
|
|
185
|
+
|
|
186
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
187
|
+
if (key === 'robot') continue
|
|
188
|
+
const { optional: isOptional } = unwrapSchema(value)
|
|
189
|
+
const param: RobotParamHelp = {
|
|
190
|
+
name: key,
|
|
191
|
+
type: describeSchemaType(value),
|
|
192
|
+
description: getParamDescription(value),
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (isOptional) {
|
|
196
|
+
optional.push(param)
|
|
197
|
+
} else {
|
|
198
|
+
required.push(param)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { required, optional }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const getRobotsMetaIndex = (): {
|
|
206
|
+
byName: Map<string, RobotMeta>
|
|
207
|
+
byPath: Map<string, RobotMeta>
|
|
208
|
+
} => {
|
|
209
|
+
const byName = new Map<string, RobotMeta>()
|
|
210
|
+
const byPath = new Map<string, RobotMeta>()
|
|
211
|
+
|
|
212
|
+
for (const meta of Object.values(robotsMeta)) {
|
|
213
|
+
byName.set(meta.name, meta)
|
|
214
|
+
byPath.set(robotNameToPath(meta.name), meta)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { byName, byPath }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const getRobotSchemaIndex = (): Map<string, z.ZodTypeAny> => {
|
|
221
|
+
const index = new Map<string, z.ZodTypeAny>()
|
|
222
|
+
for (const option of robotsSchema.options) {
|
|
223
|
+
const shape = getShape(option)
|
|
224
|
+
const robotSchema = shape.robot
|
|
225
|
+
if (!robotSchema) continue
|
|
226
|
+
const robotDef = getDef(robotSchema)
|
|
227
|
+
const robotLiteral = (robotDef.values as unknown[] | undefined)?.[0] ?? robotDef.value
|
|
228
|
+
if (typeof robotLiteral === 'string') {
|
|
229
|
+
index.set(robotLiteral, option)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return index
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let cachedMetaIndex: ReturnType<typeof getRobotsMetaIndex> | null = null
|
|
236
|
+
let cachedSchemaIndex: ReturnType<typeof getRobotSchemaIndex> | null = null
|
|
237
|
+
|
|
238
|
+
const getMetaIndex = (): ReturnType<typeof getRobotsMetaIndex> => {
|
|
239
|
+
if (!cachedMetaIndex) {
|
|
240
|
+
cachedMetaIndex = getRobotsMetaIndex()
|
|
241
|
+
}
|
|
242
|
+
return cachedMetaIndex
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const getSchemaIndex = (): ReturnType<typeof getRobotSchemaIndex> => {
|
|
246
|
+
if (!cachedSchemaIndex) {
|
|
247
|
+
cachedSchemaIndex = getRobotSchemaIndex()
|
|
248
|
+
}
|
|
249
|
+
return cachedSchemaIndex
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export const listRobots = (options: RobotListOptions = {}): RobotListResult => {
|
|
253
|
+
const normalizedSearch = options.search?.toLowerCase()
|
|
254
|
+
const normalizedCategory = options.category?.toLowerCase()
|
|
255
|
+
const { byPath } = getMetaIndex()
|
|
256
|
+
|
|
257
|
+
const allRobots: RobotListItem[] = Array.from(byPath.entries()).map(([path, meta]) => ({
|
|
258
|
+
name: path,
|
|
259
|
+
title: meta.title,
|
|
260
|
+
summary: selectSummary(meta),
|
|
261
|
+
category: meta.service_slug,
|
|
262
|
+
}))
|
|
263
|
+
|
|
264
|
+
const filtered = allRobots
|
|
265
|
+
.filter((robot) => {
|
|
266
|
+
if (normalizedCategory && robot.category?.toLowerCase() !== normalizedCategory) {
|
|
267
|
+
return false
|
|
268
|
+
}
|
|
269
|
+
if (!normalizedSearch) return true
|
|
270
|
+
const haystack = `${robot.name} ${robot.title ?? ''} ${robot.summary}`.toLowerCase()
|
|
271
|
+
return haystack.includes(normalizedSearch)
|
|
272
|
+
})
|
|
273
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
274
|
+
|
|
275
|
+
const start = options.cursor ? Number.parseInt(options.cursor, 10) : 0
|
|
276
|
+
const safeStart = Number.isFinite(start) && start > 0 ? start : 0
|
|
277
|
+
const safeLimit = options.limit && options.limit > 0 ? options.limit : 20
|
|
278
|
+
const page = filtered.slice(safeStart, safeStart + safeLimit)
|
|
279
|
+
const nextCursor =
|
|
280
|
+
safeStart + safeLimit < filtered.length ? String(safeStart + safeLimit) : undefined
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
robots: page,
|
|
284
|
+
nextCursor,
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export const getRobotHelp = (options: RobotHelpOptions): RobotHelp => {
|
|
289
|
+
const detailLevel = options.detailLevel ?? 'summary'
|
|
290
|
+
const { byPath, byName } = getMetaIndex()
|
|
291
|
+
const schemaIndex = getSchemaIndex()
|
|
292
|
+
|
|
293
|
+
const path = resolveRobotPath(options.robotName)
|
|
294
|
+
const meta = byPath.get(path) ?? byName.get(options.robotName) ?? null
|
|
295
|
+
const summary = meta ? selectSummary(meta) : `Robot ${path}`
|
|
296
|
+
const schema = schemaIndex.get(path)
|
|
297
|
+
const params = schema ? getRobotParams(schema) : { required: [], optional: [] }
|
|
298
|
+
|
|
299
|
+
const help: RobotHelp = {
|
|
300
|
+
name: path,
|
|
301
|
+
summary,
|
|
302
|
+
requiredParams: detailLevel === 'params' ? params.required : [],
|
|
303
|
+
optionalParams: detailLevel === 'params' ? params.optional : [],
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (detailLevel === 'examples' && meta?.example_code) {
|
|
307
|
+
const snippet = isRecord(meta.example_code) ? meta.example_code : {}
|
|
308
|
+
help.examples = [
|
|
309
|
+
{
|
|
310
|
+
description: meta.example_code_description ?? 'Example',
|
|
311
|
+
snippet,
|
|
312
|
+
},
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return help
|
|
317
|
+
}
|
package/src/tus.ts
CHANGED
|
@@ -9,6 +9,9 @@ import type { AssemblyStatus } from './alphalib/types/assemblyStatus.ts'
|
|
|
9
9
|
import type { UploadProgress } from './Transloadit.ts'
|
|
10
10
|
|
|
11
11
|
const log = debug('transloadit')
|
|
12
|
+
const logWarn = debug('transloadit:warn')
|
|
13
|
+
|
|
14
|
+
export type UploadBehavior = 'await' | 'background' | 'none'
|
|
12
15
|
|
|
13
16
|
export interface Stream {
|
|
14
17
|
path?: string
|
|
@@ -23,6 +26,7 @@ interface SendTusRequestOptions {
|
|
|
23
26
|
onProgress: (options: UploadProgress) => void
|
|
24
27
|
signal?: AbortSignal
|
|
25
28
|
uploadUrls?: Record<string, string>
|
|
29
|
+
uploadBehavior?: UploadBehavior
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
export async function sendTusRequest({
|
|
@@ -33,6 +37,7 @@ export async function sendTusRequest({
|
|
|
33
37
|
onProgress,
|
|
34
38
|
signal,
|
|
35
39
|
uploadUrls,
|
|
40
|
+
uploadBehavior = 'await',
|
|
36
41
|
}: SendTusRequestOptions) {
|
|
37
42
|
const streamLabels = Object.keys(streamsMap)
|
|
38
43
|
|
|
@@ -40,6 +45,7 @@ export async function sendTusRequest({
|
|
|
40
45
|
let lastEmittedProgress = 0
|
|
41
46
|
|
|
42
47
|
const sizes: Record<string, number> = {}
|
|
48
|
+
const uploadUrlsResult: Record<string, string> = { ...(uploadUrls ?? {}) }
|
|
43
49
|
|
|
44
50
|
const haveUnknownLengthStreams = streamLabels.some((label) => !streamsMap[label]?.path)
|
|
45
51
|
|
|
@@ -67,6 +73,9 @@ export async function sendTusRequest({
|
|
|
67
73
|
|
|
68
74
|
const uploadProgresses: Record<string, number> = {}
|
|
69
75
|
|
|
76
|
+
const completionPromises: Array<Promise<void>> = []
|
|
77
|
+
const uploadUrlPromises: Array<Promise<void>> = []
|
|
78
|
+
|
|
70
79
|
async function uploadSingleStream(label: string) {
|
|
71
80
|
uploadProgresses[label] = 0
|
|
72
81
|
|
|
@@ -110,7 +119,45 @@ export async function sendTusRequest({
|
|
|
110
119
|
|
|
111
120
|
const filename = path ? basename(path) : label
|
|
112
121
|
|
|
113
|
-
|
|
122
|
+
if (uploadBehavior === 'none' && uploadUrls?.[label]) {
|
|
123
|
+
uploadUrlsResult[label] = uploadUrls[label]
|
|
124
|
+
uploadUrlPromises.push(Promise.resolve())
|
|
125
|
+
completionPromises.push(Promise.resolve())
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let urlResolved = false
|
|
130
|
+
let resolveUrl: () => void = () => {}
|
|
131
|
+
let rejectUrl: (err: Error) => void = () => {}
|
|
132
|
+
const uploadUrlPromise = new Promise<void>((resolve, reject) => {
|
|
133
|
+
resolveUrl = () => {
|
|
134
|
+
if (urlResolved) return
|
|
135
|
+
urlResolved = true
|
|
136
|
+
resolve()
|
|
137
|
+
}
|
|
138
|
+
rejectUrl = (err) => {
|
|
139
|
+
if (urlResolved) return
|
|
140
|
+
urlResolved = true
|
|
141
|
+
reject(err)
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
let resolveCompletion: () => void = () => {}
|
|
146
|
+
let rejectCompletion: (err: Error) => void = () => {}
|
|
147
|
+
const completionPromise = new Promise<void>((resolve, reject) => {
|
|
148
|
+
resolveCompletion = resolve
|
|
149
|
+
rejectCompletion = reject
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
uploadUrlPromises.push(uploadUrlPromise)
|
|
153
|
+
completionPromises.push(completionPromise)
|
|
154
|
+
|
|
155
|
+
if (uploadUrls?.[label]) {
|
|
156
|
+
uploadUrlsResult[label] = uploadUrls[label]
|
|
157
|
+
resolveUrl()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const startPromise = new Promise<void>((resolvePromise, rejectPromise) => {
|
|
114
161
|
if (!assembly.assembly_ssl_url) {
|
|
115
162
|
rejectPromise(new Error('assembly_ssl_url is not present in the assembly status'))
|
|
116
163
|
return
|
|
@@ -124,15 +171,20 @@ export async function sendTusRequest({
|
|
|
124
171
|
|
|
125
172
|
// Wrap resolve/reject to clean up abort listener
|
|
126
173
|
let abortHandler: (() => void) | undefined
|
|
127
|
-
const resolve = (
|
|
174
|
+
const resolve = (_payload: OnSuccessPayload) => {
|
|
128
175
|
if (abortHandler) signal?.removeEventListener('abort', abortHandler)
|
|
129
|
-
|
|
176
|
+
resolveCompletion()
|
|
177
|
+
resolveUrl()
|
|
178
|
+
resolvePromise()
|
|
130
179
|
}
|
|
131
180
|
const reject = (err: unknown) => {
|
|
132
181
|
if (abortHandler) signal?.removeEventListener('abort', abortHandler)
|
|
182
|
+
rejectCompletion(err as Error)
|
|
183
|
+
rejectUrl(err as Error)
|
|
133
184
|
rejectPromise(err)
|
|
134
185
|
}
|
|
135
186
|
|
|
187
|
+
let tusUpload: Upload
|
|
136
188
|
const tusOptions: UploadOptions = {
|
|
137
189
|
endpoint: assembly.tus_url,
|
|
138
190
|
uploadUrl: uploadUrls?.[label],
|
|
@@ -144,13 +196,24 @@ export async function sendTusRequest({
|
|
|
144
196
|
onError: reject,
|
|
145
197
|
onProgress: onTusProgress,
|
|
146
198
|
onSuccess: resolve,
|
|
199
|
+
onUploadUrlAvailable: () => {
|
|
200
|
+
const url = tusUpload?.url
|
|
201
|
+
if (url) {
|
|
202
|
+
uploadUrlsResult[label] = url
|
|
203
|
+
}
|
|
204
|
+
resolveUrl()
|
|
205
|
+
if (uploadBehavior === 'none') {
|
|
206
|
+
tusUpload.abort()
|
|
207
|
+
resolveCompletion()
|
|
208
|
+
}
|
|
209
|
+
},
|
|
147
210
|
}
|
|
148
211
|
// tus-js-client doesn't like undefined/null
|
|
149
212
|
if (size != null) tusOptions.uploadSize = size
|
|
150
213
|
if (chunkSize) tusOptions.chunkSize = chunkSize
|
|
151
214
|
if (uploadLengthDeferred) tusOptions.uploadLengthDeferred = uploadLengthDeferred
|
|
152
215
|
|
|
153
|
-
|
|
216
|
+
tusUpload = new Upload(stream, tusOptions)
|
|
154
217
|
|
|
155
218
|
// Handle abort signal
|
|
156
219
|
if (signal) {
|
|
@@ -164,8 +227,31 @@ export async function sendTusRequest({
|
|
|
164
227
|
tusUpload.start()
|
|
165
228
|
})
|
|
166
229
|
|
|
167
|
-
|
|
230
|
+
if (uploadBehavior === 'await') {
|
|
231
|
+
await startPromise
|
|
232
|
+
log(label, 'upload done')
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
startPromise.catch((err) => {
|
|
237
|
+
logWarn('Background upload failed', err)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
await uploadUrlPromise
|
|
241
|
+
log(label, 'upload started')
|
|
168
242
|
}
|
|
169
243
|
|
|
170
244
|
await pMap(streamLabels, uploadSingleStream, { concurrency: uploadConcurrency, signal })
|
|
245
|
+
|
|
246
|
+
await Promise.all(uploadUrlPromises)
|
|
247
|
+
|
|
248
|
+
if (uploadBehavior === 'await') {
|
|
249
|
+
await Promise.all(completionPromises)
|
|
250
|
+
} else {
|
|
251
|
+
Promise.allSettled(completionPromises).catch((err) => {
|
|
252
|
+
logWarn('Background upload failed', err)
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return { uploadUrls: uploadUrlsResult }
|
|
171
257
|
}
|