canopycms 0.0.56 → 0.0.58

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 (272) hide show
  1. package/dist/ai/json-to-markdown.js +74 -3
  2. package/dist/ai/json-to-markdown.js.map +1 -1
  3. package/dist/api/__test__/mock-client.d.ts +9 -5
  4. package/dist/api/__test__/mock-client.d.ts.map +1 -1
  5. package/dist/api/__test__/mock-client.js +15 -7
  6. package/dist/api/__test__/mock-client.js.map +1 -1
  7. package/dist/api/assets.d.ts +100 -36
  8. package/dist/api/assets.d.ts.map +1 -1
  9. package/dist/api/assets.js +338 -51
  10. package/dist/api/assets.js.map +1 -1
  11. package/dist/api/branch.d.ts +6 -0
  12. package/dist/api/branch.d.ts.map +1 -1
  13. package/dist/api/branch.js +63 -19
  14. package/dist/api/branch.js.map +1 -1
  15. package/dist/api/client.d.ts +16 -5
  16. package/dist/api/client.d.ts.map +1 -1
  17. package/dist/api/client.js +24 -6
  18. package/dist/api/client.js.map +1 -1
  19. package/dist/api/content.d.ts +2 -2
  20. package/dist/api/entries.d.ts +4 -4
  21. package/dist/api/entries.d.ts.map +1 -1
  22. package/dist/api/entries.js +10 -2
  23. package/dist/api/entries.js.map +1 -1
  24. package/dist/api/index.d.ts +1 -1
  25. package/dist/api/index.d.ts.map +1 -1
  26. package/dist/api/index.js.map +1 -1
  27. package/dist/api/route-builder.d.ts +9 -0
  28. package/dist/api/route-builder.d.ts.map +1 -1
  29. package/dist/api/route-builder.js +1 -0
  30. package/dist/api/route-builder.js.map +1 -1
  31. package/dist/api/schema.d.ts +4 -4
  32. package/dist/api/types.d.ts +11 -1
  33. package/dist/api/types.d.ts.map +1 -1
  34. package/dist/assets/asset-prefixes.d.ts +31 -0
  35. package/dist/assets/asset-prefixes.d.ts.map +1 -0
  36. package/dist/assets/asset-prefixes.js +20 -0
  37. package/dist/assets/asset-prefixes.js.map +1 -0
  38. package/dist/assets/asset-src.d.ts +23 -0
  39. package/dist/assets/asset-src.d.ts.map +1 -0
  40. package/dist/assets/asset-src.js +28 -0
  41. package/dist/assets/asset-src.js.map +1 -0
  42. package/dist/assets/asset-url.d.ts +35 -0
  43. package/dist/assets/asset-url.d.ts.map +1 -0
  44. package/dist/assets/asset-url.js +77 -0
  45. package/dist/assets/asset-url.js.map +1 -0
  46. package/dist/assets/factory.d.ts +18 -0
  47. package/dist/assets/factory.d.ts.map +1 -0
  48. package/dist/assets/factory.js +42 -0
  49. package/dist/assets/factory.js.map +1 -0
  50. package/dist/assets/finalize.d.ts +36 -0
  51. package/dist/assets/finalize.d.ts.map +1 -0
  52. package/dist/assets/finalize.js +72 -0
  53. package/dist/assets/finalize.js.map +1 -0
  54. package/dist/assets/index.d.ts +20 -0
  55. package/dist/assets/index.d.ts.map +1 -0
  56. package/dist/assets/index.js +19 -0
  57. package/dist/assets/index.js.map +1 -0
  58. package/dist/assets/keys.d.ts +56 -0
  59. package/dist/assets/keys.d.ts.map +1 -0
  60. package/dist/assets/keys.js +88 -0
  61. package/dist/assets/keys.js.map +1 -0
  62. package/dist/assets/pipeline.d.ts +50 -0
  63. package/dist/assets/pipeline.d.ts.map +1 -0
  64. package/dist/assets/pipeline.js +202 -0
  65. package/dist/assets/pipeline.js.map +1 -0
  66. package/dist/assets/store-local.d.ts +84 -0
  67. package/dist/assets/store-local.d.ts.map +1 -0
  68. package/dist/assets/store-local.js +254 -0
  69. package/dist/assets/store-local.js.map +1 -0
  70. package/dist/assets/store-s3.d.ts +71 -0
  71. package/dist/assets/store-s3.d.ts.map +1 -0
  72. package/dist/assets/store-s3.js +183 -0
  73. package/dist/assets/store-s3.js.map +1 -0
  74. package/dist/assets/svg-sanitizer.d.ts +37 -0
  75. package/dist/assets/svg-sanitizer.d.ts.map +1 -0
  76. package/dist/assets/svg-sanitizer.js +222 -0
  77. package/dist/assets/svg-sanitizer.js.map +1 -0
  78. package/dist/assets/transform-directives.d.ts +97 -0
  79. package/dist/assets/transform-directives.d.ts.map +1 -0
  80. package/dist/assets/transform-directives.js +267 -0
  81. package/dist/assets/transform-directives.js.map +1 -0
  82. package/dist/assets/transform.d.ts +51 -0
  83. package/dist/assets/transform.d.ts.map +1 -0
  84. package/dist/assets/transform.js +190 -0
  85. package/dist/assets/transform.js.map +1 -0
  86. package/dist/assets/types.d.ts +82 -0
  87. package/dist/assets/types.d.ts.map +1 -0
  88. package/dist/assets/types.js +10 -0
  89. package/dist/assets/types.js.map +1 -0
  90. package/dist/authorization/groups/schema.d.ts +2 -2
  91. package/dist/authorization/permissions/schema.d.ts +2 -2
  92. package/dist/branch-metadata.d.ts +71 -6
  93. package/dist/branch-metadata.d.ts.map +1 -1
  94. package/dist/branch-metadata.js +132 -116
  95. package/dist/branch-metadata.js.map +1 -1
  96. package/dist/branch-registry.d.ts +78 -9
  97. package/dist/branch-registry.d.ts.map +1 -1
  98. package/dist/branch-registry.js +155 -29
  99. package/dist/branch-registry.js.map +1 -1
  100. package/dist/branch-schema-cache.d.ts +126 -11
  101. package/dist/branch-schema-cache.d.ts.map +1 -1
  102. package/dist/branch-schema-cache.js +208 -58
  103. package/dist/branch-schema-cache.js.map +1 -1
  104. package/dist/cli/generate-ai-content.js +1993 -1506
  105. package/dist/cli/init.js +16 -4
  106. package/dist/cli/migrate.d.ts.map +1 -1
  107. package/dist/cli/migrate.js +25 -0
  108. package/dist/cli/migrate.js.map +1 -1
  109. package/dist/cli/sync.js +5 -5
  110. package/dist/cli/sync.js.map +1 -1
  111. package/dist/comment-store.d.ts +45 -15
  112. package/dist/comment-store.d.ts.map +1 -1
  113. package/dist/comment-store.js +80 -101
  114. package/dist/comment-store.js.map +1 -1
  115. package/dist/config/helpers.d.ts.map +1 -1
  116. package/dist/config/helpers.js +2 -1
  117. package/dist/config/helpers.js.map +1 -1
  118. package/dist/config/index.d.ts +2 -2
  119. package/dist/config/index.d.ts.map +1 -1
  120. package/dist/config/index.js +1 -1
  121. package/dist/config/index.js.map +1 -1
  122. package/dist/config/schemas/config.d.ts +10 -0
  123. package/dist/config/schemas/config.d.ts.map +1 -1
  124. package/dist/config/schemas/field.d.ts +38 -3
  125. package/dist/config/schemas/field.d.ts.map +1 -1
  126. package/dist/config/schemas/field.js +18 -0
  127. package/dist/config/schemas/field.js.map +1 -1
  128. package/dist/config/schemas/media.d.ts +8 -0
  129. package/dist/config/schemas/media.d.ts.map +1 -1
  130. package/dist/config/schemas/media.js +9 -0
  131. package/dist/config/schemas/media.js.map +1 -1
  132. package/dist/config/types.d.ts +43 -3
  133. package/dist/config/types.d.ts.map +1 -1
  134. package/dist/config/types.js +4 -1
  135. package/dist/config/types.js.map +1 -1
  136. package/dist/content-index-generation.d.ts +40 -4
  137. package/dist/content-index-generation.d.ts.map +1 -1
  138. package/dist/content-index-generation.js +70 -73
  139. package/dist/content-index-generation.js.map +1 -1
  140. package/dist/content-store.d.ts +63 -0
  141. package/dist/content-store.d.ts.map +1 -1
  142. package/dist/content-store.js +421 -194
  143. package/dist/content-store.js.map +1 -1
  144. package/dist/editor/CanopyEditor.d.ts.map +1 -1
  145. package/dist/editor/CanopyEditor.js +1 -1
  146. package/dist/editor/CanopyEditor.js.map +1 -1
  147. package/dist/editor/Editor.d.ts +2 -0
  148. package/dist/editor/Editor.d.ts.map +1 -1
  149. package/dist/editor/Editor.js +82 -80
  150. package/dist/editor/Editor.js.map +1 -1
  151. package/dist/editor/FormRenderer.d.ts.map +1 -1
  152. package/dist/editor/FormRenderer.js +9 -0
  153. package/dist/editor/FormRenderer.js.map +1 -1
  154. package/dist/editor/components/EditorSidebar.d.ts +6 -1
  155. package/dist/editor/components/EditorSidebar.d.ts.map +1 -1
  156. package/dist/editor/components/EditorSidebar.js +4 -3
  157. package/dist/editor/components/EditorSidebar.js.map +1 -1
  158. package/dist/editor/context/AssetContext.d.ts +25 -0
  159. package/dist/editor/context/AssetContext.d.ts.map +1 -0
  160. package/dist/editor/context/AssetContext.js +26 -0
  161. package/dist/editor/context/AssetContext.js.map +1 -0
  162. package/dist/editor/context/index.d.ts +1 -0
  163. package/dist/editor/context/index.d.ts.map +1 -1
  164. package/dist/editor/context/index.js +1 -0
  165. package/dist/editor/context/index.js.map +1 -1
  166. package/dist/editor/fields/ImageField.d.ts +22 -0
  167. package/dist/editor/fields/ImageField.d.ts.map +1 -0
  168. package/dist/editor/fields/ImageField.js +100 -0
  169. package/dist/editor/fields/ImageField.js.map +1 -0
  170. package/dist/editor/fields/MarkdownField.d.ts.map +1 -1
  171. package/dist/editor/fields/MarkdownField.js +30 -4
  172. package/dist/editor/fields/MarkdownField.js.map +1 -1
  173. package/dist/editor/fields/MdxImageDialog.d.ts +16 -0
  174. package/dist/editor/fields/MdxImageDialog.d.ts.map +1 -0
  175. package/dist/editor/fields/MdxImageDialog.js +73 -0
  176. package/dist/editor/fields/MdxImageDialog.js.map +1 -0
  177. package/dist/editor/media/AssetCard.d.ts +21 -0
  178. package/dist/editor/media/AssetCard.d.ts.map +1 -0
  179. package/dist/editor/media/AssetCard.js +41 -0
  180. package/dist/editor/media/AssetCard.js.map +1 -0
  181. package/dist/editor/media/CropStep.d.ts +26 -0
  182. package/dist/editor/media/CropStep.d.ts.map +1 -0
  183. package/dist/editor/media/CropStep.js +38 -0
  184. package/dist/editor/media/CropStep.js.map +1 -0
  185. package/dist/editor/media/MediaLibrary.d.ts +22 -0
  186. package/dist/editor/media/MediaLibrary.d.ts.map +1 -0
  187. package/dist/editor/media/MediaLibrary.js +17 -0
  188. package/dist/editor/media/MediaLibrary.js.map +1 -0
  189. package/dist/editor/media/MediaLibraryBody.d.ts +17 -0
  190. package/dist/editor/media/MediaLibraryBody.d.ts.map +1 -0
  191. package/dist/editor/media/MediaLibraryBody.js +133 -0
  192. package/dist/editor/media/MediaLibraryBody.js.map +1 -0
  193. package/dist/editor/media/crop-math.d.ts +37 -0
  194. package/dist/editor/media/crop-math.d.ts.map +1 -0
  195. package/dist/editor/media/crop-math.js +62 -0
  196. package/dist/editor/media/crop-math.js.map +1 -0
  197. package/dist/editor/media/upload-asset.d.ts +31 -0
  198. package/dist/editor/media/upload-asset.d.ts.map +1 -0
  199. package/dist/editor/media/upload-asset.js +56 -0
  200. package/dist/editor/media/upload-asset.js.map +1 -0
  201. package/dist/editor/media/upload-constants.d.ts +27 -0
  202. package/dist/editor/media/upload-constants.d.ts.map +1 -0
  203. package/dist/editor/media/upload-constants.js +40 -0
  204. package/dist/editor/media/upload-constants.js.map +1 -0
  205. package/dist/editor/media/useAssetUpload.d.ts +19 -0
  206. package/dist/editor/media/useAssetUpload.d.ts.map +1 -0
  207. package/dist/editor/media/useAssetUpload.js +53 -0
  208. package/dist/editor/media/useAssetUpload.js.map +1 -0
  209. package/dist/editor/media/xhr-upload.d.ts +20 -0
  210. package/dist/editor/media/xhr-upload.d.ts.map +1 -0
  211. package/dist/editor/media/xhr-upload.js +42 -0
  212. package/dist/editor/media/xhr-upload.js.map +1 -0
  213. package/dist/editor/theme.d.ts +2 -1
  214. package/dist/editor/theme.d.ts.map +1 -1
  215. package/dist/editor/theme.js +1 -0
  216. package/dist/editor/theme.js.map +1 -1
  217. package/dist/entry-schema.d.ts +19 -0
  218. package/dist/entry-schema.d.ts.map +1 -1
  219. package/dist/entry-schema.js.map +1 -1
  220. package/dist/git-manager.d.ts +15 -10
  221. package/dist/git-manager.d.ts.map +1 -1
  222. package/dist/git-manager.js +16 -11
  223. package/dist/git-manager.js.map +1 -1
  224. package/dist/http/handler.d.ts +5 -2
  225. package/dist/http/handler.d.ts.map +1 -1
  226. package/dist/http/handler.js +13 -4
  227. package/dist/http/handler.js.map +1 -1
  228. package/dist/http/index.d.ts +2 -2
  229. package/dist/http/index.d.ts.map +1 -1
  230. package/dist/http/index.js +1 -1
  231. package/dist/http/index.js.map +1 -1
  232. package/dist/http/router.d.ts +14 -1
  233. package/dist/http/router.d.ts.map +1 -1
  234. package/dist/http/router.js +4 -1
  235. package/dist/http/router.js.map +1 -1
  236. package/dist/http/types.d.ts +40 -0
  237. package/dist/http/types.d.ts.map +1 -1
  238. package/dist/http/types.js +9 -0
  239. package/dist/http/types.js.map +1 -1
  240. package/dist/index.d.ts +3 -0
  241. package/dist/index.d.ts.map +1 -1
  242. package/dist/index.js +4 -0
  243. package/dist/index.js.map +1 -1
  244. package/dist/resource-generation.d.ts +54 -0
  245. package/dist/resource-generation.d.ts.map +1 -0
  246. package/dist/resource-generation.js +156 -0
  247. package/dist/resource-generation.js.map +1 -0
  248. package/dist/schema/schema-store.d.ts +31 -4
  249. package/dist/schema/schema-store.d.ts.map +1 -1
  250. package/dist/schema/schema-store.js +47 -8
  251. package/dist/schema/schema-store.js.map +1 -1
  252. package/dist/server.d.ts +45 -0
  253. package/dist/server.d.ts.map +1 -1
  254. package/dist/server.js +41 -0
  255. package/dist/server.js.map +1 -1
  256. package/dist/sync-core.js +2 -2
  257. package/dist/sync-core.js.map +1 -1
  258. package/dist/utils/occ-json-write.d.ts +100 -0
  259. package/dist/utils/occ-json-write.d.ts.map +1 -0
  260. package/dist/utils/occ-json-write.js +234 -0
  261. package/dist/utils/occ-json-write.js.map +1 -0
  262. package/dist/validation/entry-validator.d.ts.map +1 -1
  263. package/dist/validation/entry-validator.js +56 -1
  264. package/dist/validation/entry-validator.js.map +1 -1
  265. package/dist/worker/cms-worker.d.ts.map +1 -1
  266. package/dist/worker/cms-worker.js +21 -3
  267. package/dist/worker/cms-worker.js.map +1 -1
  268. package/package.json +13 -1
  269. package/dist/asset-store.d.ts +0 -32
  270. package/dist/asset-store.d.ts.map +0 -1
  271. package/dist/asset-store.js +0 -85
  272. package/dist/asset-store.js.map +0 -1
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Compute the root-relative public URL for an asset's meta. Shared helper -
3
+ * both the API layer (list/finalize responses) and later PRs (structured
4
+ * image field, MediaLibrary, `assetUrl()`) build URLs through this so the
5
+ * URL shape is defined in exactly one place.
6
+ *
7
+ * svg/pdf: served statically from the public object finalize wrote
8
+ * (`assets/{hash32}/{slug}.{ext}`, via keys.ts's `publicKey`).
9
+ *
10
+ * raster: served through the transform layer using the `orig` (identity)
11
+ * directive. The transform engine itself is PR 4's job, but the URL shape is
12
+ * decided now (rather than switching every raster URL over once transforms
13
+ * ship) so content written by this PR stays valid without a migration.
14
+ *
15
+ * Always root-relative - `media.publicBaseUrl` is editor-display-only (PR 6's
16
+ * concern) and must never be baked into stored/served content URLs.
17
+ */
18
+ import { IDENTITY_TRANSFORM_DIRECTIVE } from './transform-directives';
19
+ import type { AssetMeta } from './types';
20
+ /** Re-exported for existing importers (assets/index.ts barrel) - the value now lives in transform-directives.ts, PR 4's pure directive module, so it's reachable without pulling keys.ts's node:crypto import into client bundles. */
21
+ export { IDENTITY_TRANSFORM_DIRECTIVE };
22
+ export declare function assetSrc(meta: Pick<AssetMeta, 'hash32' | 'slug' | 'ext' | 'kind'>): string;
23
+ //# sourceMappingURL=asset-src.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-src.d.ts","sourceRoot":"","sources":["../../src/assets/asset-src.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,sOAAsO;AACtO,OAAO,EAAE,4BAA4B,EAAE,CAAA;AAEvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC,GAAG,MAAM,CAK1F"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Compute the root-relative public URL for an asset's meta. Shared helper -
3
+ * both the API layer (list/finalize responses) and later PRs (structured
4
+ * image field, MediaLibrary, `assetUrl()`) build URLs through this so the
5
+ * URL shape is defined in exactly one place.
6
+ *
7
+ * svg/pdf: served statically from the public object finalize wrote
8
+ * (`assets/{hash32}/{slug}.{ext}`, via keys.ts's `publicKey`).
9
+ *
10
+ * raster: served through the transform layer using the `orig` (identity)
11
+ * directive. The transform engine itself is PR 4's job, but the URL shape is
12
+ * decided now (rather than switching every raster URL over once transforms
13
+ * ship) so content written by this PR stays valid without a migration.
14
+ *
15
+ * Always root-relative - `media.publicBaseUrl` is editor-display-only (PR 6's
16
+ * concern) and must never be baked into stored/served content URLs.
17
+ */
18
+ import { ASSET_PREFIXES } from './asset-prefixes.js';
19
+ import { IDENTITY_TRANSFORM_DIRECTIVE } from './transform-directives.js';
20
+ /** Re-exported for existing importers (assets/index.ts barrel) - the value now lives in transform-directives.ts, PR 4's pure directive module, so it's reachable without pulling keys.ts's node:crypto import into client bundles. */
21
+ export { IDENTITY_TRANSFORM_DIRECTIVE };
22
+ export function assetSrc(meta) {
23
+ if (meta.kind === 'svg' || meta.kind === 'pdf') {
24
+ return `/${ASSET_PREFIXES.public}/${meta.hash32}/${meta.slug}.${meta.ext}`;
25
+ }
26
+ return `/${ASSET_PREFIXES.transform}/${IDENTITY_TRANSFORM_DIRECTIVE}/${meta.hash32}/${meta.slug}.${meta.ext}`;
27
+ }
28
+ //# sourceMappingURL=asset-src.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-src.js","sourceRoot":"","sources":["../../src/assets/asset-src.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAA;AAGrE,sOAAsO;AACtO,OAAO,EAAE,4BAA4B,EAAE,CAAA;AAEvC,MAAM,UAAU,QAAQ,CAAC,IAAyD;IAChF,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC/C,OAAO,IAAI,cAAc,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,CAAA;IAC5E,CAAC;IACD,OAAO,IAAI,cAAc,CAAC,SAAS,IAAI,4BAA4B,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,CAAA;AAC/G,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Build/adjust transform URLs for `<img>`/srcset without pulling in the
3
+ * server-only transform engine. Isomorphic - only depends on
4
+ * transform-directives.ts and the plain `ASSET_PREFIXES` constant, neither
5
+ * of which import node builtins, so this is safe to import from client
6
+ * (editor) code as well as during static builds.
7
+ */
8
+ import { type CropRect, type OutputFormat } from './transform-directives';
9
+ /** The minimal shape `assetUrl`/`assetSrcSet` need from a stored asset reference. */
10
+ export interface AssetRef {
11
+ src: string;
12
+ }
13
+ export interface AssetUrlOptions {
14
+ width?: number;
15
+ format?: OutputFormat;
16
+ quality?: number;
17
+ crop?: CropRect;
18
+ /** Prefixed onto the result, e.g. `media.publicBaseUrl` when the editor is served from a different origin than the site. */
19
+ baseUrl?: string;
20
+ }
21
+ /**
22
+ * Build a transform URL, merging `opts` over the directives already present
23
+ * in `ref.src` (opts win). For static srcs (svg/pdf under `/assets/{hash}/...`,
24
+ * or any src that isn't one of our own transform URLs) the src is returned
25
+ * unchanged and `opts` are ignored - there is nothing to transform.
26
+ */
27
+ export declare function assetUrl(ref: AssetRef, opts?: AssetUrlOptions): string;
28
+ /**
29
+ * Build a comma-joined `url w` srcset descriptor list. `widths` must all be
30
+ * on the transform width allowlist (multiples of 160 in [160, 4096]) - this
31
+ * is developer-facing (a host app's own responsive-image markup), so an
32
+ * invalid width throws rather than silently dropping it.
33
+ */
34
+ export declare function assetSrcSet(ref: AssetRef, widths: readonly number[], opts?: Omit<AssetUrlOptions, 'width'>): string;
35
+ //# sourceMappingURL=asset-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-url.d.ts","sourceRoot":"","sources":["../../src/assets/asset-url.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,YAAY,EAElB,MAAM,wBAAwB,CAAA;AAE/B,qFAAqF;AACrF,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,4HAA4H;IAC5H,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AA+BD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,GAAE,eAAoB,GAAG,MAAM,CAuB1E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,IAAI,GAAE,IAAI,CAAC,eAAe,EAAE,OAAO,CAAM,GACxC,MAAM,CAWR"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Build/adjust transform URLs for `<img>`/srcset without pulling in the
3
+ * server-only transform engine. Isomorphic - only depends on
4
+ * transform-directives.ts and the plain `ASSET_PREFIXES` constant, neither
5
+ * of which import node builtins, so this is safe to import from client
6
+ * (editor) code as well as during static builds.
7
+ */
8
+ import { ASSET_PREFIXES } from './asset-prefixes.js';
9
+ import { formatDirectives, isAllowedTransformWidth, parseTransformPath, } from './transform-directives.js';
10
+ const TRANSFORM_URL_PREFIX = `/${ASSET_PREFIXES.transform}/`;
11
+ function joinBaseUrl(baseUrl, urlPath) {
12
+ if (!baseUrl)
13
+ return urlPath;
14
+ const trimmedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
15
+ const trimmedPath = urlPath.startsWith('/') ? urlPath : `/${urlPath}`;
16
+ return `${trimmedBase}${trimmedPath}`;
17
+ }
18
+ /**
19
+ * Merge `opts` over an already-parsed directive set - opts win when given,
20
+ * otherwise the existing value (if any) carries over. Returns `undefined`
21
+ * fields as "unset" (there is no way to explicitly clear a directive via
22
+ * opts - only to override it).
23
+ */
24
+ function mergeDirectives(current, opts) {
25
+ const existing = current.identity ? undefined : current;
26
+ const width = opts.width ?? existing?.width;
27
+ const format = opts.format ?? existing?.format;
28
+ const quality = opts.quality ?? existing?.quality;
29
+ const crop = opts.crop ?? existing?.crop;
30
+ if (width === undefined && format === undefined && quality === undefined && crop === undefined) {
31
+ return { identity: true };
32
+ }
33
+ return { identity: false, width, format, quality, crop };
34
+ }
35
+ /**
36
+ * Build a transform URL, merging `opts` over the directives already present
37
+ * in `ref.src` (opts win). For static srcs (svg/pdf under `/assets/{hash}/...`,
38
+ * or any src that isn't one of our own transform URLs) the src is returned
39
+ * unchanged and `opts` are ignored - there is nothing to transform.
40
+ */
41
+ export function assetUrl(ref, opts = {}) {
42
+ const { src } = ref;
43
+ if (!src.startsWith(TRANSFORM_URL_PREFIX)) {
44
+ return joinBaseUrl(opts.baseUrl, src);
45
+ }
46
+ const rest = src.slice(TRANSFORM_URL_PREFIX.length);
47
+ const parsed = parseTransformPath(rest.split('/'));
48
+ if (!parsed.ok) {
49
+ // Malformed src (shouldn't happen for a src canopycms itself wrote) -
50
+ // nothing sensible to merge onto, so return it unchanged rather than throw.
51
+ return joinBaseUrl(opts.baseUrl, src);
52
+ }
53
+ const merged = mergeDirectives(parsed.directives, opts);
54
+ // Ext follows the format: an explicit format (new or carried over) always
55
+ // wins; with no format at all, the ext must keep preserving the source's
56
+ // real extension, which is exactly what `parsed.ext` already is here.
57
+ const ext = !merged.identity && merged.format !== undefined ? merged.format : parsed.ext;
58
+ const newSrc = `${TRANSFORM_URL_PREFIX}${formatDirectives(merged)}/${parsed.hash32}/${parsed.slug}.${ext}`;
59
+ return joinBaseUrl(opts.baseUrl, newSrc);
60
+ }
61
+ /**
62
+ * Build a comma-joined `url w` srcset descriptor list. `widths` must all be
63
+ * on the transform width allowlist (multiples of 160 in [160, 4096]) - this
64
+ * is developer-facing (a host app's own responsive-image markup), so an
65
+ * invalid width throws rather than silently dropping it.
66
+ */
67
+ export function assetSrcSet(ref, widths, opts = {}) {
68
+ return widths
69
+ .map((width) => {
70
+ if (!isAllowedTransformWidth(width)) {
71
+ throw new Error(`assetSrcSet: width ${width} is not allowed (must be a multiple of 160 between 160 and 4096)`);
72
+ }
73
+ return `${assetUrl(ref, { ...opts, width })} ${width}w`;
74
+ })
75
+ .join(', ');
76
+ }
77
+ //# sourceMappingURL=asset-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-url.js","sourceRoot":"","sources":["../../src/assets/asset-url.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Instantiate the configured AssetStore from a site's `media` config.
3
+ *
4
+ * This is the one place that turns the (currently-unconsumed) `media` config
5
+ * into a real store — see .claude/future-tasks/assets-media-system.md for why
6
+ * this was previously dead configuration.
7
+ */
8
+ import type { MediaConfig } from '../config/types';
9
+ import type { AssetStore } from './types';
10
+ /**
11
+ * @param media - The site's `media` config (`config.media`), or undefined if unset.
12
+ * @param opts.devAssetsDir - Root directory for the implicit local fallback store used
13
+ * when `media` is undefined, or when `adapter: 'local'` omits `directory`.
14
+ */
15
+ export declare function createAssetStore(media: MediaConfig | undefined, opts?: {
16
+ devAssetsDir?: string;
17
+ }): AssetStore | undefined;
18
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/assets/factory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,GAAG,SAAS,EAC9B,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,UAAU,GAAG,SAAS,CA2BxB"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Instantiate the configured AssetStore from a site's `media` config.
3
+ *
4
+ * This is the one place that turns the (currently-unconsumed) `media` config
5
+ * into a real store — see .claude/future-tasks/assets-media-system.md for why
6
+ * this was previously dead configuration.
7
+ */
8
+ import { LocalAssetStore } from './store-local.js';
9
+ import { S3AssetStore } from './store-s3.js';
10
+ /**
11
+ * @param media - The site's `media` config (`config.media`), or undefined if unset.
12
+ * @param opts.devAssetsDir - Root directory for the implicit local fallback store used
13
+ * when `media` is undefined, or when `adapter: 'local'` omits `directory`.
14
+ */
15
+ export function createAssetStore(media, opts = {}) {
16
+ if (!media) {
17
+ return opts.devAssetsDir ? new LocalAssetStore({ root: opts.devAssetsDir }) : undefined;
18
+ }
19
+ switch (media.adapter) {
20
+ case 's3':
21
+ return new S3AssetStore({
22
+ bucket: media.bucket,
23
+ region: media.region,
24
+ publicBaseUrl: media.publicBaseUrl,
25
+ maxUploadBytes: media.maxUploadBytes,
26
+ });
27
+ case 'local': {
28
+ const root = media.directory ?? opts.devAssetsDir;
29
+ return root ? new LocalAssetStore({ root }) : undefined;
30
+ }
31
+ case 'lfs':
32
+ // Config literal kept for forward compatibility; no lfs adapter is
33
+ // implemented yet (see BACKLOG.md "Asset adapters").
34
+ return undefined;
35
+ default:
36
+ // Defensive: mediaSchema is a closed discriminated union, so this is
37
+ // unreachable via validated config, but guards against an unrecognized
38
+ // adapter string reaching here some other way.
39
+ return undefined;
40
+ }
41
+ }
42
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/assets/factory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAGzC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAA8B,EAC9B,OAAkC,EAAE;IAEpC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACzF,CAAC;IAED,QAAQ,KAAK,CAAC,OAAO,EAAE,CAAC;QACtB,KAAK,IAAI;YACP,OAAO,IAAI,YAAY,CAAC;gBACtB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,cAAc,EAAE,KAAK,CAAC,cAAc;aACrC,CAAC,CAAA;QACJ,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY,CAAA;YACjD,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACzD,CAAC;QACD,KAAK,KAAK;YACR,mEAAmE;YACnE,qDAAqD;YACrD,OAAO,SAAS,CAAA;QAClB;YACE,qEAAqE;YACrE,uEAAuE;YACvE,+CAA+C;YAC/C,OAAO,SAAS,CAAA;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Store orchestration around the (pure) finalize pipeline: dedup, write, and
3
+ * best-effort staging cleanup. Split from pipeline.ts so the pipeline itself
4
+ * stays store-agnostic and trivially unit-testable with plain byte fixtures.
5
+ */
6
+ import { type FinalizeInput, type FinalizeRejection } from './pipeline';
7
+ import type { AssetMeta, AssetStore } from './types';
8
+ export declare function isValidStagingKey(key: string): boolean;
9
+ export type FinalizeAssetResult = {
10
+ ok: true;
11
+ meta: AssetMeta;
12
+ } | FinalizeRejection;
13
+ /**
14
+ * Run the finalize pipeline over raw bytes and persist the result.
15
+ *
16
+ * Order matters here too: dedup FIRST (after hashing, inside the pipeline) -
17
+ * if an identical blob already exists, return the existing meta and skip all
18
+ * writes entirely (first-name-wins). Otherwise write the original, then the
19
+ * optional public object, then `putMetaIfAbsent` LAST: meta is the commit
20
+ * point for an asset's existence, so a crash between `putOriginal` and here
21
+ * leaves only orphaned (harmless, content-addressed) blobs, never a meta
22
+ * record pointing at a missing blob.
23
+ */
24
+ export declare function finalizeAsset(store: AssetStore, input: FinalizeInput): Promise<FinalizeAssetResult>;
25
+ /**
26
+ * Finalize a previously-staged upload: read the staged bytes, run
27
+ * `finalizeAsset`, and best-effort delete the staging object regardless of
28
+ * outcome (success OR pipeline rejection - a rejected upload's staged bytes
29
+ * are just as much litter as an accepted one's).
30
+ */
31
+ export declare function finalizeStagedUpload(store: AssetStore, stagingKey: string, filename: string, uploadedBy?: string): Promise<FinalizeAssetResult | {
32
+ ok: false;
33
+ status: 400 | 404;
34
+ error: string;
35
+ }>;
36
+ //# sourceMappingURL=finalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finalize.d.ts","sourceRoot":"","sources":["../../src/assets/finalize.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE5F,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAYpD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGtD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG,iBAAiB,CAAA;AAEnF;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAuB9B;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAYhF"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Store orchestration around the (pure) finalize pipeline: dedup, write, and
3
+ * best-effort staging cleanup. Split from pipeline.ts so the pipeline itself
4
+ * stays store-agnostic and trivially unit-testable with plain byte fixtures.
5
+ */
6
+ import { runFinalizePipeline } from './pipeline.js';
7
+ import { ASSET_PREFIXES } from './keys.js';
8
+ /**
9
+ * A client-supplied staging key must be exactly `asset-staging/{uuid}` — the
10
+ * shape beginUpload generates. Without this check, finalize's read + cleanup
11
+ * would operate on ANY key the store can reach (asset-meta/, asset-originals/,
12
+ * or in a shared bucket even builds/), letting a non-admin delete arbitrary
13
+ * objects via the best-effort deleteStaging. Stores with overridden staging
14
+ * prefixes must parameterize this check if that escape hatch is ever used.
15
+ */
16
+ const STAGING_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
17
+ export function isValidStagingKey(key) {
18
+ const prefix = `${ASSET_PREFIXES.staging}/`;
19
+ return key.startsWith(prefix) && STAGING_UUID_PATTERN.test(key.slice(prefix.length));
20
+ }
21
+ /**
22
+ * Run the finalize pipeline over raw bytes and persist the result.
23
+ *
24
+ * Order matters here too: dedup FIRST (after hashing, inside the pipeline) -
25
+ * if an identical blob already exists, return the existing meta and skip all
26
+ * writes entirely (first-name-wins). Otherwise write the original, then the
27
+ * optional public object, then `putMetaIfAbsent` LAST: meta is the commit
28
+ * point for an asset's existence, so a crash between `putOriginal` and here
29
+ * leaves only orphaned (harmless, content-addressed) blobs, never a meta
30
+ * record pointing at a missing blob.
31
+ */
32
+ export async function finalizeAsset(store, input) {
33
+ const result = await runFinalizePipeline(input);
34
+ if (!result.ok)
35
+ return result;
36
+ const { meta, data, publicObject } = result;
37
+ const existing = await store.getMeta(meta.hash32);
38
+ if (existing)
39
+ return { ok: true, meta: existing };
40
+ await store.putOriginal({ hash32: meta.hash32, ext: meta.ext, data, contentType: meta.mime });
41
+ if (publicObject) {
42
+ await store.putPublicObject(publicObject);
43
+ }
44
+ const putResult = await store.putMetaIfAbsent(meta.hash32, meta);
45
+ if (putResult === 'already-exists') {
46
+ // Lost a race against a concurrent identical upload - the winner's meta
47
+ // (already committed) is authoritative; return it rather than ours.
48
+ const winner = await store.getMeta(meta.hash32);
49
+ if (winner)
50
+ return { ok: true, meta: winner };
51
+ }
52
+ return { ok: true, meta };
53
+ }
54
+ /**
55
+ * Finalize a previously-staged upload: read the staged bytes, run
56
+ * `finalizeAsset`, and best-effort delete the staging object regardless of
57
+ * outcome (success OR pipeline rejection - a rejected upload's staged bytes
58
+ * are just as much litter as an accepted one's).
59
+ */
60
+ export async function finalizeStagedUpload(store, stagingKey, filename, uploadedBy) {
61
+ if (!isValidStagingKey(stagingKey)) {
62
+ return { ok: false, status: 400, error: 'Invalid staging key' };
63
+ }
64
+ const staged = await store.readStaging(stagingKey);
65
+ if (!staged) {
66
+ return { ok: false, status: 404, error: 'Staged upload not found or expired' };
67
+ }
68
+ const result = await finalizeAsset(store, { data: staged, filename, uploadedBy });
69
+ await store.deleteStaging(stagingKey).catch(() => { });
70
+ return result;
71
+ }
72
+ //# sourceMappingURL=finalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finalize.js","sourceRoot":"","sources":["../../src/assets/finalize.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAA8C,MAAM,YAAY,CAAA;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAGvC;;;;;;;GAOG;AACH,MAAM,oBAAoB,GAAG,gEAAgE,CAAA;AAE7F,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,GAAG,CAAA;IAC3C,OAAO,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;AACtF,CAAC;AAID;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAiB,EACjB,KAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,CAAA;IAC/C,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAA;IAE7B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,MAAM,CAAA;IAE3C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACjD,IAAI,QAAQ;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;IAEjD,MAAM,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IAC7F,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,KAAK,CAAC,eAAe,CAAC,YAAY,CAAC,CAAA;IAC3C,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAChE,IAAI,SAAS,KAAK,gBAAgB,EAAE,CAAC;QACnC,wEAAwE;QACxE,oEAAoE;QACpE,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC/C,IAAI,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;IAC/C,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAiB,EACjB,UAAkB,EAClB,QAAgB,EAChB,UAAmB;IAEnB,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAA;IACjE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;IAClD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAA;IAChF,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAA;IACjF,MAAM,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACrD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Internal module barrel for the assets/ store implementation. NOT a package
3
+ * entrypoint — server code within canopycms imports from here or from the
4
+ * individual files; client-side code (the editor) must `import type` from
5
+ * ./types directly instead, so node:fs/S3-SDK imports never reach a browser
6
+ * bundle.
7
+ */
8
+ export type { AssetMeta, AssetStore, BeginUploadInput, PublicObject, StagedUploadTarget, } from './types';
9
+ export { ASSET_PREFIXES, createKeyBuilders, hashBytes, metaKey, metaPrefix, originalKey, originalPrefix, publicKey, slugifyFilename, stagingKey, type AssetPrefixes, } from './keys';
10
+ export { LocalAssetStore, type LocalAssetStoreOptions } from './store-local';
11
+ export { S3AssetStore, type S3AssetStoreOptions } from './store-s3';
12
+ export { createAssetStore } from './factory';
13
+ export { ALLOWED_UPLOAD_CONTENT_TYPES, runFinalizePipeline, type FinalizeInput, type FinalizePublicObject, type FinalizeResult, type FinalizeRejection, type FinalizeSuccess, } from './pipeline';
14
+ export { finalizeAsset, finalizeStagedUpload, type FinalizeAssetResult } from './finalize';
15
+ export { sanitizeSvg } from './svg-sanitizer';
16
+ export { assetSrc, IDENTITY_TRANSFORM_DIRECTIVE } from './asset-src';
17
+ export { formatDirectives, isAllowedTransformWidth, isValidCropRect, parseTransformPath, type CropRect, type IdentityDirectives, type OutputFormat, type ParsedTransformPath, type ParseTransformPathResult, type ResizeDirectives, type TransformDirectives, } from './transform-directives';
18
+ export { applyTransform, type ApplyTransformInput, type TransformResult } from './transform';
19
+ export { assetUrl, assetSrcSet, type AssetRef, type AssetUrlOptions } from './asset-url';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/assets/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EACV,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,GACnB,MAAM,SAAS,CAAA;AAEhB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACT,eAAe,EACf,UAAU,EACV,KAAK,aAAa,GACnB,MAAM,QAAQ,CAAA;AAEf,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAE5C,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,EACnB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAE1F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAEpE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAE5F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Internal module barrel for the assets/ store implementation. NOT a package
3
+ * entrypoint — server code within canopycms imports from here or from the
4
+ * individual files; client-side code (the editor) must `import type` from
5
+ * ./types directly instead, so node:fs/S3-SDK imports never reach a browser
6
+ * bundle.
7
+ */
8
+ export { ASSET_PREFIXES, createKeyBuilders, hashBytes, metaKey, metaPrefix, originalKey, originalPrefix, publicKey, slugifyFilename, stagingKey, } from './keys.js';
9
+ export { LocalAssetStore } from './store-local.js';
10
+ export { S3AssetStore } from './store-s3.js';
11
+ export { createAssetStore } from './factory.js';
12
+ export { ALLOWED_UPLOAD_CONTENT_TYPES, runFinalizePipeline, } from './pipeline.js';
13
+ export { finalizeAsset, finalizeStagedUpload } from './finalize.js';
14
+ export { sanitizeSvg } from './svg-sanitizer.js';
15
+ export { assetSrc, IDENTITY_TRANSFORM_DIRECTIVE } from './asset-src.js';
16
+ export { formatDirectives, isAllowedTransformWidth, isValidCropRect, parseTransformPath, } from './transform-directives.js';
17
+ export { applyTransform } from './transform.js';
18
+ export { assetUrl, assetSrcSet } from './asset-url.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/assets/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACT,eAAe,EACf,UAAU,GAEX,MAAM,QAAQ,CAAA;AAEf,OAAO,EAAE,eAAe,EAA+B,MAAM,eAAe,CAAA;AAC5E,OAAO,EAAE,YAAY,EAA4B,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAE5C,OAAO,EACL,4BAA4B,EAC5B,mBAAmB,GAMpB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAA4B,MAAM,YAAY,CAAA;AAE1F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAEpE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,kBAAkB,GAQnB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,cAAc,EAAkD,MAAM,aAAa,CAAA;AAE5F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAuC,MAAM,aAAa,CAAA"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Pure key/hash/slug helpers for the asset store. No filesystem or network I/O
3
+ * here — keeps this file trivially unit-testable and safe to reason about for
4
+ * path-traversal / header-injection concerns.
5
+ *
6
+ * Bucket-prefix layout (see .claude/future-tasks/assets-media-system.md):
7
+ * asset-originals/{hash32}.{ext} private; full-fidelity originals
8
+ * asset-staging/{uuid} presigned-POST target
9
+ * asset-meta/{hash32}.json private; filename/uploader/dims/mime
10
+ * assets/t/{directives}/{hash32}/{slug} transform outputs (see transform-directives.ts)
11
+ * assets/{hash32}/{slug}.{ext} public static: sanitized SVG + PDF only
12
+ *
13
+ * Stores must build keys through these helpers rather than hand-rolling prefix
14
+ * strings, so the layout stays defined in exactly one place.
15
+ */
16
+ import { ASSET_PREFIXES, type AssetPrefixes } from './asset-prefixes';
17
+ export { ASSET_PREFIXES, type AssetPrefixes };
18
+ /** sha-256 of the given bytes, truncated to 32 hex chars (128 bits). */
19
+ export declare function hashBytes(data: Uint8Array): string;
20
+ /**
21
+ * Slugify an (untrusted) original filename into a safe slug + normalized
22
+ * extension. Never trust the input for path or header use directly — this
23
+ * strips directory components, non-ASCII/unsafe characters, and caps length.
24
+ *
25
+ * - Directory components (`/`, `\`, including `..` segments) are dropped —
26
+ * only the final path segment is considered.
27
+ * - The slug charset is restricted to `[a-z0-9-]`; anything else (spaces,
28
+ * unicode, punctuation) collapses to a single `-`, with leading/trailing
29
+ * dashes stripped.
30
+ * - Diacritics are stripped (NFKD) before charset filtering, so an accented
31
+ * "e"-with-acute-accent becomes plain "e" rather than being dropped entirely.
32
+ * - The extension (text after the last `.` in the final segment) is
33
+ * lowercased and restricted to `[a-z0-9]`, capped at 10 chars.
34
+ * - An empty/unsafe result falls back to a fixed slug so callers never see
35
+ * an empty string.
36
+ */
37
+ export declare function slugifyFilename(name: string): {
38
+ slug: string;
39
+ ext: string;
40
+ };
41
+ /**
42
+ * Build the key helpers bound to a given prefix set. Stores that support prefix
43
+ * overrides (currently S3AssetStore) call this with their configured prefixes;
44
+ * everyone else uses the default export instances below.
45
+ */
46
+ export declare function createKeyBuilders(prefixes?: AssetPrefixes): {
47
+ originalKey: (hash32: string, ext: string) => string;
48
+ /** Prefix used to look up an original by hash32 alone (extension unknown ahead of time). */
49
+ originalPrefix: (hash32: string) => string;
50
+ stagingKey: (uuid: string) => string;
51
+ metaKey: (hash32: string) => string;
52
+ metaPrefix: () => string;
53
+ publicKey: (hash32: string, slug: string, ext: string) => string;
54
+ };
55
+ export declare const originalKey: (hash32: string, ext: string) => string, originalPrefix: (hash32: string) => string, stagingKey: (uuid: string) => string, metaKey: (hash32: string) => string, metaPrefix: () => string, publicKey: (hash32: string, slug: string, ext: string) => string;
56
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/assets/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErE,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,CAAA;AAE7C,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAElD;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAkC3E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,aAA8B;0BAEhD,MAAM,OAAO,MAAM,KAAG,MAAM;IAClD,4FAA4F;6BACnE,MAAM,KAAG,MAAM;uBACrB,MAAM,KAAG,MAAM;sBAChB,MAAM,KAAG,MAAM;sBACjB,MAAM;wBACF,MAAM,QAAQ,MAAM,OAAO,MAAM,KAAG,MAAM;EAGjE;AAED,eAAO,MAAQ,WAAW,WAXA,MAAM,OAAO,MAAM,KAAG,MAAM,EAW1B,cAAc,WATb,MAAM,KAAG,MAAM,EASA,UAAU,SAR/B,MAAM,KAAG,MAAM,EAQkB,OAAO,WAPzC,MAAM,KAAG,MAAM,EAO4B,UAAU,QANvD,MAAM,EAMmD,SAAS,WAL9D,MAAM,QAAQ,MAAM,OAAO,MAAM,KAAG,MAMvC,CAAA"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Pure key/hash/slug helpers for the asset store. No filesystem or network I/O
3
+ * here — keeps this file trivially unit-testable and safe to reason about for
4
+ * path-traversal / header-injection concerns.
5
+ *
6
+ * Bucket-prefix layout (see .claude/future-tasks/assets-media-system.md):
7
+ * asset-originals/{hash32}.{ext} private; full-fidelity originals
8
+ * asset-staging/{uuid} presigned-POST target
9
+ * asset-meta/{hash32}.json private; filename/uploader/dims/mime
10
+ * assets/t/{directives}/{hash32}/{slug} transform outputs (see transform-directives.ts)
11
+ * assets/{hash32}/{slug}.{ext} public static: sanitized SVG + PDF only
12
+ *
13
+ * Stores must build keys through these helpers rather than hand-rolling prefix
14
+ * strings, so the layout stays defined in exactly one place.
15
+ */
16
+ import { createHash } from 'node:crypto';
17
+ import { ASSET_PREFIXES } from './asset-prefixes.js';
18
+ export { ASSET_PREFIXES };
19
+ /** sha-256 of the given bytes, truncated to 32 hex chars (128 bits). */
20
+ export function hashBytes(data) {
21
+ return createHash('sha256').update(data).digest('hex').slice(0, 32);
22
+ }
23
+ const MAX_SLUG_LENGTH = 80;
24
+ const MAX_EXT_LENGTH = 10;
25
+ const FALLBACK_SLUG = 'file';
26
+ /**
27
+ * Slugify an (untrusted) original filename into a safe slug + normalized
28
+ * extension. Never trust the input for path or header use directly — this
29
+ * strips directory components, non-ASCII/unsafe characters, and caps length.
30
+ *
31
+ * - Directory components (`/`, `\`, including `..` segments) are dropped —
32
+ * only the final path segment is considered.
33
+ * - The slug charset is restricted to `[a-z0-9-]`; anything else (spaces,
34
+ * unicode, punctuation) collapses to a single `-`, with leading/trailing
35
+ * dashes stripped.
36
+ * - Diacritics are stripped (NFKD) before charset filtering, so an accented
37
+ * "e"-with-acute-accent becomes plain "e" rather than being dropped entirely.
38
+ * - The extension (text after the last `.` in the final segment) is
39
+ * lowercased and restricted to `[a-z0-9]`, capped at 10 chars.
40
+ * - An empty/unsafe result falls back to a fixed slug so callers never see
41
+ * an empty string.
42
+ */
43
+ export function slugifyFilename(name) {
44
+ // Drop any directory components (handles both `/` and `\`, and `..` segments)
45
+ // so the untrusted original filename can never influence a constructed path.
46
+ const segments = name.split(/[/\\]+/);
47
+ const basename = segments[segments.length - 1] ?? '';
48
+ const lastDot = basename.lastIndexOf('.');
49
+ const hasExt = lastDot > 0 && lastDot < basename.length - 1;
50
+ const base = hasExt ? basename.slice(0, lastDot) : basename;
51
+ const extRaw = hasExt ? basename.slice(lastDot + 1) : '';
52
+ const ext = extRaw
53
+ .toLowerCase()
54
+ .replace(/[^a-z0-9]/g, '')
55
+ .slice(0, MAX_EXT_LENGTH);
56
+ // U+0300-U+036F is the combining-diacritical-marks block, stripped after NFKD
57
+ // decomposition. Built from fixed char codes (not a literal regex) so this
58
+ // file's source stays pure ASCII; the pattern is not derived from input, so
59
+ // there is no injection risk despite the non-literal RegExp constructor.
60
+ // eslint-disable-next-line security/detect-non-literal-regexp
61
+ const COMBINING_MARKS = new RegExp(`[${String.fromCharCode(0x0300)}-${String.fromCharCode(0x036f)}]`, 'g');
62
+ let slug = base
63
+ .normalize('NFKD')
64
+ .replace(COMBINING_MARKS, '')
65
+ .toLowerCase()
66
+ .replace(/[^a-z0-9]+/g, '-')
67
+ .replace(/^-+|-+$/g, '');
68
+ slug = slug.slice(0, MAX_SLUG_LENGTH).replace(/-+$/g, '');
69
+ return { slug: slug || FALLBACK_SLUG, ext };
70
+ }
71
+ /**
72
+ * Build the key helpers bound to a given prefix set. Stores that support prefix
73
+ * overrides (currently S3AssetStore) call this with their configured prefixes;
74
+ * everyone else uses the default export instances below.
75
+ */
76
+ export function createKeyBuilders(prefixes = ASSET_PREFIXES) {
77
+ return {
78
+ originalKey: (hash32, ext) => `${prefixes.originals}/${hash32}.${ext}`,
79
+ /** Prefix used to look up an original by hash32 alone (extension unknown ahead of time). */
80
+ originalPrefix: (hash32) => `${prefixes.originals}/${hash32}.`,
81
+ stagingKey: (uuid) => `${prefixes.staging}/${uuid}`,
82
+ metaKey: (hash32) => `${prefixes.meta}/${hash32}.json`,
83
+ metaPrefix: () => `${prefixes.meta}/`,
84
+ publicKey: (hash32, slug, ext) => `${prefixes.public}/${hash32}/${slug}.${ext}`,
85
+ };
86
+ }
87
+ export const { originalKey, originalPrefix, stagingKey, metaKey, metaPrefix, publicKey } = createKeyBuilders();
88
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/assets/keys.ts"],"names":[],"mappings":"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"}