transloadit 6.8.0 → 6.9.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 +73 -8
- package/dist/Transloadit.d.ts +6 -0
- package/dist/Transloadit.d.ts.map +1 -1
- package/dist/Transloadit.js +9 -0
- package/dist/Transloadit.js.map +1 -1
- package/dist/bearerToken.d.ts +2 -0
- package/dist/bearerToken.d.ts.map +1 -1
- package/dist/bearerToken.js +6 -9
- package/dist/bearerToken.js.map +1 -1
- package/dist/cli/commands/assemblies.d.ts.map +1 -1
- package/dist/cli/commands/assemblies.js +6 -4
- 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 +2 -1
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/image.js +3 -3
- package/dist/cli/commands/image.js.map +1 -1
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/commands/login.js +10 -9
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/notifications.js +2 -2
- package/dist/cli/commands/notifications.js.map +1 -1
- package/dist/cli/commands/storage.d.ts.map +1 -1
- package/dist/cli/commands/storage.js +120 -47
- package/dist/cli/commands/storage.js.map +1 -1
- package/dist/cli/commands/upload.d.ts.map +1 -1
- package/dist/cli/commands/upload.js +2 -1
- package/dist/cli/commands/upload.js.map +1 -1
- package/dist/cli/deviceLogin.d.ts.map +1 -1
- package/dist/cli/deviceLogin.js +3 -3
- package/dist/cli/deviceLogin.js.map +1 -1
- package/dist/cli/helpers.d.ts +2 -1
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/helpers.js +26 -1
- package/dist/cli/helpers.js.map +1 -1
- package/dist/cli/storagePublic.d.ts +1 -1
- package/dist/cli/storagePublic.d.ts.map +1 -1
- package/dist/cli/storagePublic.js +5 -4
- package/dist/cli/storagePublic.js.map +1 -1
- package/dist/cli/storageReceipts.d.ts +80 -1
- package/dist/cli/storageReceipts.d.ts.map +1 -1
- package/dist/cli/storageReceipts.js +48 -12
- package/dist/cli/storageReceipts.js.map +1 -1
- package/dist/storageAsset.d.ts +44 -0
- package/dist/storageAsset.d.ts.map +1 -0
- package/dist/storageAsset.js +173 -0
- package/dist/storageAsset.js.map +1 -0
- package/dist/storageImage.d.ts +11 -35
- package/dist/storageImage.d.ts.map +1 -1
- package/dist/storageImage.js +21 -141
- package/dist/storageImage.js.map +1 -1
- package/package.json +2 -2
- package/src/Transloadit.ts +22 -0
- package/src/bearerToken.ts +8 -10
- package/src/cli/commands/assemblies.ts +7 -4
- package/src/cli/commands/auth.ts +2 -0
- package/src/cli/commands/image.ts +3 -3
- package/src/cli/commands/login.ts +12 -10
- package/src/cli/commands/notifications.ts +2 -2
- package/src/cli/commands/storage.ts +160 -78
- package/src/cli/commands/upload.ts +2 -1
- package/src/cli/deviceLogin.ts +3 -2
- package/src/cli/helpers.ts +31 -1
- package/src/cli/storagePublic.ts +11 -4
- package/src/cli/storageReceipts.ts +50 -11
- package/src/storageAsset.ts +271 -0
- package/src/storageImage.ts +43 -201
package/dist/storageImage.js
CHANGED
|
@@ -1,152 +1,32 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { createReadStream } from 'node:fs';
|
|
3
|
-
import debug from 'debug';
|
|
4
1
|
import { z } from 'zod';
|
|
5
|
-
import { ApiError } from "./ApiError.js";
|
|
6
2
|
import { storedAssetSchema } from "./alphalib/types/storageAsset.js";
|
|
7
3
|
import InconsistentResponseError from "./InconsistentResponseError.js";
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
path: z.string(),
|
|
15
|
-
size: positiveIntegerSchema,
|
|
16
|
-
md5hash: z.string().regex(/^[a-f0-9]{32}$/),
|
|
17
|
-
}),
|
|
4
|
+
import { getOriginalReceipt, storeOriginal } from "./storageAsset.js";
|
|
5
|
+
export { storageImagePlaceholderSchema } from "./storageAsset.js";
|
|
6
|
+
const imageReceiptSchema = storedAssetSchema.extend({
|
|
7
|
+
md5hash: storedAssetSchema.shape.md5hash.unwrap(),
|
|
8
|
+
height: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
9
|
+
width: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
18
10
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
height: positiveIntegerSchema,
|
|
26
|
-
width: positiveIntegerSchema,
|
|
27
|
-
size: positiveIntegerSchema,
|
|
28
|
-
}),
|
|
29
|
-
]),
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
function validateDestination(path) {
|
|
33
|
-
if (typeof path !== 'string' ||
|
|
34
|
-
path.trim() !== path ||
|
|
35
|
-
Buffer.byteLength(path) > 1024 ||
|
|
36
|
-
path.normalize('NFC') !== path ||
|
|
37
|
-
/[\p{Cc}\p{Cs}\\|]/u.test(path) ||
|
|
38
|
-
path.includes('${') ||
|
|
39
|
-
path.split('/').some((segment) => segment.trim() === '' || segment === '.' || segment === '..')) {
|
|
40
|
-
throw new TypeError('Storage path must be a complete relative filename without interpolation');
|
|
11
|
+
function requireImage(receipt) {
|
|
12
|
+
const image = imageReceiptSchema.safeParse(receipt);
|
|
13
|
+
if (!image.success) {
|
|
14
|
+
throw new InconsistentResponseError('The Assembly did not return a matching Storage image receipt', {
|
|
15
|
+
cause: { receipt },
|
|
16
|
+
});
|
|
41
17
|
}
|
|
18
|
+
return image.data;
|
|
42
19
|
}
|
|
43
|
-
/**
|
|
20
|
+
/** Retains the image API's transformed-byte semantics; use storeAsset for exact originals. */
|
|
44
21
|
export async function storeImage(client, filePath, options) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (overwrite !== undefined && typeof overwrite !== 'boolean')
|
|
51
|
-
throw new TypeError('overwrite must be a boolean');
|
|
52
|
-
signal?.throwIfAborted();
|
|
53
|
-
const checksum = createHash('md5');
|
|
54
|
-
let size = 0;
|
|
55
|
-
for await (const chunk of createReadStream(filePath, { signal })) {
|
|
56
|
-
checksum.update(chunk);
|
|
57
|
-
size += chunk.length;
|
|
58
|
-
}
|
|
59
|
-
if (size === 0)
|
|
60
|
-
throw new Error('Cannot store an empty image');
|
|
61
|
-
const md5hash = checksum.digest('hex');
|
|
62
|
-
signal?.throwIfAborted();
|
|
63
|
-
const assembly = await client.createAssembly({
|
|
64
|
-
chunkSize,
|
|
65
|
-
files: { image: filePath },
|
|
66
|
-
onAssemblyProgress,
|
|
67
|
-
onUploadProgress,
|
|
68
|
-
params: {
|
|
69
|
-
steps: {
|
|
70
|
-
...(placeholder === 'blur'
|
|
71
|
-
? {
|
|
72
|
-
':original': {
|
|
73
|
-
robot: '/upload/handle',
|
|
74
|
-
output_meta: { thumbhash: true },
|
|
75
|
-
},
|
|
76
|
-
}
|
|
77
|
-
: {}),
|
|
78
|
-
stored: {
|
|
79
|
-
robot: '/transloadit/store',
|
|
80
|
-
use: ':original',
|
|
81
|
-
path,
|
|
82
|
-
conflict_strategy: overwrite === true ? 'overwrite' : 'error',
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
signal,
|
|
87
|
-
timeout,
|
|
88
|
-
waitForCompletion: true,
|
|
89
|
-
});
|
|
90
|
-
const input = { path, size, md5hash };
|
|
91
|
-
// API2 can watermark uploads before Robots run; this exact write's result describes stored bytes.
|
|
92
|
-
const receipt = validateReceipt(assembly, input, true);
|
|
93
|
-
const observerFailed = () => {
|
|
94
|
-
debug('transloadit:warn')('Ignored onReceipt observer failure after a completed Storage write');
|
|
95
|
-
};
|
|
96
|
-
try {
|
|
97
|
-
// Neither a stalled observer nor its rejection may hide a successfully stored receipt.
|
|
98
|
-
void Promise.resolve(onReceipt?.({ ...receipt }, input, assembly.assembly_id)).catch(observerFailed);
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
observerFailed();
|
|
102
|
-
}
|
|
103
|
-
return receipt;
|
|
22
|
+
const receipt = await storeOriginal(client, filePath, {
|
|
23
|
+
...options,
|
|
24
|
+
onReceipt: (asset, input, assemblyId) => options.onReceipt?.(requireImage(asset), input, assemblyId),
|
|
25
|
+
}, true);
|
|
26
|
+
return requireImage(receipt);
|
|
104
27
|
}
|
|
105
|
-
/**
|
|
28
|
+
/** Recovers one image receipt with the same strict byte checks as generic receipt recovery. */
|
|
106
29
|
export async function getStoredImageReceipt(client, options) {
|
|
107
|
-
|
|
108
|
-
validateDestination(expected.path);
|
|
109
|
-
const assembly = await client.getAssembly(assemblyId);
|
|
110
|
-
if (assembly.assembly_id !== assemblyId) {
|
|
111
|
-
throw new InconsistentResponseError('The response did not match the requested Assembly', {
|
|
112
|
-
cause: { assemblyId },
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
return validateReceipt(assembly, expected);
|
|
116
|
-
}
|
|
117
|
-
function validateReceipt(assembly, expected, acceptTransformed = false) {
|
|
118
|
-
const { path, size, md5hash } = expected;
|
|
119
|
-
if (typeof assembly.error === 'string')
|
|
120
|
-
throw new ApiError({ body: assembly });
|
|
121
|
-
if (assembly.ok === 'ASSEMBLY_CANCELED') {
|
|
122
|
-
throw new InconsistentResponseError('The Storage Assembly ended with ASSEMBLY_CANCELED', {
|
|
123
|
-
cause: { assemblyId: assembly.assembly_id },
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
if (assembly.ok === 'ASSEMBLY_UPLOADING' ||
|
|
127
|
-
assembly.ok === 'ASSEMBLY_EXECUTING' ||
|
|
128
|
-
assembly.ok === 'ASSEMBLY_REPLAYING') {
|
|
129
|
-
throw new InconsistentResponseError(`The Storage Assembly is not complete (${assembly.ok})`, {
|
|
130
|
-
cause: { assemblyId: assembly.assembly_id },
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
const parsed = completedImageSchema.safeParse(assembly);
|
|
134
|
-
const result = parsed.success ? parsed.data.results[':original'][0] : undefined;
|
|
135
|
-
const originals = assembly.results?.[':original'];
|
|
136
|
-
const receiptCheck = {
|
|
137
|
-
originalCount: Array.isArray(originals) ? originals.length : 0,
|
|
138
|
-
metadataValid: parsed.success,
|
|
139
|
-
pathMatches: result === undefined ? undefined : result.path === path,
|
|
140
|
-
sizeMatches: result === undefined ? undefined : result.size === size,
|
|
141
|
-
md5Matches: result === undefined ? undefined : result.md5hash === md5hash,
|
|
142
|
-
};
|
|
143
|
-
if (result === undefined ||
|
|
144
|
-
result.path !== path ||
|
|
145
|
-
(!acceptTransformed && (!receiptCheck.sizeMatches || !receiptCheck.md5Matches))) {
|
|
146
|
-
throw new InconsistentResponseError('The Assembly did not return a matching Storage image receipt', {
|
|
147
|
-
cause: { assemblyId: assembly.assembly_id, receiptCheck },
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
return result;
|
|
30
|
+
return requireImage(await getOriginalReceipt(client, options, true));
|
|
151
31
|
}
|
|
152
32
|
//# sourceMappingURL=storageImage.js.map
|
package/dist/storageImage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageImage.js","sourceRoot":"","sources":["../src/storageImage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storageImage.js","sourceRoot":"","sources":["../src/storageImage.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,yBAAyB,MAAM,gCAAgC,CAAA;AACtE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAErE,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAA;AAoBjE,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,MAAM,CAAC;IAClD,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE;IACjD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC;IAChE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC;CAChE,CAAC,CAAA;AAEF,SAAS,YAAY,CAAC,OAA2B;IAC/C,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IACnD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,IAAI,yBAAyB,CACjC,8DAA8D,EAC9D;YACE,KAAK,EAAE,EAAE,OAAO,EAAE;SACnB,CACF,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAA;AACnB,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAmB,EACnB,QAAgB,EAChB,OAA0B;IAE1B,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,MAAM,EACN,QAAQ,EACR;QACE,GAAG,OAAO;QACV,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CACtC,OAAO,CAAC,SAAS,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC;KAC9D,EACD,IAAI,CACL,CAAA;IACD,OAAO,YAAY,CAAC,OAAO,CAAC,CAAA;AAC9B,CAAC;AAED,+FAA+F;AAC/F,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAmB,EACnB,OAAqC;IAErC,OAAO,YAAY,CAAC,MAAM,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;AACtE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "transloadit",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.1",
|
|
4
4
|
"description": "Node.js SDK and `transloadit` CLI for Transloadit",
|
|
5
5
|
"homepage": "https://github.com/transloadit/node-sdk/tree/main/packages/node",
|
|
6
6
|
"bugs": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@transloadit/sev-logger": "^0.1.9",
|
|
36
|
-
"@transloadit/utils": "^4.
|
|
36
|
+
"@transloadit/utils": "^4.11.0",
|
|
37
37
|
"cacheable-lookup": "^7.0.0",
|
|
38
38
|
"clipanion": "^4.0.0-rc.4",
|
|
39
39
|
"debug": "^4.4.3",
|
package/src/Transloadit.ts
CHANGED
|
@@ -54,6 +54,11 @@ import type {
|
|
|
54
54
|
LintAssemblyInstructionsInput,
|
|
55
55
|
LintAssemblyInstructionsResult,
|
|
56
56
|
} from './lintAssemblyInstructions.ts'
|
|
57
|
+
import type {
|
|
58
|
+
GetStoredAssetReceiptOptions,
|
|
59
|
+
StoreAssetOptions,
|
|
60
|
+
StoredAssetReceipt,
|
|
61
|
+
} from './storageAsset.ts'
|
|
57
62
|
import type {
|
|
58
63
|
GetStoredImageReceiptOptions,
|
|
59
64
|
StoredImageReceipt,
|
|
@@ -108,6 +113,7 @@ import InconsistentResponseError from './InconsistentResponseError.ts'
|
|
|
108
113
|
import { lintAssemblyInstructions as lintAssemblyInstructionsInternal } from './lintAssemblyInstructions.ts'
|
|
109
114
|
import PaginationStream from './PaginationStream.ts'
|
|
110
115
|
import PollingTimeoutError from './PollingTimeoutError.ts'
|
|
116
|
+
import { getStoredAssetReceipt, storeAsset } from './storageAsset.ts'
|
|
111
117
|
import { getStoredImageReceipt, storeImage } from './storageImage.ts'
|
|
112
118
|
import {
|
|
113
119
|
normalizeStoragePublicPrefix,
|
|
@@ -151,6 +157,12 @@ export type {
|
|
|
151
157
|
RobotListResult,
|
|
152
158
|
RobotParamHelp,
|
|
153
159
|
} from './robots.ts'
|
|
160
|
+
export type {
|
|
161
|
+
GetStoredAssetReceiptOptions,
|
|
162
|
+
StoreAssetOptions,
|
|
163
|
+
StoredAssetExpectation,
|
|
164
|
+
StoredAssetReceipt,
|
|
165
|
+
} from './storageAsset.ts'
|
|
154
166
|
export type {
|
|
155
167
|
GetStoredImageReceiptOptions,
|
|
156
168
|
StoredImageExpectation,
|
|
@@ -573,6 +585,16 @@ export class Transloadit {
|
|
|
573
585
|
this._defaultTimeout = timeout
|
|
574
586
|
}
|
|
575
587
|
|
|
588
|
+
/** Stores one byte-identical local original of any media type and returns its verified receipt. */
|
|
589
|
+
storeAsset(filePath: string, options: StoreAssetOptions): Promise<StoredAssetReceipt> {
|
|
590
|
+
return storeAsset(this, filePath, options)
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/** Recovers a generic original receipt without uploading or accepting changed bytes. */
|
|
594
|
+
getStoredAssetReceipt(options: GetStoredAssetReceiptOptions): Promise<StoredAssetReceipt> {
|
|
595
|
+
return getStoredAssetReceipt(this, options)
|
|
596
|
+
}
|
|
597
|
+
|
|
576
598
|
/** Stores one local original at an explicit path and returns its verified image metadata. */
|
|
577
599
|
storeImage(filePath: string, options: StoreImageOptions): Promise<StoredImageReceipt> {
|
|
578
600
|
return storeImage(this, filePath, options)
|
package/src/bearerToken.ts
CHANGED
|
@@ -24,6 +24,8 @@ export type MintBearerTokenOptions = {
|
|
|
24
24
|
*/
|
|
25
25
|
scope?: string[] | string
|
|
26
26
|
timeoutMs?: number
|
|
27
|
+
/** Optional presentation of API refusals; omitted for the SDK's existing error strings. */
|
|
28
|
+
formatError?: (body: unknown, message: string) => string
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export type MintBearerTokenResult =
|
|
@@ -208,17 +210,13 @@ export async function mintBearerTokenWithCredentials(
|
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
const parsedError = tokenErrorSchema.safeParse(parsedJson)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
: parsedError.data.error,
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
213
|
+
const error = parsedError.success
|
|
214
|
+
? parsedError.data.message
|
|
215
|
+
? `${parsedError.data.error}: ${parsedError.data.message}`
|
|
216
|
+
: parsedError.data.error
|
|
217
|
+
: `Token request failed (${res.status}): ${trimmed || res.statusText}`
|
|
220
218
|
return {
|
|
221
219
|
ok: false,
|
|
222
|
-
error:
|
|
220
|
+
error: options.formatError?.(parsedJson, error) ?? error,
|
|
223
221
|
}
|
|
224
222
|
}
|
|
@@ -308,7 +308,7 @@ export async function lint(
|
|
|
308
308
|
})
|
|
309
309
|
}
|
|
310
310
|
} catch (error) {
|
|
311
|
-
output.error(
|
|
311
|
+
output.error(formatAPIError(error))
|
|
312
312
|
return 1
|
|
313
313
|
}
|
|
314
314
|
|
|
@@ -2098,7 +2098,10 @@ async function createWithLocalInputs(
|
|
|
2098
2098
|
})
|
|
2099
2099
|
} catch (err) {
|
|
2100
2100
|
const error = ensureError(err)
|
|
2101
|
-
const message =
|
|
2101
|
+
const message =
|
|
2102
|
+
error instanceof RequestError
|
|
2103
|
+
? formatAPIError(error)
|
|
2104
|
+
: formatAPIError(error, error.message)
|
|
2102
2105
|
throw new Error(`${message} (${assemblyReference})`, { cause: error })
|
|
2103
2106
|
}
|
|
2104
2107
|
|
|
@@ -2130,13 +2133,13 @@ async function createWithLocalInputs(
|
|
|
2130
2133
|
)
|
|
2131
2134
|
}
|
|
2132
2135
|
|
|
2133
|
-
//
|
|
2136
|
+
// Retain the response so final formatting can show its reason after bounding a long message.
|
|
2134
2137
|
if (assembly.error || (assembly.ok && assembly.ok !== 'ASSEMBLY_COMPLETED')) {
|
|
2135
2138
|
const details =
|
|
2136
2139
|
[summary.error ?? summary.ok, summary.message].filter(Boolean).join(': ') ||
|
|
2137
2140
|
'Unknown Assembly error'
|
|
2138
2141
|
const msg = `Assembly failed: ${details} (${assemblyReference})`
|
|
2139
|
-
throw new Error(msg)
|
|
2142
|
+
throw new Error(msg, { cause: assembly })
|
|
2140
2143
|
}
|
|
2141
2144
|
|
|
2142
2145
|
return { assembly, assemblyId }
|
package/src/cli/commands/auth.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { Transloadit } from '../../Transloadit.ts'
|
|
|
18
18
|
import {
|
|
19
19
|
buildMissingCredentialsMessage,
|
|
20
20
|
cliSignatureAlgorithmSchema,
|
|
21
|
+
formatAPIError,
|
|
21
22
|
readCliInput,
|
|
22
23
|
requireCliCredentials,
|
|
23
24
|
resolveCliConfig,
|
|
@@ -455,6 +456,7 @@ export class TokenCommand extends UnauthenticatedCommand {
|
|
|
455
456
|
endpoint: this.endpoint ?? resolved.config.credentialsEndpoint,
|
|
456
457
|
aud: this.aud,
|
|
457
458
|
scope: this.scope,
|
|
459
|
+
formatError: formatAPIError,
|
|
458
460
|
})
|
|
459
461
|
|
|
460
462
|
if (result.ok) {
|
|
@@ -5,7 +5,7 @@ import { validateStoragePathPrefix } from '@transloadit/utils'
|
|
|
5
5
|
import { Command, Option } from 'clipanion'
|
|
6
6
|
import { z } from 'zod'
|
|
7
7
|
|
|
8
|
-
import { noticeCliCredentialSource, resolveCliConfig } from '../helpers.ts'
|
|
8
|
+
import { formatAPIError, noticeCliCredentialSource, resolveCliConfig } from '../helpers.ts'
|
|
9
9
|
import { resolveStorageWorkspace } from '../storageCatalog.ts'
|
|
10
10
|
import { storagePublicError } from '../storagePublic.ts'
|
|
11
11
|
import {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
updateStorageReceipts,
|
|
18
18
|
} from '../storageReceipts.ts'
|
|
19
19
|
import { nextAppRoot, storageImageEnvBlock, storageImagePage } from '../storageSnippets.ts'
|
|
20
|
-
import {
|
|
20
|
+
import { isErrnoException } from '../types.ts'
|
|
21
21
|
import { UnauthenticatedCommand } from './BaseCommand.ts'
|
|
22
22
|
|
|
23
23
|
/** Scaffolds the Node-runtime Next.js integration without overwriting code or env files. */
|
|
@@ -274,7 +274,7 @@ export class ImageInitCommand extends UnauthenticatedCommand {
|
|
|
274
274
|
})
|
|
275
275
|
}
|
|
276
276
|
this.output.error(
|
|
277
|
-
`${
|
|
277
|
+
`${formatAPIError(error)}${published === undefined ? '' : ` The server prefix ${published} remains public; use storage unpublish deliberately if needed.`}`,
|
|
278
278
|
)
|
|
279
279
|
return 1
|
|
280
280
|
}
|
|
@@ -8,17 +8,19 @@ import { Command, Option } from 'clipanion'
|
|
|
8
8
|
import { parse } from 'dotenv'
|
|
9
9
|
import { z } from 'zod'
|
|
10
10
|
|
|
11
|
+
import { tryCatch } from '../../alphalib/tryCatch.ts'
|
|
11
12
|
import { Transloadit } from '../../Transloadit.ts'
|
|
12
13
|
import { deviceLogin } from '../deviceLogin.ts'
|
|
13
14
|
import {
|
|
14
15
|
cliSignatureAlgorithmSchema,
|
|
16
|
+
formatAPIError,
|
|
15
17
|
getConfiguredCredentialsFilePath,
|
|
16
18
|
parseCliLoginSnapshot,
|
|
17
19
|
readCliInput,
|
|
18
20
|
resolveCliConfig,
|
|
19
21
|
} from '../helpers.ts'
|
|
20
22
|
import { quoteCredential } from '../secretInput.ts'
|
|
21
|
-
import {
|
|
23
|
+
import { isErrnoException } from '../types.ts'
|
|
22
24
|
import { UnauthenticatedCommand } from './BaseCommand.ts'
|
|
23
25
|
|
|
24
26
|
const credentialSchema = z
|
|
@@ -185,17 +187,14 @@ export class AuthLoginCommand extends UnauthenticatedCommand {
|
|
|
185
187
|
}
|
|
186
188
|
// A signed read checks dam:write access and catalog readiness without publishing anything.
|
|
187
189
|
// It does not prove that the worker's object store can accept a later upload.
|
|
188
|
-
const
|
|
190
|
+
const storageClient = new Transloadit({
|
|
189
191
|
...credentials,
|
|
190
192
|
endpoint: origin,
|
|
191
193
|
maxRetries: 0,
|
|
192
194
|
timeout: 10_000,
|
|
193
195
|
})
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
() => true,
|
|
197
|
-
() => false,
|
|
198
|
-
)
|
|
196
|
+
const [storagePolicyError] = await tryCatch(storageClient.listPublicStoragePrefixes())
|
|
197
|
+
const storagePolicyAccess = storagePolicyError === null
|
|
199
198
|
if (!storagePolicyAccess) {
|
|
200
199
|
const workspace =
|
|
201
200
|
credentials.workspace !== undefined &&
|
|
@@ -203,7 +202,10 @@ export class AuthLoginCommand extends UnauthenticatedCommand {
|
|
|
203
202
|
? credentials.workspace
|
|
204
203
|
: '<workspace>'
|
|
205
204
|
this.output.warn(
|
|
206
|
-
|
|
205
|
+
formatAPIError(
|
|
206
|
+
storagePolicyError,
|
|
207
|
+
`Login saved, but Storage policy access could not be verified. Before uploading, check Storage availability and the Auth Key dam:write scope at https://transloadit.com/c/${workspace}/template-credentials/. A temporary network failure can also prevent this check; retry with transloadit storage publications.`,
|
|
208
|
+
),
|
|
207
209
|
)
|
|
208
210
|
}
|
|
209
211
|
const message =
|
|
@@ -231,7 +233,7 @@ export class AuthLoginCommand extends UnauthenticatedCommand {
|
|
|
231
233
|
: `Review it in Console → Credentials: https://transloadit.com/c/${loginWorkspace ?? '<workspace>'}/template-credentials/; revoke it there if no longer needed.`,
|
|
232
234
|
'Be careful: auth logout would use the saved login, not this unsaved one.',
|
|
233
235
|
].join('\n')
|
|
234
|
-
:
|
|
236
|
+
: formatAPIError(error),
|
|
235
237
|
)
|
|
236
238
|
return 1
|
|
237
239
|
} finally {
|
|
@@ -365,7 +367,7 @@ export class AuthLogoutCommand extends UnauthenticatedCommand {
|
|
|
365
367
|
this.output.error(
|
|
366
368
|
isErrnoException(error) && error.code === 'ENOENT'
|
|
367
369
|
? 'Not logged in; no saved credentials file.'
|
|
368
|
-
:
|
|
370
|
+
: formatAPIError(error),
|
|
369
371
|
)
|
|
370
372
|
return 1
|
|
371
373
|
}
|
|
@@ -4,7 +4,7 @@ import type { IOutputCtl } from '../OutputCtl.ts'
|
|
|
4
4
|
import { Command, Option } from 'clipanion'
|
|
5
5
|
|
|
6
6
|
import { tryCatch } from '../../alphalib/tryCatch.ts'
|
|
7
|
-
import {
|
|
7
|
+
import { formatAPIError } from '../helpers.ts'
|
|
8
8
|
import { AuthenticatedCommand } from './BaseCommand.ts'
|
|
9
9
|
|
|
10
10
|
// --- Types and business logic ---
|
|
@@ -22,7 +22,7 @@ async function replay(
|
|
|
22
22
|
const promises = assemblies.map((id) => client.replayAssemblyNotification(id, { notify_url }))
|
|
23
23
|
const [err] = await tryCatch(Promise.all(promises))
|
|
24
24
|
if (err) {
|
|
25
|
-
output.error(
|
|
25
|
+
output.error(formatAPIError(err))
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|