transloadit 4.13.0 → 4.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -5
- package/dist/Transloadit.d.ts +2 -0
- package/dist/Transloadit.d.ts.map +1 -1
- package/dist/Transloadit.js +12 -2
- package/dist/Transloadit.js.map +1 -1
- package/dist/alphalib/types/assemblyStatus.d.ts +758 -0
- package/dist/alphalib/types/assemblyStatus.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyStatus.js +6 -0
- package/dist/alphalib/types/assemblyStatus.js.map +1 -1
- package/dist/alphalib/types/robots/_instructions-primitives.d.ts.map +1 -1
- package/dist/alphalib/types/robots/_instructions-primitives.js +2 -0
- package/dist/alphalib/types/robots/_instructions-primitives.js.map +1 -1
- package/dist/alphalib/types/robots/ai-chat.d.ts.map +1 -1
- package/dist/alphalib/types/robots/ai-chat.js +1 -0
- package/dist/alphalib/types/robots/ai-chat.js.map +1 -1
- package/dist/alphalib/types/robots/image-generate.js +4 -4
- package/dist/alphalib/types/robots/image-generate.js.map +1 -1
- package/dist/alphalib/types/storageAsset.d.ts +27 -1
- package/dist/alphalib/types/storageAsset.d.ts.map +1 -1
- package/dist/alphalib/types/storageAsset.js +6 -0
- package/dist/alphalib/types/storageAsset.js.map +1 -1
- package/dist/alphalib/types/templateCredential.d.ts +2 -2
- package/dist/cli/commands/storage.d.ts +1 -0
- package/dist/cli/commands/storage.d.ts.map +1 -1
- package/dist/cli/commands/storage.js +27 -2
- package/dist/cli/commands/storage.js.map +1 -1
- package/dist/cli/semanticIntents/imageGenerate.d.ts +2 -2
- package/dist/cli/semanticIntents/imageGenerate.js +4 -4
- package/dist/cli/semanticIntents/imageGenerate.js.map +1 -1
- package/dist/cli/storageReceipts.d.ts.map +1 -1
- package/dist/cli/storageReceipts.js +4 -1
- package/dist/cli/storageReceipts.js.map +1 -1
- package/dist/storageImage.d.ts +6 -3
- package/dist/storageImage.d.ts.map +1 -1
- package/dist/storageImage.js +15 -44
- package/dist/storageImage.js.map +1 -1
- package/package.json +1 -5
- package/src/Transloadit.ts +18 -2
- package/src/alphalib/types/assemblyStatus.ts +6 -0
- package/src/alphalib/types/robots/_instructions-primitives.ts +2 -0
- package/src/alphalib/types/robots/ai-chat.ts +1 -0
- package/src/alphalib/types/robots/image-generate.ts +4 -4
- package/src/alphalib/types/storageAsset.ts +9 -1
- package/src/cli/commands/storage.ts +28 -2
- package/src/cli/semanticIntents/imageGenerate.ts +4 -4
- package/src/cli/storageReceipts.ts +4 -1
- package/src/storageImage.ts +20 -49
package/src/storageImage.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AssemblyStatus } from './alphalib/types/assemblyStatus.ts'
|
|
2
|
+
import type { InterpolatableRobotUploadHandleInstructionsInput } from './alphalib/types/robots/upload-handle.ts'
|
|
2
3
|
import type { StoredAsset } from './alphalib/types/storageAsset.ts'
|
|
3
4
|
import type { CreateAssemblyOptions, Transloadit } from './Transloadit.ts'
|
|
4
5
|
|
|
@@ -17,15 +18,16 @@ import InconsistentResponseError from './InconsistentResponseError.ts'
|
|
|
17
18
|
* Width and height reflect EXIF auto-orientation, matching Storage preview delivery.
|
|
18
19
|
*/
|
|
19
20
|
export interface StoredImageReceipt extends Readonly<StoredAsset> {
|
|
20
|
-
/**
|
|
21
|
+
/** Legacy catalog spelling; new server receipts use has_alpha. */
|
|
21
22
|
readonly hasAlpha?: boolean
|
|
22
23
|
readonly height: number
|
|
23
24
|
readonly md5hash: string
|
|
24
|
-
/** Optional base64 ThumbHash of the original pixels, for an inline blur placeholder. */
|
|
25
|
-
readonly thumbhash?: string
|
|
26
25
|
readonly width: number
|
|
27
26
|
}
|
|
28
27
|
|
|
28
|
+
/** Shared SDK/CLI opt-in for server extraction; rendering remains a separate choice. */
|
|
29
|
+
export const storageImagePlaceholderSchema = z.enum(['blur', 'empty'])
|
|
30
|
+
|
|
29
31
|
/** One explicit destination, with the existing Assembly upload and polling controls. */
|
|
30
32
|
export interface StoreImageOptions
|
|
31
33
|
extends Pick<
|
|
@@ -36,6 +38,8 @@ export interface StoreImageOptions
|
|
|
36
38
|
path: string
|
|
37
39
|
/** Explicit opt-in replacement of an existing path; defaults to false. */
|
|
38
40
|
overwrite?: boolean
|
|
41
|
+
/** Request a server ThumbHash. Successful extraction adds metadata usage of 20% of the file bytes. */
|
|
42
|
+
placeholder?: z.infer<typeof storageImagePlaceholderSchema>
|
|
39
43
|
/** Observe verified metadata. Not awaited; sync and async observer errors cannot undo a write. */
|
|
40
44
|
onReceipt?: (
|
|
41
45
|
receipt: StoredImageReceipt,
|
|
@@ -94,35 +98,6 @@ function validateDestination(path: string): void {
|
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
|
|
97
|
-
async function imagePlaceholderMetadata(
|
|
98
|
-
bytes: Buffer,
|
|
99
|
-
): Promise<Pick<StoredImageReceipt, 'thumbhash' | 'hasAlpha'> | undefined> {
|
|
100
|
-
try {
|
|
101
|
-
const [{ default: sharp }, { rgbaToThumbHash }] = await Promise.all([
|
|
102
|
-
import('sharp'),
|
|
103
|
-
import('thumbhash'),
|
|
104
|
-
])
|
|
105
|
-
const image = sharp(bytes, { limitInputPixels: 40_000_000 })
|
|
106
|
-
// Read original-channel metadata, not the alpha channel added for ThumbHash's RGBA input.
|
|
107
|
-
const { hasAlpha } = await image.metadata()
|
|
108
|
-
const { data, info } = await image
|
|
109
|
-
.autoOrient()
|
|
110
|
-
.resize(100, 100, { fit: 'inside', withoutEnlargement: true })
|
|
111
|
-
.ensureAlpha()
|
|
112
|
-
.raw()
|
|
113
|
-
.timeout({ seconds: 2 })
|
|
114
|
-
.toBuffer({ resolveWithObject: true })
|
|
115
|
-
return {
|
|
116
|
-
thumbhash: Buffer.from(rgbaToThumbHash(info.width, info.height, data)).toString('base64'),
|
|
117
|
-
...(hasAlpha ? { hasAlpha: true } : {}),
|
|
118
|
-
}
|
|
119
|
-
} catch {
|
|
120
|
-
// A locally unsupported/oversized image can still be stored and decoded by the origin.
|
|
121
|
-
debug('transloadit:warn')('Omitted optional ThumbHash: local image decoding was unavailable')
|
|
122
|
-
return undefined
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
101
|
/** Stores one original without overwriting; receipt validation occurs after the Storage write. */
|
|
127
102
|
export async function storeImage(
|
|
128
103
|
client: Transloadit,
|
|
@@ -140,28 +115,21 @@ export async function storeImage(
|
|
|
140
115
|
timeout,
|
|
141
116
|
} = options
|
|
142
117
|
validateDestination(path)
|
|
118
|
+
const placeholder = storageImagePlaceholderSchema.optional().parse(options.placeholder, {
|
|
119
|
+
path: ['placeholder'],
|
|
120
|
+
})
|
|
143
121
|
if (overwrite !== undefined && typeof overwrite !== 'boolean')
|
|
144
122
|
throw new TypeError('overwrite must be a boolean')
|
|
145
123
|
signal?.throwIfAborted()
|
|
146
124
|
const checksum = createHash('md5')
|
|
147
|
-
// Reuse the checksum read, bounded independently of file size; uploads still stream from disk.
|
|
148
|
-
let thumbnailChunks: Buffer[] | undefined = []
|
|
149
125
|
let size = 0
|
|
150
126
|
for await (const chunk of createReadStream(filePath, { signal })) {
|
|
151
127
|
checksum.update(chunk)
|
|
152
128
|
size += chunk.length
|
|
153
|
-
if (size > 32 * 1024 * 1024) thumbnailChunks = undefined
|
|
154
|
-
else thumbnailChunks?.push(chunk)
|
|
155
129
|
}
|
|
156
130
|
if (size === 0) throw new Error('Cannot store an empty image')
|
|
157
131
|
const md5hash = checksum.digest('hex')
|
|
158
132
|
signal?.throwIfAborted()
|
|
159
|
-
const placeholder =
|
|
160
|
-
thumbnailChunks === undefined
|
|
161
|
-
? undefined
|
|
162
|
-
: await imagePlaceholderMetadata(Buffer.concat(thumbnailChunks))
|
|
163
|
-
thumbnailChunks = undefined
|
|
164
|
-
signal?.throwIfAborted()
|
|
165
133
|
const assembly = await client.createAssembly({
|
|
166
134
|
chunkSize,
|
|
167
135
|
files: { image: filePath },
|
|
@@ -169,6 +137,14 @@ export async function storeImage(
|
|
|
169
137
|
onUploadProgress,
|
|
170
138
|
params: {
|
|
171
139
|
steps: {
|
|
140
|
+
...(placeholder === 'blur'
|
|
141
|
+
? {
|
|
142
|
+
':original': {
|
|
143
|
+
robot: '/upload/handle',
|
|
144
|
+
output_meta: { thumbhash: true },
|
|
145
|
+
} satisfies InterpolatableRobotUploadHandleInstructionsInput,
|
|
146
|
+
}
|
|
147
|
+
: {}),
|
|
172
148
|
stored: {
|
|
173
149
|
robot: '/transloadit/store',
|
|
174
150
|
use: ':original',
|
|
@@ -184,23 +160,18 @@ export async function storeImage(
|
|
|
184
160
|
const input = { path, size, md5hash }
|
|
185
161
|
// API2 can watermark uploads before Robots run; this exact write's result describes stored bytes.
|
|
186
162
|
const receipt = validateReceipt(assembly, input, true)
|
|
187
|
-
// A watermark or other origin-side rewrite makes the local pixels the wrong placeholder.
|
|
188
|
-
const withPlaceholder =
|
|
189
|
-
placeholder === undefined || receipt.md5hash !== md5hash || receipt.size !== size
|
|
190
|
-
? receipt
|
|
191
|
-
: { ...receipt, ...placeholder }
|
|
192
163
|
const observerFailed = (): void => {
|
|
193
164
|
debug('transloadit:warn')('Ignored onReceipt observer failure after a completed Storage write')
|
|
194
165
|
}
|
|
195
166
|
try {
|
|
196
167
|
// Neither a stalled observer nor its rejection may hide a successfully stored receipt.
|
|
197
|
-
void Promise.resolve(onReceipt?.({ ...
|
|
168
|
+
void Promise.resolve(onReceipt?.({ ...receipt }, input, assembly.assembly_id)).catch(
|
|
198
169
|
observerFailed,
|
|
199
170
|
)
|
|
200
171
|
} catch {
|
|
201
172
|
observerFailed()
|
|
202
173
|
}
|
|
203
|
-
return
|
|
174
|
+
return receipt
|
|
204
175
|
}
|
|
205
176
|
|
|
206
177
|
/** Fetches authoritative Assembly status and applies the same validation as a local image store. */
|