@anvilkit/plugin-asset-manager 0.1.8 → 0.1.10
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 +96 -3
- package/dist/adapters/data-url.d.cts +1 -0
- package/dist/adapters/data-url.d.cts.map +1 -1
- package/dist/adapters/data-url.d.ts +1 -0
- package/dist/adapters/data-url.d.ts.map +1 -1
- package/dist/adapters/s3-multipart.cjs +425 -0
- package/dist/adapters/s3-multipart.d.cts +43 -0
- package/dist/adapters/s3-multipart.d.cts.map +1 -0
- package/dist/adapters/s3-multipart.d.ts +43 -0
- package/dist/adapters/s3-multipart.d.ts.map +1 -0
- package/dist/adapters/s3-multipart.js +387 -0
- package/dist/adapters/s3-presigned.d.cts +2 -0
- package/dist/adapters/s3-presigned.d.cts.map +1 -1
- package/dist/adapters/s3-presigned.d.ts +2 -0
- package/dist/adapters/s3-presigned.d.ts.map +1 -1
- package/dist/i18n/provider.d.cts +1 -0
- package/dist/i18n/provider.d.cts.map +1 -1
- package/dist/i18n/provider.d.ts +1 -0
- package/dist/i18n/provider.d.ts.map +1 -1
- package/dist/index.cjs +14 -0
- package/dist/index.d.cts +9 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/plugin.cjs +152 -12
- package/dist/plugin.d.cts +49 -1
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.ts +49 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +147 -13
- package/dist/sources/composite-source.cjs +3 -0
- package/dist/sources/composite-source.d.cts.map +1 -1
- package/dist/sources/composite-source.d.ts.map +1 -1
- package/dist/sources/composite-source.js +3 -0
- package/dist/sources/federated-search.cjs +45 -7
- package/dist/sources/federated-search.d.cts.map +1 -1
- package/dist/sources/federated-search.d.ts.map +1 -1
- package/dist/sources/federated-search.js +45 -7
- package/dist/sources/provider.d.cts +5 -0
- package/dist/sources/provider.d.cts.map +1 -1
- package/dist/sources/provider.d.ts +5 -0
- package/dist/sources/provider.d.ts.map +1 -1
- package/dist/sources/unsplash/index.d.cts +1 -0
- package/dist/sources/unsplash/index.d.cts.map +1 -1
- package/dist/sources/unsplash/index.d.ts +1 -0
- package/dist/sources/unsplash/index.d.ts.map +1 -1
- package/dist/testing/index.d.cts +4 -0
- package/dist/testing/index.d.cts.map +1 -1
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/types/categories.d.cts +3 -0
- package/dist/types/categories.d.cts.map +1 -1
- package/dist/types/categories.d.ts +3 -0
- package/dist/types/categories.d.ts.map +1 -1
- package/dist/types/data-source.d.cts +9 -0
- package/dist/types/data-source.d.cts.map +1 -1
- package/dist/types/data-source.d.ts +9 -0
- package/dist/types/data-source.d.ts.map +1 -1
- package/dist/types/filter.d.cts +11 -0
- package/dist/types/filter.d.cts.map +1 -1
- package/dist/types/filter.d.ts +11 -0
- package/dist/types/filter.d.ts.map +1 -1
- package/dist/types/folders.d.cts +2 -0
- package/dist/types/folders.d.cts.map +1 -1
- package/dist/types/folders.d.ts +2 -0
- package/dist/types/folders.d.ts.map +1 -1
- package/dist/types/options.d.cts +57 -1
- package/dist/types/options.d.cts.map +1 -1
- package/dist/types/options.d.ts +57 -1
- package/dist/types/options.d.ts.map +1 -1
- package/dist/types/resumable.cjs +42 -0
- package/dist/types/resumable.d.cts +204 -0
- package/dist/types/resumable.d.cts.map +1 -0
- package/dist/types/resumable.d.ts +204 -0
- package/dist/types/resumable.d.ts.map +1 -0
- package/dist/types/resumable.js +4 -0
- package/dist/types/transform.cjs +18 -0
- package/dist/types/transform.d.cts +45 -0
- package/dist/types/transform.d.cts.map +1 -0
- package/dist/types/transform.d.ts +45 -0
- package/dist/types/transform.d.ts.map +1 -0
- package/dist/types/transform.js +1 -0
- package/dist/types/types.d.cts +17 -0
- package/dist/types/types.d.cts.map +1 -1
- package/dist/types/types.d.ts +17 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/unsplash.d.cts +2 -0
- package/dist/types/unsplash.d.cts.map +1 -1
- package/dist/types/unsplash.d.ts +2 -0
- package/dist/types/unsplash.d.ts.map +1 -1
- package/dist/ui/AssetBrowser.d.cts +3 -1
- package/dist/ui/AssetBrowser.d.cts.map +1 -1
- package/dist/ui/AssetBrowser.d.ts +3 -1
- package/dist/ui/AssetBrowser.d.ts.map +1 -1
- package/dist/ui/AssetCommandPalette.d.cts +4 -1
- package/dist/ui/AssetCommandPalette.d.cts.map +1 -1
- package/dist/ui/AssetCommandPalette.d.ts +4 -1
- package/dist/ui/AssetCommandPalette.d.ts.map +1 -1
- package/dist/ui/AssetManagerUI.cjs +3 -1
- package/dist/ui/AssetManagerUI.d.cts +11 -2
- package/dist/ui/AssetManagerUI.d.cts.map +1 -1
- package/dist/ui/AssetManagerUI.d.ts +11 -2
- package/dist/ui/AssetManagerUI.d.ts.map +1 -1
- package/dist/ui/AssetManagerUI.js +3 -1
- package/dist/ui/DeleteAssetDialog.d.cts +4 -1
- package/dist/ui/DeleteAssetDialog.d.cts.map +1 -1
- package/dist/ui/DeleteAssetDialog.d.ts +4 -1
- package/dist/ui/DeleteAssetDialog.d.ts.map +1 -1
- package/dist/ui/DeleteFolderDialog.d.cts +4 -1
- package/dist/ui/DeleteFolderDialog.d.cts.map +1 -1
- package/dist/ui/DeleteFolderDialog.d.ts +4 -1
- package/dist/ui/DeleteFolderDialog.d.ts.map +1 -1
- package/dist/ui/EmptyFolderState.d.cts +4 -1
- package/dist/ui/EmptyFolderState.d.cts.map +1 -1
- package/dist/ui/EmptyFolderState.d.ts +4 -1
- package/dist/ui/EmptyFolderState.d.ts.map +1 -1
- package/dist/ui/FolderBreadcrumb.d.cts +4 -1
- package/dist/ui/FolderBreadcrumb.d.cts.map +1 -1
- package/dist/ui/FolderBreadcrumb.d.ts +4 -1
- package/dist/ui/FolderBreadcrumb.d.ts.map +1 -1
- package/dist/ui/FolderNameDialog.d.cts +3 -1
- package/dist/ui/FolderNameDialog.d.cts.map +1 -1
- package/dist/ui/FolderNameDialog.d.ts +3 -1
- package/dist/ui/FolderNameDialog.d.ts.map +1 -1
- package/dist/ui/FolderTree.d.cts +4 -1
- package/dist/ui/FolderTree.d.cts.map +1 -1
- package/dist/ui/FolderTree.d.ts +4 -1
- package/dist/ui/FolderTree.d.ts.map +1 -1
- package/dist/ui/MetadataPanel.d.cts +4 -1
- package/dist/ui/MetadataPanel.d.cts.map +1 -1
- package/dist/ui/MetadataPanel.d.ts +4 -1
- package/dist/ui/MetadataPanel.d.ts.map +1 -1
- package/dist/ui/MoveTargetPicker.d.cts +3 -1
- package/dist/ui/MoveTargetPicker.d.cts.map +1 -1
- package/dist/ui/MoveTargetPicker.d.ts +3 -1
- package/dist/ui/MoveTargetPicker.d.ts.map +1 -1
- package/dist/ui/ReplaceAssetDialog.cjs +7 -2
- package/dist/ui/ReplaceAssetDialog.d.cts +5 -2
- package/dist/ui/ReplaceAssetDialog.d.cts.map +1 -1
- package/dist/ui/ReplaceAssetDialog.d.ts +5 -2
- package/dist/ui/ReplaceAssetDialog.d.ts.map +1 -1
- package/dist/ui/ReplaceAssetDialog.js +7 -2
- package/dist/ui/UnsplashPanel.d.cts +4 -1
- package/dist/ui/UnsplashPanel.d.cts.map +1 -1
- package/dist/ui/UnsplashPanel.d.ts +4 -1
- package/dist/ui/UnsplashPanel.d.ts.map +1 -1
- package/dist/ui/UploadButton.cjs +7 -2
- package/dist/ui/UploadButton.d.cts +6 -2
- package/dist/ui/UploadButton.d.cts.map +1 -1
- package/dist/ui/UploadButton.d.ts +6 -2
- package/dist/ui/UploadButton.d.ts.map +1 -1
- package/dist/ui/UploadButton.js +7 -2
- package/dist/utils/asset-reference.cjs +87 -4
- package/dist/utils/asset-reference.d.cts +30 -6
- package/dist/utils/asset-reference.d.cts.map +1 -1
- package/dist/utils/asset-reference.d.ts +30 -6
- package/dist/utils/asset-reference.d.ts.map +1 -1
- package/dist/utils/asset-reference.js +83 -3
- package/dist/utils/csp.cjs +16 -0
- package/dist/utils/csp.d.cts +23 -0
- package/dist/utils/csp.d.cts.map +1 -1
- package/dist/utils/csp.d.ts +23 -0
- package/dist/utils/csp.d.ts.map +1 -1
- package/dist/utils/csp.js +16 -0
- package/dist/utils/data-source.cjs +19 -5
- package/dist/utils/data-source.d.cts +5 -1
- package/dist/utils/data-source.d.cts.map +1 -1
- package/dist/utils/data-source.d.ts +5 -1
- package/dist/utils/data-source.d.ts.map +1 -1
- package/dist/utils/data-source.js +19 -5
- package/dist/utils/errors.d.cts +5 -0
- package/dist/utils/errors.d.cts.map +1 -1
- package/dist/utils/errors.d.ts +5 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/query-param-transform.cjs +101 -0
- package/dist/utils/query-param-transform.d.cts +46 -0
- package/dist/utils/query-param-transform.d.cts.map +1 -0
- package/dist/utils/query-param-transform.d.ts +46 -0
- package/dist/utils/query-param-transform.d.ts.map +1 -0
- package/dist/utils/query-param-transform.js +60 -0
- package/dist/utils/registry.cjs +3 -0
- package/dist/utils/registry.d.cts +8 -0
- package/dist/utils/registry.d.cts.map +1 -1
- package/dist/utils/registry.d.ts +8 -0
- package/dist/utils/registry.d.ts.map +1 -1
- package/dist/utils/registry.js +3 -0
- package/dist/utils/resolver.cjs +19 -11
- package/dist/utils/resolver.d.cts +24 -0
- package/dist/utils/resolver.d.cts.map +1 -1
- package/dist/utils/resolver.d.ts +24 -0
- package/dist/utils/resolver.d.ts.map +1 -1
- package/dist/utils/resolver.js +19 -11
- package/dist/utils/retry.d.cts +2 -0
- package/dist/utils/retry.d.cts.map +1 -1
- package/dist/utils/retry.d.ts +2 -0
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/run-resumable-upload.cjs +160 -0
- package/dist/utils/run-resumable-upload.d.cts +56 -0
- package/dist/utils/run-resumable-upload.d.cts.map +1 -0
- package/dist/utils/run-resumable-upload.d.ts +56 -0
- package/dist/utils/run-resumable-upload.d.ts.map +1 -0
- package/dist/utils/run-resumable-upload.js +122 -0
- package/dist/utils/sniff-file-type.cjs +209 -0
- package/dist/utils/sniff-file-type.d.cts +25 -0
- package/dist/utils/sniff-file-type.d.cts.map +1 -0
- package/dist/utils/sniff-file-type.d.ts +25 -0
- package/dist/utils/sniff-file-type.d.ts.map +1 -0
- package/dist/utils/sniff-file-type.js +164 -0
- package/dist/utils/studio-asset-source.cjs +11 -6
- package/dist/utils/studio-asset-source.d.cts +5 -1
- package/dist/utils/studio-asset-source.d.cts.map +1 -1
- package/dist/utils/studio-asset-source.d.ts +5 -1
- package/dist/utils/studio-asset-source.d.ts.map +1 -1
- package/dist/utils/studio-asset-source.js +11 -6
- package/dist/utils/upload-session-store.cjs +125 -0
- package/dist/utils/upload-session-store.d.cts +55 -0
- package/dist/utils/upload-session-store.d.cts.map +1 -0
- package/dist/utils/upload-session-store.d.ts +55 -0
- package/dist/utils/upload-session-store.d.ts.map +1 -0
- package/dist/utils/upload-session-store.js +84 -0
- package/dist/utils/validate-upload-result.cjs +9 -1
- package/dist/utils/validate-upload-result.d.cts +1 -0
- package/dist/utils/validate-upload-result.d.cts.map +1 -1
- package/dist/utils/validate-upload-result.d.ts +1 -0
- package/dist/utils/validate-upload-result.d.ts.map +1 -1
- package/dist/utils/validate-upload-result.js +9 -1
- package/dist/version.cjs +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.cts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/meta/config.json +1 -1
- package/package.json +42 -12
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Resumable / multipart upload contract (PRD 0004 §5.1 — "High #1").
|
|
3
|
+
*
|
|
4
|
+
* A session-based alternative to the single-shot {@link UploadAdapter}. A large
|
|
5
|
+
* file is split into ordered parts; each part uploads independently and is
|
|
6
|
+
* retried in isolation, and an interrupted upload can resume from the parts the
|
|
7
|
+
* backend already accepted (the session store added in M2 persists those
|
|
8
|
+
* acknowledgements). The final artifact is still a single {@link UploadResult}
|
|
9
|
+
* that flows through `validateUploadResult()` before registry insertion — the
|
|
10
|
+
* trust boundary is unchanged.
|
|
11
|
+
*
|
|
12
|
+
* Dependency-free by design: the built-in S3 implementation (M4) drives an
|
|
13
|
+
* extended presign endpoint rather than bundling the AWS SDK, mirroring
|
|
14
|
+
* `s3PresignedAdapter`. The runner (M3) is adapter-agnostic — it owns slicing,
|
|
15
|
+
* per-part retry, progress, resume, and abort, and never assumes S3.
|
|
16
|
+
*
|
|
17
|
+
* @experimental Public surface may change before v1.0.
|
|
18
|
+
*/
|
|
19
|
+
import type { UploadAdapter, UploadAdapterOptions, UploadResult } from "./types.js";
|
|
20
|
+
/**
|
|
21
|
+
* One contiguous chunk of the source file handed to
|
|
22
|
+
* {@link ResumableUploadAdapter.uploadPart}.
|
|
23
|
+
*/
|
|
24
|
+
export interface UploadPart {
|
|
25
|
+
/**
|
|
26
|
+
* 1-based part index — contiguous and ascending. S3 multipart numbers parts
|
|
27
|
+
* from 1, so the runner and adapters share that convention with no offset.
|
|
28
|
+
*/
|
|
29
|
+
readonly partNumber: number;
|
|
30
|
+
/** Byte offset of this part within the source file. */
|
|
31
|
+
readonly start: number;
|
|
32
|
+
/** Exclusive end offset; `end - start === blob.size`. */
|
|
33
|
+
readonly end: number;
|
|
34
|
+
/** The chunk body — a `File.slice(start, end)` of the source. */
|
|
35
|
+
readonly blob: Blob;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Opaque acknowledgement of a successfully stored part. `etag` is the value the
|
|
39
|
+
* backend requires at completion (S3 returns one per `UploadPart`); the runner
|
|
40
|
+
* persists it so the part is skipped when a session resumes.
|
|
41
|
+
*/
|
|
42
|
+
export interface PartTag {
|
|
43
|
+
readonly partNumber: number;
|
|
44
|
+
readonly etag: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Backend handle for an in-progress multipart upload, returned by
|
|
48
|
+
* {@link ResumableUploadAdapter.begin}.
|
|
49
|
+
*
|
|
50
|
+
* `uploadId` is the backend's session id (e.g. S3 `UploadId`). A non-empty
|
|
51
|
+
* `parts` marks a *resumed* session — the runner skips those part numbers
|
|
52
|
+
* rather than re-uploading them. `meta` is host-opaque continuation data that
|
|
53
|
+
* round-trips unchanged back to `uploadPart` / `complete` / `abort`.
|
|
54
|
+
*/
|
|
55
|
+
export interface UploadSession {
|
|
56
|
+
readonly uploadId: string;
|
|
57
|
+
/** Parts already accepted by the backend (empty/omitted for a fresh session). */
|
|
58
|
+
readonly parts?: readonly PartTag[];
|
|
59
|
+
/**
|
|
60
|
+
* Effective part size in bytes, **locked for the life of the session**. The
|
|
61
|
+
* runner slices every part at this size, so resuming MUST reuse the same
|
|
62
|
+
* value — otherwise a skipped `partNumber` would map to a different byte
|
|
63
|
+
* range and corrupt the object. A backend may dictate it here; otherwise the
|
|
64
|
+
* runner sets it from config and persists it (see {@link
|
|
65
|
+
* PersistedUploadSession.partSize}). Once parts have been uploaded it must
|
|
66
|
+
* not change.
|
|
67
|
+
*/
|
|
68
|
+
readonly partSize?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Host-opaque continuation data echoed back to subsequent calls. Typed
|
|
71
|
+
* JSON-safe so the runner can persist it directly into
|
|
72
|
+
* {@link PersistedUploadSession.meta} (which the M2 session store round-trips
|
|
73
|
+
* through `localStorage`) without a lossy conversion.
|
|
74
|
+
*/
|
|
75
|
+
readonly meta?: Readonly<Record<string, JsonValue>>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Any value that survives `JSON.stringify` → `JSON.parse` (and `structuredClone`)
|
|
79
|
+
* unchanged. Used to type persisted continuation data so the M2 session store
|
|
80
|
+
* can round-trip it through `localStorage` without silently dropping functions,
|
|
81
|
+
* symbols, `BigInt`, class instances, or cyclic references.
|
|
82
|
+
*
|
|
83
|
+
* NOTE: numbers must be **finite** — `NaN` and `±Infinity` serialize to `null`
|
|
84
|
+
* via `JSON.stringify`, so they do not round-trip. The session store treats
|
|
85
|
+
* non-finite numeric meta as a host bug.
|
|
86
|
+
*/
|
|
87
|
+
export type JsonValue = string | number | boolean | null | readonly JsonValue[] | {
|
|
88
|
+
readonly [key: string]: JsonValue;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The serializable subset of an {@link UploadSession} that the M2 session store
|
|
92
|
+
* persists so an interrupted upload can resume after a reload. The runner loads
|
|
93
|
+
* it (keyed by file fingerprint) and hands it to
|
|
94
|
+
* {@link ResumableUploadAdapter.begin} as the `resume` argument. MUST be JSON /
|
|
95
|
+
* structured-clone safe end-to-end — it round-trips through `localStorage`.
|
|
96
|
+
*/
|
|
97
|
+
export interface PersistedUploadSession {
|
|
98
|
+
/** Backend session id (e.g. S3 `UploadId`) to reconcile against. */
|
|
99
|
+
readonly uploadId: string;
|
|
100
|
+
/** The effective part size locked in when the session started (bytes). */
|
|
101
|
+
readonly partSize: number;
|
|
102
|
+
/** Parts the backend had accepted at persist time. */
|
|
103
|
+
readonly parts: readonly PartTag[];
|
|
104
|
+
/**
|
|
105
|
+
* Host-opaque continuation data. Typed as JSON-safe so the persisted handle
|
|
106
|
+
* is serializable by construction, not just by convention.
|
|
107
|
+
*/
|
|
108
|
+
readonly meta?: Readonly<Record<string, JsonValue>>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Persistence seam for resumable uploads. The runner loads a prior session
|
|
112
|
+
* before {@link ResumableUploadAdapter.begin} (so an interrupted upload can
|
|
113
|
+
* resume), saves progress as parts complete, and clears it once the upload
|
|
114
|
+
* finishes or is abandoned. Keyed internally by a stable file fingerprint
|
|
115
|
+
* (name + size + lastModified), so the same picked file resumes while a
|
|
116
|
+
* different file does not.
|
|
117
|
+
*
|
|
118
|
+
* The built-in `createUploadSessionStore` persists to `localStorage` (with an
|
|
119
|
+
* in-memory fallback where unavailable); hosts may supply their own (e.g.
|
|
120
|
+
* IndexedDB or remote), hence the optionally-async return types.
|
|
121
|
+
*/
|
|
122
|
+
export interface UploadSessionStore {
|
|
123
|
+
/** Look up a persisted session for `file`, or `undefined` if none. */
|
|
124
|
+
load(file: File): PersistedUploadSession | undefined | Promise<PersistedUploadSession | undefined>;
|
|
125
|
+
/** Persist (or overwrite) the in-progress session for `file`. Best-effort. */
|
|
126
|
+
save(file: File, session: PersistedUploadSession): void | Promise<void>;
|
|
127
|
+
/** Remove any persisted session for `file` — called on complete or abort. */
|
|
128
|
+
clear(file: File): void | Promise<void>;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Session-based upload backend. Contrast with {@link UploadAdapter}, which is a
|
|
132
|
+
* single `File → UploadResult` call. Implementations own the four lifecycle
|
|
133
|
+
* steps; the adapter-agnostic runner (M3) drives them and handles slicing,
|
|
134
|
+
* per-part retry, progress, resume, and abort.
|
|
135
|
+
*
|
|
136
|
+
* Transient failures (HTTP 5xx, network) should be thrown as `RetryableError`
|
|
137
|
+
* so the runner retries the individual part; non-retryable failures (4xx,
|
|
138
|
+
* shape errors) should throw `AssetValidationError`, matching the single-shot
|
|
139
|
+
* adapter convention.
|
|
140
|
+
*/
|
|
141
|
+
export interface ResumableUploadAdapter {
|
|
142
|
+
/**
|
|
143
|
+
* Open — or resume — a multipart session for `file`.
|
|
144
|
+
*
|
|
145
|
+
* When `resume` is supplied (a persisted handle from a prior, interrupted
|
|
146
|
+
* run), the adapter SHOULD reconcile against that backend session — e.g. S3
|
|
147
|
+
* `ListParts` against `resume.uploadId` — and return a session that echoes
|
|
148
|
+
* the still-valid `uploadId` and accepted `parts` so the runner skips them.
|
|
149
|
+
* If `resume.uploadId` is reused, the returned session's effective
|
|
150
|
+
* `partSize` MUST equal `resume.partSize` — the byte ranges of already-
|
|
151
|
+
* uploaded parts depend on it. If the backend session is gone or expired the
|
|
152
|
+
* adapter MUST start fresh: return a new `uploadId` with empty `parts`. When
|
|
153
|
+
* `resume` is omitted this always starts a fresh session.
|
|
154
|
+
*/
|
|
155
|
+
readonly begin: (file: File, resume?: PersistedUploadSession, options?: UploadAdapterOptions) => Promise<UploadSession>;
|
|
156
|
+
/** Upload one part and return its completion tag. */
|
|
157
|
+
readonly uploadPart: (session: UploadSession, part: UploadPart, options?: UploadAdapterOptions) => Promise<PartTag>;
|
|
158
|
+
/**
|
|
159
|
+
* Finalize the session once every part is stored. `parts` is the full,
|
|
160
|
+
* part-number-ordered tag set (resumed + freshly uploaded). Returns the
|
|
161
|
+
* asset row, which is then validated like any other upload result.
|
|
162
|
+
*/
|
|
163
|
+
readonly complete: (session: UploadSession, parts: readonly PartTag[], options?: UploadAdapterOptions) => Promise<UploadResult>;
|
|
164
|
+
/**
|
|
165
|
+
* Best-effort teardown of an aborted or failed session (e.g. S3
|
|
166
|
+
* `AbortMultipartUpload`). The runner calls this on abort; implementations
|
|
167
|
+
* should swallow their own errors so cleanup never masks the original
|
|
168
|
+
* failure.
|
|
169
|
+
*/
|
|
170
|
+
readonly abort: (session: UploadSession, options?: UploadAdapterOptions) => Promise<void>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Resumable / multipart upload configuration on {@link AssetManagerOptions}.
|
|
174
|
+
*/
|
|
175
|
+
export interface ResumableUploadConfig {
|
|
176
|
+
/** The multipart backend driving begin / uploadPart / complete / abort. */
|
|
177
|
+
readonly adapter: ResumableUploadAdapter;
|
|
178
|
+
/**
|
|
179
|
+
* Bytes per part. Defaults to 8 MiB in the runner. S3 requires every part
|
|
180
|
+
* except the last to be ≥ 5 MiB, so the S3 adapter clamps smaller values.
|
|
181
|
+
*/
|
|
182
|
+
readonly partSize?: number;
|
|
183
|
+
/**
|
|
184
|
+
* Minimum file size (bytes) routed through the resumable path; smaller files
|
|
185
|
+
* use the single-shot `uploader`. Defaults to `partSize` — a file that fits
|
|
186
|
+
* in one part gains nothing from multipart.
|
|
187
|
+
*/
|
|
188
|
+
readonly threshold?: number;
|
|
189
|
+
/**
|
|
190
|
+
* Where in-progress sessions are persisted so an interrupted upload can
|
|
191
|
+
* resume. Omitted ⇒ the runner uses the built-in `createUploadSessionStore`
|
|
192
|
+
* (localStorage, with an in-memory fallback). Supply a custom store
|
|
193
|
+
* (IndexedDB, remote) to change the backing.
|
|
194
|
+
*/
|
|
195
|
+
readonly sessionStore?: UploadSessionStore;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Narrow an upload backend to a {@link ResumableUploadAdapter}. The single-shot
|
|
199
|
+
* {@link UploadAdapter} is a function; the resumable adapter is an object with
|
|
200
|
+
* the four lifecycle methods, so a `typeof === "object"` plus method check
|
|
201
|
+
* distinguishes them unambiguously.
|
|
202
|
+
*/
|
|
203
|
+
export declare function isResumableAdapter(value: UploadAdapter | ResumableUploadAdapter | undefined): value is ResumableUploadAdapter;
|
|
204
|
+
//# sourceMappingURL=resumable.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resumable.d.cts","sourceRoot":"","sources":["../../src/types/resumable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Resumable / multipart upload contract (PRD 0004 §5.1 — "High #1").
|
|
3
|
+
*
|
|
4
|
+
* A session-based alternative to the single-shot {@link UploadAdapter}. A large
|
|
5
|
+
* file is split into ordered parts; each part uploads independently and is
|
|
6
|
+
* retried in isolation, and an interrupted upload can resume from the parts the
|
|
7
|
+
* backend already accepted (the session store added in M2 persists those
|
|
8
|
+
* acknowledgements). The final artifact is still a single {@link UploadResult}
|
|
9
|
+
* that flows through `validateUploadResult()` before registry insertion — the
|
|
10
|
+
* trust boundary is unchanged.
|
|
11
|
+
*
|
|
12
|
+
* Dependency-free by design: the built-in S3 implementation (M4) drives an
|
|
13
|
+
* extended presign endpoint rather than bundling the AWS SDK, mirroring
|
|
14
|
+
* `s3PresignedAdapter`. The runner (M3) is adapter-agnostic — it owns slicing,
|
|
15
|
+
* per-part retry, progress, resume, and abort, and never assumes S3.
|
|
16
|
+
*
|
|
17
|
+
* @experimental Public surface may change before v1.0.
|
|
18
|
+
*/
|
|
19
|
+
import type { UploadAdapter, UploadAdapterOptions, UploadResult } from "./types.js";
|
|
20
|
+
/**
|
|
21
|
+
* One contiguous chunk of the source file handed to
|
|
22
|
+
* {@link ResumableUploadAdapter.uploadPart}.
|
|
23
|
+
*/
|
|
24
|
+
export interface UploadPart {
|
|
25
|
+
/**
|
|
26
|
+
* 1-based part index — contiguous and ascending. S3 multipart numbers parts
|
|
27
|
+
* from 1, so the runner and adapters share that convention with no offset.
|
|
28
|
+
*/
|
|
29
|
+
readonly partNumber: number;
|
|
30
|
+
/** Byte offset of this part within the source file. */
|
|
31
|
+
readonly start: number;
|
|
32
|
+
/** Exclusive end offset; `end - start === blob.size`. */
|
|
33
|
+
readonly end: number;
|
|
34
|
+
/** The chunk body — a `File.slice(start, end)` of the source. */
|
|
35
|
+
readonly blob: Blob;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Opaque acknowledgement of a successfully stored part. `etag` is the value the
|
|
39
|
+
* backend requires at completion (S3 returns one per `UploadPart`); the runner
|
|
40
|
+
* persists it so the part is skipped when a session resumes.
|
|
41
|
+
*/
|
|
42
|
+
export interface PartTag {
|
|
43
|
+
readonly partNumber: number;
|
|
44
|
+
readonly etag: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Backend handle for an in-progress multipart upload, returned by
|
|
48
|
+
* {@link ResumableUploadAdapter.begin}.
|
|
49
|
+
*
|
|
50
|
+
* `uploadId` is the backend's session id (e.g. S3 `UploadId`). A non-empty
|
|
51
|
+
* `parts` marks a *resumed* session — the runner skips those part numbers
|
|
52
|
+
* rather than re-uploading them. `meta` is host-opaque continuation data that
|
|
53
|
+
* round-trips unchanged back to `uploadPart` / `complete` / `abort`.
|
|
54
|
+
*/
|
|
55
|
+
export interface UploadSession {
|
|
56
|
+
readonly uploadId: string;
|
|
57
|
+
/** Parts already accepted by the backend (empty/omitted for a fresh session). */
|
|
58
|
+
readonly parts?: readonly PartTag[];
|
|
59
|
+
/**
|
|
60
|
+
* Effective part size in bytes, **locked for the life of the session**. The
|
|
61
|
+
* runner slices every part at this size, so resuming MUST reuse the same
|
|
62
|
+
* value — otherwise a skipped `partNumber` would map to a different byte
|
|
63
|
+
* range and corrupt the object. A backend may dictate it here; otherwise the
|
|
64
|
+
* runner sets it from config and persists it (see {@link
|
|
65
|
+
* PersistedUploadSession.partSize}). Once parts have been uploaded it must
|
|
66
|
+
* not change.
|
|
67
|
+
*/
|
|
68
|
+
readonly partSize?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Host-opaque continuation data echoed back to subsequent calls. Typed
|
|
71
|
+
* JSON-safe so the runner can persist it directly into
|
|
72
|
+
* {@link PersistedUploadSession.meta} (which the M2 session store round-trips
|
|
73
|
+
* through `localStorage`) without a lossy conversion.
|
|
74
|
+
*/
|
|
75
|
+
readonly meta?: Readonly<Record<string, JsonValue>>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Any value that survives `JSON.stringify` → `JSON.parse` (and `structuredClone`)
|
|
79
|
+
* unchanged. Used to type persisted continuation data so the M2 session store
|
|
80
|
+
* can round-trip it through `localStorage` without silently dropping functions,
|
|
81
|
+
* symbols, `BigInt`, class instances, or cyclic references.
|
|
82
|
+
*
|
|
83
|
+
* NOTE: numbers must be **finite** — `NaN` and `±Infinity` serialize to `null`
|
|
84
|
+
* via `JSON.stringify`, so they do not round-trip. The session store treats
|
|
85
|
+
* non-finite numeric meta as a host bug.
|
|
86
|
+
*/
|
|
87
|
+
export type JsonValue = string | number | boolean | null | readonly JsonValue[] | {
|
|
88
|
+
readonly [key: string]: JsonValue;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The serializable subset of an {@link UploadSession} that the M2 session store
|
|
92
|
+
* persists so an interrupted upload can resume after a reload. The runner loads
|
|
93
|
+
* it (keyed by file fingerprint) and hands it to
|
|
94
|
+
* {@link ResumableUploadAdapter.begin} as the `resume` argument. MUST be JSON /
|
|
95
|
+
* structured-clone safe end-to-end — it round-trips through `localStorage`.
|
|
96
|
+
*/
|
|
97
|
+
export interface PersistedUploadSession {
|
|
98
|
+
/** Backend session id (e.g. S3 `UploadId`) to reconcile against. */
|
|
99
|
+
readonly uploadId: string;
|
|
100
|
+
/** The effective part size locked in when the session started (bytes). */
|
|
101
|
+
readonly partSize: number;
|
|
102
|
+
/** Parts the backend had accepted at persist time. */
|
|
103
|
+
readonly parts: readonly PartTag[];
|
|
104
|
+
/**
|
|
105
|
+
* Host-opaque continuation data. Typed as JSON-safe so the persisted handle
|
|
106
|
+
* is serializable by construction, not just by convention.
|
|
107
|
+
*/
|
|
108
|
+
readonly meta?: Readonly<Record<string, JsonValue>>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Persistence seam for resumable uploads. The runner loads a prior session
|
|
112
|
+
* before {@link ResumableUploadAdapter.begin} (so an interrupted upload can
|
|
113
|
+
* resume), saves progress as parts complete, and clears it once the upload
|
|
114
|
+
* finishes or is abandoned. Keyed internally by a stable file fingerprint
|
|
115
|
+
* (name + size + lastModified), so the same picked file resumes while a
|
|
116
|
+
* different file does not.
|
|
117
|
+
*
|
|
118
|
+
* The built-in `createUploadSessionStore` persists to `localStorage` (with an
|
|
119
|
+
* in-memory fallback where unavailable); hosts may supply their own (e.g.
|
|
120
|
+
* IndexedDB or remote), hence the optionally-async return types.
|
|
121
|
+
*/
|
|
122
|
+
export interface UploadSessionStore {
|
|
123
|
+
/** Look up a persisted session for `file`, or `undefined` if none. */
|
|
124
|
+
load(file: File): PersistedUploadSession | undefined | Promise<PersistedUploadSession | undefined>;
|
|
125
|
+
/** Persist (or overwrite) the in-progress session for `file`. Best-effort. */
|
|
126
|
+
save(file: File, session: PersistedUploadSession): void | Promise<void>;
|
|
127
|
+
/** Remove any persisted session for `file` — called on complete or abort. */
|
|
128
|
+
clear(file: File): void | Promise<void>;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Session-based upload backend. Contrast with {@link UploadAdapter}, which is a
|
|
132
|
+
* single `File → UploadResult` call. Implementations own the four lifecycle
|
|
133
|
+
* steps; the adapter-agnostic runner (M3) drives them and handles slicing,
|
|
134
|
+
* per-part retry, progress, resume, and abort.
|
|
135
|
+
*
|
|
136
|
+
* Transient failures (HTTP 5xx, network) should be thrown as `RetryableError`
|
|
137
|
+
* so the runner retries the individual part; non-retryable failures (4xx,
|
|
138
|
+
* shape errors) should throw `AssetValidationError`, matching the single-shot
|
|
139
|
+
* adapter convention.
|
|
140
|
+
*/
|
|
141
|
+
export interface ResumableUploadAdapter {
|
|
142
|
+
/**
|
|
143
|
+
* Open — or resume — a multipart session for `file`.
|
|
144
|
+
*
|
|
145
|
+
* When `resume` is supplied (a persisted handle from a prior, interrupted
|
|
146
|
+
* run), the adapter SHOULD reconcile against that backend session — e.g. S3
|
|
147
|
+
* `ListParts` against `resume.uploadId` — and return a session that echoes
|
|
148
|
+
* the still-valid `uploadId` and accepted `parts` so the runner skips them.
|
|
149
|
+
* If `resume.uploadId` is reused, the returned session's effective
|
|
150
|
+
* `partSize` MUST equal `resume.partSize` — the byte ranges of already-
|
|
151
|
+
* uploaded parts depend on it. If the backend session is gone or expired the
|
|
152
|
+
* adapter MUST start fresh: return a new `uploadId` with empty `parts`. When
|
|
153
|
+
* `resume` is omitted this always starts a fresh session.
|
|
154
|
+
*/
|
|
155
|
+
readonly begin: (file: File, resume?: PersistedUploadSession, options?: UploadAdapterOptions) => Promise<UploadSession>;
|
|
156
|
+
/** Upload one part and return its completion tag. */
|
|
157
|
+
readonly uploadPart: (session: UploadSession, part: UploadPart, options?: UploadAdapterOptions) => Promise<PartTag>;
|
|
158
|
+
/**
|
|
159
|
+
* Finalize the session once every part is stored. `parts` is the full,
|
|
160
|
+
* part-number-ordered tag set (resumed + freshly uploaded). Returns the
|
|
161
|
+
* asset row, which is then validated like any other upload result.
|
|
162
|
+
*/
|
|
163
|
+
readonly complete: (session: UploadSession, parts: readonly PartTag[], options?: UploadAdapterOptions) => Promise<UploadResult>;
|
|
164
|
+
/**
|
|
165
|
+
* Best-effort teardown of an aborted or failed session (e.g. S3
|
|
166
|
+
* `AbortMultipartUpload`). The runner calls this on abort; implementations
|
|
167
|
+
* should swallow their own errors so cleanup never masks the original
|
|
168
|
+
* failure.
|
|
169
|
+
*/
|
|
170
|
+
readonly abort: (session: UploadSession, options?: UploadAdapterOptions) => Promise<void>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Resumable / multipart upload configuration on {@link AssetManagerOptions}.
|
|
174
|
+
*/
|
|
175
|
+
export interface ResumableUploadConfig {
|
|
176
|
+
/** The multipart backend driving begin / uploadPart / complete / abort. */
|
|
177
|
+
readonly adapter: ResumableUploadAdapter;
|
|
178
|
+
/**
|
|
179
|
+
* Bytes per part. Defaults to 8 MiB in the runner. S3 requires every part
|
|
180
|
+
* except the last to be ≥ 5 MiB, so the S3 adapter clamps smaller values.
|
|
181
|
+
*/
|
|
182
|
+
readonly partSize?: number;
|
|
183
|
+
/**
|
|
184
|
+
* Minimum file size (bytes) routed through the resumable path; smaller files
|
|
185
|
+
* use the single-shot `uploader`. Defaults to `partSize` — a file that fits
|
|
186
|
+
* in one part gains nothing from multipart.
|
|
187
|
+
*/
|
|
188
|
+
readonly threshold?: number;
|
|
189
|
+
/**
|
|
190
|
+
* Where in-progress sessions are persisted so an interrupted upload can
|
|
191
|
+
* resume. Omitted ⇒ the runner uses the built-in `createUploadSessionStore`
|
|
192
|
+
* (localStorage, with an in-memory fallback). Supply a custom store
|
|
193
|
+
* (IndexedDB, remote) to change the backing.
|
|
194
|
+
*/
|
|
195
|
+
readonly sessionStore?: UploadSessionStore;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Narrow an upload backend to a {@link ResumableUploadAdapter}. The single-shot
|
|
199
|
+
* {@link UploadAdapter} is a function; the resumable adapter is an object with
|
|
200
|
+
* the four lifecycle methods, so a `typeof === "object"` plus method check
|
|
201
|
+
* distinguishes them unambiguously.
|
|
202
|
+
*/
|
|
203
|
+
export declare function isResumableAdapter(value: UploadAdapter | ResumableUploadAdapter | undefined): value is ResumableUploadAdapter;
|
|
204
|
+
//# sourceMappingURL=resumable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resumable.d.ts","sourceRoot":"","sources":["../../src/types/resumable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
function isResumableAdapter(value) {
|
|
2
|
+
return "object" == typeof value && null !== value && "function" == typeof value.begin && "function" == typeof value.uploadPart && "function" == typeof value.complete && "function" == typeof value.abort;
|
|
3
|
+
}
|
|
4
|
+
export { isResumableAdapter };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.r = (exports1)=>{
|
|
5
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
6
|
+
value: 'Module'
|
|
7
|
+
});
|
|
8
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
9
|
+
value: true
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
})();
|
|
13
|
+
var __webpack_exports__ = {};
|
|
14
|
+
__webpack_require__.r(__webpack_exports__);
|
|
15
|
+
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
16
|
+
Object.defineProperty(exports, '__esModule', {
|
|
17
|
+
value: true
|
|
18
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Asset transformation contract (PRD 0004 — review finding #9).
|
|
3
|
+
*
|
|
4
|
+
* A headless, processing-free transformation seam. The plugin never resizes or
|
|
5
|
+
* transcodes bytes itself (it has no storage either — uploads go through host
|
|
6
|
+
* adapters); instead a transform is a declarative spec carried alongside an
|
|
7
|
+
* `asset://<id>` reference, and a host-pluggable {@link TransformResolver} maps
|
|
8
|
+
* `(asset, transform)` to a derivative URL produced by the host's image CDN /
|
|
9
|
+
* service (imgix, Cloudinary, S3 + Lambda, …). The built-in
|
|
10
|
+
* `createQueryParamTransformResolver` covers the common query-param CDN case.
|
|
11
|
+
*
|
|
12
|
+
* @experimental Public surface may change before v1.0.
|
|
13
|
+
*/
|
|
14
|
+
import type { UploadResult } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* A declarative, backend-neutral image transformation request. All fields are
|
|
17
|
+
* optional; a resolver maps the ones it supports onto its CDN's vocabulary and
|
|
18
|
+
* ignores the rest.
|
|
19
|
+
*/
|
|
20
|
+
export interface AssetTransform {
|
|
21
|
+
/** Target width in pixels. */
|
|
22
|
+
readonly width?: number;
|
|
23
|
+
/** Target height in pixels. */
|
|
24
|
+
readonly height?: number;
|
|
25
|
+
/**
|
|
26
|
+
* How the image fills the target box when both `width` and `height` are set.
|
|
27
|
+
* Names follow the common CDN/sharp vocabulary; a resolver maps them onto its
|
|
28
|
+
* own parameter values.
|
|
29
|
+
*/
|
|
30
|
+
readonly fit?: "cover" | "contain" | "fill" | "inside" | "outside";
|
|
31
|
+
/** Output format. `"auto"` lets the CDN negotiate (e.g. WebP/AVIF by Accept). */
|
|
32
|
+
readonly format?: "webp" | "avif" | "jpeg" | "png" | "auto";
|
|
33
|
+
/** Output quality, 1–100. */
|
|
34
|
+
readonly quality?: number;
|
|
35
|
+
/** Device pixel ratio multiplier (e.g. `2` for retina). */
|
|
36
|
+
readonly dpr?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Host-pluggable mapping from an asset + transform spec to a derivative URL.
|
|
40
|
+
* Return `undefined` to fall back to the asset's original URL (e.g. the
|
|
41
|
+
* transform isn't supported, or the asset isn't an image). The returned URL is
|
|
42
|
+
* re-validated through the same trust boundary as any other resolved asset URL.
|
|
43
|
+
*/
|
|
44
|
+
export type TransformResolver = (asset: UploadResult, transform: AssetTransform) => string | undefined;
|
|
45
|
+
//# sourceMappingURL=transform.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.cts","sourceRoot":"","sources":["../../src/types/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACnE,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5D,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC/B,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,cAAc,KACrB,MAAM,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Asset transformation contract (PRD 0004 — review finding #9).
|
|
3
|
+
*
|
|
4
|
+
* A headless, processing-free transformation seam. The plugin never resizes or
|
|
5
|
+
* transcodes bytes itself (it has no storage either — uploads go through host
|
|
6
|
+
* adapters); instead a transform is a declarative spec carried alongside an
|
|
7
|
+
* `asset://<id>` reference, and a host-pluggable {@link TransformResolver} maps
|
|
8
|
+
* `(asset, transform)` to a derivative URL produced by the host's image CDN /
|
|
9
|
+
* service (imgix, Cloudinary, S3 + Lambda, …). The built-in
|
|
10
|
+
* `createQueryParamTransformResolver` covers the common query-param CDN case.
|
|
11
|
+
*
|
|
12
|
+
* @experimental Public surface may change before v1.0.
|
|
13
|
+
*/
|
|
14
|
+
import type { UploadResult } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* A declarative, backend-neutral image transformation request. All fields are
|
|
17
|
+
* optional; a resolver maps the ones it supports onto its CDN's vocabulary and
|
|
18
|
+
* ignores the rest.
|
|
19
|
+
*/
|
|
20
|
+
export interface AssetTransform {
|
|
21
|
+
/** Target width in pixels. */
|
|
22
|
+
readonly width?: number;
|
|
23
|
+
/** Target height in pixels. */
|
|
24
|
+
readonly height?: number;
|
|
25
|
+
/**
|
|
26
|
+
* How the image fills the target box when both `width` and `height` are set.
|
|
27
|
+
* Names follow the common CDN/sharp vocabulary; a resolver maps them onto its
|
|
28
|
+
* own parameter values.
|
|
29
|
+
*/
|
|
30
|
+
readonly fit?: "cover" | "contain" | "fill" | "inside" | "outside";
|
|
31
|
+
/** Output format. `"auto"` lets the CDN negotiate (e.g. WebP/AVIF by Accept). */
|
|
32
|
+
readonly format?: "webp" | "avif" | "jpeg" | "png" | "auto";
|
|
33
|
+
/** Output quality, 1–100. */
|
|
34
|
+
readonly quality?: number;
|
|
35
|
+
/** Device pixel ratio multiplier (e.g. `2` for retina). */
|
|
36
|
+
readonly dpr?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Host-pluggable mapping from an asset + transform spec to a derivative URL.
|
|
40
|
+
* Return `undefined` to fall back to the asset's original URL (e.g. the
|
|
41
|
+
* transform isn't supported, or the asset isn't an image). The returned URL is
|
|
42
|
+
* re-validated through the same trust boundary as any other resolved asset URL.
|
|
43
|
+
*/
|
|
44
|
+
export type TransformResolver = (asset: UploadResult, transform: AssetTransform) => string | undefined;
|
|
45
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/types/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACnE,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5D,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC/B,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,cAAc,KACrB,MAAM,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/types/types.d.cts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
/** Optional metadata associated with an uploaded asset. */
|
|
1
2
|
export interface AssetMeta {
|
|
2
3
|
readonly size?: number;
|
|
3
4
|
readonly mimeType?: string;
|
|
4
5
|
readonly width?: number;
|
|
5
6
|
readonly height?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Lowercase-hex content digest (SHA-256) of the uploaded bytes. Populated by
|
|
9
|
+
* the plugin when `dedupe` is enabled — used to detect duplicate uploads and
|
|
10
|
+
* as an integrity/cacheability signal. A host uploader may also set it
|
|
11
|
+
* directly; it is preserved through the validate/freeze reconstruction.
|
|
12
|
+
*/
|
|
13
|
+
readonly hash?: string;
|
|
6
14
|
/**
|
|
7
15
|
* Optional provenance/attribution for externally-sourced assets (PRD 0002
|
|
8
16
|
* §8.4). Set when an asset is inserted from a credit-requiring provider such
|
|
@@ -32,6 +40,7 @@ export interface AssetMeta {
|
|
|
32
40
|
* the headless registry and the Studio surface without translation.
|
|
33
41
|
*/
|
|
34
42
|
export type AssetKind = "image" | "video" | "audio" | "font" | "document" | "other";
|
|
43
|
+
/** Normalized asset row returned by upload adapters and registry mutations. */
|
|
35
44
|
export interface UploadResult {
|
|
36
45
|
readonly url: string;
|
|
37
46
|
readonly id: string;
|
|
@@ -61,6 +70,13 @@ export interface UploadAdapterOptions {
|
|
|
61
70
|
readonly signal?: AbortSignal;
|
|
62
71
|
}
|
|
63
72
|
export type UploadAdapter = (file: File, options?: UploadAdapterOptions) => Promise<UploadResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Lifecycle hook fired when an asset is deleted through the asset source, with
|
|
75
|
+
* the record as it existed at deletion time. Lets a host release backend
|
|
76
|
+
* objects tied to the upload (e.g. delete the stored S3 object, revoke a
|
|
77
|
+
* `blob:` URL). Awaited; throwing rejects the delete.
|
|
78
|
+
*/
|
|
79
|
+
export type AssetDeletedHook = (asset: UploadResult) => void | Promise<void>;
|
|
64
80
|
/**
|
|
65
81
|
* Listener invoked after every registry mutation
|
|
66
82
|
* (`register` / `delete` / `rename` / `replace` / `setTags`). The
|
|
@@ -96,6 +112,7 @@ export interface AssetSearchPage {
|
|
|
96
112
|
readonly total: number;
|
|
97
113
|
readonly nextCursor: string | undefined;
|
|
98
114
|
}
|
|
115
|
+
/** In-memory catalog API that stores and searches uploaded assets. */
|
|
99
116
|
export interface AssetRegistry {
|
|
100
117
|
readonly register: (asset: UploadResult) => UploadResult;
|
|
101
118
|
readonly get: (id: string) => UploadResult | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE;QACtB;;;;;WAKG;QACH,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;KAClC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAClB,OAAO,GACP,OAAO,GACP,OAAO,GACP,MAAM,GACN,UAAU,GACV,OAAO,CAAC;AAEX,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,MAAM,aAAa,GAAG,CAC3B,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,oBAAoB,KAC1B,OAAO,CAAC,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
/** Optional metadata associated with an uploaded asset. */
|
|
1
2
|
export interface AssetMeta {
|
|
2
3
|
readonly size?: number;
|
|
3
4
|
readonly mimeType?: string;
|
|
4
5
|
readonly width?: number;
|
|
5
6
|
readonly height?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Lowercase-hex content digest (SHA-256) of the uploaded bytes. Populated by
|
|
9
|
+
* the plugin when `dedupe` is enabled — used to detect duplicate uploads and
|
|
10
|
+
* as an integrity/cacheability signal. A host uploader may also set it
|
|
11
|
+
* directly; it is preserved through the validate/freeze reconstruction.
|
|
12
|
+
*/
|
|
13
|
+
readonly hash?: string;
|
|
6
14
|
/**
|
|
7
15
|
* Optional provenance/attribution for externally-sourced assets (PRD 0002
|
|
8
16
|
* §8.4). Set when an asset is inserted from a credit-requiring provider such
|
|
@@ -32,6 +40,7 @@ export interface AssetMeta {
|
|
|
32
40
|
* the headless registry and the Studio surface without translation.
|
|
33
41
|
*/
|
|
34
42
|
export type AssetKind = "image" | "video" | "audio" | "font" | "document" | "other";
|
|
43
|
+
/** Normalized asset row returned by upload adapters and registry mutations. */
|
|
35
44
|
export interface UploadResult {
|
|
36
45
|
readonly url: string;
|
|
37
46
|
readonly id: string;
|
|
@@ -61,6 +70,13 @@ export interface UploadAdapterOptions {
|
|
|
61
70
|
readonly signal?: AbortSignal;
|
|
62
71
|
}
|
|
63
72
|
export type UploadAdapter = (file: File, options?: UploadAdapterOptions) => Promise<UploadResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Lifecycle hook fired when an asset is deleted through the asset source, with
|
|
75
|
+
* the record as it existed at deletion time. Lets a host release backend
|
|
76
|
+
* objects tied to the upload (e.g. delete the stored S3 object, revoke a
|
|
77
|
+
* `blob:` URL). Awaited; throwing rejects the delete.
|
|
78
|
+
*/
|
|
79
|
+
export type AssetDeletedHook = (asset: UploadResult) => void | Promise<void>;
|
|
64
80
|
/**
|
|
65
81
|
* Listener invoked after every registry mutation
|
|
66
82
|
* (`register` / `delete` / `rename` / `replace` / `setTags`). The
|
|
@@ -96,6 +112,7 @@ export interface AssetSearchPage {
|
|
|
96
112
|
readonly total: number;
|
|
97
113
|
readonly nextCursor: string | undefined;
|
|
98
114
|
}
|
|
115
|
+
/** In-memory catalog API that stores and searches uploaded assets. */
|
|
99
116
|
export interface AssetRegistry {
|
|
100
117
|
readonly register: (asset: UploadResult) => UploadResult;
|
|
101
118
|
readonly get: (id: string) => UploadResult | undefined;
|