@anvilkit/plugin-asset-manager 0.1.9 → 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.
Files changed (235) hide show
  1. package/README.md +96 -3
  2. package/dist/adapters/data-url.d.cts +1 -0
  3. package/dist/adapters/data-url.d.cts.map +1 -1
  4. package/dist/adapters/data-url.d.ts +1 -0
  5. package/dist/adapters/data-url.d.ts.map +1 -1
  6. package/dist/adapters/s3-multipart.cjs +425 -0
  7. package/dist/adapters/s3-multipart.d.cts +43 -0
  8. package/dist/adapters/s3-multipart.d.cts.map +1 -0
  9. package/dist/adapters/s3-multipart.d.ts +43 -0
  10. package/dist/adapters/s3-multipart.d.ts.map +1 -0
  11. package/dist/adapters/s3-multipart.js +387 -0
  12. package/dist/adapters/s3-presigned.d.cts +2 -0
  13. package/dist/adapters/s3-presigned.d.cts.map +1 -1
  14. package/dist/adapters/s3-presigned.d.ts +2 -0
  15. package/dist/adapters/s3-presigned.d.ts.map +1 -1
  16. package/dist/i18n/provider.d.cts +1 -0
  17. package/dist/i18n/provider.d.cts.map +1 -1
  18. package/dist/i18n/provider.d.ts +1 -0
  19. package/dist/i18n/provider.d.ts.map +1 -1
  20. package/dist/index.cjs +14 -0
  21. package/dist/index.d.cts +9 -3
  22. package/dist/index.d.cts.map +1 -1
  23. package/dist/index.d.ts +9 -3
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3 -1
  26. package/dist/plugin.cjs +152 -12
  27. package/dist/plugin.d.cts +49 -1
  28. package/dist/plugin.d.cts.map +1 -1
  29. package/dist/plugin.d.ts +49 -1
  30. package/dist/plugin.d.ts.map +1 -1
  31. package/dist/plugin.js +147 -13
  32. package/dist/sources/composite-source.cjs +3 -0
  33. package/dist/sources/composite-source.d.cts.map +1 -1
  34. package/dist/sources/composite-source.d.ts.map +1 -1
  35. package/dist/sources/composite-source.js +3 -0
  36. package/dist/sources/federated-search.cjs +45 -7
  37. package/dist/sources/federated-search.d.cts.map +1 -1
  38. package/dist/sources/federated-search.d.ts.map +1 -1
  39. package/dist/sources/federated-search.js +45 -7
  40. package/dist/sources/provider.d.cts +5 -0
  41. package/dist/sources/provider.d.cts.map +1 -1
  42. package/dist/sources/provider.d.ts +5 -0
  43. package/dist/sources/provider.d.ts.map +1 -1
  44. package/dist/sources/unsplash/index.d.cts +1 -0
  45. package/dist/sources/unsplash/index.d.cts.map +1 -1
  46. package/dist/sources/unsplash/index.d.ts +1 -0
  47. package/dist/sources/unsplash/index.d.ts.map +1 -1
  48. package/dist/testing/index.d.cts +4 -0
  49. package/dist/testing/index.d.cts.map +1 -1
  50. package/dist/testing/index.d.ts +4 -0
  51. package/dist/testing/index.d.ts.map +1 -1
  52. package/dist/types/categories.d.cts +3 -0
  53. package/dist/types/categories.d.cts.map +1 -1
  54. package/dist/types/categories.d.ts +3 -0
  55. package/dist/types/categories.d.ts.map +1 -1
  56. package/dist/types/data-source.d.cts +9 -0
  57. package/dist/types/data-source.d.cts.map +1 -1
  58. package/dist/types/data-source.d.ts +9 -0
  59. package/dist/types/data-source.d.ts.map +1 -1
  60. package/dist/types/filter.d.cts +11 -0
  61. package/dist/types/filter.d.cts.map +1 -1
  62. package/dist/types/filter.d.ts +11 -0
  63. package/dist/types/filter.d.ts.map +1 -1
  64. package/dist/types/folders.d.cts +2 -0
  65. package/dist/types/folders.d.cts.map +1 -1
  66. package/dist/types/folders.d.ts +2 -0
  67. package/dist/types/folders.d.ts.map +1 -1
  68. package/dist/types/options.d.cts +57 -1
  69. package/dist/types/options.d.cts.map +1 -1
  70. package/dist/types/options.d.ts +57 -1
  71. package/dist/types/options.d.ts.map +1 -1
  72. package/dist/types/resumable.cjs +42 -0
  73. package/dist/types/resumable.d.cts +204 -0
  74. package/dist/types/resumable.d.cts.map +1 -0
  75. package/dist/types/resumable.d.ts +204 -0
  76. package/dist/types/resumable.d.ts.map +1 -0
  77. package/dist/types/resumable.js +4 -0
  78. package/dist/types/transform.cjs +18 -0
  79. package/dist/types/transform.d.cts +45 -0
  80. package/dist/types/transform.d.cts.map +1 -0
  81. package/dist/types/transform.d.ts +45 -0
  82. package/dist/types/transform.d.ts.map +1 -0
  83. package/dist/types/transform.js +1 -0
  84. package/dist/types/types.d.cts +17 -0
  85. package/dist/types/types.d.cts.map +1 -1
  86. package/dist/types/types.d.ts +17 -0
  87. package/dist/types/types.d.ts.map +1 -1
  88. package/dist/types/unsplash.d.cts +2 -0
  89. package/dist/types/unsplash.d.cts.map +1 -1
  90. package/dist/types/unsplash.d.ts +2 -0
  91. package/dist/types/unsplash.d.ts.map +1 -1
  92. package/dist/ui/AssetBrowser.d.cts +3 -1
  93. package/dist/ui/AssetBrowser.d.cts.map +1 -1
  94. package/dist/ui/AssetBrowser.d.ts +3 -1
  95. package/dist/ui/AssetBrowser.d.ts.map +1 -1
  96. package/dist/ui/AssetCommandPalette.d.cts +4 -1
  97. package/dist/ui/AssetCommandPalette.d.cts.map +1 -1
  98. package/dist/ui/AssetCommandPalette.d.ts +4 -1
  99. package/dist/ui/AssetCommandPalette.d.ts.map +1 -1
  100. package/dist/ui/AssetManagerUI.cjs +3 -1
  101. package/dist/ui/AssetManagerUI.d.cts +11 -2
  102. package/dist/ui/AssetManagerUI.d.cts.map +1 -1
  103. package/dist/ui/AssetManagerUI.d.ts +11 -2
  104. package/dist/ui/AssetManagerUI.d.ts.map +1 -1
  105. package/dist/ui/AssetManagerUI.js +3 -1
  106. package/dist/ui/DeleteAssetDialog.d.cts +4 -1
  107. package/dist/ui/DeleteAssetDialog.d.cts.map +1 -1
  108. package/dist/ui/DeleteAssetDialog.d.ts +4 -1
  109. package/dist/ui/DeleteAssetDialog.d.ts.map +1 -1
  110. package/dist/ui/DeleteFolderDialog.d.cts +4 -1
  111. package/dist/ui/DeleteFolderDialog.d.cts.map +1 -1
  112. package/dist/ui/DeleteFolderDialog.d.ts +4 -1
  113. package/dist/ui/DeleteFolderDialog.d.ts.map +1 -1
  114. package/dist/ui/EmptyFolderState.d.cts +4 -1
  115. package/dist/ui/EmptyFolderState.d.cts.map +1 -1
  116. package/dist/ui/EmptyFolderState.d.ts +4 -1
  117. package/dist/ui/EmptyFolderState.d.ts.map +1 -1
  118. package/dist/ui/FolderBreadcrumb.d.cts +4 -1
  119. package/dist/ui/FolderBreadcrumb.d.cts.map +1 -1
  120. package/dist/ui/FolderBreadcrumb.d.ts +4 -1
  121. package/dist/ui/FolderBreadcrumb.d.ts.map +1 -1
  122. package/dist/ui/FolderNameDialog.d.cts +3 -1
  123. package/dist/ui/FolderNameDialog.d.cts.map +1 -1
  124. package/dist/ui/FolderNameDialog.d.ts +3 -1
  125. package/dist/ui/FolderNameDialog.d.ts.map +1 -1
  126. package/dist/ui/FolderTree.d.cts +4 -1
  127. package/dist/ui/FolderTree.d.cts.map +1 -1
  128. package/dist/ui/FolderTree.d.ts +4 -1
  129. package/dist/ui/FolderTree.d.ts.map +1 -1
  130. package/dist/ui/MetadataPanel.d.cts +4 -1
  131. package/dist/ui/MetadataPanel.d.cts.map +1 -1
  132. package/dist/ui/MetadataPanel.d.ts +4 -1
  133. package/dist/ui/MetadataPanel.d.ts.map +1 -1
  134. package/dist/ui/MoveTargetPicker.d.cts +3 -1
  135. package/dist/ui/MoveTargetPicker.d.cts.map +1 -1
  136. package/dist/ui/MoveTargetPicker.d.ts +3 -1
  137. package/dist/ui/MoveTargetPicker.d.ts.map +1 -1
  138. package/dist/ui/ReplaceAssetDialog.cjs +7 -2
  139. package/dist/ui/ReplaceAssetDialog.d.cts +5 -2
  140. package/dist/ui/ReplaceAssetDialog.d.cts.map +1 -1
  141. package/dist/ui/ReplaceAssetDialog.d.ts +5 -2
  142. package/dist/ui/ReplaceAssetDialog.d.ts.map +1 -1
  143. package/dist/ui/ReplaceAssetDialog.js +7 -2
  144. package/dist/ui/UnsplashPanel.d.cts +4 -1
  145. package/dist/ui/UnsplashPanel.d.cts.map +1 -1
  146. package/dist/ui/UnsplashPanel.d.ts +4 -1
  147. package/dist/ui/UnsplashPanel.d.ts.map +1 -1
  148. package/dist/ui/UploadButton.cjs +7 -2
  149. package/dist/ui/UploadButton.d.cts +6 -2
  150. package/dist/ui/UploadButton.d.cts.map +1 -1
  151. package/dist/ui/UploadButton.d.ts +6 -2
  152. package/dist/ui/UploadButton.d.ts.map +1 -1
  153. package/dist/ui/UploadButton.js +7 -2
  154. package/dist/utils/asset-reference.cjs +87 -4
  155. package/dist/utils/asset-reference.d.cts +30 -6
  156. package/dist/utils/asset-reference.d.cts.map +1 -1
  157. package/dist/utils/asset-reference.d.ts +30 -6
  158. package/dist/utils/asset-reference.d.ts.map +1 -1
  159. package/dist/utils/asset-reference.js +83 -3
  160. package/dist/utils/csp.cjs +16 -0
  161. package/dist/utils/csp.d.cts +23 -0
  162. package/dist/utils/csp.d.cts.map +1 -1
  163. package/dist/utils/csp.d.ts +23 -0
  164. package/dist/utils/csp.d.ts.map +1 -1
  165. package/dist/utils/csp.js +16 -0
  166. package/dist/utils/data-source.cjs +19 -5
  167. package/dist/utils/data-source.d.cts +5 -1
  168. package/dist/utils/data-source.d.cts.map +1 -1
  169. package/dist/utils/data-source.d.ts +5 -1
  170. package/dist/utils/data-source.d.ts.map +1 -1
  171. package/dist/utils/data-source.js +19 -5
  172. package/dist/utils/errors.d.cts +5 -0
  173. package/dist/utils/errors.d.cts.map +1 -1
  174. package/dist/utils/errors.d.ts +5 -0
  175. package/dist/utils/errors.d.ts.map +1 -1
  176. package/dist/utils/query-param-transform.cjs +101 -0
  177. package/dist/utils/query-param-transform.d.cts +46 -0
  178. package/dist/utils/query-param-transform.d.cts.map +1 -0
  179. package/dist/utils/query-param-transform.d.ts +46 -0
  180. package/dist/utils/query-param-transform.d.ts.map +1 -0
  181. package/dist/utils/query-param-transform.js +60 -0
  182. package/dist/utils/registry.cjs +3 -0
  183. package/dist/utils/registry.d.cts +8 -0
  184. package/dist/utils/registry.d.cts.map +1 -1
  185. package/dist/utils/registry.d.ts +8 -0
  186. package/dist/utils/registry.d.ts.map +1 -1
  187. package/dist/utils/registry.js +3 -0
  188. package/dist/utils/resolver.cjs +19 -11
  189. package/dist/utils/resolver.d.cts +24 -0
  190. package/dist/utils/resolver.d.cts.map +1 -1
  191. package/dist/utils/resolver.d.ts +24 -0
  192. package/dist/utils/resolver.d.ts.map +1 -1
  193. package/dist/utils/resolver.js +19 -11
  194. package/dist/utils/retry.d.cts +2 -0
  195. package/dist/utils/retry.d.cts.map +1 -1
  196. package/dist/utils/retry.d.ts +2 -0
  197. package/dist/utils/retry.d.ts.map +1 -1
  198. package/dist/utils/run-resumable-upload.cjs +160 -0
  199. package/dist/utils/run-resumable-upload.d.cts +56 -0
  200. package/dist/utils/run-resumable-upload.d.cts.map +1 -0
  201. package/dist/utils/run-resumable-upload.d.ts +56 -0
  202. package/dist/utils/run-resumable-upload.d.ts.map +1 -0
  203. package/dist/utils/run-resumable-upload.js +122 -0
  204. package/dist/utils/sniff-file-type.cjs +209 -0
  205. package/dist/utils/sniff-file-type.d.cts +25 -0
  206. package/dist/utils/sniff-file-type.d.cts.map +1 -0
  207. package/dist/utils/sniff-file-type.d.ts +25 -0
  208. package/dist/utils/sniff-file-type.d.ts.map +1 -0
  209. package/dist/utils/sniff-file-type.js +164 -0
  210. package/dist/utils/studio-asset-source.cjs +11 -6
  211. package/dist/utils/studio-asset-source.d.cts +5 -1
  212. package/dist/utils/studio-asset-source.d.cts.map +1 -1
  213. package/dist/utils/studio-asset-source.d.ts +5 -1
  214. package/dist/utils/studio-asset-source.d.ts.map +1 -1
  215. package/dist/utils/studio-asset-source.js +11 -6
  216. package/dist/utils/upload-session-store.cjs +125 -0
  217. package/dist/utils/upload-session-store.d.cts +55 -0
  218. package/dist/utils/upload-session-store.d.cts.map +1 -0
  219. package/dist/utils/upload-session-store.d.ts +55 -0
  220. package/dist/utils/upload-session-store.d.ts.map +1 -0
  221. package/dist/utils/upload-session-store.js +84 -0
  222. package/dist/utils/validate-upload-result.cjs +9 -1
  223. package/dist/utils/validate-upload-result.d.cts +1 -0
  224. package/dist/utils/validate-upload-result.d.cts.map +1 -1
  225. package/dist/utils/validate-upload-result.d.ts +1 -0
  226. package/dist/utils/validate-upload-result.d.ts.map +1 -1
  227. package/dist/utils/validate-upload-result.js +9 -1
  228. package/dist/version.cjs +1 -1
  229. package/dist/version.d.cts +1 -1
  230. package/dist/version.d.cts.map +1 -1
  231. package/dist/version.d.ts +1 -1
  232. package/dist/version.d.ts.map +1 -1
  233. package/dist/version.js +1 -1
  234. package/meta/config.json +1 -1
  235. package/package.json +40 -10
@@ -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":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACX,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,MAAM,WAAW,UAAU;IAC1B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACpD;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,SAAS,GAClB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,SAAS,EAAE,GACpB;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACtC,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IAClC,sEAAsE;IACtE,IAAI,CACH,IAAI,EAAE,IAAI,GAER,sBAAsB,GACtB,SAAS,GACT,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAAC;IAC/C,8EAA8E;IAC9E,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,sBAAsB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,6EAA6E;IAC7E,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,sBAAsB;IACtC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,KAAK,EAAE,CACf,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,sBAAsB,EAC/B,OAAO,CAAC,EAAE,oBAAoB,KAC1B,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,UAAU,EAAE,CACpB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,oBAAoB,KAC1B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAClB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,oBAAoB,KAC1B,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,CACf,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,oBAAoB,KAC1B,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,aAAa,GAAG,sBAAsB,GAAG,SAAS,GACvD,KAAK,IAAI,sBAAsB,CASjC"}
@@ -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 { };
@@ -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":"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"}
1
+ {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"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"}
@@ -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;