fundus 0.0.2 → 0.0.3

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 (300) hide show
  1. package/README.md +58 -0
  2. package/build/client/_app/immutable/assets/0.DLhIsYA_.css.br +0 -0
  3. package/build/client/_app/immutable/assets/0.DLhIsYA_.css.gz +0 -0
  4. package/build/client/_app/immutable/assets/2.wavcNhPC.css +1 -0
  5. package/build/client/_app/immutable/assets/2.wavcNhPC.css.br +0 -0
  6. package/build/client/_app/immutable/assets/2.wavcNhPC.css.gz +0 -0
  7. package/build/client/_app/immutable/assets/3.Cjh_fXPY.css +1 -0
  8. package/build/client/_app/immutable/assets/3.Cjh_fXPY.css.br +0 -0
  9. package/build/client/_app/immutable/assets/3.Cjh_fXPY.css.gz +0 -0
  10. package/build/client/_app/immutable/assets/4.p004hmEN.css +1 -0
  11. package/build/client/_app/immutable/assets/4.p004hmEN.css.br +0 -0
  12. package/build/client/_app/immutable/assets/4.p004hmEN.css.gz +0 -0
  13. package/build/client/_app/immutable/assets/ConfirmDialog.BdKlitwi.css +1 -0
  14. package/build/client/_app/immutable/assets/ConfirmDialog.BdKlitwi.css.br +0 -0
  15. package/build/client/_app/immutable/assets/ConfirmDialog.BdKlitwi.css.gz +0 -0
  16. package/build/client/_app/immutable/assets/LibraryContextMenu.zyZtpKzC.css +1 -0
  17. package/build/client/_app/immutable/assets/LibraryContextMenu.zyZtpKzC.css.br +0 -0
  18. package/build/client/_app/immutable/assets/LibraryContextMenu.zyZtpKzC.css.gz +0 -0
  19. package/build/client/_app/immutable/chunks/BiIto6ft.js +1 -0
  20. package/build/client/_app/immutable/chunks/BiIto6ft.js.br +0 -0
  21. package/build/client/_app/immutable/chunks/BiIto6ft.js.gz +0 -0
  22. package/build/client/_app/immutable/chunks/Bjy-W4x2.js.br +0 -0
  23. package/build/client/_app/immutable/chunks/Bjy-W4x2.js.gz +0 -0
  24. package/build/client/_app/immutable/chunks/CNRz3sSw.js.br +0 -0
  25. package/build/client/_app/immutable/chunks/CNRz3sSw.js.gz +0 -0
  26. package/build/client/_app/immutable/chunks/CO4RBJfa.js.br +0 -0
  27. package/build/client/_app/immutable/chunks/CO4RBJfa.js.gz +0 -0
  28. package/{dist/editor/_app/immutable/chunks/DjvOiDmq.js → build/client/_app/immutable/chunks/CvY6YsFE.js} +1 -1
  29. package/build/client/_app/immutable/chunks/CvY6YsFE.js.br +0 -0
  30. package/build/client/_app/immutable/chunks/CvY6YsFE.js.gz +0 -0
  31. package/build/client/_app/immutable/chunks/DL0_39Ys.js +5 -0
  32. package/build/client/_app/immutable/chunks/DL0_39Ys.js.br +0 -0
  33. package/build/client/_app/immutable/chunks/DL0_39Ys.js.gz +0 -0
  34. package/{dist/editor/_app/immutable/chunks/BfPE5wdt.js → build/client/_app/immutable/chunks/DQ8SXFaX.js} +1 -1
  35. package/build/client/_app/immutable/chunks/DQ8SXFaX.js.br +0 -0
  36. package/build/client/_app/immutable/chunks/DQ8SXFaX.js.gz +0 -0
  37. package/build/client/_app/immutable/chunks/DjdrdRzT.js.br +0 -0
  38. package/build/client/_app/immutable/chunks/DjdrdRzT.js.gz +0 -0
  39. package/build/client/_app/immutable/chunks/xihTtKlq.js.br +1 -0
  40. package/build/client/_app/immutable/chunks/xihTtKlq.js.gz +0 -0
  41. package/{dist/editor/_app/immutable/entry/app.BkqbfI8n.js → build/client/_app/immutable/entry/app.ubN0v9bN.js} +2 -2
  42. package/build/client/_app/immutable/entry/app.ubN0v9bN.js.br +0 -0
  43. package/build/client/_app/immutable/entry/app.ubN0v9bN.js.gz +0 -0
  44. package/build/client/_app/immutable/entry/start.BW8dBDh6.js +1 -0
  45. package/build/client/_app/immutable/entry/start.BW8dBDh6.js.br +0 -0
  46. package/build/client/_app/immutable/entry/start.BW8dBDh6.js.gz +0 -0
  47. package/{dist/editor/_app/immutable/nodes/0.xdMI5GEU.js → build/client/_app/immutable/nodes/0.Dr5ijCIl.js} +1 -1
  48. package/build/client/_app/immutable/nodes/0.Dr5ijCIl.js.br +0 -0
  49. package/build/client/_app/immutable/nodes/0.Dr5ijCIl.js.gz +0 -0
  50. package/{dist/editor/_app/immutable/nodes/1.D9p2tfoJ.js → build/client/_app/immutable/nodes/1.DiIGIRAb.js} +1 -1
  51. package/build/client/_app/immutable/nodes/1.DiIGIRAb.js.br +3 -0
  52. package/build/client/_app/immutable/nodes/1.DiIGIRAb.js.gz +0 -0
  53. package/{dist/editor/_app/immutable/nodes/2.BrA0Hyzu.js → build/client/_app/immutable/nodes/2.B8KYmQcV.js} +3 -3
  54. package/build/client/_app/immutable/nodes/2.B8KYmQcV.js.br +0 -0
  55. package/build/client/_app/immutable/nodes/2.B8KYmQcV.js.gz +0 -0
  56. package/build/client/_app/immutable/nodes/3.B1jc7arT.js +104 -0
  57. package/build/client/_app/immutable/nodes/3.B1jc7arT.js.br +0 -0
  58. package/build/client/_app/immutable/nodes/3.B1jc7arT.js.gz +0 -0
  59. package/build/client/_app/immutable/nodes/4.BPK9n1mH.js +2 -0
  60. package/build/client/_app/immutable/nodes/4.BPK9n1mH.js.br +0 -0
  61. package/build/client/_app/immutable/nodes/4.BPK9n1mH.js.gz +0 -0
  62. package/build/client/_app/version.json +1 -0
  63. package/build/client/_app/version.json.br +0 -0
  64. package/build/client/_app/version.json.gz +0 -0
  65. package/build/env.js +100 -0
  66. package/build/env.js.map +1 -0
  67. package/build/handler.js +22 -0
  68. package/build/handler.js.map +1 -0
  69. package/build/index.js +145 -0
  70. package/build/index.js.map +1 -0
  71. package/build/server/chunks/chunks/context.js-Bw4WWLhG.js +443 -0
  72. package/build/server/chunks/chunks/context.js-Bw4WWLhG.js.map +1 -0
  73. package/build/server/chunks/chunks/core.js-DDntpb72.js +409 -0
  74. package/build/server/chunks/chunks/core.js-DDntpb72.js.map +1 -0
  75. package/build/server/chunks/chunks/env.js-l0sNRNKZ.js +2 -0
  76. package/build/server/chunks/chunks/env.js-l0sNRNKZ.js.map +1 -0
  77. package/build/server/chunks/chunks/exports.js-CLTzaOxn.js +152 -0
  78. package/build/server/chunks/chunks/exports.js-CLTzaOxn.js.map +1 -0
  79. package/build/server/chunks/chunks/folder-path.js-ytx9ucgg.js +64 -0
  80. package/build/server/chunks/chunks/folder-path.js-ytx9ucgg.js.map +1 -0
  81. package/build/server/chunks/chunks/http.js-Dxoa-jtP.js +100 -0
  82. package/build/server/chunks/chunks/http.js-Dxoa-jtP.js.map +1 -0
  83. package/build/server/chunks/chunks/internal.js-BDBSzJId.js +5753 -0
  84. package/build/server/chunks/chunks/internal.js-BDBSzJId.js.map +1 -0
  85. package/build/server/chunks/chunks/internal2.js-BlXt2rfE.js +22 -0
  86. package/build/server/chunks/chunks/internal2.js-BlXt2rfE.js.map +1 -0
  87. package/{dist/operations-DYM-5KVl.js → build/server/chunks/chunks/library-store.js-BP8cL-qD.js} +344 -444
  88. package/build/server/chunks/chunks/library-store.js-BP8cL-qD.js.map +1 -0
  89. package/build/server/chunks/chunks/manifest-appearance.js-DTk355LQ.js +146 -0
  90. package/build/server/chunks/chunks/manifest-appearance.js-DTk355LQ.js.map +1 -0
  91. package/build/server/chunks/chunks/routing.js-y-tryuip.js +213 -0
  92. package/build/server/chunks/chunks/routing.js-y-tryuip.js.map +1 -0
  93. package/build/server/chunks/chunks/shared.js-BWXgl1Xf.js +255 -0
  94. package/build/server/chunks/chunks/shared.js-BWXgl1Xf.js.map +1 -0
  95. package/build/server/chunks/chunks/utils.js-9oI5Oz0w.js +1048 -0
  96. package/build/server/chunks/chunks/utils.js-9oI5Oz0w.js.map +1 -0
  97. package/build/server/chunks/entries/endpoints/api/_...path_/_server.ts.js-WknZVW_S.js +27 -0
  98. package/build/server/chunks/entries/endpoints/api/_...path_/_server.ts.js-WknZVW_S.js.map +1 -0
  99. package/build/server/chunks/entries/endpoints/api/assets/_id_/_server.ts.js-BrZ__-HZ.js +24 -0
  100. package/build/server/chunks/entries/endpoints/api/assets/_id_/_server.ts.js-BrZ__-HZ.js.map +1 -0
  101. package/build/server/chunks/entries/endpoints/api/assets/_server.ts.js-PqADGPXc.js +45 -0
  102. package/build/server/chunks/entries/endpoints/api/assets/_server.ts.js-PqADGPXc.js.map +1 -0
  103. package/build/server/chunks/entries/endpoints/api/assets/delete/_server.ts.js-OqoE5PN-.js +31 -0
  104. package/build/server/chunks/entries/endpoints/api/assets/delete/_server.ts.js-OqoE5PN-.js.map +1 -0
  105. package/build/server/chunks/entries/endpoints/api/assets/move/_server.ts.js-CJ08e1ho.js +31 -0
  106. package/build/server/chunks/entries/endpoints/api/assets/move/_server.ts.js-CJ08e1ho.js.map +1 -0
  107. package/build/server/chunks/entries/endpoints/api/folders/_path_/_server.ts.js-DdF3eK2I.js +38 -0
  108. package/build/server/chunks/entries/endpoints/api/folders/_path_/_server.ts.js-DdF3eK2I.js.map +1 -0
  109. package/build/server/chunks/entries/endpoints/api/folders/_server.ts.js-Cxt6jsJ5.js +31 -0
  110. package/build/server/chunks/entries/endpoints/api/folders/_server.ts.js-Cxt6jsJ5.js.map +1 -0
  111. package/build/server/chunks/entries/endpoints/api/manifests/_name_/_server.ts.js-BWVM2Ntl.js +24 -0
  112. package/build/server/chunks/entries/endpoints/api/manifests/_name_/_server.ts.js-BWVM2Ntl.js.map +1 -0
  113. package/build/server/chunks/entries/endpoints/api/manifests/_server.ts.js-Z2bM-qHM.js +31 -0
  114. package/build/server/chunks/entries/endpoints/api/manifests/_server.ts.js-Z2bM-qHM.js.map +1 -0
  115. package/build/server/chunks/entries/endpoints/api/state/_server.ts.js-BX9H2Z34.js +24 -0
  116. package/build/server/chunks/entries/endpoints/api/state/_server.ts.js-BX9H2Z34.js.map +1 -0
  117. package/build/server/chunks/entries/endpoints/files/_...path_/_server.ts.js-BWHDZ8mz.js +27 -0
  118. package/build/server/chunks/entries/endpoints/files/_...path_/_server.ts.js-BWHDZ8mz.js.map +1 -0
  119. package/build/server/chunks/entries/endpoints/files/proxy/_...path_/_server.ts.js-CR_7mndO.js +24 -0
  120. package/build/server/chunks/entries/endpoints/files/proxy/_...path_/_server.ts.js-CR_7mndO.js.map +1 -0
  121. package/build/server/chunks/entries/endpoints/files/raw/_...path_/_server.ts.js-Cw1PDBvb.js +24 -0
  122. package/build/server/chunks/entries/endpoints/files/raw/_...path_/_server.ts.js-Cw1PDBvb.js.map +1 -0
  123. package/build/server/chunks/entries/hooks.server.js-BHoE0yBi.js +23 -0
  124. package/build/server/chunks/entries/hooks.server.js-BHoE0yBi.js.map +1 -0
  125. package/build/server/chunks/handler-10cx4zHn.js +1475 -0
  126. package/build/server/chunks/handler-10cx4zHn.js.map +1 -0
  127. package/build/server/chunks/index.js-DvPfiC00.js +3789 -0
  128. package/build/server/chunks/index.js-DvPfiC00.js.map +1 -0
  129. package/build/server/chunks/manifest.js-DoPjUnzD.js +149 -0
  130. package/build/server/chunks/manifest.js-DoPjUnzD.js.map +1 -0
  131. package/build/server/chunks/nodes/0.js-Di3qgAtW.js +11 -0
  132. package/build/server/chunks/nodes/0.js-Di3qgAtW.js.map +1 -0
  133. package/build/server/chunks/nodes/1.js-BlWSFIA8.js +7 -0
  134. package/build/server/chunks/nodes/1.js-BlWSFIA8.js.map +1 -0
  135. package/build/server/chunks/nodes/2.js-CO9nSPUN.js +7 -0
  136. package/build/server/chunks/nodes/2.js-CO9nSPUN.js.map +1 -0
  137. package/build/server/chunks/nodes/3.js-C2D6xpEO.js +7 -0
  138. package/build/server/chunks/nodes/3.js-C2D6xpEO.js.map +1 -0
  139. package/build/server/chunks/nodes/4.js-B3IuagJW.js +7 -0
  140. package/build/server/chunks/nodes/4.js-B3IuagJW.js.map +1 -0
  141. package/build/shims.js +33 -0
  142. package/build/shims.js.map +1 -0
  143. package/dist/cli.d.ts +2 -1
  144. package/dist/cli.js +109 -1332
  145. package/dist/config.d.ts +3 -2
  146. package/dist/config.js +2 -2
  147. package/dist/core/api-types.d.ts +141 -0
  148. package/dist/core/api-types.js +1 -0
  149. package/dist/core/asset-id.d.ts +28 -0
  150. package/dist/core/asset-id.js +59 -0
  151. package/dist/core/asset-reference.d.ts +23 -0
  152. package/dist/core/asset-reference.js +15 -0
  153. package/dist/core/canonicalize.d.ts +9 -0
  154. package/dist/core/canonicalize.js +36 -0
  155. package/dist/core/chroma-key.d.ts +30 -0
  156. package/dist/core/chroma-key.js +55 -0
  157. package/dist/core/config.d.ts +35 -0
  158. package/dist/core/config.js +4 -0
  159. package/dist/core/folder-path.d.ts +19 -0
  160. package/dist/core/folder-path.js +86 -0
  161. package/dist/core/index.d.ts +33 -499
  162. package/dist/core/index.js +17 -962
  163. package/dist/core/ingest.d.ts +18 -0
  164. package/dist/core/ingest.js +58 -0
  165. package/dist/core/library.d.ts +54 -0
  166. package/dist/core/library.js +138 -0
  167. package/dist/core/manifest-appearance.d.ts +35 -0
  168. package/dist/core/manifest-appearance.js +123 -0
  169. package/dist/core/manifest-entry.d.ts +104 -0
  170. package/dist/core/manifest-entry.js +1 -0
  171. package/dist/core/manifest-membership.d.ts +56 -0
  172. package/dist/core/manifest-membership.js +54 -0
  173. package/dist/core/plugins/audio.d.ts +26 -0
  174. package/dist/core/plugins/audio.js +44 -0
  175. package/dist/core/plugins/chroma-key-video.d.ts +29 -0
  176. package/dist/core/plugins/chroma-key-video.js +69 -0
  177. package/dist/core/plugins/contract.d.ts +35 -0
  178. package/dist/core/plugins/contract.js +1 -0
  179. package/dist/core/plugins/image.d.ts +30 -0
  180. package/dist/core/plugins/image.js +45 -0
  181. package/dist/core/plugins/slice.d.ts +22 -0
  182. package/dist/core/plugins/slice.js +60 -0
  183. package/dist/core/plugins/video.d.ts +45 -0
  184. package/dist/core/plugins/video.js +77 -0
  185. package/dist/core/reference-graph.d.ts +41 -0
  186. package/dist/core/reference-graph.js +138 -0
  187. package/dist/core/slice-data.d.ts +61 -0
  188. package/dist/core/slice-data.js +49 -0
  189. package/dist/runtime/chroma-key-gl.d.ts +40 -22
  190. package/dist/runtime/chroma-key-gl.js +189 -183
  191. package/dist/runtime/components/ChromaKeyVideo.svelte +3 -3
  192. package/dist/runtime/components/ChromaKeyVideo.svelte.d.ts +21 -0
  193. package/dist/runtime/components/Image.svelte +1 -1
  194. package/dist/runtime/components/Image.svelte.d.ts +9 -0
  195. package/dist/runtime/components/Slice.svelte +1 -1
  196. package/dist/runtime/components/Slice.svelte.d.ts +19 -0
  197. package/dist/runtime/components/SliceCanvas.svelte +3 -3
  198. package/dist/runtime/components/SliceCanvas.svelte.d.ts +10 -0
  199. package/dist/runtime/components/SliceDom.svelte +3 -3
  200. package/dist/runtime/components/SliceDom.svelte.d.ts +10 -0
  201. package/dist/runtime/components/Video.svelte +2 -2
  202. package/dist/runtime/components/Video.svelte.d.ts +18 -0
  203. package/dist/runtime/geometry.d.ts +55 -35
  204. package/dist/runtime/geometry.js +186 -191
  205. package/dist/runtime/index.d.ts +9 -9
  206. package/dist/runtime/index.js +9 -9
  207. package/dist/runtime/kind-handlers.d.ts +33 -24
  208. package/dist/runtime/kind-handlers.js +74 -65
  209. package/dist/runtime/manifest.d.ts +53 -47
  210. package/dist/runtime/manifest.js +133 -113
  211. package/dist/runtime/observe-border-box-size.d.ts +1 -4
  212. package/dist/runtime/observe-border-box-size.js +9 -10
  213. package/dist/runtime/preload-registry.d.ts +22 -8
  214. package/dist/runtime/preload-registry.js +65 -62
  215. package/dist/server/build.d.ts +8 -0
  216. package/dist/server/build.js +25 -0
  217. package/dist/server/check.d.ts +24 -0
  218. package/dist/server/check.js +199 -0
  219. package/dist/server/cli-commands.d.ts +25 -0
  220. package/dist/server/cli-commands.js +1178 -0
  221. package/dist/server/cli-init.d.ts +3 -0
  222. package/dist/server/cli-init.js +53 -0
  223. package/dist/server/cli-io.d.ts +46 -0
  224. package/dist/server/cli-io.js +105 -0
  225. package/dist/server/codegen.d.ts +58 -0
  226. package/dist/server/codegen.js +185 -0
  227. package/dist/server/config-loader.d.ts +34 -0
  228. package/dist/server/config-loader.js +103 -0
  229. package/dist/server/context.d.ts +8 -0
  230. package/dist/server/context.js +19 -0
  231. package/dist/server/folder-filesystem.d.ts +7 -0
  232. package/dist/server/folder-filesystem.js +39 -0
  233. package/dist/server/http.d.ts +12 -0
  234. package/dist/server/http.js +100 -0
  235. package/dist/server/index.d.ts +16 -0
  236. package/dist/server/index.js +9 -0
  237. package/dist/server/job-hash.d.ts +10 -0
  238. package/dist/server/job-hash.js +23 -0
  239. package/dist/server/library-store.d.ts +82 -0
  240. package/dist/server/library-store.js +763 -0
  241. package/dist/server/operations.d.ts +87 -0
  242. package/dist/server/operations.js +427 -0
  243. package/dist/server/plugins/audio.d.ts +7 -0
  244. package/dist/server/plugins/audio.js +27 -0
  245. package/dist/server/plugins/chroma-key-video.d.ts +9 -0
  246. package/dist/server/plugins/chroma-key-video.js +38 -0
  247. package/dist/server/plugins/contract.d.ts +100 -0
  248. package/dist/server/plugins/contract.js +16 -0
  249. package/dist/server/plugins/image.d.ts +8 -0
  250. package/dist/server/plugins/image.js +30 -0
  251. package/dist/server/plugins/slice.d.ts +14 -0
  252. package/dist/server/plugins/slice.js +63 -0
  253. package/dist/server/plugins/video.d.ts +6 -0
  254. package/dist/server/plugins/video.js +29 -0
  255. package/dist/server/plugins.d.ts +23 -0
  256. package/dist/server/plugins.js +33 -0
  257. package/dist/server/processing/audio-processing.d.ts +17 -0
  258. package/dist/server/processing/audio-processing.js +46 -0
  259. package/dist/server/processing/ffmpeg.d.ts +9 -0
  260. package/dist/server/processing/ffmpeg.js +50 -0
  261. package/dist/server/processing/image-processing.d.ts +16 -0
  262. package/dist/server/processing/image-processing.js +26 -0
  263. package/dist/server/processing/media-probe.d.ts +15 -0
  264. package/dist/server/processing/media-probe.js +27 -0
  265. package/dist/server/processing/processor.d.ts +50 -0
  266. package/dist/server/processing/processor.js +158 -0
  267. package/dist/server/processing/video-processing.d.ts +35 -0
  268. package/dist/server/processing/video-processing.js +87 -0
  269. package/dist/server/server.d.ts +13 -0
  270. package/dist/server/server.js +57 -0
  271. package/dist/server/start.d.ts +1 -0
  272. package/dist/server/start.js +33 -0
  273. package/package.json +29 -16
  274. package/dist/build-CZYFLLvl.js +0 -191
  275. package/dist/core/image-Dqmz8FXS.js +0 -54
  276. package/dist/core/reference-graph-CjuHbLDw.d.ts +0 -280
  277. package/dist/core/testing.d.ts +0 -27
  278. package/dist/core/testing.js +0 -80
  279. package/dist/editor/200.html +0 -37
  280. package/dist/editor/_app/immutable/assets/2.DIbbW7U1.css +0 -1
  281. package/dist/editor/_app/immutable/assets/3.C-9vFQ9A.css +0 -1
  282. package/dist/editor/_app/immutable/assets/4.BS8ElpOV.css +0 -1
  283. package/dist/editor/_app/immutable/assets/ConfirmDialog.CHEISE-L.css +0 -1
  284. package/dist/editor/_app/immutable/assets/LibraryContextMenu.CDjCmdV-.css +0 -1
  285. package/dist/editor/_app/immutable/chunks/Cx6qtxJg.js +0 -1
  286. package/dist/editor/_app/immutable/chunks/n7mvYc42.js +0 -5
  287. package/dist/editor/_app/immutable/entry/start.C8HHOLly.js +0 -1
  288. package/dist/editor/_app/immutable/nodes/3.WO7tZH_d.js +0 -104
  289. package/dist/editor/_app/immutable/nodes/4.DQtx17aW.js +0 -2
  290. package/dist/editor/_app/version.json +0 -1
  291. package/dist/index.d.ts +0 -370
  292. package/dist/index.js +0 -4
  293. package/dist/start-Bhnqt9Dc.js +0 -279
  294. package/dist/start-D2IXOrni.js +0 -2
  295. /package/{dist/editor → build/client}/_app/immutable/assets/0.DLhIsYA_.css +0 -0
  296. /package/{dist/editor → build/client}/_app/immutable/chunks/Bjy-W4x2.js +0 -0
  297. /package/{dist/editor → build/client}/_app/immutable/chunks/CNRz3sSw.js +0 -0
  298. /package/{dist/editor → build/client}/_app/immutable/chunks/CO4RBJfa.js +0 -0
  299. /package/{dist/editor → build/client}/_app/immutable/chunks/DjdrdRzT.js +0 -0
  300. /package/{dist/editor → build/client}/_app/immutable/chunks/xihTtKlq.js +0 -0
@@ -1,87 +1,330 @@
1
- import { mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
2
- import { basename, dirname, extname, isAbsolute, join, resolve } from "node:path";
3
- import { AUDIO_BUILT_IN_PRESETS, FOLDER_SENTINEL, IMAGE_BUILT_IN_PRESETS, SLICE_BUILT_IN_PRESETS, VIDEO_BUILT_IN_PRESETS, allDeliveredAssetIds, assetIdError, audioPlugin, canonicalizeParameters, chromaKeyVideoPlugin, collectAllReferences, compareCodeUnits, computeLibraryMembership, createEmptyLibrary, defaultInsetsForSize, folderNameError, folderNameOf, folderOfRawPath, folderPathError, imagePlugin, isAssetReference, isFolderOrDescendant, joinFolderPath, manifestColorError, manifestEmojiError, manifestNameError, normalizeFolderPath, parentFolderPath, parseLibrary, portableFolderPathKey, rawFileNameOfPath, referenceErrors, replaceFolderPrefix, serializeLibrary, slicePlugin, topologicalReferenceOrder, validateAudioPreset, validateImagePreset, validateVideoPreset, videoPlugin } from "#fundus/core";
4
- import { existsSync } from "node:fs";
5
- import { createJiti } from "jiti";
6
- import { createHash } from "node:crypto";
7
- import ffmpegStaticPath from "ffmpeg-static";
8
- import { path } from "ffprobe-static";
9
- import { execFile } from "node:child_process";
10
- import { promisify } from "node:util";
11
- import sharp from "sharp";
12
- //#region src/config-loader.ts
13
- /**
14
- * Loads and resolves the host's `fundus.config.ts` through jiti, validates
15
- * the shape, resolves all paths to
16
- * absolute, and merges the built-in plugin preset defaults under the host's.
17
- */
1
+ import { n as normalizeFolderPath, f as folderOfRawPath, r as rawFileNameOfPath, a as folderPathError, p as parentFolderPath, b as folderNameError, j as joinFolderPath, c as folderNameOf, i as isFolderOrDescendant, d as replaceFolderPrefix, e as portableFolderPathKey, F as FOLDER_SENTINEL } from './folder-path.js-ytx9ucgg.js';
2
+ import { a as audioPlugin, c as chromaKeyVideoPlugin, v as videoPlugin, s as slicePlugin, i as imagePlugin, d as defaultInsetsForSize, b as assetIdError, m as manifestNameError, e as isAssetReference } from './core.js-DDntpb72.js';
3
+ import { m as manifestColorError, a as manifestEmojiError } from './manifest-appearance.js-DTk355LQ.js';
4
+ import { join, extname, dirname, basename } from 'node:path';
5
+ import { existsSync } from 'node:fs';
6
+ import { readFile, mkdir, writeFile, rename, rm, unlink, stat, readdir } from 'node:fs/promises';
7
+ import { createHash } from 'node:crypto';
8
+ import ffmpegStaticPath from 'ffmpeg-static';
9
+ import { path } from 'ffprobe-static';
10
+ import { execFile } from 'node:child_process';
11
+ import { promisify } from 'node:util';
12
+ import sharp from 'sharp';
13
+
14
+ //#region src/lib/core/library.ts
15
+ /** A fresh, empty library. */
16
+ function createEmptyLibrary() {
17
+ return {
18
+ version: 1,
19
+ folders: [],
20
+ assets: {},
21
+ manifests: {}
22
+ };
23
+ }
18
24
  function isRecord(value) {
19
25
  return typeof value === "object" && value !== null && !Array.isArray(value);
20
26
  }
21
- function requiredString(config, key) {
22
- const value = config[key];
23
- if (typeof value !== "string" || value.length === 0) throw new Error(`fundus.config: "${key}" must be a non-empty string.`);
24
- return value;
27
+ /**
28
+ * Keys that are prototype-pollution hazards as record keys: assigning
29
+ * `assets["__proto__"] = …` on a plain object replaces its prototype instead
30
+ * of adding an entry. Rejected outright at parse time — id *validity* beyond
31
+ * this is a validator concern (reported as issues, not parse failures).
32
+ */
33
+ var DANGEROUS_KEYS = [
34
+ "__proto__",
35
+ "constructor",
36
+ "prototype"
37
+ ];
38
+ function assertSafeKey(kind, key) {
39
+ if (DANGEROUS_KEYS.includes(key)) throw new Error(`Library ${kind} key "${key}" is not allowed.`);
25
40
  }
26
- function resolvePath(projectRoot, value) {
27
- return isAbsolute(value) ? value : resolve(projectRoot, value);
28
- }
29
- function mergePresets(label, builtIn, pluginConfig, validatePreset) {
30
- const merged = { ...builtIn };
31
- if (pluginConfig === void 0) return merged;
32
- if (!isRecord(pluginConfig)) throw new Error(`fundus.config: "plugins.${label}" must be an object.`);
33
- if (pluginConfig.presets === void 0) return merged;
34
- if (!isRecord(pluginConfig.presets)) throw new Error(`fundus.config: "plugins.${label}.presets" must be an object.`);
35
- for (const [name, preset] of Object.entries(pluginConfig.presets)) merged[name] = validatePreset(name, preset);
36
- return merged;
37
- }
38
- /** `plugins.video.ffmpegPath` / `ffprobePath`: optional system-binary overrides. */
39
- function binaryPathOverride(projectRoot, pluginConfig, key) {
40
- if (!isRecord(pluginConfig) || pluginConfig[key] === void 0) return null;
41
- const value = pluginConfig[key];
42
- if (typeof value !== "string" || value.length === 0) throw new Error(`fundus.config: "plugins.video.${key}" must be a non-empty string.`);
43
- return resolvePath(projectRoot, value);
44
- }
45
- /** Pure resolution step (testable without a config file on disk). */
46
- function resolveConfig(projectRoot, value) {
47
- if (!isRecord(value)) throw new Error("fundus.config must default-export a configuration object.");
48
- const proxyBasePath = requiredString(value, "proxyBasePath");
49
- if (!proxyBasePath.endsWith("/")) throw new Error("fundus.config: \"proxyBasePath\" must end with \"/\".");
50
- const plugins = value.plugins === void 0 ? {} : value.plugins;
51
- if (!isRecord(plugins)) throw new Error("fundus.config: \"plugins\" must be an object.");
41
+ function parseAssetRecord(id, value) {
42
+ if (!isRecord(value)) throw new Error(`Library asset "${id}" must be an object.`);
43
+ if (typeof value.type !== "string" || value.type.length === 0) throw new Error(`Library asset "${id}" is missing a string "type".`);
44
+ if (typeof value.raw !== "string" || value.raw.length === 0) throw new Error(`Library asset "${id}" is missing a string "raw" file name.`);
45
+ if (typeof value.rawHash !== "string" || value.rawHash.length === 0) throw new Error(`Library asset "${id}" is missing a string "rawHash".`);
46
+ if (!("parameters" in value)) throw new Error(`Library asset "${id}" is missing "parameters".`);
47
+ if (!Array.isArray(value.manifests) || value.manifests.some((entry) => typeof entry !== "string")) throw new Error(`Library asset "${id}" must have a "manifests" array of strings.`);
52
48
  return {
53
- rawDir: resolvePath(projectRoot, requiredString(value, "rawDir")),
54
- proxyDir: resolvePath(projectRoot, requiredString(value, "proxyDir")),
55
- library: resolvePath(projectRoot, requiredString(value, "library")),
56
- manifestsDir: resolvePath(projectRoot, requiredString(value, "manifestsDir")),
57
- proxyBasePath,
58
- plugins: {
59
- image: { presets: mergePresets("image", IMAGE_BUILT_IN_PRESETS, plugins.image, validateImagePreset) },
60
- slice: { presets: mergePresets("slice", SLICE_BUILT_IN_PRESETS, plugins.slice, validateImagePreset) },
61
- video: {
62
- presets: mergePresets("video", VIDEO_BUILT_IN_PRESETS, plugins.video, validateVideoPreset),
63
- ffmpegPath: binaryPathOverride(projectRoot, plugins.video, "ffmpegPath"),
64
- ffprobePath: binaryPathOverride(projectRoot, plugins.video, "ffprobePath")
65
- },
66
- audio: { presets: mergePresets("audio", AUDIO_BUILT_IN_PRESETS, plugins.audio, validateAudioPreset) }
67
- }
49
+ type: value.type,
50
+ raw: value.raw,
51
+ rawHash: value.rawHash,
52
+ parameters: value.parameters,
53
+ manifests: value.manifests
68
54
  };
69
55
  }
70
- /** Load `fundus.config.ts` from the host project root. */
71
- async function loadConfig(projectRoot) {
72
- const root = resolve(projectRoot);
73
- const configPath = resolve(root, "fundus.config.ts");
74
- if (!existsSync(configPath)) throw new Error(`No fundus.config.ts found in ${root}.`);
75
- let module;
56
+ function parseManifestRecord(name, value) {
57
+ const record = {};
58
+ if ("color" in value && value.color !== void 0) {
59
+ if (typeof value.color !== "string") throw new Error(`Library manifest "${name}" has a non-string "color".`);
60
+ record.color = value.color;
61
+ }
62
+ if ("emoji" in value && value.emoji !== void 0) {
63
+ if (typeof value.emoji !== "string") throw new Error(`Library manifest "${name}" has a non-string "emoji".`);
64
+ record.emoji = value.emoji;
65
+ }
66
+ return record;
67
+ }
68
+ /**
69
+ * Parse and structurally validate a library file's JSON text. Throws with a
70
+ * clear message on any malformed part; plugin parameter validation is a
71
+ * separate, plugin-owned step.
72
+ */
73
+ function parseLibrary(json) {
74
+ let value;
76
75
  try {
77
- module = await createJiti(import.meta.url, { interopDefault: false }).import(configPath);
76
+ value = JSON.parse(json);
78
77
  } catch (cause) {
79
- throw new Error(`Cannot load fundus.config.ts: ${cause instanceof Error ? cause.message : String(cause)}`);
78
+ throw new Error(`Library file is not valid JSON: ${cause instanceof Error ? cause.message : String(cause)}`);
79
+ }
80
+ if (!isRecord(value)) throw new Error("Library file must contain a JSON object.");
81
+ if (value.version !== 1) throw new Error(`Unsupported library version ${JSON.stringify(value.version)} (expected 1).`);
82
+ if (!isRecord(value.assets)) throw new Error("Library \"assets\" must be an object.");
83
+ if (!isRecord(value.manifests)) throw new Error("Library \"manifests\" must be an object.");
84
+ if (value.folders !== void 0 && (!Array.isArray(value.folders) || value.folders.some((entry) => typeof entry !== "string"))) throw new Error("Library \"folders\" must be an array of strings.");
85
+ const folders = value.folders === void 0 ? [] : value.folders;
86
+ for (const folder of folders) {
87
+ const problem = folderPathError(folder);
88
+ if (problem) throw new Error(`Invalid library folder: ${problem}`);
89
+ }
90
+ const assets = {};
91
+ for (const [id, record] of Object.entries(value.assets)) {
92
+ assertSafeKey("asset", id);
93
+ assets[id] = parseAssetRecord(id, record);
94
+ }
95
+ const manifests = {};
96
+ for (const [name, record] of Object.entries(value.manifests)) {
97
+ assertSafeKey("manifest", name);
98
+ if (!isRecord(record)) throw new Error(`Library manifest "${name}" must be an object.`);
99
+ manifests[name] = parseManifestRecord(name, record);
100
+ }
101
+ return {
102
+ version: 1,
103
+ folders,
104
+ assets,
105
+ manifests
106
+ };
107
+ }
108
+ /** Recursively sort object keys so serialization is order-independent. */
109
+ function sortValue(value) {
110
+ if (Array.isArray(value)) return value.map(sortValue);
111
+ if (typeof value === "object" && value !== null) {
112
+ const sorted = {};
113
+ for (const key of Object.keys(value).sort()) {
114
+ const entry = value[key];
115
+ if (entry !== void 0) sorted[key] = sortValue(entry);
116
+ }
117
+ return sorted;
118
+ }
119
+ return value;
120
+ }
121
+ /**
122
+ * Serialize a library deterministically: recursively sorted keys, tab-indented,
123
+ * trailing newline. Same library → byte-identical file, whatever the in-memory
124
+ * insertion order was.
125
+ */
126
+ function serializeLibrary(library) {
127
+ return `${JSON.stringify(sortValue({
128
+ ...library,
129
+ folders: [...library.folders].sort()
130
+ }), null, " ")}\n`;
131
+ }
132
+ //#endregion
133
+ //#region src/lib/core/canonicalize.ts
134
+ /**
135
+ * Stable JSON for hash inputs: recursively sorted keys, no whitespace,
136
+ * `undefined` object values dropped. Two parameter objects that differ only in
137
+ * key order (or in explicitly-undefined optionals) canonicalize identically,
138
+ * so the derived job hash — and thus the proxy file name — stays stable.
139
+ */
140
+ function canonicalizeParameters(parameters) {
141
+ return stringify(parameters);
142
+ }
143
+ /** Deterministic UTF-16 code-unit ordering, independent of host locale. */
144
+ function compareCodeUnits(left, right) {
145
+ return left < right ? -1 : left > right ? 1 : 0;
146
+ }
147
+ function stringify(value) {
148
+ if (value === void 0) return "null";
149
+ if (value === null || typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
150
+ if (typeof value === "string") return JSON.stringify(value);
151
+ if (Array.isArray(value)) return `[${value.map(stringify).join(",")}]`;
152
+ if (typeof value === "object") {
153
+ const record = value;
154
+ const parts = [];
155
+ for (const key of Object.keys(record).sort()) {
156
+ if (record[key] === void 0) continue;
157
+ parts.push(`${JSON.stringify(key)}:${stringify(record[key])}`);
158
+ }
159
+ return `{${parts.join(",")}}`;
80
160
  }
81
- return resolveConfig(root, isRecord(module) && "default" in module ? module.default : module);
161
+ throw new Error(`Cannot canonicalize a ${typeof value} value.`);
82
162
  }
83
163
  //#endregion
84
- //#region src/processing/ffmpeg.ts
164
+ //#region src/lib/core/reference-graph.ts
165
+ /**
166
+ * Ask each asset's owning plugin for the references in its parameters. Assets
167
+ * whose type is unknown or whose parameters do not validate contribute no
168
+ * references — those problems are reported by the regular validation pass.
169
+ */
170
+ function collectAllReferences(library, plugins) {
171
+ const referencesByAsset = {};
172
+ for (const [assetId, record] of Object.entries(library.assets)) {
173
+ referencesByAsset[assetId] = [];
174
+ const plugin = plugins[record.type];
175
+ if (!plugin?.collectReferences) continue;
176
+ try {
177
+ referencesByAsset[assetId] = plugin.collectReferences(plugin.validateParameters(record.parameters));
178
+ } catch {}
179
+ }
180
+ return referencesByAsset;
181
+ }
182
+ /**
183
+ * Reference *errors* (they block build/codegen): a reference to an unknown
184
+ * asset, a target whose type is not among the field's expected types, and
185
+ * cycles (composition is acyclic by nature).
186
+ */
187
+ function referenceErrors(library, referencesByAsset) {
188
+ const issues = [];
189
+ for (const [assetId, references] of Object.entries(referencesByAsset)) for (const reference of references) {
190
+ if (!Object.hasOwn(library.assets, reference.assetId)) {
191
+ issues.push({
192
+ assetId,
193
+ message: `Reference "${reference.field}" points at unknown asset "${reference.assetId}".`
194
+ });
195
+ continue;
196
+ }
197
+ const targetType = library.assets[reference.assetId].type;
198
+ if (reference.expectedTypes.length > 0 && !reference.expectedTypes.includes(targetType)) issues.push({
199
+ assetId,
200
+ message: `Reference "${reference.field}" points at "${reference.assetId}" of type "${targetType}" — expected ${reference.expectedTypes.map((type) => `"${type}"`).join(" or ")}.`
201
+ });
202
+ }
203
+ issues.push(...cycleErrors(referencesByAsset));
204
+ return issues;
205
+ }
206
+ /** DFS cycle detection with an explicit stack path; each cycle reported once. */
207
+ function cycleErrors(referencesByAsset) {
208
+ const issues = [];
209
+ const finished = /* @__PURE__ */ new Set();
210
+ const reportedCycles = /* @__PURE__ */ new Set();
211
+ const stack = [];
212
+ const onStack = /* @__PURE__ */ new Set();
213
+ function visit(assetId) {
214
+ if (finished.has(assetId)) return;
215
+ if (onStack.has(assetId)) {
216
+ const cyclePath = [...stack.slice(stack.indexOf(assetId)), assetId];
217
+ const cycleKey = [...new Set(cyclePath)].sort().join("\0");
218
+ if (!reportedCycles.has(cycleKey)) {
219
+ reportedCycles.add(cycleKey);
220
+ issues.push({
221
+ assetId: cyclePath[0],
222
+ message: `Reference cycle: ${cyclePath.map((id) => `"${id}"`).join(" → ")} — references express composition and must stay acyclic.`
223
+ });
224
+ }
225
+ return;
226
+ }
227
+ stack.push(assetId);
228
+ onStack.add(assetId);
229
+ for (const reference of referencesByAsset[assetId] ?? []) if (Object.hasOwn(referencesByAsset, reference.assetId)) visit(reference.assetId);
230
+ stack.pop();
231
+ onStack.delete(assetId);
232
+ finished.add(assetId);
233
+ }
234
+ for (const assetId of Object.keys(referencesByAsset)) visit(assetId);
235
+ return issues;
236
+ }
237
+ /**
238
+ * The transitive reference closure of a set of assets, including the starting
239
+ * set — the assets that must be delivered so the starting set renders as
240
+ * authored. Tolerates cycles and ignores dangling targets (both are reported
241
+ * as errors by `referenceErrors`).
242
+ */
243
+ function referenceClosure(assetIds, referencesByAsset) {
244
+ const closure = /* @__PURE__ */ new Set();
245
+ const pending = [...assetIds];
246
+ while (pending.length > 0) {
247
+ const assetId = pending.pop();
248
+ if (closure.has(assetId) || !Object.hasOwn(referencesByAsset, assetId)) continue;
249
+ closure.add(assetId);
250
+ for (const reference of referencesByAsset[assetId]) pending.push(reference.assetId);
251
+ }
252
+ return closure;
253
+ }
254
+ /**
255
+ * A dependencies-first order over `assetIds` and everything they transitively
256
+ * reference — the build order that lets each entry inline its references from
257
+ * already-built entries. Throws on a cycle (with the cycle path).
258
+ */
259
+ function topologicalReferenceOrder(assetIds, referencesByAsset) {
260
+ const order = [];
261
+ const finished = /* @__PURE__ */ new Set();
262
+ const stack = [];
263
+ const onStack = /* @__PURE__ */ new Set();
264
+ function visit(assetId) {
265
+ if (finished.has(assetId) || !Object.hasOwn(referencesByAsset, assetId)) return;
266
+ if (onStack.has(assetId)) {
267
+ const cyclePath = [...stack.slice(stack.indexOf(assetId)), assetId];
268
+ throw new Error(`Reference cycle: ${cyclePath.map((id) => `"${id}"`).join(" → ")} — cannot order entries.`);
269
+ }
270
+ stack.push(assetId);
271
+ onStack.add(assetId);
272
+ for (const reference of referencesByAsset[assetId]) visit(reference.assetId);
273
+ stack.pop();
274
+ onStack.delete(assetId);
275
+ finished.add(assetId);
276
+ order.push(assetId);
277
+ }
278
+ for (const assetId of assetIds) visit(assetId);
279
+ return order;
280
+ }
281
+ //#endregion
282
+ //#region src/lib/core/manifest-membership.ts
283
+ /**
284
+ * Compute the full membership picture from a library and its collected
285
+ * references: for each manifest the explicit members, the passive members
286
+ * (`referenceClosure(explicit) − explicit`) with their via-attribution, and
287
+ * the resulting delivery set.
288
+ */
289
+ function computeLibraryMembership(library, referencesByAsset) {
290
+ const manifestNames = new Set(Object.keys(library.manifests));
291
+ for (const record of Object.values(library.assets)) for (const manifestName of record.manifests) manifestNames.add(manifestName);
292
+ const membership = {};
293
+ for (const manifestName of [...manifestNames].sort(compareCodeUnits)) {
294
+ const explicitMemberIds = Object.entries(library.assets).filter(([, record]) => record.manifests.includes(manifestName)).map(([assetId]) => assetId).sort(compareCodeUnits);
295
+ const explicitMemberSet = new Set(explicitMemberIds);
296
+ const deliveredAssetIds = new Set(explicitMemberIds);
297
+ const viaByPassiveAssetId = /* @__PURE__ */ new Map();
298
+ for (const explicitMemberId of explicitMemberIds) for (const reachedAssetId of referenceClosure([explicitMemberId], referencesByAsset)) {
299
+ deliveredAssetIds.add(reachedAssetId);
300
+ if (explicitMemberSet.has(reachedAssetId)) continue;
301
+ const via = viaByPassiveAssetId.get(reachedAssetId) ?? [];
302
+ via.push(explicitMemberId);
303
+ viaByPassiveAssetId.set(reachedAssetId, via);
304
+ }
305
+ membership[manifestName] = {
306
+ explicitMemberIds,
307
+ passiveMembers: [...viaByPassiveAssetId.entries()].map(([assetId, via]) => ({
308
+ assetId,
309
+ via
310
+ })).sort((a, b) => compareCodeUnits(a.assetId, b.assetId)),
311
+ deliveredAssetIds
312
+ };
313
+ }
314
+ return membership;
315
+ }
316
+ /**
317
+ * Every asset delivered by at least one manifest, explicitly or passively —
318
+ * the processing set (assets outside it are inert). An asset is
319
+ * *unreachable* (nothing delivers it) exactly when it is missing here.
320
+ */
321
+ function allDeliveredAssetIds(membership) {
322
+ const delivered = /* @__PURE__ */ new Set();
323
+ for (const manifestMembership of Object.values(membership)) for (const assetId of manifestMembership.deliveredAssetIds) delivered.add(assetId);
324
+ return delivered;
325
+ }
326
+ //#endregion
327
+ //#region src/lib/server/processing/ffmpeg.ts
85
328
  /**
86
329
  * The ffmpeg/ffprobe toolchain layer: binary resolution (bundled `-static`
87
330
  * packages by default, with host-config overrides) and a spawn helper.
@@ -117,7 +360,7 @@ async function runToolchainBinary(binaryPath, commandArguments) {
117
360
  }
118
361
  }
119
362
  //#endregion
120
- //#region src/processing/media-probe.ts
363
+ //#region src/lib/server/processing/media-probe.ts
121
364
  /** Parse ffprobe's JSON output (pure, testable without a binary). */
122
365
  function parseProbeOutput(json, filePath) {
123
366
  const output = JSON.parse(json);
@@ -144,13 +387,13 @@ async function probeMedia(filePath, config) {
144
387
  ]), filePath);
145
388
  }
146
389
  //#endregion
147
- //#region src/processing/audio-processing.ts
390
+ //#region src/lib/server/processing/audio-processing.ts
148
391
  /**
149
392
  * The ffmpeg transcode step of the audio plugin: one audio-only proxy per
150
393
  * preset (opus/webm or aac/m4a). Deterministic like the video step:
151
394
  * metadata stripped, bitexact muxing.
152
395
  */
153
- const ENCODER_BY_CODEC = {
396
+ var ENCODER_BY_CODEC = {
154
397
  opus: "libopus",
155
398
  aac: "aac"
156
399
  };
@@ -187,7 +430,7 @@ async function processAudioFile(options) {
187
430
  return { durationMs: (await probeMedia(options.targetPath, options.config)).durationMs };
188
431
  }
189
432
  //#endregion
190
- //#region src/plugins/contract.ts
433
+ //#region src/lib/server/plugins/contract.ts
191
434
  /** Resolve a named preset out of a plugin's merged preset map, or throw listing the known names. */
192
435
  function resolveNamedPreset(label, presetName, presets) {
193
436
  const preset = presets[presetName];
@@ -201,12 +444,12 @@ function requireProxyField(proxy, field) {
201
444
  return value;
202
445
  }
203
446
  //#endregion
204
- //#region src/plugins/audio.ts
447
+ //#region src/lib/server/plugins/audio.ts
205
448
  /**
206
449
  * Audio plugin (server part): one ffmpeg transcode per preset.
207
450
  * No dimensions — the proxy's only output metadata is its duration.
208
451
  */
209
- const audioServerPlugin = {
452
+ var audioServerPlugin = {
210
453
  descriptor: audioPlugin,
211
454
  pluginConfig: (config) => config.plugins.audio,
212
455
  presets: (config) => config.plugins.audio.presets,
@@ -226,7 +469,7 @@ const audioServerPlugin = {
226
469
  })
227
470
  };
228
471
  //#endregion
229
- //#region src/processing/video-processing.ts
472
+ //#region src/lib/server/processing/video-processing.ts
230
473
  /**
231
474
  * The ffmpeg transcode step shared by the video and chroma-key-video plugins
232
475
  * (chroma-key-video builds on video's processing; its keying data is
@@ -309,14 +552,14 @@ async function processVideoFile(options) {
309
552
  };
310
553
  }
311
554
  //#endregion
312
- //#region src/plugins/chroma-key-video.ts
555
+ //#region src/lib/server/plugins/chroma-key-video.ts
313
556
  /**
314
557
  * Chroma-key-video plugin (server part): shares the video plugin's transcode
315
558
  * pipeline and preset namespace — the keying parameters and the
316
559
  * mask/fallback references never reach ffmpeg, they are entry-only data
317
560
  * (the descriptor's `processingParameters` keeps them out of the job hash).
318
561
  */
319
- const chromaKeyVideoServerPlugin = {
562
+ var chromaKeyVideoServerPlugin = {
320
563
  descriptor: chromaKeyVideoPlugin,
321
564
  pluginConfig: (config) => config.plugins.video,
322
565
  presets: (config) => config.plugins.video.presets,
@@ -342,7 +585,7 @@ const chromaKeyVideoServerPlugin = {
342
585
  })
343
586
  };
344
587
  //#endregion
345
- //#region src/processing/image-processing.ts
588
+ //#region src/lib/server/processing/image-processing.ts
346
589
  /**
347
590
  * The sharp step shared by the image and slice plugins: optional resize to a
348
591
  * target width, format conversion per preset, write the proxy file. Returns
@@ -369,7 +612,7 @@ async function readImageDimensions(filePath) {
369
612
  };
370
613
  }
371
614
  //#endregion
372
- //#region src/plugins/image.ts
615
+ //#region src/lib/server/plugins/image.ts
373
616
  /**
374
617
  * Image plugin (server part): sharp scale + convert per preset.
375
618
  */
@@ -377,7 +620,7 @@ async function readImageDimensions(filePath) {
377
620
  function extensionForImageFormat(format) {
378
621
  return format === "jpeg" ? "jpg" : format;
379
622
  }
380
- const imageServerPlugin = {
623
+ var imageServerPlugin = {
381
624
  descriptor: imagePlugin,
382
625
  pluginConfig: (config) => config.plugins.image,
383
626
  presets: (config) => config.plugins.image.presets,
@@ -398,7 +641,7 @@ const imageServerPlugin = {
398
641
  })
399
642
  };
400
643
  //#endregion
401
- //#region src/plugins/slice.ts
644
+ //#region src/lib/server/plugins/slice.ts
402
645
  /**
403
646
  * Slice plugin (server part): the same sharp conversion as the image plugin,
404
647
  * never resized — insets are authored in source pixels, so the delivered proxy
@@ -418,7 +661,7 @@ function detectPixelRatio(fileName) {
418
661
  const ratio = match ? Number(match[1]) : 1;
419
662
  return ratio >= 1 ? ratio : 1;
420
663
  }
421
- const sliceServerPlugin = {
664
+ var sliceServerPlugin = {
422
665
  descriptor: slicePlugin,
423
666
  pluginConfig: (config) => config.plugins.slice,
424
667
  presets: (config) => config.plugins.slice.presets,
@@ -454,11 +697,11 @@ const sliceServerPlugin = {
454
697
  }
455
698
  };
456
699
  //#endregion
457
- //#region src/plugins/video.ts
700
+ //#region src/lib/server/plugins/video.ts
458
701
  /**
459
702
  * Video plugin (server part): one ffmpeg transcode per preset.
460
703
  */
461
- const videoServerPlugin = {
704
+ var videoServerPlugin = {
462
705
  descriptor: videoPlugin,
463
706
  pluginConfig: (config) => config.plugins.video,
464
707
  presets: (config) => config.plugins.video.presets,
@@ -481,8 +724,8 @@ const videoServerPlugin = {
481
724
  })
482
725
  };
483
726
  //#endregion
484
- //#region src/plugins.ts
485
- const serverPluginsByType = {
727
+ //#region src/lib/server/plugins.ts
728
+ var serverPluginsByType = {
486
729
  [imageServerPlugin.descriptor.type]: imageServerPlugin,
487
730
  [sliceServerPlugin.descriptor.type]: sliceServerPlugin,
488
731
  [videoServerPlugin.descriptor.type]: videoServerPlugin,
@@ -498,8 +741,7 @@ function serverPluginForType(type, registry = serverPluginsByType) {
498
741
  function descriptorsByType(registry) {
499
742
  return Object.fromEntries(Object.entries(registry).map(([type, plugin]) => [type, plugin.descriptor]));
500
743
  }
501
- /** The built-in registry's descriptor map (the common case; registry-aware code derives its own). */
502
- const pluginsByType = descriptorsByType(serverPluginsByType);
744
+ descriptorsByType(serverPluginsByType);
503
745
  /**
504
746
  * The job-hash parameter input for an asset: the plugin-declared
505
747
  * processing-relevant subset when the plugin distinguishes one (chroma-key-
@@ -509,7 +751,7 @@ function processingParametersOf(plugin, parameters) {
509
751
  return plugin.processingParameters ? plugin.processingParameters(parameters) : parameters;
510
752
  }
511
753
  //#endregion
512
- //#region src/codegen.ts
754
+ //#region src/lib/server/codegen.ts
513
755
  /**
514
756
  * Manifest module codegen: one `<manifest-name-kebab>.generated.ts`
515
757
  * per manifest in the configured manifests directory, containing data only —
@@ -517,7 +759,7 @@ function processingParametersOf(plugin, parameters) {
517
759
  * sorted asset ids, fixed property order, tab indentation. Generated modules
518
760
  * for deleted manifests are removed (only files carrying the fundus header).
519
761
  */
520
- const GENERATED_HEADER = "// generated by fundus — do not edit\n";
762
+ var GENERATED_HEADER = "// generated by fundus — do not edit\n";
521
763
  /** `mainCatalog` → `main-catalog`. */
522
764
  function kebabCaseFromCamel(name) {
523
765
  return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
@@ -664,7 +906,7 @@ function jobHash(rawHash, parameters, pipelineVersion = 1) {
664
906
  return createHash("sha256").update(rawHash + canonicalizeParameters(parameters) + String(pipelineVersion)).digest("hex").slice(0, 8);
665
907
  }
666
908
  //#endregion
667
- //#region src/folder-filesystem.ts
909
+ //#region src/lib/server/folder-filesystem.ts
668
910
  async function ensureManagedFolder(root, folder) {
669
911
  const directory = join(root, folder);
670
912
  await mkdir(directory, { recursive: true });
@@ -691,7 +933,7 @@ function encodeRelativePathForUrl(path) {
691
933
  return path.split("/").map(encodeURIComponent).join("/");
692
934
  }
693
935
  //#endregion
694
- //#region src/processing/processor.ts
936
+ //#region src/lib/server/processing/processor.ts
695
937
  /**
696
938
  * The processing pipeline: every delivered asset gets exactly one
697
939
  * proxy named `<assetId>.<jobHash>.<extension>`. Delivered = explicit or
@@ -708,7 +950,7 @@ function encodeRelativePathForUrl(path) {
708
950
  * drive the pipeline with fixture asset types.
709
951
  */
710
952
  /** Proxy file name shape; its id segment is pinned to core's asset-id grammar. */
711
- const PROXY_FILE_PATTERN = /^[a-z][A-Za-z0-9]*\.[0-9a-f]{8}\.[a-z0-9]+$/;
953
+ var PROXY_FILE_PATTERN = /^[a-z][A-Za-z0-9]*\.[0-9a-f]{8}\.[a-z0-9]+$/;
712
954
  /** Whether a file name in the proxy directory is (shaped like) a fundus proxy. */
713
955
  function isProxyFileName(fileName) {
714
956
  return PROXY_FILE_PATTERN.test(fileName);
@@ -845,7 +1087,7 @@ async function processAssets(config, library, registry = serverPluginsByType) {
845
1087
  return report;
846
1088
  }
847
1089
  //#endregion
848
- //#region src/library-store.ts
1090
+ //#region src/lib/server/library-store.ts
849
1091
  /**
850
1092
  * The fs-backed store over the library file (SSOT) and the raw directory.
851
1093
  * Every mutation is load → modify → deterministic write, so the file on disk
@@ -853,7 +1095,7 @@ async function processAssets(config, library, registry = serverPluginsByType) {
853
1095
  * store only removes them on asset deletion (the pipeline also prunes orphans).
854
1096
  */
855
1097
  /** A single path segment with no traversal — guards against `../` escapes. */
856
- const SAFE_SEGMENT = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
1098
+ var SAFE_SEGMENT = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
857
1099
  function assertSafeFileName(fileName) {
858
1100
  if (!SAFE_SEGMENT.test(fileName) || fileName.includes("/") || fileName.includes("\\")) throw new Error(`Unsafe file name "${fileName}".`);
859
1101
  }
@@ -1450,348 +1692,6 @@ var LibraryStore = class {
1450
1692
  if (collision !== void 0) throw new Error(`Folder "${path}" collides with existing folder "${collision}".`);
1451
1693
  }
1452
1694
  };
1453
- //#endregion
1454
- //#region src/operations.ts
1455
- /**
1456
- * The one operations layer: builds the state payload and runs
1457
- * every mutation through the autosave chain — write library → process affected
1458
- * assets → regenerate codegen → return fresh state. Both the REST server
1459
- * and the CLI consume this class, so every
1460
- * operation has exactly one implementation and there is no other save path.
1461
- */
1462
- /**
1463
- * The CLI's `--parameters` merge semantics (M7): a SHALLOW merge at the top
1464
- * level onto the current parameters — a nested object value replaces the whole
1465
- * current object under that key, a top-level `null` clears an optional field,
1466
- * and an asset reference is set with the normal `{"$asset": "<id>"}` marker.
1467
- * The merged result still passes the owning plugin's full validation.
1468
- */
1469
- function mergeParameterPatch(currentParameters, patch) {
1470
- if (typeof patch !== "object" || patch === null || Array.isArray(patch)) throw new Error("The parameter patch must be a JSON object, e.g. {\"preset\": \"default\"}.");
1471
- const merged = typeof currentParameters === "object" && currentParameters !== null && !Array.isArray(currentParameters) ? { ...currentParameters } : {};
1472
- for (const [key, value] of Object.entries(patch)) if (value === null) delete merged[key];
1473
- else merged[key] = value;
1474
- return merged;
1475
- }
1476
- var FundusOperations = class {
1477
- #config;
1478
- #registry;
1479
- #store;
1480
- constructor(config, registry = serverPluginsByType) {
1481
- this.#config = config;
1482
- this.#registry = registry;
1483
- this.#store = new LibraryStore(config, registry);
1484
- }
1485
- get config() {
1486
- return this.#config;
1487
- }
1488
- get store() {
1489
- return this.#store;
1490
- }
1491
- /** Read-only state snapshot (no processing). */
1492
- async state() {
1493
- return this.#buildState(await this.#store.read(), []);
1494
- }
1495
- /**
1496
- * Ingest an upload: store the raw file + record, then let the owning
1497
- * plugin's optional `seedIngestParameters` derive better starting
1498
- * parameters from the stored raw file (slices: insets from the image
1499
- * dimensions, pixel ratio from the file name — the schema default can't
1500
- * know either). The CLI additionally applies a parameter patch and/or an
1501
- * explicit membership set in the same operation; a failing application
1502
- * rolls the whole ingest back, so a failed ingest leaves nothing behind.
1503
- */
1504
- async ingest(options) {
1505
- let library = await this.#store.ingest(options);
1506
- try {
1507
- const plugin = serverPluginForType(options.type, this.#registry);
1508
- if (plugin.seedIngestParameters) {
1509
- const record = library.assets[options.id];
1510
- const seeded = await plugin.seedIngestParameters({
1511
- rawPath: join(this.#config.rawDir, record.raw),
1512
- rawFileName: rawFileNameOfPath(record.raw),
1513
- parameters: plugin.descriptor.validateParameters(record.parameters),
1514
- config: this.#config
1515
- });
1516
- if (seeded !== void 0) library = await this.#store.updateParameters(options.id, seeded);
1517
- }
1518
- if (options.parametersPatch !== void 0 || options.manifests !== void 0) library = await this.#applyAssetChanges(library, options.id, {
1519
- parametersPatch: options.parametersPatch,
1520
- manifests: options.manifests
1521
- });
1522
- } catch (cause) {
1523
- await this.#store.deleteAsset(options.id);
1524
- throw cause;
1525
- }
1526
- return this.#afterMutation(library);
1527
- }
1528
- /** Apply a PATCH body: parameters and/or manifests and/or a rename — in that order. */
1529
- async patchAsset(id, body) {
1530
- let library = await this.#store.read();
1531
- this.#requireAsset(library, id);
1532
- if (body.parameters !== void 0) library = await this.#store.updateParameters(id, body.parameters);
1533
- if (body.manifests !== void 0) {
1534
- if (!Array.isArray(body.manifests) || body.manifests.some((name) => typeof name !== "string")) throw new Error("\"manifests\" must be an array of manifest names.");
1535
- library = await this.#store.setManifests(id, body.manifests);
1536
- }
1537
- if (body.renameTo !== void 0) {
1538
- if (typeof body.renameTo !== "string") throw new Error("\"renameTo\" must be a string.");
1539
- library = await this.#store.renameAsset(id, body.renameTo);
1540
- }
1541
- if (body.folder !== void 0) {
1542
- if (typeof body.folder !== "string") throw new Error("\"folder\" must be a string.");
1543
- library = await this.#store.moveAsset(body.renameTo ?? id, body.folder);
1544
- }
1545
- return this.#afterMutation(library);
1546
- }
1547
- async moveAsset(id, folder) {
1548
- return this.#afterMutation(await this.#store.moveAsset(id, folder));
1549
- }
1550
- /** Move a selected asset set as one editor action and roll back on any failure. */
1551
- async moveAssets(assetIds, folder) {
1552
- const uniqueIds = [...new Set(assetIds)];
1553
- if (uniqueIds.length === 0) throw new Error("At least one asset id is required.");
1554
- const originalFolders = /* @__PURE__ */ new Map();
1555
- const library = await this.#store.read();
1556
- for (const id of uniqueIds) {
1557
- this.#requireAsset(library, id);
1558
- originalFolders.set(id, folderOfRawPath(library.assets[id].raw));
1559
- }
1560
- const movedIds = [];
1561
- try {
1562
- let updated = library;
1563
- for (const id of uniqueIds) {
1564
- if (originalFolders.get(id) === folder) continue;
1565
- updated = await this.#store.moveAsset(id, folder);
1566
- movedIds.push(id);
1567
- }
1568
- return this.#afterMutation(updated);
1569
- } catch (cause) {
1570
- for (const id of movedIds.reverse()) await this.#store.moveAsset(id, originalFolders.get(id) ?? "");
1571
- throw cause;
1572
- }
1573
- }
1574
- async createFolder(path) {
1575
- return this.#afterMutation(await this.#store.createFolder(path));
1576
- }
1577
- async renameFolder(path, newName) {
1578
- return this.#afterMutation(await this.#store.renameFolder(path, newName));
1579
- }
1580
- async moveFolder(path, parent) {
1581
- return this.#afterMutation(await this.#store.moveFolder(path, parent));
1582
- }
1583
- async deleteFolder(path) {
1584
- const result = await this.#store.deleteFolder(path);
1585
- return this.#afterMutation(result.library);
1586
- }
1587
- /**
1588
- * CLI-facing asset update (M7): shallow-merge a parameter patch and/or
1589
- * replace the explicit manifest membership — validating the *result* before
1590
- * anything is persisted, so a change that would leave the library invalid
1591
- * (dangling or cyclic reference, unknown manifest, invalid parameters) is
1592
- * rejected with nothing written. The REST `patchAsset` keeps the editor's
1593
- * lenient replace semantics.
1594
- */
1595
- async setAsset(id, changes) {
1596
- const library = await this.#store.read();
1597
- this.#requireAsset(library, id);
1598
- return this.#afterMutation(await this.#applyAssetChanges(library, id, changes));
1599
- }
1600
- /**
1601
- * CLI-facing rename (M7): rejects a rename that would break references —
1602
- * a referrer keeps pointing at the old id, so renaming a referenced asset
1603
- * introduces dangling-reference errors. Update the referrers first.
1604
- */
1605
- async renameAsset(id, newId) {
1606
- const library = await this.#store.read();
1607
- this.#requireAsset(library, id);
1608
- if (newId !== id && !Object.hasOwn(library.assets, newId)) {
1609
- const candidate = structuredClone(library);
1610
- candidate.assets[newId] = candidate.assets[id];
1611
- delete candidate.assets[id];
1612
- await this.#assertNoIntroducedIssues(library, candidate);
1613
- }
1614
- return this.#afterMutation(await this.#store.renameAsset(id, newId));
1615
- }
1616
- /**
1617
- * Delete an asset: the record, its raw file, and its proxies. With
1618
- * `failOnIntroducedIssues` (the CLI), a delete that would break references
1619
- * (the asset is a reference target) is rejected before anything —
1620
- * including the raw file — is removed; the REST route stays lenient.
1621
- */
1622
- async deleteAsset(id, options) {
1623
- if (options?.failOnIntroducedIssues) {
1624
- const library = await this.#store.read();
1625
- this.#requireAsset(library, id);
1626
- const candidate = structuredClone(library);
1627
- delete candidate.assets[id];
1628
- await this.#assertNoIntroducedIssues(library, candidate);
1629
- }
1630
- return this.#afterMutation(await this.#store.deleteAsset(id));
1631
- }
1632
- /** Delete a selected asset set as one lenient editor mutation. */
1633
- async deleteAssets(assetIds) {
1634
- const uniqueIds = [...new Set(assetIds)];
1635
- if (uniqueIds.length === 0) throw new Error("At least one asset id is required.");
1636
- return this.#afterMutation(await this.#store.deleteAssets(uniqueIds));
1637
- }
1638
- async createManifest(name) {
1639
- return this.#afterMutation(await this.#store.createManifest(name));
1640
- }
1641
- async setManifestAppearance(name, appearance) {
1642
- return this.#afterMutation(await this.#store.setManifestAppearance(name, appearance));
1643
- }
1644
- /** Apply a PATCH body: appearance fields and/or a rename — in that order. */
1645
- async patchManifest(name, body) {
1646
- let library = await this.#store.setManifestAppearance(name, {
1647
- color: body.color,
1648
- emoji: body.emoji
1649
- });
1650
- if (body.renameTo !== void 0) {
1651
- if (typeof body.renameTo !== "string") throw new Error("\"renameTo\" must be a string.");
1652
- library = await this.#store.renameManifest(name, body.renameTo);
1653
- }
1654
- return this.#afterMutation(library);
1655
- }
1656
- /**
1657
- * Rename a manifest: rewrites every asset's membership and replaces the
1658
- * generated module (the old one is pruned as a stray). Host code importing
1659
- * the module must be updated by hand — both the file name and the exported
1660
- * const change with the manifest name.
1661
- */
1662
- async renameManifest(name, newName) {
1663
- return this.#afterMutation(await this.#store.renameManifest(name, newName));
1664
- }
1665
- async deleteManifest(name) {
1666
- return this.#afterMutation(await this.#store.deleteManifest(name));
1667
- }
1668
- /** The autosave chain tail: process + regenerate, then report fresh state. */
1669
- async #afterMutation(library) {
1670
- const pipelineIssues = [];
1671
- const issues = await this.#store.validate(library);
1672
- if (issues.length === 0) try {
1673
- const report = await processAssets(this.#config, library, this.#registry);
1674
- await generateManifestModules(this.#config, library, report.proxies, this.#registry);
1675
- } catch (cause) {
1676
- pipelineIssues.push({ message: `Processing failed: ${cause instanceof Error ? cause.message : String(cause)}` });
1677
- }
1678
- return this.#buildState(library, pipelineIssues, issues);
1679
- }
1680
- async #buildState(library, extraIssues, precomputedIssues) {
1681
- const issues = [...precomputedIssues ?? await this.#store.validate(library), ...extraIssues];
1682
- const referencesByAsset = collectAllReferences(library, descriptorsByType(this.#registry));
1683
- const membershipByManifest = computeLibraryMembership(library, referencesByAsset);
1684
- const delivered = allDeliveredAssetIds(membershipByManifest);
1685
- const passiveManifestsByAsset = /* @__PURE__ */ new Map();
1686
- for (const manifestName of Object.keys(library.manifests).sort(compareCodeUnits)) for (const passiveMember of membershipByManifest[manifestName].passiveMembers) {
1687
- const passiveManifests = passiveManifestsByAsset.get(passiveMember.assetId) ?? [];
1688
- passiveManifests.push({
1689
- manifest: manifestName,
1690
- via: passiveMember.via
1691
- });
1692
- passiveManifestsByAsset.set(passiveMember.assetId, passiveManifests);
1693
- }
1694
- const incomingByAsset = /* @__PURE__ */ new Map();
1695
- for (const [referrerId, references] of Object.entries(referencesByAsset)) for (const reference of references) {
1696
- const incoming = incomingByAsset.get(reference.assetId) ?? [];
1697
- incoming.push({
1698
- field: reference.field,
1699
- assetId: referrerId
1700
- });
1701
- incomingByAsset.set(reference.assetId, incoming);
1702
- }
1703
- const assets = [];
1704
- for (const assetId of Object.keys(library.assets).sort(compareCodeUnits)) {
1705
- const record = library.assets[assetId];
1706
- const warnings = [];
1707
- for (const issue of issues) if (issue.assetId === assetId) warnings.push(issue.message);
1708
- if (record.manifests.length === 0 && !delivered.has(assetId)) warnings.push("In no manifest and not referenced by any delivered asset — nothing is processed or generated for it.");
1709
- let proxy = null;
1710
- if (delivered.has(assetId)) try {
1711
- const currentProxy = await readCurrentProxy(assetId, record, this.#config, this.#registry);
1712
- if (currentProxy) proxy = {
1713
- url: `/files/proxy/${encodeRelativePathForUrl(currentProxy.relativePath)}`,
1714
- upToDate: true,
1715
- ...currentProxy
1716
- };
1717
- else warnings.push("Proxy is stale or missing — it will be (re)processed on the next save.");
1718
- } catch (cause) {
1719
- warnings.push(cause instanceof Error ? cause.message : String(cause));
1720
- }
1721
- assets.push({
1722
- id: assetId,
1723
- type: record.type,
1724
- raw: record.raw,
1725
- folder: folderOfRawPath(record.raw),
1726
- rawUrl: `/files/raw/${encodeRelativePathForUrl(record.raw)}`,
1727
- rawHash: record.rawHash,
1728
- parameters: record.parameters,
1729
- manifests: record.manifests,
1730
- passiveManifests: passiveManifestsByAsset.get(assetId) ?? [],
1731
- proxy,
1732
- warnings,
1733
- references: {
1734
- outgoing: referencesByAsset[assetId].map((reference) => ({
1735
- field: reference.field,
1736
- assetId: reference.assetId
1737
- })),
1738
- incoming: incomingByAsset.get(assetId) ?? []
1739
- }
1740
- });
1741
- }
1742
- const proxySizeByAssetId = new Map(assets.filter((asset) => asset.proxy).map((asset) => [asset.id, asset.proxy?.fileSize ?? 0]));
1743
- const manifestMemberships = {};
1744
- const manifestDeliveredBytes = {};
1745
- for (const manifestName of Object.keys(library.manifests).sort(compareCodeUnits)) {
1746
- const membership = membershipByManifest[manifestName];
1747
- manifestMemberships[manifestName] = {
1748
- explicitMemberIds: membership.explicitMemberIds,
1749
- passiveMembers: membership.passiveMembers
1750
- };
1751
- let deliveredBytes = 0;
1752
- for (const deliveredAssetId of membership.deliveredAssetIds) deliveredBytes += proxySizeByAssetId.get(deliveredAssetId) ?? 0;
1753
- manifestDeliveredBytes[manifestName] = deliveredBytes;
1754
- }
1755
- const presetNames = {};
1756
- for (const [type, plugin] of Object.entries(this.#registry)) presetNames[type] = Object.keys(plugin.presets(this.#config)).sort();
1757
- return {
1758
- library,
1759
- assets,
1760
- issues,
1761
- presetNames,
1762
- manifestMemberships,
1763
- manifestDeliveredBytes
1764
- };
1765
- }
1766
- #requireAsset(library, id) {
1767
- if (!Object.hasOwn(library.assets, id)) throw new Error(`Unknown asset "${id}".`);
1768
- }
1769
- /**
1770
- * Apply a CLI asset change to the store, validating the resulting library
1771
- * on an in-memory candidate first — nothing is persisted when the change
1772
- * would introduce validation issues. Pre-existing issues never block an
1773
- * unrelated mutation (only *introduced* issues are rejected).
1774
- */
1775
- async #applyAssetChanges(library, id, changes) {
1776
- const candidate = structuredClone(library);
1777
- const candidateRecord = candidate.assets[id];
1778
- if (changes.parametersPatch !== void 0) candidateRecord.parameters = serverPluginForType(candidateRecord.type, this.#registry).descriptor.validateParameters(mergeParameterPatch(candidateRecord.parameters, changes.parametersPatch));
1779
- if (changes.manifests !== void 0) candidateRecord.manifests = [...new Set(changes.manifests)].sort();
1780
- await this.#assertNoIntroducedIssues(library, candidate);
1781
- let updated = library;
1782
- if (changes.parametersPatch !== void 0) updated = await this.#store.updateParameters(id, candidateRecord.parameters);
1783
- if (changes.manifests !== void 0) updated = await this.#store.setManifests(id, changes.manifests);
1784
- return updated;
1785
- }
1786
- /** Reject a candidate library that has validation issues the current one lacks. */
1787
- async #assertNoIntroducedIssues(library, candidate) {
1788
- const existingIssueKeys = new Set((await this.#store.validate(library)).map((issue) => `${issue.assetId ?? ""}|${issue.message}`));
1789
- const introduced = (await this.#store.validate(candidate)).filter((issue) => !existingIssueKeys.has(`${issue.assetId ?? ""}|${issue.message}`));
1790
- if (introduced.length > 0) {
1791
- const lines = introduced.map((issue) => ` - ${issue.assetId ? `[${issue.assetId}] ` : ""}${issue.message}`);
1792
- throw new Error(`Rejected — the change would leave the library invalid (nothing was written):\n${lines.join("\n")}`);
1793
- }
1794
- }
1795
- };
1796
- //#endregion
1797
- export { runToolchainBinary as C, ffmpegBinaryPath as S, resolveConfig as T, strayGeneratedModuleNames as _, deliveredAssetIds as a, serverPluginForType as b, isProxyFileName as c, readProxyOutputInfo as d, listRelativeFiles as f, renderManifestModule as g, manifestModuleFileName as h, sha256Hex as i, processAssets as l, generateManifestModules as m, LibraryStore as n, expectedProxyFileName as o, buildManifestEntries as p, assertSafeRelativeFilePath as r, expectedProxyRelativePath as s, FundusOperations as t, readCurrentProxy as u, descriptorsByType as v, loadConfig as w, serverPluginsByType as x, pluginsByType as y };
1695
+
1696
+ export { LibraryStore as L, serverPluginForType as a, computeLibraryMembership as b, collectAllReferences as c, descriptorsByType as d, allDeliveredAssetIds as e, compareCodeUnits as f, generateManifestModules as g, encodeRelativePathForUrl as h, assertSafeRelativeFilePath as i, processAssets as p, readCurrentProxy as r, serverPluginsByType as s };
1697
+ //# sourceMappingURL=library-store.js-BP8cL-qD.js.map