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.
- package/README.md +58 -0
- package/build/client/_app/immutable/assets/0.DLhIsYA_.css.br +0 -0
- package/build/client/_app/immutable/assets/0.DLhIsYA_.css.gz +0 -0
- package/build/client/_app/immutable/assets/2.wavcNhPC.css +1 -0
- package/build/client/_app/immutable/assets/2.wavcNhPC.css.br +0 -0
- package/build/client/_app/immutable/assets/2.wavcNhPC.css.gz +0 -0
- package/build/client/_app/immutable/assets/3.Cjh_fXPY.css +1 -0
- package/build/client/_app/immutable/assets/3.Cjh_fXPY.css.br +0 -0
- package/build/client/_app/immutable/assets/3.Cjh_fXPY.css.gz +0 -0
- package/build/client/_app/immutable/assets/4.p004hmEN.css +1 -0
- package/build/client/_app/immutable/assets/4.p004hmEN.css.br +0 -0
- package/build/client/_app/immutable/assets/4.p004hmEN.css.gz +0 -0
- package/build/client/_app/immutable/assets/ConfirmDialog.BdKlitwi.css +1 -0
- package/build/client/_app/immutable/assets/ConfirmDialog.BdKlitwi.css.br +0 -0
- package/build/client/_app/immutable/assets/ConfirmDialog.BdKlitwi.css.gz +0 -0
- package/build/client/_app/immutable/assets/LibraryContextMenu.zyZtpKzC.css +1 -0
- package/build/client/_app/immutable/assets/LibraryContextMenu.zyZtpKzC.css.br +0 -0
- package/build/client/_app/immutable/assets/LibraryContextMenu.zyZtpKzC.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BiIto6ft.js +1 -0
- package/build/client/_app/immutable/chunks/BiIto6ft.js.br +0 -0
- package/build/client/_app/immutable/chunks/BiIto6ft.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bjy-W4x2.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bjy-W4x2.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CNRz3sSw.js.br +0 -0
- package/build/client/_app/immutable/chunks/CNRz3sSw.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CO4RBJfa.js.br +0 -0
- package/build/client/_app/immutable/chunks/CO4RBJfa.js.gz +0 -0
- package/{dist/editor/_app/immutable/chunks/DjvOiDmq.js → build/client/_app/immutable/chunks/CvY6YsFE.js} +1 -1
- package/build/client/_app/immutable/chunks/CvY6YsFE.js.br +0 -0
- package/build/client/_app/immutable/chunks/CvY6YsFE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DL0_39Ys.js +5 -0
- package/build/client/_app/immutable/chunks/DL0_39Ys.js.br +0 -0
- package/build/client/_app/immutable/chunks/DL0_39Ys.js.gz +0 -0
- package/{dist/editor/_app/immutable/chunks/BfPE5wdt.js → build/client/_app/immutable/chunks/DQ8SXFaX.js} +1 -1
- package/build/client/_app/immutable/chunks/DQ8SXFaX.js.br +0 -0
- package/build/client/_app/immutable/chunks/DQ8SXFaX.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DjdrdRzT.js.br +0 -0
- package/build/client/_app/immutable/chunks/DjdrdRzT.js.gz +0 -0
- package/build/client/_app/immutable/chunks/xihTtKlq.js.br +1 -0
- package/build/client/_app/immutable/chunks/xihTtKlq.js.gz +0 -0
- package/{dist/editor/_app/immutable/entry/app.BkqbfI8n.js → build/client/_app/immutable/entry/app.ubN0v9bN.js} +2 -2
- package/build/client/_app/immutable/entry/app.ubN0v9bN.js.br +0 -0
- package/build/client/_app/immutable/entry/app.ubN0v9bN.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BW8dBDh6.js +1 -0
- package/build/client/_app/immutable/entry/start.BW8dBDh6.js.br +0 -0
- package/build/client/_app/immutable/entry/start.BW8dBDh6.js.gz +0 -0
- package/{dist/editor/_app/immutable/nodes/0.xdMI5GEU.js → build/client/_app/immutable/nodes/0.Dr5ijCIl.js} +1 -1
- package/build/client/_app/immutable/nodes/0.Dr5ijCIl.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.Dr5ijCIl.js.gz +0 -0
- package/{dist/editor/_app/immutable/nodes/1.D9p2tfoJ.js → build/client/_app/immutable/nodes/1.DiIGIRAb.js} +1 -1
- package/build/client/_app/immutable/nodes/1.DiIGIRAb.js.br +3 -0
- package/build/client/_app/immutable/nodes/1.DiIGIRAb.js.gz +0 -0
- package/{dist/editor/_app/immutable/nodes/2.BrA0Hyzu.js → build/client/_app/immutable/nodes/2.B8KYmQcV.js} +3 -3
- package/build/client/_app/immutable/nodes/2.B8KYmQcV.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.B8KYmQcV.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.B1jc7arT.js +104 -0
- package/build/client/_app/immutable/nodes/3.B1jc7arT.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.B1jc7arT.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.BPK9n1mH.js +2 -0
- package/build/client/_app/immutable/nodes/4.BPK9n1mH.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.BPK9n1mH.js.gz +0 -0
- package/build/client/_app/version.json +1 -0
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/env.js +100 -0
- package/build/env.js.map +1 -0
- package/build/handler.js +22 -0
- package/build/handler.js.map +1 -0
- package/build/index.js +145 -0
- package/build/index.js.map +1 -0
- package/build/server/chunks/chunks/context.js-Bw4WWLhG.js +443 -0
- package/build/server/chunks/chunks/context.js-Bw4WWLhG.js.map +1 -0
- package/build/server/chunks/chunks/core.js-DDntpb72.js +409 -0
- package/build/server/chunks/chunks/core.js-DDntpb72.js.map +1 -0
- package/build/server/chunks/chunks/env.js-l0sNRNKZ.js +2 -0
- package/build/server/chunks/chunks/env.js-l0sNRNKZ.js.map +1 -0
- package/build/server/chunks/chunks/exports.js-CLTzaOxn.js +152 -0
- package/build/server/chunks/chunks/exports.js-CLTzaOxn.js.map +1 -0
- package/build/server/chunks/chunks/folder-path.js-ytx9ucgg.js +64 -0
- package/build/server/chunks/chunks/folder-path.js-ytx9ucgg.js.map +1 -0
- package/build/server/chunks/chunks/http.js-Dxoa-jtP.js +100 -0
- package/build/server/chunks/chunks/http.js-Dxoa-jtP.js.map +1 -0
- package/build/server/chunks/chunks/internal.js-BDBSzJId.js +5753 -0
- package/build/server/chunks/chunks/internal.js-BDBSzJId.js.map +1 -0
- package/build/server/chunks/chunks/internal2.js-BlXt2rfE.js +22 -0
- package/build/server/chunks/chunks/internal2.js-BlXt2rfE.js.map +1 -0
- package/{dist/operations-DYM-5KVl.js → build/server/chunks/chunks/library-store.js-BP8cL-qD.js} +344 -444
- package/build/server/chunks/chunks/library-store.js-BP8cL-qD.js.map +1 -0
- package/build/server/chunks/chunks/manifest-appearance.js-DTk355LQ.js +146 -0
- package/build/server/chunks/chunks/manifest-appearance.js-DTk355LQ.js.map +1 -0
- package/build/server/chunks/chunks/routing.js-y-tryuip.js +213 -0
- package/build/server/chunks/chunks/routing.js-y-tryuip.js.map +1 -0
- package/build/server/chunks/chunks/shared.js-BWXgl1Xf.js +255 -0
- package/build/server/chunks/chunks/shared.js-BWXgl1Xf.js.map +1 -0
- package/build/server/chunks/chunks/utils.js-9oI5Oz0w.js +1048 -0
- package/build/server/chunks/chunks/utils.js-9oI5Oz0w.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/_...path_/_server.ts.js-WknZVW_S.js +27 -0
- package/build/server/chunks/entries/endpoints/api/_...path_/_server.ts.js-WknZVW_S.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/assets/_id_/_server.ts.js-BrZ__-HZ.js +24 -0
- package/build/server/chunks/entries/endpoints/api/assets/_id_/_server.ts.js-BrZ__-HZ.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/assets/_server.ts.js-PqADGPXc.js +45 -0
- package/build/server/chunks/entries/endpoints/api/assets/_server.ts.js-PqADGPXc.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/assets/delete/_server.ts.js-OqoE5PN-.js +31 -0
- package/build/server/chunks/entries/endpoints/api/assets/delete/_server.ts.js-OqoE5PN-.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/assets/move/_server.ts.js-CJ08e1ho.js +31 -0
- package/build/server/chunks/entries/endpoints/api/assets/move/_server.ts.js-CJ08e1ho.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/folders/_path_/_server.ts.js-DdF3eK2I.js +38 -0
- package/build/server/chunks/entries/endpoints/api/folders/_path_/_server.ts.js-DdF3eK2I.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/folders/_server.ts.js-Cxt6jsJ5.js +31 -0
- package/build/server/chunks/entries/endpoints/api/folders/_server.ts.js-Cxt6jsJ5.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/manifests/_name_/_server.ts.js-BWVM2Ntl.js +24 -0
- package/build/server/chunks/entries/endpoints/api/manifests/_name_/_server.ts.js-BWVM2Ntl.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/manifests/_server.ts.js-Z2bM-qHM.js +31 -0
- package/build/server/chunks/entries/endpoints/api/manifests/_server.ts.js-Z2bM-qHM.js.map +1 -0
- package/build/server/chunks/entries/endpoints/api/state/_server.ts.js-BX9H2Z34.js +24 -0
- package/build/server/chunks/entries/endpoints/api/state/_server.ts.js-BX9H2Z34.js.map +1 -0
- package/build/server/chunks/entries/endpoints/files/_...path_/_server.ts.js-BWHDZ8mz.js +27 -0
- package/build/server/chunks/entries/endpoints/files/_...path_/_server.ts.js-BWHDZ8mz.js.map +1 -0
- package/build/server/chunks/entries/endpoints/files/proxy/_...path_/_server.ts.js-CR_7mndO.js +24 -0
- package/build/server/chunks/entries/endpoints/files/proxy/_...path_/_server.ts.js-CR_7mndO.js.map +1 -0
- package/build/server/chunks/entries/endpoints/files/raw/_...path_/_server.ts.js-Cw1PDBvb.js +24 -0
- package/build/server/chunks/entries/endpoints/files/raw/_...path_/_server.ts.js-Cw1PDBvb.js.map +1 -0
- package/build/server/chunks/entries/hooks.server.js-BHoE0yBi.js +23 -0
- package/build/server/chunks/entries/hooks.server.js-BHoE0yBi.js.map +1 -0
- package/build/server/chunks/handler-10cx4zHn.js +1475 -0
- package/build/server/chunks/handler-10cx4zHn.js.map +1 -0
- package/build/server/chunks/index.js-DvPfiC00.js +3789 -0
- package/build/server/chunks/index.js-DvPfiC00.js.map +1 -0
- package/build/server/chunks/manifest.js-DoPjUnzD.js +149 -0
- package/build/server/chunks/manifest.js-DoPjUnzD.js.map +1 -0
- package/build/server/chunks/nodes/0.js-Di3qgAtW.js +11 -0
- package/build/server/chunks/nodes/0.js-Di3qgAtW.js.map +1 -0
- package/build/server/chunks/nodes/1.js-BlWSFIA8.js +7 -0
- package/build/server/chunks/nodes/1.js-BlWSFIA8.js.map +1 -0
- package/build/server/chunks/nodes/2.js-CO9nSPUN.js +7 -0
- package/build/server/chunks/nodes/2.js-CO9nSPUN.js.map +1 -0
- package/build/server/chunks/nodes/3.js-C2D6xpEO.js +7 -0
- package/build/server/chunks/nodes/3.js-C2D6xpEO.js.map +1 -0
- package/build/server/chunks/nodes/4.js-B3IuagJW.js +7 -0
- package/build/server/chunks/nodes/4.js-B3IuagJW.js.map +1 -0
- package/build/shims.js +33 -0
- package/build/shims.js.map +1 -0
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +109 -1332
- package/dist/config.d.ts +3 -2
- package/dist/config.js +2 -2
- package/dist/core/api-types.d.ts +141 -0
- package/dist/core/api-types.js +1 -0
- package/dist/core/asset-id.d.ts +28 -0
- package/dist/core/asset-id.js +59 -0
- package/dist/core/asset-reference.d.ts +23 -0
- package/dist/core/asset-reference.js +15 -0
- package/dist/core/canonicalize.d.ts +9 -0
- package/dist/core/canonicalize.js +36 -0
- package/dist/core/chroma-key.d.ts +30 -0
- package/dist/core/chroma-key.js +55 -0
- package/dist/core/config.d.ts +35 -0
- package/dist/core/config.js +4 -0
- package/dist/core/folder-path.d.ts +19 -0
- package/dist/core/folder-path.js +86 -0
- package/dist/core/index.d.ts +33 -499
- package/dist/core/index.js +17 -962
- package/dist/core/ingest.d.ts +18 -0
- package/dist/core/ingest.js +58 -0
- package/dist/core/library.d.ts +54 -0
- package/dist/core/library.js +138 -0
- package/dist/core/manifest-appearance.d.ts +35 -0
- package/dist/core/manifest-appearance.js +123 -0
- package/dist/core/manifest-entry.d.ts +104 -0
- package/dist/core/manifest-entry.js +1 -0
- package/dist/core/manifest-membership.d.ts +56 -0
- package/dist/core/manifest-membership.js +54 -0
- package/dist/core/plugins/audio.d.ts +26 -0
- package/dist/core/plugins/audio.js +44 -0
- package/dist/core/plugins/chroma-key-video.d.ts +29 -0
- package/dist/core/plugins/chroma-key-video.js +69 -0
- package/dist/core/plugins/contract.d.ts +35 -0
- package/dist/core/plugins/contract.js +1 -0
- package/dist/core/plugins/image.d.ts +30 -0
- package/dist/core/plugins/image.js +45 -0
- package/dist/core/plugins/slice.d.ts +22 -0
- package/dist/core/plugins/slice.js +60 -0
- package/dist/core/plugins/video.d.ts +45 -0
- package/dist/core/plugins/video.js +77 -0
- package/dist/core/reference-graph.d.ts +41 -0
- package/dist/core/reference-graph.js +138 -0
- package/dist/core/slice-data.d.ts +61 -0
- package/dist/core/slice-data.js +49 -0
- package/dist/runtime/chroma-key-gl.d.ts +40 -22
- package/dist/runtime/chroma-key-gl.js +189 -183
- package/dist/runtime/components/ChromaKeyVideo.svelte +3 -3
- package/dist/runtime/components/ChromaKeyVideo.svelte.d.ts +21 -0
- package/dist/runtime/components/Image.svelte +1 -1
- package/dist/runtime/components/Image.svelte.d.ts +9 -0
- package/dist/runtime/components/Slice.svelte +1 -1
- package/dist/runtime/components/Slice.svelte.d.ts +19 -0
- package/dist/runtime/components/SliceCanvas.svelte +3 -3
- package/dist/runtime/components/SliceCanvas.svelte.d.ts +10 -0
- package/dist/runtime/components/SliceDom.svelte +3 -3
- package/dist/runtime/components/SliceDom.svelte.d.ts +10 -0
- package/dist/runtime/components/Video.svelte +2 -2
- package/dist/runtime/components/Video.svelte.d.ts +18 -0
- package/dist/runtime/geometry.d.ts +55 -35
- package/dist/runtime/geometry.js +186 -191
- package/dist/runtime/index.d.ts +9 -9
- package/dist/runtime/index.js +9 -9
- package/dist/runtime/kind-handlers.d.ts +33 -24
- package/dist/runtime/kind-handlers.js +74 -65
- package/dist/runtime/manifest.d.ts +53 -47
- package/dist/runtime/manifest.js +133 -113
- package/dist/runtime/observe-border-box-size.d.ts +1 -4
- package/dist/runtime/observe-border-box-size.js +9 -10
- package/dist/runtime/preload-registry.d.ts +22 -8
- package/dist/runtime/preload-registry.js +65 -62
- package/dist/server/build.d.ts +8 -0
- package/dist/server/build.js +25 -0
- package/dist/server/check.d.ts +24 -0
- package/dist/server/check.js +199 -0
- package/dist/server/cli-commands.d.ts +25 -0
- package/dist/server/cli-commands.js +1178 -0
- package/dist/server/cli-init.d.ts +3 -0
- package/dist/server/cli-init.js +53 -0
- package/dist/server/cli-io.d.ts +46 -0
- package/dist/server/cli-io.js +105 -0
- package/dist/server/codegen.d.ts +58 -0
- package/dist/server/codegen.js +185 -0
- package/dist/server/config-loader.d.ts +34 -0
- package/dist/server/config-loader.js +103 -0
- package/dist/server/context.d.ts +8 -0
- package/dist/server/context.js +19 -0
- package/dist/server/folder-filesystem.d.ts +7 -0
- package/dist/server/folder-filesystem.js +39 -0
- package/dist/server/http.d.ts +12 -0
- package/dist/server/http.js +100 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.js +9 -0
- package/dist/server/job-hash.d.ts +10 -0
- package/dist/server/job-hash.js +23 -0
- package/dist/server/library-store.d.ts +82 -0
- package/dist/server/library-store.js +763 -0
- package/dist/server/operations.d.ts +87 -0
- package/dist/server/operations.js +427 -0
- package/dist/server/plugins/audio.d.ts +7 -0
- package/dist/server/plugins/audio.js +27 -0
- package/dist/server/plugins/chroma-key-video.d.ts +9 -0
- package/dist/server/plugins/chroma-key-video.js +38 -0
- package/dist/server/plugins/contract.d.ts +100 -0
- package/dist/server/plugins/contract.js +16 -0
- package/dist/server/plugins/image.d.ts +8 -0
- package/dist/server/plugins/image.js +30 -0
- package/dist/server/plugins/slice.d.ts +14 -0
- package/dist/server/plugins/slice.js +63 -0
- package/dist/server/plugins/video.d.ts +6 -0
- package/dist/server/plugins/video.js +29 -0
- package/dist/server/plugins.d.ts +23 -0
- package/dist/server/plugins.js +33 -0
- package/dist/server/processing/audio-processing.d.ts +17 -0
- package/dist/server/processing/audio-processing.js +46 -0
- package/dist/server/processing/ffmpeg.d.ts +9 -0
- package/dist/server/processing/ffmpeg.js +50 -0
- package/dist/server/processing/image-processing.d.ts +16 -0
- package/dist/server/processing/image-processing.js +26 -0
- package/dist/server/processing/media-probe.d.ts +15 -0
- package/dist/server/processing/media-probe.js +27 -0
- package/dist/server/processing/processor.d.ts +50 -0
- package/dist/server/processing/processor.js +158 -0
- package/dist/server/processing/video-processing.d.ts +35 -0
- package/dist/server/processing/video-processing.js +87 -0
- package/dist/server/server.d.ts +13 -0
- package/dist/server/server.js +57 -0
- package/dist/server/start.d.ts +1 -0
- package/dist/server/start.js +33 -0
- package/package.json +29 -16
- package/dist/build-CZYFLLvl.js +0 -191
- package/dist/core/image-Dqmz8FXS.js +0 -54
- package/dist/core/reference-graph-CjuHbLDw.d.ts +0 -280
- package/dist/core/testing.d.ts +0 -27
- package/dist/core/testing.js +0 -80
- package/dist/editor/200.html +0 -37
- package/dist/editor/_app/immutable/assets/2.DIbbW7U1.css +0 -1
- package/dist/editor/_app/immutable/assets/3.C-9vFQ9A.css +0 -1
- package/dist/editor/_app/immutable/assets/4.BS8ElpOV.css +0 -1
- package/dist/editor/_app/immutable/assets/ConfirmDialog.CHEISE-L.css +0 -1
- package/dist/editor/_app/immutable/assets/LibraryContextMenu.CDjCmdV-.css +0 -1
- package/dist/editor/_app/immutable/chunks/Cx6qtxJg.js +0 -1
- package/dist/editor/_app/immutable/chunks/n7mvYc42.js +0 -5
- package/dist/editor/_app/immutable/entry/start.C8HHOLly.js +0 -1
- package/dist/editor/_app/immutable/nodes/3.WO7tZH_d.js +0 -104
- package/dist/editor/_app/immutable/nodes/4.DQtx17aW.js +0 -2
- package/dist/editor/_app/version.json +0 -1
- package/dist/index.d.ts +0 -370
- package/dist/index.js +0 -4
- package/dist/start-Bhnqt9Dc.js +0 -279
- package/dist/start-D2IXOrni.js +0 -2
- /package/{dist/editor → build/client}/_app/immutable/assets/0.DLhIsYA_.css +0 -0
- /package/{dist/editor → build/client}/_app/immutable/chunks/Bjy-W4x2.js +0 -0
- /package/{dist/editor → build/client}/_app/immutable/chunks/CNRz3sSw.js +0 -0
- /package/{dist/editor → build/client}/_app/immutable/chunks/CO4RBJfa.js +0 -0
- /package/{dist/editor → build/client}/_app/immutable/chunks/DjdrdRzT.js +0 -0
- /package/{dist/editor → build/client}/_app/immutable/chunks/xihTtKlq.js +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The processing pipeline: every delivered asset gets exactly one
|
|
3
|
+
* proxy named `<assetId>.<jobHash>.<extension>`. Delivered = explicit or
|
|
4
|
+
* passive member of ≥ 1 manifest (codegen inlines referenced
|
|
5
|
+
* entries, so a passive member's proxy must exist even when the asset is in
|
|
6
|
+
* no manifest itself). Because the name is computable without running the job,
|
|
7
|
+
* staleness is a name check: expected name exists → up to date, else →
|
|
8
|
+
* process. Afterwards, files in the proxy directory that no asset expects are
|
|
9
|
+
* pruned.
|
|
10
|
+
*
|
|
11
|
+
* Type-agnostic: every per-type decision (preset resolution, extension, the
|
|
12
|
+
* sharp/ffmpeg step, proxy probing) lives on the server plugins; this module
|
|
13
|
+
* only consults the registry — which it takes as a parameter, so tests can
|
|
14
|
+
* drive the pipeline with fixture asset types.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync } from 'node:fs';
|
|
17
|
+
import { mkdir, rename, stat, unlink } from 'node:fs/promises';
|
|
18
|
+
import { basename, dirname, extname, join } from 'node:path';
|
|
19
|
+
import { allDeliveredAssetIds, collectAllReferences, computeLibraryMembership, folderOfRawPath, rawFileNameOfPath } from '../../core/index.js';
|
|
20
|
+
import { jobHash } from '../job-hash.js';
|
|
21
|
+
import { descriptorsByType, processingParametersOf, serverPluginForType, serverPluginsByType } from '../plugins.js';
|
|
22
|
+
import { ensureManagedFolder, listRelativeFiles } from '../folder-filesystem.js';
|
|
23
|
+
/** Proxy file name shape; its id segment is pinned to core's asset-id grammar. */
|
|
24
|
+
const PROXY_FILE_PATTERN = /^[a-z][A-Za-z0-9]*\.[0-9a-f]{8}\.[a-z0-9]+$/;
|
|
25
|
+
/** Whether a file name in the proxy directory is (shaped like) a fundus proxy. */
|
|
26
|
+
export function isProxyFileName(fileName) {
|
|
27
|
+
return PROXY_FILE_PATTERN.test(fileName);
|
|
28
|
+
}
|
|
29
|
+
/** Whether a shaped proxy file belongs to one specific asset id. */
|
|
30
|
+
export function isProxyFileNameFor(assetId, fileName) {
|
|
31
|
+
return isProxyFileName(fileName) && fileName.startsWith(`${assetId}.`);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The proxy file name an asset's current raw content + parameters demand.
|
|
35
|
+
* Throws when the parameters are invalid or reference an unknown preset.
|
|
36
|
+
*
|
|
37
|
+
* The hash input is the *effective* processing input: the asset's
|
|
38
|
+
* processing-relevant parameters (the plugin-declared subset — entry-only data
|
|
39
|
+
* like chroma-key tuning and references must not rename the proxy)
|
|
40
|
+
* plus the preset's **resolved settings** — parameters only carry the preset
|
|
41
|
+
* *name*, so hashing them alone would keep serving stale proxy bytes after a
|
|
42
|
+
* preset's quality/format is edited in the host config.
|
|
43
|
+
*/
|
|
44
|
+
export function expectedProxyFileName(assetId, record, config, registry = serverPluginsByType) {
|
|
45
|
+
const plugin = serverPluginForType(record.type, registry);
|
|
46
|
+
const parameters = plugin.descriptor.validateParameters(record.parameters);
|
|
47
|
+
const preset = plugin.resolvePreset(parameters, config);
|
|
48
|
+
const hash = jobHash(record.rawHash, {
|
|
49
|
+
parameters: processingParametersOf(plugin.descriptor, parameters),
|
|
50
|
+
presetSettings: preset
|
|
51
|
+
});
|
|
52
|
+
return `${assetId}.${hash}.${plugin.proxyExtension(preset)}`;
|
|
53
|
+
}
|
|
54
|
+
/** Expected proxy path relative to proxyDir, mirroring the raw asset folder. */
|
|
55
|
+
export function expectedProxyRelativePath(assetId, record, config, registry = serverPluginsByType) {
|
|
56
|
+
const fileName = expectedProxyFileName(assetId, record, config, registry);
|
|
57
|
+
const folder = folderOfRawPath(record.raw);
|
|
58
|
+
return folder === '' ? fileName : `${folder}/${fileName}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Output metadata of an existing proxy file, probed per the owning plugin's
|
|
62
|
+
* strategy: image-backed proxies via sharp, media proxies via ffprobe.
|
|
63
|
+
*/
|
|
64
|
+
export async function readProxyOutputInfo(type, proxyPath, config, registry = serverPluginsByType) {
|
|
65
|
+
return serverPluginForType(type, registry).readProxyInfo(proxyPath, config);
|
|
66
|
+
}
|
|
67
|
+
/** Read one asset's current proxy projection, or null when its expected file is absent. */
|
|
68
|
+
export async function readCurrentProxy(assetId, record, config, registry = serverPluginsByType) {
|
|
69
|
+
const fileName = expectedProxyFileName(assetId, record, config, registry);
|
|
70
|
+
const relativePath = expectedProxyRelativePath(assetId, record, config, registry);
|
|
71
|
+
const proxyPath = join(config.proxyDir, relativePath);
|
|
72
|
+
if (!existsSync(proxyPath))
|
|
73
|
+
return null;
|
|
74
|
+
const [outputInfo, proxyStat] = await Promise.all([
|
|
75
|
+
readProxyOutputInfo(record.type, proxyPath, config, registry),
|
|
76
|
+
stat(proxyPath)
|
|
77
|
+
]);
|
|
78
|
+
return { assetId, fileName, relativePath, ...outputInfo, fileSize: proxyStat.size };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The delivered set: every explicit or passive member of ≥ 1 manifest —
|
|
82
|
+
* derived by the shared membership computation. Assets outside
|
|
83
|
+
* it are inert.
|
|
84
|
+
*/
|
|
85
|
+
export function deliveredAssetIds(library, registry = serverPluginsByType) {
|
|
86
|
+
return allDeliveredAssetIds(computeLibraryMembership(library, collectAllReferences(library, descriptorsByType(registry))));
|
|
87
|
+
}
|
|
88
|
+
/** Run the owning plugin's processing job for one stale/missing proxy. */
|
|
89
|
+
async function processAssetFile(record, rawPath, proxyPath, config, registry) {
|
|
90
|
+
const plugin = serverPluginForType(record.type, registry);
|
|
91
|
+
const parameters = plugin.descriptor.validateParameters(record.parameters);
|
|
92
|
+
const extension = extname(proxyPath);
|
|
93
|
+
const stem = basename(proxyPath, extension);
|
|
94
|
+
const temporaryPath = join(dirname(proxyPath), `.${stem}.${crypto.randomUUID()}.tmp${extension}`);
|
|
95
|
+
try {
|
|
96
|
+
const output = await plugin.process({
|
|
97
|
+
sourcePath: rawPath,
|
|
98
|
+
targetPath: temporaryPath,
|
|
99
|
+
parameters,
|
|
100
|
+
preset: plugin.resolvePreset(parameters, config),
|
|
101
|
+
config
|
|
102
|
+
});
|
|
103
|
+
await rename(temporaryPath, proxyPath);
|
|
104
|
+
return output;
|
|
105
|
+
}
|
|
106
|
+
catch (cause) {
|
|
107
|
+
await unlink(temporaryPath).catch(() => { });
|
|
108
|
+
throw cause;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Ensure every delivered asset's proxy exists (processing stale/missing ones)
|
|
113
|
+
* and prune orphans. Assets outside the delivered set are skipped entirely.
|
|
114
|
+
*/
|
|
115
|
+
export async function processAssets(config, library, registry = serverPluginsByType) {
|
|
116
|
+
const report = { processed: [], reused: [], pruned: [], proxies: {} };
|
|
117
|
+
await mkdir(config.proxyDir, { recursive: true });
|
|
118
|
+
await Promise.all(library.folders.map((folder) => ensureManagedFolder(config.proxyDir, folder)));
|
|
119
|
+
const delivered = deliveredAssetIds(library, registry);
|
|
120
|
+
const expectedRelativePaths = new Set();
|
|
121
|
+
for (const [assetId, record] of Object.entries(library.assets)) {
|
|
122
|
+
if (!delivered.has(assetId))
|
|
123
|
+
continue;
|
|
124
|
+
const fileName = expectedProxyFileName(assetId, record, config, registry);
|
|
125
|
+
const relativePath = expectedProxyRelativePath(assetId, record, config, registry);
|
|
126
|
+
expectedRelativePaths.add(relativePath);
|
|
127
|
+
const proxyPath = join(config.proxyDir, relativePath);
|
|
128
|
+
const rawPath = join(config.rawDir, record.raw);
|
|
129
|
+
await mkdir(dirname(proxyPath), { recursive: true });
|
|
130
|
+
let proxy = await readCurrentProxy(assetId, record, config, registry);
|
|
131
|
+
if (proxy) {
|
|
132
|
+
report.reused.push(assetId);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
if (!existsSync(rawPath)) {
|
|
136
|
+
throw new Error(`Cannot process "${assetId}": raw file "${record.raw}" is missing.`);
|
|
137
|
+
}
|
|
138
|
+
const outputInfo = await processAssetFile(record, rawPath, proxyPath, config, registry);
|
|
139
|
+
report.processed.push(assetId);
|
|
140
|
+
const proxyStat = await stat(proxyPath);
|
|
141
|
+
proxy = { assetId, fileName, relativePath, ...outputInfo, fileSize: proxyStat.size };
|
|
142
|
+
}
|
|
143
|
+
report.proxies[assetId] = proxy;
|
|
144
|
+
}
|
|
145
|
+
// Prune orphans: only files matching the proxy naming pattern are touched,
|
|
146
|
+
// so a stray non-fundus file in the directory is left alone.
|
|
147
|
+
for (const relativePath of await listRelativeFiles(config.proxyDir)) {
|
|
148
|
+
const fileName = rawFileNameOfPath(relativePath);
|
|
149
|
+
if (!isProxyFileName(fileName))
|
|
150
|
+
continue;
|
|
151
|
+
if (expectedRelativePaths.has(relativePath))
|
|
152
|
+
continue;
|
|
153
|
+
await unlink(join(config.proxyDir, relativePath));
|
|
154
|
+
report.pruned.push(relativePath);
|
|
155
|
+
}
|
|
156
|
+
report.pruned.sort();
|
|
157
|
+
return report;
|
|
158
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { VideoPreset } from '../../core/index.js';
|
|
2
|
+
import type { ResolvedFundusConfig } from '../config-loader.js';
|
|
3
|
+
/**
|
|
4
|
+
* The delivered width the scale filter must produce, or null when no filter is
|
|
5
|
+
* needed. `maxWidth` is a downscale-only cap; yuv420p demands even dimensions,
|
|
6
|
+
* so an odd (capped or source) width rounds down and an odd source height
|
|
7
|
+
* forces a filter even without a cap (the `-2` idiom rounds it).
|
|
8
|
+
*/
|
|
9
|
+
export declare function videoScaleWidth(sourceWidth: number, sourceHeight: number, maxWidth?: number): number | null;
|
|
10
|
+
/**
|
|
11
|
+
* The full ffmpeg argument list for one video transcode (pure, testable
|
|
12
|
+
* without a binary). `-map_metadata -1` + bitexact flags keep the output
|
|
13
|
+
* byte-stable across runs (no embedded timestamps or encoder version tags);
|
|
14
|
+
* a source audio track is kept (re-encoded as AAC — a UI video may carry
|
|
15
|
+
* sound; nothing is stripped silently).
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildVideoTranscodeArguments(options: {
|
|
18
|
+
sourcePath: string;
|
|
19
|
+
targetPath: string;
|
|
20
|
+
preset: VideoPreset;
|
|
21
|
+
/** From `videoScaleWidth`; null = no scaling. */
|
|
22
|
+
scaleWidth: number | null;
|
|
23
|
+
}): string[];
|
|
24
|
+
export interface VideoProcessingOutput {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
durationMs: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function processVideoFile(options: {
|
|
30
|
+
sourcePath: string;
|
|
31
|
+
targetPath: string;
|
|
32
|
+
preset: VideoPreset;
|
|
33
|
+
maxWidth?: number;
|
|
34
|
+
config: ResolvedFundusConfig;
|
|
35
|
+
}): Promise<VideoProcessingOutput>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ffmpeg transcode step shared by the video and chroma-key-video plugins
|
|
3
|
+
* (chroma-key-video builds on video's processing; its keying data is
|
|
4
|
+
* entry-only and never reaches ffmpeg). Deterministic output: all
|
|
5
|
+
* metadata is stripped and bitexact muxing is forced, so re-running a job
|
|
6
|
+
* yields byte-identical proxy files.
|
|
7
|
+
*/
|
|
8
|
+
import { mkdir } from 'node:fs/promises';
|
|
9
|
+
import { dirname } from 'node:path';
|
|
10
|
+
import { ffmpegBinaryPath, runToolchainBinary } from './ffmpeg.js';
|
|
11
|
+
import { probeMedia } from './media-probe.js';
|
|
12
|
+
/**
|
|
13
|
+
* The delivered width the scale filter must produce, or null when no filter is
|
|
14
|
+
* needed. `maxWidth` is a downscale-only cap; yuv420p demands even dimensions,
|
|
15
|
+
* so an odd (capped or source) width rounds down and an odd source height
|
|
16
|
+
* forces a filter even without a cap (the `-2` idiom rounds it).
|
|
17
|
+
*/
|
|
18
|
+
export function videoScaleWidth(sourceWidth, sourceHeight, maxWidth) {
|
|
19
|
+
const cappedWidth = maxWidth !== undefined ? Math.min(maxWidth, sourceWidth) : sourceWidth;
|
|
20
|
+
const evenWidth = Math.max(2, cappedWidth - (cappedWidth % 2));
|
|
21
|
+
if (evenWidth === sourceWidth && sourceHeight % 2 === 0)
|
|
22
|
+
return null;
|
|
23
|
+
return evenWidth;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The full ffmpeg argument list for one video transcode (pure, testable
|
|
27
|
+
* without a binary). `-map_metadata -1` + bitexact flags keep the output
|
|
28
|
+
* byte-stable across runs (no embedded timestamps or encoder version tags);
|
|
29
|
+
* a source audio track is kept (re-encoded as AAC — a UI video may carry
|
|
30
|
+
* sound; nothing is stripped silently).
|
|
31
|
+
*/
|
|
32
|
+
export function buildVideoTranscodeArguments(options) {
|
|
33
|
+
const { sourcePath, targetPath, preset, scaleWidth } = options;
|
|
34
|
+
return [
|
|
35
|
+
'-hide_banner',
|
|
36
|
+
'-loglevel',
|
|
37
|
+
'error',
|
|
38
|
+
'-y',
|
|
39
|
+
'-i',
|
|
40
|
+
sourcePath,
|
|
41
|
+
...(scaleWidth !== null ? ['-vf', `scale=${scaleWidth}:-2`] : []),
|
|
42
|
+
'-c:v',
|
|
43
|
+
'libx264',
|
|
44
|
+
'-preset',
|
|
45
|
+
preset.encoderPreset,
|
|
46
|
+
...(preset.tune !== undefined ? ['-tune', preset.tune] : []),
|
|
47
|
+
'-crf',
|
|
48
|
+
String(preset.crf),
|
|
49
|
+
'-pix_fmt',
|
|
50
|
+
preset.pixelFormat,
|
|
51
|
+
'-c:a',
|
|
52
|
+
'aac',
|
|
53
|
+
'-b:a',
|
|
54
|
+
'128k',
|
|
55
|
+
'-map_metadata',
|
|
56
|
+
'-1',
|
|
57
|
+
'-fflags',
|
|
58
|
+
'+bitexact',
|
|
59
|
+
'-flags:v',
|
|
60
|
+
'+bitexact',
|
|
61
|
+
'-flags:a',
|
|
62
|
+
'+bitexact',
|
|
63
|
+
'-movflags',
|
|
64
|
+
'+faststart',
|
|
65
|
+
targetPath
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
export async function processVideoFile(options) {
|
|
69
|
+
await mkdir(dirname(options.targetPath), { recursive: true });
|
|
70
|
+
const source = await probeMedia(options.sourcePath, options.config);
|
|
71
|
+
if (source.width === undefined || source.height === undefined) {
|
|
72
|
+
throw new Error(`${options.sourcePath} has no video stream.`);
|
|
73
|
+
}
|
|
74
|
+
const scaleWidth = videoScaleWidth(source.width, source.height, options.maxWidth);
|
|
75
|
+
await runToolchainBinary(ffmpegBinaryPath(options.config), buildVideoTranscodeArguments({
|
|
76
|
+
sourcePath: options.sourcePath,
|
|
77
|
+
targetPath: options.targetPath,
|
|
78
|
+
preset: options.preset,
|
|
79
|
+
scaleWidth
|
|
80
|
+
}));
|
|
81
|
+
// Probe the output — the delivered dimensions/duration are what the entry carries.
|
|
82
|
+
const output = await probeMedia(options.targetPath, options.config);
|
|
83
|
+
if (output.width === undefined || output.height === undefined) {
|
|
84
|
+
throw new Error(`Transcoding ${options.sourcePath} produced no video stream.`);
|
|
85
|
+
}
|
|
86
|
+
return { width: output.width, height: output.height, durationMs: output.durationMs };
|
|
87
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
2
|
+
export { parseByteRange } from './http.js';
|
|
3
|
+
export type FundusHandler = (request: IncomingMessage, response: ServerResponse, next: (error?: unknown) => void) => void;
|
|
4
|
+
export interface FundusServerOptions {
|
|
5
|
+
handler: FundusHandler;
|
|
6
|
+
port: number;
|
|
7
|
+
forceCloseAfterMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface FundusServer {
|
|
10
|
+
port: number;
|
|
11
|
+
stop(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare function startServer(options: FundusServerOptions): Promise<FundusServer>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
export { parseByteRange } from './http.js';
|
|
3
|
+
export async function startServer(options) {
|
|
4
|
+
const server = createServer((request, response) => {
|
|
5
|
+
// adapter-node otherwise assumes HTTPS when a custom server does not
|
|
6
|
+
// provide protocol metadata, which makes same-origin multipart uploads
|
|
7
|
+
// fail SvelteKit's CSRF check on this intentionally HTTP-only local server.
|
|
8
|
+
request.headers['x-fundus-proto'] = 'http';
|
|
9
|
+
options.handler(request, response, (cause) => {
|
|
10
|
+
if (response.writableEnded)
|
|
11
|
+
return;
|
|
12
|
+
response.statusCode = 500;
|
|
13
|
+
response.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
14
|
+
response.end(JSON.stringify({
|
|
15
|
+
error: {
|
|
16
|
+
message: cause instanceof Error ? cause.message : 'Fundus handler declined the request.'
|
|
17
|
+
}
|
|
18
|
+
}));
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
await new Promise((resolve, reject) => {
|
|
22
|
+
const onError = (cause) => {
|
|
23
|
+
server.off('listening', onListening);
|
|
24
|
+
reject(cause);
|
|
25
|
+
};
|
|
26
|
+
const onListening = () => {
|
|
27
|
+
server.off('error', onError);
|
|
28
|
+
resolve();
|
|
29
|
+
};
|
|
30
|
+
server.once('error', onError);
|
|
31
|
+
server.once('listening', onListening);
|
|
32
|
+
server.listen(options.port, '127.0.0.1');
|
|
33
|
+
});
|
|
34
|
+
const address = server.address();
|
|
35
|
+
if (!address || typeof address === 'string') {
|
|
36
|
+
throw new Error('Fundus server did not expose a TCP listening address.');
|
|
37
|
+
}
|
|
38
|
+
let stopping;
|
|
39
|
+
return {
|
|
40
|
+
port: address.port,
|
|
41
|
+
stop() {
|
|
42
|
+
stopping ??= new Promise((resolve, reject) => {
|
|
43
|
+
const timeout = setTimeout(() => server.closeAllConnections(), options.forceCloseAfterMs ?? 1000);
|
|
44
|
+
timeout.unref();
|
|
45
|
+
server.closeIdleConnections();
|
|
46
|
+
server.close((cause) => {
|
|
47
|
+
clearTimeout(timeout);
|
|
48
|
+
if (cause)
|
|
49
|
+
reject(cause);
|
|
50
|
+
else
|
|
51
|
+
resolve();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return stopping;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runStart(projectRoot: string): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Start the packaged SvelteKit Node editor and API for one host project. */
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { startServer } from './server.js';
|
|
6
|
+
export async function runStart(projectRoot) {
|
|
7
|
+
process.env.FUNDUS_PROJECT_ROOT = resolve(projectRoot);
|
|
8
|
+
process.env.FUNDUS_BODY_SIZE_LIMIT ??= 'Infinity';
|
|
9
|
+
process.env.FUNDUS_ADAPTER_BODY_SIZE_LIMIT = process.env.FUNDUS_BODY_SIZE_LIMIT;
|
|
10
|
+
process.env.FUNDUS_ADAPTER_PROTOCOL_HEADER = 'x-fundus-proto';
|
|
11
|
+
const handlerUrl = new URL('../../build/handler.js', import.meta.url);
|
|
12
|
+
if (!existsSync(handlerUrl)) {
|
|
13
|
+
throw new Error(`The packaged Fundus SvelteKit handler is missing from ${fileURLToPath(handlerUrl)}. Reinstall the fundus package or report a packaging error.`);
|
|
14
|
+
}
|
|
15
|
+
const module = (await import(handlerUrl.href));
|
|
16
|
+
if (typeof module.handler !== 'function') {
|
|
17
|
+
throw new Error(`The packaged Fundus handler at ${fileURLToPath(handlerUrl)} is invalid.`);
|
|
18
|
+
}
|
|
19
|
+
const configuredPort = Number(process.env.FUNDUS_API_PORT ?? 5176);
|
|
20
|
+
const server = await startServer({ handler: module.handler, port: configuredPort });
|
|
21
|
+
console.log(`fundus editor: http://127.0.0.1:${server.port} (project: ${process.env.FUNDUS_PROJECT_ROOT})`);
|
|
22
|
+
let signalStop;
|
|
23
|
+
const stopForSignal = () => {
|
|
24
|
+
signalStop ??= server.stop().then(() => {
|
|
25
|
+
process.exitCode = 0;
|
|
26
|
+
}, (cause) => {
|
|
27
|
+
console.error(cause);
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
process.once('SIGINT', stopForSignal);
|
|
32
|
+
process.once('SIGTERM', stopForSignal);
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fundus",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/grischaerbe/fundus.git"
|
|
8
8
|
},
|
|
9
|
-
"imports": {
|
|
10
|
-
"#fundus/core": {
|
|
11
|
-
"types": "./dist/core/index.d.ts",
|
|
12
|
-
"default": "./dist/core/index.js"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
9
|
"bin": {
|
|
16
10
|
"fundus": "./dist/cli.js"
|
|
17
11
|
},
|
|
@@ -23,8 +17,8 @@
|
|
|
23
17
|
"default": "./dist/runtime/index.js"
|
|
24
18
|
},
|
|
25
19
|
"./server": {
|
|
26
|
-
"types": "./dist/index.d.ts",
|
|
27
|
-
"default": "./dist/index.js"
|
|
20
|
+
"types": "./dist/server/index.d.ts",
|
|
21
|
+
"default": "./dist/server/index.js"
|
|
28
22
|
},
|
|
29
23
|
"./config": {
|
|
30
24
|
"types": "./dist/config.d.ts",
|
|
@@ -32,18 +26,26 @@
|
|
|
32
26
|
}
|
|
33
27
|
},
|
|
34
28
|
"files": [
|
|
35
|
-
"dist"
|
|
29
|
+
"dist",
|
|
30
|
+
"build"
|
|
36
31
|
],
|
|
37
32
|
"engines": {
|
|
38
33
|
"node": ">=20.19.0"
|
|
39
34
|
},
|
|
40
35
|
"scripts": {
|
|
41
|
-
"
|
|
42
|
-
"
|
|
36
|
+
"dev": "vite dev",
|
|
37
|
+
"build:package": "svelte-package --input src/lib --output dist && node scripts/postbuild-package.mjs && publint",
|
|
38
|
+
"build:app": "vite build",
|
|
39
|
+
"build": "npm run build:package && npm run build:app",
|
|
43
40
|
"test": "npm run build && vitest run",
|
|
44
|
-
"
|
|
41
|
+
"smoke:pack": "node scripts/smoke-packed.mjs",
|
|
42
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && tsc --noEmit",
|
|
45
43
|
"lint": "prettier --check .",
|
|
46
|
-
"format": "prettier --write ."
|
|
44
|
+
"format": "prettier --write .",
|
|
45
|
+
"prepack": "npm run build",
|
|
46
|
+
"changeset": "changeset",
|
|
47
|
+
"version-packages": "changeset version",
|
|
48
|
+
"release": "changeset publish"
|
|
47
49
|
},
|
|
48
50
|
"dependencies": {
|
|
49
51
|
"ffmpeg-static": "^5.3.0",
|
|
@@ -55,11 +57,22 @@
|
|
|
55
57
|
"svelte": "^5.0.0"
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
60
|
+
"@changesets/changelog-github": "^0.7.0",
|
|
61
|
+
"@changesets/cli": "^2.31.0",
|
|
62
|
+
"@sveltejs/adapter-node": "^5.5.7",
|
|
63
|
+
"@sveltejs/kit": "^2.69.2",
|
|
64
|
+
"@sveltejs/package": "^2.5.8",
|
|
65
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
58
66
|
"@types/ffprobe-static": "^2.0.3",
|
|
59
|
-
"@types/node": "^24.
|
|
67
|
+
"@types/node": "^24.13.3",
|
|
68
|
+
"fuse.js": "^7.4.2",
|
|
69
|
+
"prettier": "^3.8.3",
|
|
70
|
+
"prettier-plugin-svelte": "^4.1.0",
|
|
71
|
+
"publint": "^0.3.21",
|
|
60
72
|
"svelte": "^5.56.1",
|
|
61
|
-
"
|
|
73
|
+
"svelte-check": "^4.6.0",
|
|
62
74
|
"typescript": "^6.0.3",
|
|
75
|
+
"vite": "^8.0.16",
|
|
63
76
|
"vitest": "^3.2.4"
|
|
64
77
|
}
|
|
65
78
|
}
|
package/dist/build-CZYFLLvl.js
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { _ as strayGeneratedModuleNames, a as deliveredAssetIds, c as isProxyFileName, f as listRelativeFiles, g as renderManifestModule, h as manifestModuleFileName, i as sha256Hex, l as processAssets, m as generateManifestModules, n as LibraryStore, p as buildManifestEntries, s as expectedProxyRelativePath, u as readCurrentProxy, v as descriptorsByType, w as loadConfig, x as serverPluginsByType } from "./operations-DYM-5KVl.js";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { collectAllReferences, compareCodeUnits, computeLibraryMembership, rawFileNameOfPath } from "#fundus/core";
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
//#region src/check.ts
|
|
7
|
-
/**
|
|
8
|
-
* `fundus check` — the verify-only CI gate: no writes, ever. It
|
|
9
|
-
* fails when the library does not validate, when a committed proxy is stale,
|
|
10
|
-
* missing, or orphaned, or when a generated manifest module differs from an
|
|
11
|
-
* in-memory regeneration. Warnings (unreachable asset, raw-hash drift) are
|
|
12
|
-
* treated as errors unless `--allow-warnings` downgrades them — errors are
|
|
13
|
-
* never downgradable.
|
|
14
|
-
*/
|
|
15
|
-
/** The human rendering of a finding — `[assetId] message`, as `fundus check` prints it. */
|
|
16
|
-
function formatCheckFinding(finding) {
|
|
17
|
-
return `${finding.assetId ? `[${finding.assetId}] ` : ""}${finding.message}`;
|
|
18
|
-
}
|
|
19
|
-
async function runCheck(projectRoot, registry = serverPluginsByType) {
|
|
20
|
-
const config = await loadConfig(projectRoot);
|
|
21
|
-
const store = new LibraryStore(config, registry);
|
|
22
|
-
const library = await store.read();
|
|
23
|
-
const report = {
|
|
24
|
-
errors: [],
|
|
25
|
-
warnings: [],
|
|
26
|
-
assetCount: Object.keys(library.assets).length,
|
|
27
|
-
manifestCount: Object.keys(library.manifests).length
|
|
28
|
-
};
|
|
29
|
-
const issues = await store.validate(library);
|
|
30
|
-
for (const issue of issues) report.errors.push({
|
|
31
|
-
kind: "validation",
|
|
32
|
-
message: issue.message,
|
|
33
|
-
...issue.assetId !== void 0 ? { assetId: issue.assetId } : {}
|
|
34
|
-
});
|
|
35
|
-
const delivered = deliveredAssetIds(library, registry);
|
|
36
|
-
const expectedProxyPaths = /* @__PURE__ */ new Set();
|
|
37
|
-
const proxies = {};
|
|
38
|
-
let proxiesComplete = true;
|
|
39
|
-
for (const assetId of [...delivered].sort(compareCodeUnits)) {
|
|
40
|
-
const record = library.assets[assetId];
|
|
41
|
-
let proxy;
|
|
42
|
-
try {
|
|
43
|
-
proxy = await readCurrentProxy(assetId, record, config, registry);
|
|
44
|
-
} catch (cause) {
|
|
45
|
-
if (!issues.some((issue) => issue.assetId === assetId)) report.errors.push({
|
|
46
|
-
kind: "proxy-unresolvable",
|
|
47
|
-
message: cause instanceof Error ? cause.message : String(cause),
|
|
48
|
-
assetId
|
|
49
|
-
});
|
|
50
|
-
proxiesComplete = false;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
if (!proxy) {
|
|
54
|
-
const relativePath = expectedProxyRelativePath(assetId, record, config, registry);
|
|
55
|
-
expectedProxyPaths.add(relativePath);
|
|
56
|
-
report.errors.push({
|
|
57
|
-
kind: "proxy-missing",
|
|
58
|
-
message: `Proxy "${relativePath}" is missing or stale — run \`fundus build\` and commit the result.`,
|
|
59
|
-
assetId,
|
|
60
|
-
fileName: relativePath
|
|
61
|
-
});
|
|
62
|
-
proxiesComplete = false;
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
expectedProxyPaths.add(proxy.relativePath);
|
|
66
|
-
proxies[assetId] = proxy;
|
|
67
|
-
}
|
|
68
|
-
if (existsSync(config.proxyDir)) for (const relativePath of (await listRelativeFiles(config.proxyDir)).sort()) {
|
|
69
|
-
if (!isProxyFileName(rawFileNameOfPath(relativePath)) || expectedProxyPaths.has(relativePath)) continue;
|
|
70
|
-
report.errors.push({
|
|
71
|
-
kind: "proxy-orphaned",
|
|
72
|
-
message: `Orphaned proxy "${relativePath}" — no asset expects it; run \`fundus build\` and commit the result.`,
|
|
73
|
-
fileName: relativePath
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
if (issues.length === 0 && proxiesComplete) {
|
|
77
|
-
await checkGeneratedModules(report, library, config, proxies, registry);
|
|
78
|
-
await checkStrayModules(report, library, config);
|
|
79
|
-
}
|
|
80
|
-
collectUnreachableAssets(report, library, delivered);
|
|
81
|
-
await collectRawHashDrift(report, library, config);
|
|
82
|
-
return report;
|
|
83
|
-
}
|
|
84
|
-
async function checkGeneratedModules(report, library, config, proxies, registry) {
|
|
85
|
-
const referencesByAsset = collectAllReferences(library, descriptorsByType(registry));
|
|
86
|
-
const membershipByManifest = computeLibraryMembership(library, referencesByAsset);
|
|
87
|
-
for (const manifestName of Object.keys(library.manifests).sort(compareCodeUnits)) {
|
|
88
|
-
const fileName = manifestModuleFileName(manifestName);
|
|
89
|
-
const modulePath = join(config.manifestsDir, fileName);
|
|
90
|
-
let expectedContent;
|
|
91
|
-
try {
|
|
92
|
-
expectedContent = renderManifestModule(manifestName, buildManifestEntries({
|
|
93
|
-
membership: membershipByManifest[manifestName],
|
|
94
|
-
library,
|
|
95
|
-
proxies,
|
|
96
|
-
config,
|
|
97
|
-
referencesByAsset,
|
|
98
|
-
registry
|
|
99
|
-
}));
|
|
100
|
-
} catch (cause) {
|
|
101
|
-
report.errors.push({
|
|
102
|
-
kind: "module-regeneration-failed",
|
|
103
|
-
message: `Cannot regenerate module "${fileName}": ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
104
|
-
manifest: manifestName,
|
|
105
|
-
fileName
|
|
106
|
-
});
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
if (!existsSync(modulePath)) {
|
|
110
|
-
report.errors.push({
|
|
111
|
-
kind: "module-missing",
|
|
112
|
-
message: `Generated module "${fileName}" is missing — run \`fundus build\` and commit the result.`,
|
|
113
|
-
manifest: manifestName,
|
|
114
|
-
fileName
|
|
115
|
-
});
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
if (await readFile(modulePath, "utf8") !== expectedContent) report.errors.push({
|
|
119
|
-
kind: "module-out-of-sync",
|
|
120
|
-
message: `Generated module "${fileName}" is out of sync with the library — run \`fundus build\` and commit the result.`,
|
|
121
|
-
manifest: manifestName,
|
|
122
|
-
fileName
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
async function checkStrayModules(report, library, config) {
|
|
127
|
-
const expectedFileNames = new Set(Object.keys(library.manifests).map((manifestName) => manifestModuleFileName(manifestName)));
|
|
128
|
-
for (const fileName of await strayGeneratedModuleNames(config.manifestsDir, expectedFileNames)) report.errors.push({
|
|
129
|
-
kind: "module-stray",
|
|
130
|
-
message: `Stray generated module "${fileName}" — its manifest no longer exists; run \`fundus build\`.`,
|
|
131
|
-
fileName
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* The unreachable-asset warning: fires only when nothing delivers the asset —
|
|
136
|
-
* no explicit membership AND no passive membership in any manifest. An asset
|
|
137
|
-
* that is only passively delivered (referenced by a delivered asset) is fine.
|
|
138
|
-
*/
|
|
139
|
-
function collectUnreachableAssets(report, library, delivered) {
|
|
140
|
-
for (const [assetId, record] of Object.entries(library.assets)) if (record.manifests.length === 0 && !delivered.has(assetId)) report.warnings.push({
|
|
141
|
-
kind: "unreachable-asset",
|
|
142
|
-
message: "In no manifest and not referenced by any delivered asset — nothing is processed or generated for it.",
|
|
143
|
-
assetId
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Raw-hash drift: a raw file replaced on disk while the library still pins the
|
|
148
|
-
* old content hash. The proxy name derives from the *recorded* hash, so the
|
|
149
|
-
* name check alone would keep passing while the delivered pixels are outdated.
|
|
150
|
-
*/
|
|
151
|
-
async function collectRawHashDrift(report, library, config) {
|
|
152
|
-
for (const [assetId, record] of Object.entries(library.assets)) {
|
|
153
|
-
const rawPath = join(config.rawDir, record.raw);
|
|
154
|
-
if (!existsSync(rawPath)) continue;
|
|
155
|
-
if (sha256Hex(new Uint8Array(await readFile(rawPath))) !== record.rawHash) report.warnings.push({
|
|
156
|
-
kind: "raw-hash-drift",
|
|
157
|
-
message: `Raw file "${record.raw}" changed since it was ingested (hash drift) — re-ingest or update it through the editor, then run \`fundus build\`.`,
|
|
158
|
-
assetId,
|
|
159
|
-
fileName: record.raw
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
//#endregion
|
|
164
|
-
//#region src/build.ts
|
|
165
|
-
/**
|
|
166
|
-
* `fundus build` — headless pipeline run: validate the library, process all
|
|
167
|
-
* stale/missing proxies, prune orphans, regenerate every manifest module.
|
|
168
|
-
* Throws on validation errors (the CLI exits non-zero).
|
|
169
|
-
*/
|
|
170
|
-
async function runBuild(projectRoot, registry = serverPluginsByType) {
|
|
171
|
-
const config = await loadConfig(projectRoot);
|
|
172
|
-
const store = new LibraryStore(config, registry);
|
|
173
|
-
const library = await store.read();
|
|
174
|
-
await store.syncFolders(library);
|
|
175
|
-
const issues = await store.validate(library);
|
|
176
|
-
if (issues.length > 0) {
|
|
177
|
-
const lines = issues.map((issue) => ` - ${formatCheckFinding({
|
|
178
|
-
kind: "validation",
|
|
179
|
-
assetId: issue.assetId,
|
|
180
|
-
message: issue.message
|
|
181
|
-
})}`);
|
|
182
|
-
throw new Error(`Library validation failed:\n${lines.join("\n")}`);
|
|
183
|
-
}
|
|
184
|
-
const processing = await processAssets(config, library, registry);
|
|
185
|
-
return {
|
|
186
|
-
processing,
|
|
187
|
-
codegen: await generateManifestModules(config, library, processing.proxies, registry)
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
//#endregion
|
|
191
|
-
export { formatCheckFinding as n, runCheck as r, runBuild as t };
|