Merge branch 'main' into ai-image-generator

* main:
  [ci] release (#5997)
  Use assembly_ssl_url for final status fetch (#5996)
  [ci] release (#5988)
  @uppy/svelte: fix props reactivity (#5991)
  Improve changeset again
  Improve a changeset
  fixup! Use workspace:* for all packages in packages/uppy
  Use workspace:* for all packages in packages/uppy
  Re-use types from the Transloadit node-sdk (#5992)
This commit is contained in:
Murderlon 2025-10-02 15:32:29 +02:00
commit ff7bc6a095
No known key found for this signature in database
GPG key ID: 1FF861FF1DDBB953
21 changed files with 1729 additions and 278 deletions

View file

@ -1,5 +0,0 @@
---
"@uppy/components": patch
---
add imageThumbnail prop to FilesList/FilesGrid

View file

@ -2,7 +2,7 @@
Hi, thanks for trying out the bundled version of the Uppy File Uploader. You can
use this from a CDN
(`<script src="https://releases.transloadit.com/uppy/v5.1.2/uppy.min.js"></script>`)
(`<script src="https://releases.transloadit.com/uppy/v5.1.4/uppy.min.js"></script>`)
or bundle it with your webapp.
Note that the recommended way to use Uppy is to install it with yarn/npm and use

View file

@ -103,7 +103,7 @@ npm install @uppy/core @uppy/dashboard @uppy/tus
```
Add CSS
[uppy.min.css](https://releases.transloadit.com/uppy/v5.1.2/uppy.min.css),
[uppy.min.css](https://releases.transloadit.com/uppy/v5.1.4/uppy.min.css),
either to your HTML pages `<head>` or include in JS, if your bundler of choice
supports it.
@ -117,7 +117,7 @@ CDN. In that case `Uppy` will attach itself to the global `window.Uppy` object.
```html
<!-- 1. Add CSS to `<head>` -->
<link
href="https://releases.transloadit.com/uppy/v5.1.2/uppy.min.css"
href="https://releases.transloadit.com/uppy/v5.1.4/uppy.min.css"
rel="stylesheet"
/>
@ -128,7 +128,7 @@ CDN. In that case `Uppy` will attach itself to the global `window.Uppy` object.
Uppy,
Dashboard,
Tus,
} from 'https://releases.transloadit.com/uppy/v5.1.2/uppy.min.mjs'
} from 'https://releases.transloadit.com/uppy/v5.1.4/uppy.min.mjs'
const uppy = new Uppy()
uppy.use(Dashboard, { target: '#files-drag-drop' })

View file

@ -0,0 +1,23 @@
<script lang="ts">
import Uppy from '@uppy/core'
import Dashboard from '@uppy/svelte/dashboard'
import StatusBar from '@uppy/svelte/status-bar'
import '@uppy/core/css/style.css'
import '@uppy/dashboard/css/style.css'
import '@uppy/status-bar/css/style.css'
const uppy = new Uppy()
uppy.addFile(new File(['hello world'], 'hello.txt'))
let disabled = false
let hideUploadButton = false
</script>
<main class="p-5 max-w-xl mx-auto">
<button onclick={() => (disabled = !disabled)}>Toggle dashboard</button>
<Dashboard props={{disabled: disabled}} uppy={uppy} />
<button onclick={() => (hideUploadButton = !hideUploadButton)}>Toggle statusbar</button>
<div id="statusbar-container">
<StatusBar props={{ hideUploadButton }} uppy={uppy} />
</div>
</main>

View file

@ -1,6 +1,7 @@
import { userEvent } from '@vitest/browser/context'
import { describe, expect, test } from 'vitest'
import { render } from 'vitest-browser-svelte'
import PropsReactivity from '../src/components/test/props-reactivity.svelte'
import App from '../src/routes/+page.svelte'
const createMockFile = (name: string, type: string, size: number = 1024) => {
@ -124,3 +125,27 @@ describe('RemoteSource Component', () => {
await expect.element(loginButton).toBeInTheDocument()
})
})
test('Dashboard reacts to prop changes', async () => {
const screen = render(PropsReactivity)
const toggleButton = screen.getByText('Toggle dashboard')
const dashboard = screen.container.querySelector('.uppy-Dashboard')
expect(dashboard).toBeTruthy()
expect(dashboard?.ariaDisabled).toEqual('false')
await userEvent.click(toggleButton)
expect(dashboard?.ariaDisabled).toEqual('true')
})
test('StatusBar reacts to prop changes', async () => {
const screen = render(PropsReactivity)
const toggleButton = screen.getByText('Toggle statusbar')
expect(
screen.container.querySelector('#statusbar-container .uppy-c-btn-primary'),
).toBeVisible()
await userEvent.click(toggleButton)
expect(
screen.container.querySelector('#statusbar-container .uppy-c-btn-primary'),
).toEqual(null)
})

View file

@ -1,5 +1,11 @@
# @uppy/components
## 1.0.3
### Patch Changes
- 34639ba: add imageThumbnail prop to FilesList/FilesGrid
## 1.0.2
### Patch Changes

View file

@ -1,7 +1,7 @@
{
"name": "@uppy/components",
"description": "Headless Uppy components, made in Preact",
"version": "1.0.2",
"version": "1.0.3",
"license": "MIT",
"type": "module",
"sideEffects": [

View file

@ -1,5 +1,13 @@
# @uppy/svelte
## 5.0.2
### Patch Changes
- da754b7: Fix props reactivity. Now when the value of a prop you pass to a component changes, it is actually picked up.
- Updated dependencies [34639ba]
- @uppy/components@1.0.3
## 5.0.1
### Patch Changes

View file

@ -1,6 +1,6 @@
{
"name": "@uppy/svelte",
"version": "5.0.1",
"version": "5.0.2",
"description": "Uppy plugin that helps integrate Uppy into your Svelte project.",
"type": "module",
"sideEffects": [

View file

@ -40,7 +40,7 @@ $: {
...props,
target: container,
} satisfies DashboardOptions<M, B>;
uppy.setOptions(options);
plugin?.setOptions(options);
}
</script>

View file

@ -42,7 +42,7 @@ $: {
...props,
target: container,
} satisfies DashboardOptions<M, B>;
uppy.setOptions(options);
plugin?.setOptions(options);
}
$: {
if (open && !lastOpen) {

View file

@ -35,7 +35,7 @@ $: {
...props,
target: container,
} satisfies StatusBarOptions;
uppy.setOptions(options);
plugin?.setOptions(options);
}
</script>

View file

@ -1,5 +1,24 @@
# @uppy/transloadit
## 5.1.1
### Patch Changes
- bc2d0ed: Ensure final assembly status fetch uses `assembly_ssl_url` so Transloadit requests stay on HTTPS.
## 5.1.0
### Minor Changes
- 6f76412: Use the `transloadit` Node.js SDK's exported Assembly types instead of our inaccurate, hand-rolled ones.
**Warning**
The names of our type exports here are unchanged, but they do pack slightly different types. Overall you'll find they are both more complete, but also more loose. Runtime wise there should be no breaking changes, but it could mean you may need a couple of extra guards to make TypeScript happy.
A cool benefit from the new types tho, is that Robot parameters will now autocomplete for you.
More information on these types, and our approach rolling them out, can be found here https://transloadit.com/blog/2025/09/nodejs-sdk-v4/#our-approach-to-type-retrofitting
## 5.0.1
### Patch Changes

View file

@ -1,7 +1,7 @@
{
"name": "@uppy/transloadit",
"description": "The Transloadit plugin can be used to upload files to Transloadit for all kinds of processing, such as transcoding video, resizing images, zipping/unzipping, and more",
"version": "5.0.1",
"version": "5.1.1",
"license": "MIT",
"type": "module",
"sideEffects": false,
@ -55,6 +55,7 @@
"@uppy/core": "workspace:^",
"jsdom": "^26.1.0",
"msw": "^2.10.4",
"transloadit": "^4.0.2",
"typescript": "^5.8.3",
"vitest": "^3.2.4",
"whatwg-fetch": "^3.6.2"

View file

@ -6,7 +6,12 @@ import {
NetworkError,
} from '@uppy/utils'
import Emitter from 'component-emitter'
import type { AssemblyResponse } from './index.js'
import {
type AssemblyFile,
type AssemblyResponse,
type AssemblyResult,
getAssemblyUrlSsl,
} from './index.js'
const ASSEMBLY_UPLOADING = 'ASSEMBLY_UPLOADING'
const ASSEMBLY_EXECUTING = 'ASSEMBLY_EXECUTING'
@ -24,7 +29,11 @@ const statusOrder = [ASSEMBLY_UPLOADING, ASSEMBLY_EXECUTING, ASSEMBLY_COMPLETED]
* so that we can emit the 'executing' event even if the execution step was so
* fast that we missed it.
*/
function isStatus(status: string, test: string) {
function isStatus(status: unknown, test: string) {
if (typeof status !== 'string') {
return false
}
return statusOrder.indexOf(status) >= statusOrder.indexOf(test)
}
@ -101,16 +110,22 @@ class TransloaditAssembly extends Emitter {
})
this.#sse.addEventListener('assembly_upload_finished', (e) => {
const file = JSON.parse(e.data)
const file = JSON.parse(e.data) as AssemblyFile
this.status.uploads ??= []
this.status.uploads.push(file)
this.emit('upload', file)
})
this.#sse.addEventListener('assembly_result_finished', (e) => {
const [stepName, result] = JSON.parse(e.data)
// biome-ignore lint/suspicious/noAssignInExpressions: ...
;(this.status.results[stepName] ??= []).push(result)
this.emit('result', stepName, result)
const [stepName, rawResult] = JSON.parse(e.data) as [
string,
AssemblyResult,
]
this.status.results ??= {}
this.status.results[stepName] ??= []
this.status.results[stepName].push(rawResult)
this.emit('result', stepName, rawResult)
})
this.#sse.addEventListener('assembly_execution_progress', (e) => {
@ -165,9 +180,9 @@ class TransloaditAssembly extends Emitter {
try {
this.#previousFetchStatusStillPending = true
const response = await this.#fetchWithNetworkError(
this.status.assembly_ssl_url,
)
const statusUrl = getAssemblyUrlSsl(this.status)
const response = await this.#fetchWithNetworkError(statusUrl)
this.#previousFetchStatusStillPending = false
if (this.closed) return
@ -244,29 +259,38 @@ class TransloaditAssembly extends Emitter {
}
// Only emit if the upload is new (not in prev.uploads).
Object.keys(next.uploads)
.filter((upload) => !has(prev.uploads, upload))
.forEach((upload) => {
// @ts-ignore either the types are wrong or the tests are wrong.
// types think next.uploads is an array, but the tests pass an object.
this.emit('upload', next.uploads[upload])
})
const prevUploads = prev.uploads
const nextUploads = next.uploads
if (nextUploads != null && prevUploads != null) {
Object.keys(nextUploads)
.filter((upload) => !has(prevUploads, upload))
.forEach((upload) => {
// This is a bit confusing. Not sure why Object.keys was chosen here, because nextUploads is an Array. Object.keys returns strings for array keys ("0", "1", etc.). Typescript expects arrays to be indexed with a number, not a string nextUploads[0], even though JavaScript is fine with it, so we need to type assert here:
this.emit('upload', nextUploads[upload as unknown as number])
})
}
if (nowExecuting) {
this.emit('metadata')
}
// Find new results.
Object.keys(next.results).forEach((stepName) => {
const nextResults = next.results[stepName]
const prevResults = prev.results[stepName]
const nextResultsMap = next.results
const prevResultsMap = prev.results
if (nextResultsMap != null && prevResultsMap != null) {
Object.keys(nextResultsMap).forEach((stepName) => {
const nextResults = nextResultsMap[stepName] ?? []
const prevResults = prevResultsMap[stepName] ?? []
nextResults
.filter((n) => !prevResults || !prevResults.some((p) => p.id === n.id))
.forEach((result) => {
this.emit('result', stepName, result)
})
})
nextResults
.filter(
(n) => !prevResults || !prevResults.some((p) => p.id === n.id),
)
.forEach((result) => {
this.emit('result', stepName, result)
})
})
}
if (
isStatus(nextStatus, ASSEMBLY_COMPLETED) &&

View file

@ -49,21 +49,23 @@ class TransloaditAssemblyWatcher<
}
#onAssemblyComplete = (assembly: AssemblyResponse) => {
if (!this.#watching(assembly.assembly_id)) {
const assemblyId = assembly.assembly_id
if (assemblyId == null || !this.#watching(assemblyId)) {
return
}
this.#uppy.log(
`[Transloadit] AssemblyWatcher: Got Assembly finish ${assembly.assembly_id}`,
`[Transloadit] AssemblyWatcher: Got Assembly finish ${assemblyId}`,
)
this.emit('assembly-complete', assembly.assembly_id)
this.emit('assembly-complete', assemblyId)
this.#checkAllComplete()
}
#onAssemblyCancel = (assembly: AssemblyResponse) => {
if (!this.#watching(assembly.assembly_id)) {
const assemblyId = assembly.assembly_id
if (assemblyId == null || !this.#watching(assemblyId)) {
return
}
@ -71,16 +73,17 @@ class TransloaditAssemblyWatcher<
}
#onAssemblyError = (assembly: AssemblyResponse, error: Error) => {
if (!this.#watching(assembly.assembly_id)) {
const assemblyId = assembly.assembly_id
if (assemblyId == null || !this.#watching(assemblyId)) {
return
}
this.#uppy.log(
`[Transloadit] AssemblyWatcher: Got Assembly error ${assembly.assembly_id}`,
`[Transloadit] AssemblyWatcher: Got Assembly error ${assemblyId}`,
)
this.#uppy.log(error)
this.emit('assembly-error', assembly.assembly_id, error)
this.emit('assembly-error', assemblyId, error)
this.#checkAllComplete()
}
@ -90,7 +93,8 @@ class TransloaditAssemblyWatcher<
fileID: string,
error: Error,
) => {
if (!this.#watching(assembly.assembly_id)) {
const assemblyId = assembly.assembly_id
if (assemblyId == null || !this.#watching(assemblyId)) {
return
}

View file

@ -6,9 +6,10 @@ import type {
WrapPromiseFunctionType,
} from '@uppy/utils'
import { fetchWithNetworkError } from '@uppy/utils'
import type {
AssemblyResponse,
OptionsWithRestructuredFields,
import {
type AssemblyResponse,
getAssemblyUrlSsl,
type OptionsWithRestructuredFields,
} from './index.js'
const ASSEMBLIES_ENDPOINT = '/assemblies'
@ -139,7 +140,8 @@ export default class Client<M extends Meta, B extends Body> {
file: UppyFile<M, B>,
): Promise<AssemblyResponse> {
const size = encodeURIComponent(file.size!)
const url = `${assembly.assembly_ssl_url}/reserve_file?size=${size}`
const assemblyUrl = getAssemblyUrlSsl(assembly)
const url = `${assemblyUrl}/reserve_file?size=${size}`
return this.#fetchJSON(url, {
method: 'POST',
headers: this.#headers,
@ -164,7 +166,8 @@ export default class Client<M extends Meta, B extends Body> {
const fieldname = 'file'
const qs = `size=${size}&filename=${filename}&fieldname=${fieldname}&s3Url=${uploadUrl}`
const url = `${assembly.assembly_ssl_url}/add_file?${qs}`
const assemblyUrl = getAssemblyUrlSsl(assembly)
const url = `${assemblyUrl}/add_file?${qs}`
return this.#fetchJSON(url, {
method: 'POST',
headers: this.#headers,
@ -177,7 +180,7 @@ export default class Client<M extends Meta, B extends Body> {
* Cancel a running Assembly.
*/
async cancelAssembly(assembly: AssemblyResponse): Promise<void> {
const url = assembly.assembly_ssl_url
const url = getAssemblyUrlSsl(assembly)
await this.#fetchWithNetworkError(url, {
method: 'DELETE',
headers: this.#headers,

View file

@ -9,111 +9,25 @@ import type {
import { BasePlugin } from '@uppy/core'
import Tus, { type TusDetailedError, type TusOpts } from '@uppy/tus'
import { ErrorWithCause, hasProperty, RateLimitedQueue } from '@uppy/utils'
import type {
AssemblyStatus,
AssemblyStatusResult,
AssemblyStatusUpload,
CreateAssemblyParams,
} from 'transloadit'
import packageJson from '../package.json' with { type: 'json' }
import Assembly from './Assembly.js'
import AssemblyWatcher from './AssemblyWatcher.js'
import Client, { type AssemblyError } from './Client.js'
import locale from './locale.js'
export interface AssemblyFile {
id: string
name: string
basename: string
ext: string
size: number
mime: string
type: string
field: string
md5hash: string
is_tus_file: boolean
original_md5hash: string
original_id: string
original_name: string
original_basename: string
original_path: string
url: string
ssl_url: string
tus_upload_url: string
meta: Record<string, any>
}
export interface AssemblyResult extends AssemblyFile {
cost: number
execTime: number
queue: string
queueTime: number
localId: string | null
user_meta?: Record<string, string>
}
export interface AssemblyResponse {
ok: string
message?: string
assembly_id: string
parent_id?: string
account_id: string
template_id?: string
instance: string
assembly_url: string
assembly_ssl_url: string
uppyserver_url: string
companion_url: string
websocket_url: string
tus_url: string
bytes_received: number
bytes_expected: number
upload_duration: number
client_agent?: string
client_ip?: string
client_referer?: string
transloadit_client: string
start_date: string
upload_meta_data_extracted: boolean
warnings: any[]
is_infinite: boolean
has_dupe_jobs: boolean
execution_start: string
execution_duration: number
execution_progress?: number
queue_duration: number
jobs_queue_duration: number
notify_start?: any
notify_url?: string
notify_status?: any
notify_response_code?: any
notify_duration?: any
last_job_completed?: string
fields: Record<string, any>
running_jobs: any[]
bytes_usage: number
executing_jobs: any[]
started_jobs: string[]
parent_assembly_status: any
params: string
template?: any
merged_params: string
uploads: AssemblyFile[]
results: Record<string, AssemblyResult[]>
build_id: string
error?: string
stderr?: string
stdout?: string
reason?: string
}
export interface AssemblyParameters {
auth: {
key: string
expires?: string
}
template_id?: string
steps?: { [step: string]: Record<string, unknown> }
fields?: { [name: string]: number | string }
notify_url?: string
}
export type AssemblyResponse = AssemblyStatus
export type AssemblyFile = AssemblyStatusUpload
export type AssemblyResult = AssemblyStatusResult & { localId: string | null }
export type AssemblyParameters = CreateAssemblyParams
export interface AssemblyOptions {
params?: AssemblyParameters | null
params?: AssemblyParameters | string | null
fields?: Record<string, string | number> | string[] | null
signature?: string | null
}
@ -229,14 +143,15 @@ const sendErrorToConsole = (originalErr: Error) => (err: Error) => {
console.error(error, originalErr)
}
function validateParams(params?: AssemblyParameters | null): void {
function validateParams(params?: AssemblyOptions['params']): void {
if (params == null) {
throw new Error('Transloadit: The `params` option is required.')
}
let parsed: AssemblyParameters
if (typeof params === 'string') {
try {
params = JSON.parse(params)
parsed = JSON.parse(params) as AssemblyParameters
} catch (err) {
// Tell the user that this is not an Uppy bug!
throw new ErrorWithCause(
@ -244,9 +159,11 @@ function validateParams(params?: AssemblyParameters | null): void {
{ cause: err },
)
}
} else {
parsed = params
}
if (!params!.auth || !params!.auth.key) {
if (!parsed.auth || !parsed.auth.key) {
throw new Error(
'Transloadit: The `params.auth.key` option is required. ' +
'You can find your Transloadit API key at https://transloadit.com/c/template-credentials',
@ -254,6 +171,46 @@ function validateParams(params?: AssemblyParameters | null): void {
}
}
function ensureAssemblyId(status: AssemblyResponse): string {
if (!status.assembly_id) {
console.warn('Assembly status is missing `assembly_id`.', status)
throw new Error('Transloadit: Assembly status is missing `assembly_id`.')
}
return status.assembly_id
}
function ensureUrl(
label: string,
...candidates: Array<string | undefined>
): string {
for (const value of candidates) {
if (typeof value === 'string' && value.length > 0) {
return value
}
}
throw new Error(`Transloadit: Assembly status is missing ${label}.`)
}
export function getAssemblyUrl(
assembly: Pick<AssemblyResponse, 'assembly_ssl_url' | 'assembly_url'>,
): string {
return ensureUrl(
'`assembly_url`',
assembly.assembly_url,
assembly.assembly_ssl_url,
)
}
export function getAssemblyUrlSsl(
assembly: Pick<AssemblyResponse, 'assembly_ssl_url' | 'assembly_url'>,
): string {
return ensureUrl(
'`assembly_ssl_url`',
assembly.assembly_ssl_url,
assembly.assembly_url,
)
}
const COMPANION_URL = 'https://api2.transloadit.com/companion'
// Regex matching acceptable postMessage() origins for authentication feedback from companion.
const COMPANION_ALLOWED_HOSTS = /\.transloadit\.com$/
@ -355,16 +312,21 @@ export default class Transloadit<
*/
#attachAssemblyMetadata(file: UppyFile<M, B>, status: AssemblyResponse) {
// Add the metadata parameters Transloadit needs.
const assemblyUrl = getAssemblyUrl(status)
const tusEndpoint = ensureUrl('`tus_url`', status.tus_url)
const assemblyId = ensureAssemblyId(status)
const meta = {
...file.meta,
assembly_url: status.assembly_url,
// @TODO(tim-kos), can we safely bump this to assembly_ssl_url / getAssemblyUrlSsl?
assembly_url: assemblyUrl,
filename: file.name,
fieldname: 'file',
}
// Add Assembly-specific Tus endpoint.
const tus = {
...file.tus,
endpoint: status.tus_url,
endpoint: tusEndpoint,
// Include X-Request-ID headers for better debugging.
addRequestId: true,
}
@ -375,7 +337,11 @@ export default class Transloadit<
// people can also self-host them while still using Transloadit for encoding.
let { remote } = file
if (file.remote && TL_COMPANION.test(file.remote.companionUrl)) {
if (
file.remote &&
status.companion_url &&
TL_COMPANION.test(file.remote.companionUrl)
) {
const newHost = status.companion_url.replace(/\/$/, '')
const path = file.remote.url
.replace(file.remote.companionUrl, '')
@ -392,7 +358,7 @@ export default class Transloadit<
const newFile = {
...file,
transloadit: {
assembly: status.assembly_id,
assembly: assemblyId,
},
}
// Only configure the Tus plugin if we are uploading straight to Transloadit (the default).
@ -426,7 +392,7 @@ export default class Transloadit<
const assembly = new Assembly(newAssembly, this.#rateLimitedQueue)
const { status } = assembly
const assemblyID = status.assembly_id
const assemblyID = ensureAssemblyId(status)
const updatedFiles: Record<string, UppyFile<M, B>> = {}
files.forEach((file) => {
@ -585,9 +551,15 @@ export default class Transloadit<
#onResult(assemblyId: string, stepName: string, result: AssemblyResult) {
const state = this.getPluginState()
const file = state.files[result.original_id]
// The `file` may not exist if an import robot was used instead of a file upload.
result.localId = file ? file.id : null
if (!('id' in result)) {
console.warn('Result has no id', result)
return
}
if (typeof result.id !== 'string') {
console.warn('Result has no id of type string', result)
return
}
const entry = {
result,
@ -599,7 +571,12 @@ export default class Transloadit<
this.setPluginState({
results: [...state.results, entry],
})
this.uppy.emit('transloadit:result', stepName, result, this.getAssembly()!)
this.uppy.emit(
'transloadit:result',
stepName,
entry.result,
this.getAssembly()!,
)
}
/**
@ -607,7 +584,7 @@ export default class Transloadit<
* and emit it.
*/
#onAssemblyFinished(assembly: Assembly) {
const url = assembly.status.assembly_ssl_url
const url = getAssemblyUrlSsl(assembly.status)
this.client.getAssemblyStatus(url).then((finalStatus) => {
assembly.status = finalStatus
this.uppy.emit('transloadit:complete', finalStatus)
@ -668,9 +645,9 @@ export default class Transloadit<
id: string
assembly: string
}[] = []
const { assembly_id: id } = previousAssembly
const id = ensureAssemblyId(previousAssembly)
previousAssembly.uploads.forEach((uploadedFile) => {
previousAssembly.uploads?.forEach((uploadedFile) => {
const file = this.#findFile(uploadedFile)
files[uploadedFile.id] = {
id: file!.id,
@ -680,13 +657,31 @@ export default class Transloadit<
})
const state = this.getPluginState()
Object.keys(previousAssembly.results).forEach((stepName) => {
for (const result of previousAssembly.results[stepName]) {
const restoredResults = previousAssembly.results ?? {}
Object.keys(restoredResults).forEach((stepName) => {
const stepResults = restoredResults[stepName] ?? []
for (const result of stepResults) {
if (!('id' in result)) {
console.warn('Result has no id', result)
continue
}
if (typeof result.id !== 'string') {
console.warn('Result has no id of type string', result)
continue
}
if (!('original_id' in result)) {
console.warn('Result has no original_id', result)
continue
}
if (typeof result.original_id !== 'string') {
console.warn('Result has no original_id of type string', result)
continue
}
const file = state.files[result.original_id]
result.localId = file ? file.id : null
results.push({
id: result.id,
result,
result: { ...result, localId: file ? file.id : null },
stepName,
assembly: id,
})
@ -701,7 +696,7 @@ export default class Transloadit<
// Set up the Assembly instances and AssemblyWatchers for existing Assemblies.
const restoreAssemblies = (ids: string[]) => {
this.#createAssemblyWatcher(previousAssembly.assembly_id)
this.#createAssemblyWatcher(ensureAssemblyId(previousAssembly))
this.#connectAssembly(this.assembly!, ids)
}
@ -725,7 +720,7 @@ export default class Transloadit<
#connectAssembly(assembly: Assembly, ids: UppyFile<M, B>['id'][]) {
const { status } = assembly
const id = status.assembly_id
const id = ensureAssemblyId(status)
this.assembly = assembly
assembly.on('upload', (file: AssemblyFile) => {
@ -820,7 +815,7 @@ export default class Transloadit<
const file = this.uppy.getFile(fileID)
this.uppy.emit('preprocess-complete', file)
})
this.#createAssemblyWatcher(assembly.status.assembly_id)
this.#createAssemblyWatcher(ensureAssemblyId(assembly.status))
this.#connectAssembly(assembly, fileIDs)
} catch (err) {
fileIDs.forEach((fileID) => {
@ -844,7 +839,9 @@ export default class Transloadit<
// Only use files without errors
.filter((file) => !file.error)
const assemblyID = this.assembly?.status.assembly_id
const assemblyID = this.assembly
? ensureAssemblyId(this.assembly.status)
: undefined
const closeSocketConnections = () => {
this.assembly?.close()

View file

@ -1,5 +1,19 @@
# uppy
## 5.1.4
### Patch Changes
- Updated dependencies [bc2d0ed]
- @uppy/transloadit@5.1.1
## 5.1.3
### Patch Changes
- Updated dependencies [6f76412]
- @uppy/transloadit@5.1.0
## 5.1.2
### Patch Changes

View file

@ -1,7 +1,7 @@
{
"name": "uppy",
"description": "Extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more :dog:",
"version": "5.1.2",
"version": "5.1.4",
"license": "MIT",
"main": "lib/index.js",
"module": "lib/index.js",
@ -37,41 +37,40 @@
"url": "git+https://github.com/transloadit/uppy.git"
},
"dependencies": {
"@uppy/audio": "workspace:^",
"@uppy/aws-s3": "workspace:^",
"@uppy/box": "workspace:^",
"@uppy/companion-client": "workspace:^",
"@uppy/compressor": "workspace:^",
"@uppy/core": "workspace:^",
"@uppy/dashboard": "workspace:^",
"@uppy/drag-drop": "workspace:^",
"@uppy/drop-target": "workspace:^",
"@uppy/dropbox": "workspace:^",
"@uppy/facebook": "workspace:^",
"@uppy/form": "workspace:^",
"@uppy/golden-retriever": "workspace:^",
"@uppy/google-drive": "workspace:^",
"@uppy/google-drive-picker": "workspace:^",
"@uppy/google-photos-picker": "workspace:^",
"@uppy/image-editor": "workspace:^",
"@uppy/image-generator": "workspace:^",
"@uppy/instagram": "workspace:^",
"@uppy/locales": "workspace:^",
"@uppy/onedrive": "workspace:^",
"@uppy/provider-views": "workspace:^",
"@uppy/remote-sources": "workspace:^",
"@uppy/screen-capture": "workspace:^",
"@uppy/status-bar": "workspace:^",
"@uppy/store-default": "workspace:^",
"@uppy/thumbnail-generator": "workspace:^",
"@uppy/transloadit": "workspace:^",
"@uppy/tus": "workspace:^",
"@uppy/unsplash": "workspace:^",
"@uppy/url": "workspace:^",
"@uppy/webcam": "workspace:^",
"@uppy/webdav": "workspace:^",
"@uppy/xhr-upload": "workspace:^",
"@uppy/zoom": "workspace:^"
"@uppy/audio": "workspace:*",
"@uppy/aws-s3": "workspace:*",
"@uppy/box": "workspace:*",
"@uppy/companion-client": "workspace:*",
"@uppy/compressor": "workspace:*",
"@uppy/core": "workspace:*",
"@uppy/dashboard": "workspace:*",
"@uppy/drag-drop": "workspace:*",
"@uppy/drop-target": "workspace:*",
"@uppy/dropbox": "workspace:*",
"@uppy/facebook": "workspace:*",
"@uppy/form": "workspace:*",
"@uppy/golden-retriever": "workspace:*",
"@uppy/google-drive": "workspace:*",
"@uppy/google-drive-picker": "workspace:*",
"@uppy/google-photos-picker": "workspace:*",
"@uppy/image-editor": "workspace:*",
"@uppy/instagram": "workspace:*",
"@uppy/locales": "workspace:*",
"@uppy/onedrive": "workspace:*",
"@uppy/provider-views": "workspace:*",
"@uppy/remote-sources": "workspace:*",
"@uppy/screen-capture": "workspace:*",
"@uppy/status-bar": "workspace:*",
"@uppy/store-default": "workspace:*",
"@uppy/thumbnail-generator": "workspace:*",
"@uppy/transloadit": "workspace:*",
"@uppy/tus": "workspace:*",
"@uppy/unsplash": "workspace:*",
"@uppy/url": "workspace:*",
"@uppy/webcam": "workspace:*",
"@uppy/webdav": "workspace:*",
"@uppy/xhr-upload": "workspace:*",
"@uppy/zoom": "workspace:*"
},
"scripts": {
"build": "tsc --build tsconfig.build.json && yarn build:bundle",

1467
yarn.lock

File diff suppressed because it is too large Load diff