transloadit 5.0.0 → 5.0.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 +6 -3
- package/dist/alphalib/types/storageResults.d.ts +29 -0
- package/dist/alphalib/types/storageResults.d.ts.map +1 -0
- package/dist/alphalib/types/storageResults.js +53 -0
- package/dist/alphalib/types/storageResults.js.map +1 -0
- package/dist/storageResults.d.ts +2 -13
- package/dist/storageResults.d.ts.map +1 -1
- package/dist/storageResults.js +9 -34
- package/dist/storageResults.js.map +1 -1
- package/package.json +1 -1
- package/src/alphalib/types/storageResults.ts +75 -0
- package/src/storageResults.ts +19 -56
package/README.md
CHANGED
|
@@ -108,9 +108,9 @@ Most commands can authenticate with either `TRANSLOADIT_AUTH_TOKEN` or `TRANSLOA
|
|
|
108
108
|
|
|
109
109
|
### Storage images for Next.js
|
|
110
110
|
|
|
111
|
-
`@transloadit/viewer` is
|
|
112
|
-
[
|
|
113
|
-
|
|
111
|
+
`@transloadit/viewer` is a published alpha. Follow the
|
|
112
|
+
[Viewer Quickstart](https://github.com/transloadit/node-sdk/blob/main/packages/img/README.md)
|
|
113
|
+
to install it. In a Next.js 16.3.3+ App Router project with Storage enabled, run:
|
|
114
114
|
|
|
115
115
|
```bash
|
|
116
116
|
yarn transloadit auth login
|
|
@@ -143,6 +143,9 @@ Images are never decoded locally. Add `--placeholder blur` to request a server T
|
|
|
143
143
|
omission or `--placeholder empty` performs no extraction. Successful extraction adds metadata
|
|
144
144
|
usage equal to 20% of the file's bytes. Viewer's separate `placeholder="blur"` opts into rendering.
|
|
145
145
|
Extraction is best-effort: a missing hash does not fail the upload or trigger another one.
|
|
146
|
+
For live user-upload galleries, use [dynamic React receipts](https://github.com/transloadit/node-sdk/blob/main/packages/img/docs/react-storage.md)
|
|
147
|
+
instead of a committed catalog. Authorize preview access before returning a receipt's ThumbHash;
|
|
148
|
+
the hash contains recognizable image data.
|
|
146
149
|
An occupied path conflicts unless `--overwrite` is explicit; prefer `--hashed` for immutable
|
|
147
150
|
filenames. Matching receipts skip repeat uploads; changed bytes get a new name.
|
|
148
151
|
Storage receipts pin the returned `asset_id` and `version_id`. The image URL selects that exact
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { StoredAsset } from './storageAsset.ts';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/** Server-owned Assembly identity and expected Workspace, never untrusted notification fields. */
|
|
4
|
+
export declare const storedAssemblyResultsOptionsSchema: z.ZodObject<{
|
|
5
|
+
assemblyId: z.ZodString;
|
|
6
|
+
workspace: z.ZodString;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
workspace: string;
|
|
9
|
+
assemblyId: string;
|
|
10
|
+
}, {
|
|
11
|
+
workspace: string;
|
|
12
|
+
assemblyId: string;
|
|
13
|
+
}>;
|
|
14
|
+
export type GetStoredAssemblyResultsOptions = z.infer<typeof storedAssemblyResultsOptionsSchema>;
|
|
15
|
+
/** Canonical retained receipt and producing result provenance, for idempotent registration. */
|
|
16
|
+
export interface StoredAssemblyResult {
|
|
17
|
+
assembly_id: string;
|
|
18
|
+
step: string;
|
|
19
|
+
result_id: string;
|
|
20
|
+
original_id?: string | (string | null)[];
|
|
21
|
+
asset: StoredAsset;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Pure extraction from a fetched/verified Assembly bound to an authorized app upload. Validates
|
|
25
|
+
* every retained result atomically; temporary outputs are ignored, partial receipts are rejected.
|
|
26
|
+
* This does not authenticate notifications or check application permissions.
|
|
27
|
+
*/
|
|
28
|
+
export declare function extractStoredAssemblyResults(input: unknown, options: GetStoredAssemblyResultsOptions): StoredAssemblyResult[];
|
|
29
|
+
//# sourceMappingURL=storageResults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storageResults.d.ts","sourceRoot":"","sources":["../../../src/alphalib/types/storageResults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAOvB,kGAAkG;AAClG,eAAO,MAAM,kCAAkC;;;;;;;;;EAG7C,CAAA;AAEF,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAA;AAEhG,+FAA+F;AAC/F,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;IACxC,KAAK,EAAE,WAAW,CAAA;CACnB;AAaD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,+BAA+B,GACvC,oBAAoB,EAAE,CA6BxB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { storedAssetSchema } from "./storageAsset.js";
|
|
3
|
+
// SDK-owned extraction is outside alphalib-sync's explicit node-sdk syncIncludes. Co-location
|
|
4
|
+
// reuses canonical schemas and their Types/Zod generation without adding a runtime package.
|
|
5
|
+
/** Server-owned Assembly identity and expected Workspace, never untrusted notification fields. */
|
|
6
|
+
export const storedAssemblyResultsOptionsSchema = z.object({
|
|
7
|
+
assemblyId: z.string().regex(/^[A-Za-z0-9_-]+$/),
|
|
8
|
+
workspace: z.string().min(1),
|
|
9
|
+
});
|
|
10
|
+
const resultSchema = storedAssetSchema.extend({
|
|
11
|
+
id: z.string().min(1),
|
|
12
|
+
original_id: z.union([z.string(), z.array(z.string().nullable())]).optional(),
|
|
13
|
+
});
|
|
14
|
+
const assemblySchema = z.object({
|
|
15
|
+
assembly_id: z.string(),
|
|
16
|
+
ok: z.string().nullable().optional(),
|
|
17
|
+
error: z.string().optional(),
|
|
18
|
+
results: z.record(z.array(z.record(z.unknown()))).optional(),
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Pure extraction from a fetched/verified Assembly bound to an authorized app upload. Validates
|
|
22
|
+
* every retained result atomically; temporary outputs are ignored, partial receipts are rejected.
|
|
23
|
+
* This does not authenticate notifications or check application permissions.
|
|
24
|
+
*/
|
|
25
|
+
export function extractStoredAssemblyResults(input, options) {
|
|
26
|
+
const { assemblyId, workspace } = storedAssemblyResultsOptionsSchema.parse(options);
|
|
27
|
+
const assembly = assemblySchema.parse(input);
|
|
28
|
+
if (assembly.assembly_id !== assemblyId)
|
|
29
|
+
throw new Error('The response did not match the requested Assembly');
|
|
30
|
+
if (assembly.error !== undefined || assembly.ok !== 'ASSEMBLY_COMPLETED')
|
|
31
|
+
throw new Error(`The Storage Assembly is not complete (${assembly.error ?? assembly.ok})`);
|
|
32
|
+
if (assembly.results === undefined)
|
|
33
|
+
throw new Error('The completed Assembly did not contain results');
|
|
34
|
+
const results = [];
|
|
35
|
+
for (const [step, files] of Object.entries(assembly.results)) {
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
if (file.asset_id === undefined &&
|
|
38
|
+
file.version_id === undefined &&
|
|
39
|
+
file.workspace === undefined)
|
|
40
|
+
continue;
|
|
41
|
+
const parsed = resultSchema.safeParse(file);
|
|
42
|
+
if (!parsed.success || parsed.data.workspace !== workspace) {
|
|
43
|
+
throw new Error('The Assembly returned an invalid or cross-Workspace Storage result', {
|
|
44
|
+
cause: { assemblyId, step },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const { id, original_id, ...asset } = parsed.data;
|
|
48
|
+
results.push({ assembly_id: assemblyId, step, result_id: id, original_id, asset });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return results;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=storageResults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storageResults.js","sourceRoot":"","sources":["../../../src/alphalib/types/storageResults.ts"],"names":[],"mappings":"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"}
|
package/dist/storageResults.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { StoredAsset } from './alphalib/types/storageAsset.ts';
|
|
2
|
+
import type { GetStoredAssemblyResultsOptions, StoredAssemblyResult } from './alphalib/types/storageResults.ts';
|
|
2
3
|
import type { Transloadit } from './Transloadit.ts';
|
|
3
4
|
/** Original-byte delivery, not a preview or transcode; authorize the application's asset first. */
|
|
4
5
|
export interface StoredAssetUrlOptions {
|
|
@@ -9,19 +10,7 @@ export interface StoredAssetUrlOptions {
|
|
|
9
10
|
}
|
|
10
11
|
/** Signs a retained original, including non-image media, without fetching or proxying its bytes. */
|
|
11
12
|
export declare function getStoredAssetUrl(client: Transloadit, input: StoredAsset, options?: StoredAssetUrlOptions): string;
|
|
12
|
-
|
|
13
|
-
export interface GetStoredAssemblyResultsOptions {
|
|
14
|
-
assemblyId: string;
|
|
15
|
-
workspace: string;
|
|
16
|
-
}
|
|
17
|
-
/** A canonical stored asset with the producing result's provenance; one input can have many outputs. */
|
|
18
|
-
export interface StoredAssemblyResult {
|
|
19
|
-
assembly_id: string;
|
|
20
|
-
step: string;
|
|
21
|
-
result_id: string;
|
|
22
|
-
original_id?: string | (string | null)[];
|
|
23
|
-
asset: StoredAsset;
|
|
24
|
-
}
|
|
13
|
+
export type { GetStoredAssemblyResultsOptions, StoredAssemblyResult, } from './alphalib/types/storageResults.ts';
|
|
25
14
|
/**
|
|
26
15
|
* Fetches a completed Assembly and verifies all retained results, including non-image media.
|
|
27
16
|
* The caller must first bind the Assembly to an authorized application upload. Register results
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageResults.d.ts","sourceRoot":"","sources":["../src/storageResults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"storageResults.d.ts","sourceRoot":"","sources":["../src/storageResults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EACV,+BAA+B,EAC/B,oBAAoB,EACrB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAWnD,mGAAmG;AACnG,MAAM,WAAW,qBAAqB;IACpC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC3B,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,qBAA0B,GAClC,MAAM,CAuBR;AAED,YAAY,EACV,+BAA+B,EAC/B,oBAAoB,GACrB,MAAM,oCAAoC,CAAA;AAE3C;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAcjC"}
|
package/dist/storageResults.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import { ApiError } from "./ApiError.js";
|
|
3
2
|
import { robotFileServeInstructionsSchema } from "./alphalib/types/robots/file-serve.js";
|
|
4
3
|
import { storedAssetSchema } from "./alphalib/types/storageAsset.js";
|
|
4
|
+
import { extractStoredAssemblyResults, storedAssemblyResultsOptionsSchema, } from "./alphalib/types/storageResults.js";
|
|
5
5
|
import InconsistentResponseError from "./InconsistentResponseError.js";
|
|
6
6
|
/** Signs a retained original, including non-image media, without fetching or proxying its bytes. */
|
|
7
7
|
export function getStoredAssetUrl(client, input, options = {}) {
|
|
@@ -28,52 +28,27 @@ export function getStoredAssetUrl(client, input, options = {}) {
|
|
|
28
28
|
expiresAt,
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
const requestSchema = z.object({
|
|
32
|
-
assemblyId: z.string().regex(/^[A-Za-z0-9_-]+$/),
|
|
33
|
-
workspace: z.string().min(1),
|
|
34
|
-
});
|
|
35
|
-
const resultSchema = storedAssetSchema.extend({
|
|
36
|
-
id: z.string().min(1),
|
|
37
|
-
original_id: z.union([z.string(), z.array(z.string().nullable())]).optional(),
|
|
38
|
-
});
|
|
39
31
|
/**
|
|
40
32
|
* Fetches a completed Assembly and verifies all retained results, including non-image media.
|
|
41
33
|
* The caller must first bind the Assembly to an authorized application upload. Register results
|
|
42
34
|
* idempotently by Assembly/step/result ID (or asset/version), not by filename or notification count.
|
|
43
35
|
*/
|
|
44
36
|
export async function getStoredAssemblyResults(client, options) {
|
|
45
|
-
const { assemblyId, workspace } =
|
|
37
|
+
const { assemblyId, workspace } = storedAssemblyResultsOptionsSchema.parse(options);
|
|
46
38
|
const assembly = await client.getAssembly(assemblyId);
|
|
47
39
|
if (assembly.assembly_id !== assemblyId) {
|
|
48
40
|
throw new InconsistentResponseError('The response did not match the requested Assembly');
|
|
49
41
|
}
|
|
50
42
|
if (typeof assembly.error === 'string')
|
|
51
43
|
throw new ApiError({ body: assembly });
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
try {
|
|
45
|
+
return extractStoredAssemblyResults(assembly, { assemblyId, workspace });
|
|
54
46
|
}
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
catch (error) {
|
|
48
|
+
// Keep the Node SDK error contract while sharing strict extraction with Web runtimes.
|
|
49
|
+
if (!(error instanceof Error))
|
|
50
|
+
throw new Error('Invalid Assembly response', { cause: error });
|
|
51
|
+
throw new InconsistentResponseError(error.message, { cause: error.cause ?? error });
|
|
57
52
|
}
|
|
58
|
-
const results = [];
|
|
59
|
-
for (const [step, files] of Object.entries(assembly.results)) {
|
|
60
|
-
for (const file of files) {
|
|
61
|
-
// Ordinary temporary/exported outputs are not Storage receipts. Partial Storage records
|
|
62
|
-
// must fail validation rather than disappearing from an otherwise successful batch.
|
|
63
|
-
if (file.asset_id === undefined &&
|
|
64
|
-
file.version_id === undefined &&
|
|
65
|
-
file.workspace === undefined)
|
|
66
|
-
continue;
|
|
67
|
-
const parsed = resultSchema.safeParse(file);
|
|
68
|
-
if (!parsed.success || parsed.data.workspace !== workspace) {
|
|
69
|
-
throw new InconsistentResponseError('The Assembly returned an invalid or cross-Workspace Storage result', {
|
|
70
|
-
cause: { assemblyId, step },
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
const { id, original_id, ...asset } = parsed.data;
|
|
74
|
-
results.push({ assembly_id: assemblyId, step, result_id: id, original_id, asset });
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return results;
|
|
78
53
|
}
|
|
79
54
|
//# sourceMappingURL=storageResults.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageResults.js","sourceRoot":"","sources":["../src/storageResults.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storageResults.js","sourceRoot":"","sources":["../src/storageResults.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { StoredAsset } from './storageAsset.ts'
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
import { storedAssetSchema } from './storageAsset.ts'
|
|
6
|
+
|
|
7
|
+
// SDK-owned extraction is outside alphalib-sync's explicit node-sdk syncIncludes. Co-location
|
|
8
|
+
// reuses canonical schemas and their Types/Zod generation without adding a runtime package.
|
|
9
|
+
|
|
10
|
+
/** Server-owned Assembly identity and expected Workspace, never untrusted notification fields. */
|
|
11
|
+
export const storedAssemblyResultsOptionsSchema = z.object({
|
|
12
|
+
assemblyId: z.string().regex(/^[A-Za-z0-9_-]+$/),
|
|
13
|
+
workspace: z.string().min(1),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export type GetStoredAssemblyResultsOptions = z.infer<typeof storedAssemblyResultsOptionsSchema>
|
|
17
|
+
|
|
18
|
+
/** Canonical retained receipt and producing result provenance, for idempotent registration. */
|
|
19
|
+
export interface StoredAssemblyResult {
|
|
20
|
+
assembly_id: string
|
|
21
|
+
step: string
|
|
22
|
+
result_id: string
|
|
23
|
+
original_id?: string | (string | null)[]
|
|
24
|
+
asset: StoredAsset
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const resultSchema = storedAssetSchema.extend({
|
|
28
|
+
id: z.string().min(1),
|
|
29
|
+
original_id: z.union([z.string(), z.array(z.string().nullable())]).optional(),
|
|
30
|
+
})
|
|
31
|
+
const assemblySchema = z.object({
|
|
32
|
+
assembly_id: z.string(),
|
|
33
|
+
ok: z.string().nullable().optional(),
|
|
34
|
+
error: z.string().optional(),
|
|
35
|
+
results: z.record(z.array(z.record(z.unknown()))).optional(),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pure extraction from a fetched/verified Assembly bound to an authorized app upload. Validates
|
|
40
|
+
* every retained result atomically; temporary outputs are ignored, partial receipts are rejected.
|
|
41
|
+
* This does not authenticate notifications or check application permissions.
|
|
42
|
+
*/
|
|
43
|
+
export function extractStoredAssemblyResults(
|
|
44
|
+
input: unknown,
|
|
45
|
+
options: GetStoredAssemblyResultsOptions,
|
|
46
|
+
): StoredAssemblyResult[] {
|
|
47
|
+
const { assemblyId, workspace } = storedAssemblyResultsOptionsSchema.parse(options)
|
|
48
|
+
const assembly = assemblySchema.parse(input)
|
|
49
|
+
if (assembly.assembly_id !== assemblyId)
|
|
50
|
+
throw new Error('The response did not match the requested Assembly')
|
|
51
|
+
if (assembly.error !== undefined || assembly.ok !== 'ASSEMBLY_COMPLETED')
|
|
52
|
+
throw new Error(`The Storage Assembly is not complete (${assembly.error ?? assembly.ok})`)
|
|
53
|
+
if (assembly.results === undefined)
|
|
54
|
+
throw new Error('The completed Assembly did not contain results')
|
|
55
|
+
const results: StoredAssemblyResult[] = []
|
|
56
|
+
for (const [step, files] of Object.entries(assembly.results)) {
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
if (
|
|
59
|
+
file.asset_id === undefined &&
|
|
60
|
+
file.version_id === undefined &&
|
|
61
|
+
file.workspace === undefined
|
|
62
|
+
)
|
|
63
|
+
continue
|
|
64
|
+
const parsed = resultSchema.safeParse(file)
|
|
65
|
+
if (!parsed.success || parsed.data.workspace !== workspace) {
|
|
66
|
+
throw new Error('The Assembly returned an invalid or cross-Workspace Storage result', {
|
|
67
|
+
cause: { assemblyId, step },
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
const { id, original_id, ...asset } = parsed.data
|
|
71
|
+
results.push({ assembly_id: assemblyId, step, result_id: id, original_id, asset })
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return results
|
|
75
|
+
}
|
package/src/storageResults.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { StoredAsset } from './alphalib/types/storageAsset.ts'
|
|
2
|
+
import type {
|
|
3
|
+
GetStoredAssemblyResultsOptions,
|
|
4
|
+
StoredAssemblyResult,
|
|
5
|
+
} from './alphalib/types/storageResults.ts'
|
|
2
6
|
import type { Transloadit } from './Transloadit.ts'
|
|
3
7
|
|
|
4
|
-
import { z } from 'zod'
|
|
5
|
-
|
|
6
8
|
import { ApiError } from './ApiError.ts'
|
|
7
9
|
import { robotFileServeInstructionsSchema } from './alphalib/types/robots/file-serve.ts'
|
|
8
10
|
import { storedAssetSchema } from './alphalib/types/storageAsset.ts'
|
|
11
|
+
import {
|
|
12
|
+
extractStoredAssemblyResults,
|
|
13
|
+
storedAssemblyResultsOptionsSchema,
|
|
14
|
+
} from './alphalib/types/storageResults.ts'
|
|
9
15
|
import InconsistentResponseError from './InconsistentResponseError.ts'
|
|
10
16
|
|
|
11
17
|
/** Original-byte delivery, not a preview or transcode; authorize the application's asset first. */
|
|
@@ -46,29 +52,10 @@ export function getStoredAssetUrl(
|
|
|
46
52
|
})
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** A canonical stored asset with the producing result's provenance; one input can have many outputs. */
|
|
56
|
-
export interface StoredAssemblyResult {
|
|
57
|
-
assembly_id: string
|
|
58
|
-
step: string
|
|
59
|
-
result_id: string
|
|
60
|
-
original_id?: string | (string | null)[]
|
|
61
|
-
asset: StoredAsset
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const requestSchema = z.object({
|
|
65
|
-
assemblyId: z.string().regex(/^[A-Za-z0-9_-]+$/),
|
|
66
|
-
workspace: z.string().min(1),
|
|
67
|
-
})
|
|
68
|
-
const resultSchema = storedAssetSchema.extend({
|
|
69
|
-
id: z.string().min(1),
|
|
70
|
-
original_id: z.union([z.string(), z.array(z.string().nullable())]).optional(),
|
|
71
|
-
})
|
|
55
|
+
export type {
|
|
56
|
+
GetStoredAssemblyResultsOptions,
|
|
57
|
+
StoredAssemblyResult,
|
|
58
|
+
} from './alphalib/types/storageResults.ts'
|
|
72
59
|
|
|
73
60
|
/**
|
|
74
61
|
* Fetches a completed Assembly and verifies all retained results, including non-image media.
|
|
@@ -79,41 +66,17 @@ export async function getStoredAssemblyResults(
|
|
|
79
66
|
client: Transloadit,
|
|
80
67
|
options: GetStoredAssemblyResultsOptions,
|
|
81
68
|
): Promise<StoredAssemblyResult[]> {
|
|
82
|
-
const { assemblyId, workspace } =
|
|
69
|
+
const { assemblyId, workspace } = storedAssemblyResultsOptionsSchema.parse(options)
|
|
83
70
|
const assembly = await client.getAssembly(assemblyId)
|
|
84
71
|
if (assembly.assembly_id !== assemblyId) {
|
|
85
72
|
throw new InconsistentResponseError('The response did not match the requested Assembly')
|
|
86
73
|
}
|
|
87
74
|
if (typeof assembly.error === 'string') throw new ApiError({ body: assembly })
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
throw new
|
|
93
|
-
|
|
94
|
-
const results: StoredAssemblyResult[] = []
|
|
95
|
-
for (const [step, files] of Object.entries(assembly.results)) {
|
|
96
|
-
for (const file of files) {
|
|
97
|
-
// Ordinary temporary/exported outputs are not Storage receipts. Partial Storage records
|
|
98
|
-
// must fail validation rather than disappearing from an otherwise successful batch.
|
|
99
|
-
if (
|
|
100
|
-
file.asset_id === undefined &&
|
|
101
|
-
file.version_id === undefined &&
|
|
102
|
-
file.workspace === undefined
|
|
103
|
-
)
|
|
104
|
-
continue
|
|
105
|
-
const parsed = resultSchema.safeParse(file)
|
|
106
|
-
if (!parsed.success || parsed.data.workspace !== workspace) {
|
|
107
|
-
throw new InconsistentResponseError(
|
|
108
|
-
'The Assembly returned an invalid or cross-Workspace Storage result',
|
|
109
|
-
{
|
|
110
|
-
cause: { assemblyId, step },
|
|
111
|
-
},
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
const { id, original_id, ...asset } = parsed.data
|
|
115
|
-
results.push({ assembly_id: assemblyId, step, result_id: id, original_id, asset })
|
|
116
|
-
}
|
|
75
|
+
try {
|
|
76
|
+
return extractStoredAssemblyResults(assembly, { assemblyId, workspace })
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// Keep the Node SDK error contract while sharing strict extraction with Web runtimes.
|
|
79
|
+
if (!(error instanceof Error)) throw new Error('Invalid Assembly response', { cause: error })
|
|
80
|
+
throw new InconsistentResponseError(error.message, { cause: error.cause ?? error })
|
|
117
81
|
}
|
|
118
|
-
return results
|
|
119
82
|
}
|