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.
Files changed (67) hide show
  1. package/README.md +73 -8
  2. package/dist/Transloadit.d.ts +6 -0
  3. package/dist/Transloadit.d.ts.map +1 -1
  4. package/dist/Transloadit.js +9 -0
  5. package/dist/Transloadit.js.map +1 -1
  6. package/dist/bearerToken.d.ts +2 -0
  7. package/dist/bearerToken.d.ts.map +1 -1
  8. package/dist/bearerToken.js +6 -9
  9. package/dist/bearerToken.js.map +1 -1
  10. package/dist/cli/commands/assemblies.d.ts.map +1 -1
  11. package/dist/cli/commands/assemblies.js +6 -4
  12. package/dist/cli/commands/assemblies.js.map +1 -1
  13. package/dist/cli/commands/auth.d.ts.map +1 -1
  14. package/dist/cli/commands/auth.js +2 -1
  15. package/dist/cli/commands/auth.js.map +1 -1
  16. package/dist/cli/commands/image.js +3 -3
  17. package/dist/cli/commands/image.js.map +1 -1
  18. package/dist/cli/commands/login.d.ts.map +1 -1
  19. package/dist/cli/commands/login.js +10 -9
  20. package/dist/cli/commands/login.js.map +1 -1
  21. package/dist/cli/commands/notifications.js +2 -2
  22. package/dist/cli/commands/notifications.js.map +1 -1
  23. package/dist/cli/commands/storage.d.ts.map +1 -1
  24. package/dist/cli/commands/storage.js +120 -47
  25. package/dist/cli/commands/storage.js.map +1 -1
  26. package/dist/cli/commands/upload.d.ts.map +1 -1
  27. package/dist/cli/commands/upload.js +2 -1
  28. package/dist/cli/commands/upload.js.map +1 -1
  29. package/dist/cli/deviceLogin.d.ts.map +1 -1
  30. package/dist/cli/deviceLogin.js +3 -3
  31. package/dist/cli/deviceLogin.js.map +1 -1
  32. package/dist/cli/helpers.d.ts +2 -1
  33. package/dist/cli/helpers.d.ts.map +1 -1
  34. package/dist/cli/helpers.js +26 -1
  35. package/dist/cli/helpers.js.map +1 -1
  36. package/dist/cli/storagePublic.d.ts +1 -1
  37. package/dist/cli/storagePublic.d.ts.map +1 -1
  38. package/dist/cli/storagePublic.js +5 -4
  39. package/dist/cli/storagePublic.js.map +1 -1
  40. package/dist/cli/storageReceipts.d.ts +80 -1
  41. package/dist/cli/storageReceipts.d.ts.map +1 -1
  42. package/dist/cli/storageReceipts.js +48 -12
  43. package/dist/cli/storageReceipts.js.map +1 -1
  44. package/dist/storageAsset.d.ts +44 -0
  45. package/dist/storageAsset.d.ts.map +1 -0
  46. package/dist/storageAsset.js +173 -0
  47. package/dist/storageAsset.js.map +1 -0
  48. package/dist/storageImage.d.ts +11 -35
  49. package/dist/storageImage.d.ts.map +1 -1
  50. package/dist/storageImage.js +21 -141
  51. package/dist/storageImage.js.map +1 -1
  52. package/package.json +2 -2
  53. package/src/Transloadit.ts +22 -0
  54. package/src/bearerToken.ts +8 -10
  55. package/src/cli/commands/assemblies.ts +7 -4
  56. package/src/cli/commands/auth.ts +2 -0
  57. package/src/cli/commands/image.ts +3 -3
  58. package/src/cli/commands/login.ts +12 -10
  59. package/src/cli/commands/notifications.ts +2 -2
  60. package/src/cli/commands/storage.ts +160 -78
  61. package/src/cli/commands/upload.ts +2 -1
  62. package/src/cli/deviceLogin.ts +3 -2
  63. package/src/cli/helpers.ts +31 -1
  64. package/src/cli/storagePublic.ts +11 -4
  65. package/src/cli/storageReceipts.ts +50 -11
  66. package/src/storageAsset.ts +271 -0
  67. package/src/storageImage.ts +43 -201
@@ -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
- /** Shared SDK/CLI opt-in for server extraction; rendering remains a separate choice. */
9
- export const storageImagePlaceholderSchema = z.enum(['blur', 'empty']);
10
- const positiveIntegerSchema = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
11
- const receiptRequestSchema = z.object({
12
- assemblyId: z.string().regex(/^[A-Za-z0-9_-]+$/),
13
- expected: z.object({
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
- const completedImageSchema = z.object({
20
- ok: z.literal('ASSEMBLY_COMPLETED'),
21
- results: z.object({
22
- ':original': z.tuple([
23
- storedAssetSchema.extend({
24
- md5hash: storedAssetSchema.shape.md5hash.unwrap(),
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
- /** Stores one original without overwriting; receipt validation occurs after the Storage write. */
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 { path, chunkSize, onAssemblyProgress, onUploadProgress, onReceipt, overwrite, signal, timeout, } = options;
46
- validateDestination(path);
47
- const placeholder = storageImagePlaceholderSchema.optional().parse(options.placeholder, {
48
- path: ['placeholder'],
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
- /** Fetches authoritative Assembly status and applies the same validation as a local image store. */
28
+ /** Recovers one image receipt with the same strict byte checks as generic receipt recovery. */
106
29
  export async function getStoredImageReceipt(client, options) {
107
- const { assemblyId, expected } = receiptRequestSchema.parse(options);
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
@@ -1 +1 @@
1
- {"version":3,"file":"storageImage.js","sourceRoot":"","sources":["../src/storageImage.ts"],"names":[],"mappings":"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"}
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.8.0",
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.10.0",
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",
@@ -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)
@@ -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
- if (parsedError.success) {
212
- return {
213
- ok: false,
214
- error: parsedError.data.message
215
- ? `${parsedError.data.error}: ${parsedError.data.message}`
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: `Token request failed (${res.status}): ${trimmed || res.statusText}`,
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(ensureError(error).message)
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 = error instanceof RequestError ? formatAPIError(error) : error.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
- // Malformed error fields still signal failure, but only sanitized values enter the message.
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 }
@@ -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 { ensureError, isErrnoException } from '../types.ts'
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
- `${ensureError(error).message}${published === undefined ? '' : ` The server prefix ${published} remains public; use storage unpublish deliberately if needed.`}`,
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 { ensureError, isErrnoException } from '../types.ts'
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 storagePolicyAccess = await new Transloadit({
190
+ const storageClient = new Transloadit({
189
191
  ...credentials,
190
192
  endpoint: origin,
191
193
  maxRetries: 0,
192
194
  timeout: 10_000,
193
195
  })
194
- .listPublicStoragePrefixes()
195
- .then(
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
- `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.`,
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
- : ensureError(error).message,
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
- : ensureError(error).message,
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 { ensureError } from '../types.ts'
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(ensureError(err).message)
25
+ output.error(formatAPIError(err))
26
26
  }
27
27
  }
28
28