fundus 0.17.2 → 0.19.0
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 +60 -121
- package/build/client/_app/immutable/assets/2.C-1MfvLQ.css +1 -0
- package/build/client/_app/immutable/assets/2.C-1MfvLQ.css.br +0 -0
- package/build/client/_app/immutable/assets/2.C-1MfvLQ.css.gz +0 -0
- package/build/client/_app/immutable/assets/{3.66PJT3JC.css → 3.q3CUOEpz.css} +1 -1
- package/build/client/_app/immutable/assets/3.q3CUOEpz.css.br +0 -0
- package/build/client/_app/immutable/assets/3.q3CUOEpz.css.gz +0 -0
- package/build/client/_app/immutable/assets/{AssetSourceMenu.Buj2UxUg.css → AssetSourceMenu.CgyMTAb6.css} +1 -1
- package/build/client/_app/immutable/assets/AssetSourceMenu.CgyMTAb6.css.br +0 -0
- package/build/client/_app/immutable/assets/AssetSourceMenu.CgyMTAb6.css.gz +0 -0
- package/build/client/_app/immutable/chunks/Bly9uffh.js +1 -0
- package/build/client/_app/immutable/chunks/Bly9uffh.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bly9uffh.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{R0o69z6O.js → BpsKkIFc.js} +1 -1
- package/build/client/_app/immutable/chunks/BpsKkIFc.js.br +2 -0
- package/build/client/_app/immutable/chunks/BpsKkIFc.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{jEVVu5G9.js → CrIZjnDr.js} +1 -1
- package/build/client/_app/immutable/chunks/CrIZjnDr.js.br +0 -0
- package/build/client/_app/immutable/chunks/CrIZjnDr.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ZGU9Utak.js +108 -0
- package/build/client/_app/immutable/chunks/ZGU9Utak.js.br +0 -0
- package/build/client/_app/immutable/chunks/ZGU9Utak.js.gz +0 -0
- package/build/client/_app/immutable/chunks/lw3KP4og.js +2 -0
- package/build/client/_app/immutable/chunks/lw3KP4og.js.br +0 -0
- package/build/client/_app/immutable/chunks/lw3KP4og.js.gz +0 -0
- package/build/client/_app/immutable/entry/{app.DxYfHxs-.js → app.D-lO1MC-.js} +2 -2
- package/build/client/_app/immutable/entry/app.D-lO1MC-.js.br +0 -0
- package/build/client/_app/immutable/entry/app.D-lO1MC-.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BrSEFrid.js +1 -0
- package/build/client/_app/immutable/entry/start.BrSEFrid.js.br +1 -0
- package/build/client/_app/immutable/entry/start.BrSEFrid.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{0.Do0MsVUC.js → 0.BPGg3A-F.js} +1 -1
- package/build/client/_app/immutable/nodes/0.BPGg3A-F.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.BPGg3A-F.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{1.DhfAdUbg.js → 1.-VJ5Mlss.js} +1 -1
- package/build/client/_app/immutable/nodes/1.-VJ5Mlss.js.br +1 -0
- package/build/client/_app/immutable/nodes/1.-VJ5Mlss.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.Dhyvb4bF.js +3 -0
- package/build/client/_app/immutable/nodes/2.Dhyvb4bF.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.Dhyvb4bF.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.D9Fgsq-b.js +1 -0
- package/build/client/_app/immutable/nodes/3.D9Fgsq-b.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.D9Fgsq-b.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{4.gPNAednG.js → 4.DErtysFP.js} +1 -1
- package/build/client/_app/immutable/nodes/4.DErtysFP.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.DErtysFP.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/handler.js +7 -7
- package/build/index.js +7 -7
- package/build/server/chunks/chunks/{context.js-Dh0ibRIF.js → context.js-BIgcUcEl.js} +216 -604
- package/build/server/chunks/chunks/context.js-BIgcUcEl.js.map +1 -0
- package/build/server/chunks/chunks/{contract.js-_LTMZBo2.js → contract.js-B6KBK8D9.js} +59 -95
- package/build/server/chunks/chunks/contract.js-B6KBK8D9.js.map +1 -0
- package/build/server/chunks/chunks/{core.js-CTyKR4bu.js → core.js-Bp-ReC60.js} +38 -38
- package/build/server/chunks/chunks/core.js-Bp-ReC60.js.map +1 -0
- package/build/server/chunks/chunks/dependencies.js-pUkjICr5.js +45 -0
- package/build/server/chunks/chunks/dependencies.js-pUkjICr5.js.map +1 -0
- package/build/server/chunks/chunks/{exports.js-gUMFfqhw.js → exports.js-bhKV7cEL.js} +2 -2
- package/build/server/chunks/chunks/{exports.js-gUMFfqhw.js.map → exports.js-bhKV7cEL.js.map} +1 -1
- package/build/server/chunks/chunks/{http.js-BiqUcAuu.js → http.js-BTq44nR5.js} +2 -2
- package/build/server/chunks/chunks/{http.js-BiqUcAuu.js.map → http.js-BTq44nR5.js.map} +1 -1
- package/build/server/chunks/chunks/{internal.js-DvC1GD8s.js → internal.js-7MmaxxwZ.js} +3 -3
- package/build/server/chunks/chunks/{internal.js-DvC1GD8s.js.map → internal.js-7MmaxxwZ.js.map} +1 -1
- package/build/server/chunks/chunks/internal2.js-BlXt2rfE.js.map +1 -1
- package/build/server/chunks/chunks/{manifest-membership.js-at1ixQdW.js → manifest-membership.js-Dj3WwZgz.js} +2 -2
- package/build/server/chunks/chunks/{manifest-membership.js-at1ixQdW.js.map → manifest-membership.js-Dj3WwZgz.js.map} +1 -1
- package/build/server/chunks/chunks/{raw-reconciliation.js-CUH8IIJx.js → raw-reconciliation.js-mWOAOdgL.js} +3 -3
- package/build/server/chunks/chunks/raw-reconciliation.js-mWOAOdgL.js.map +1 -0
- package/build/server/chunks/chunks/{raw-reconciliation2.js-z4xl5zw2.js → raw-reconciliation2.js-Bo1jJgvd.js} +2 -2
- package/build/server/chunks/chunks/{raw-reconciliation2.js-z4xl5zw2.js.map → raw-reconciliation2.js-Bo1jJgvd.js.map} +1 -1
- package/build/server/chunks/chunks/{shared.js-nXNT--BO.js → shared.js-B0m3s2U9.js} +2 -2
- package/build/server/chunks/chunks/{shared.js-nXNT--BO.js.map → shared.js-B0m3s2U9.js.map} +1 -1
- package/build/server/chunks/chunks/{utils.js-C5pr7OK-.js → utils.js-BXV0zq44.js} +3 -3
- package/build/server/chunks/chunks/{utils.js-C5pr7OK-.js.map → utils.js-BXV0zq44.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/_...path_/{_server.ts.js-CdDjuW0r.js → _server.ts.js-B_aa_zh7.js} +6 -6
- package/build/server/chunks/entries/endpoints/api/_...path_/{_server.ts.js-CdDjuW0r.js.map → _server.ts.js-B_aa_zh7.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/assets/_id_/{_server.ts.js-OWM1eORG.js → _server.ts.js-DbEPdkbO.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/assets/_id_/{_server.ts.js-OWM1eORG.js.map → _server.ts.js-DbEPdkbO.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/assets/_id_/raw/{_server.ts.js-DoG-7ZpZ.js → _server.ts.js-BzA96yBM.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/assets/_id_/raw/{_server.ts.js-DoG-7ZpZ.js.map → _server.ts.js-BzA96yBM.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/assets/_id_/reimport/{_server.ts.js-CAWjVeGd.js → _server.ts.js-fQAXFRLh.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/assets/_id_/reimport/{_server.ts.js-CAWjVeGd.js.map → _server.ts.js-fQAXFRLh.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/assets/_id_/retag/{_server.ts.js-CqS4aALY.js → _server.ts.js-RTBrlhk5.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/assets/_id_/retag/{_server.ts.js-CqS4aALY.js.map → _server.ts.js-RTBrlhk5.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/assets/{_server.ts.js-Bo_EsYXJ.js → _server.ts.js-Baz4gPRd.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/assets/{_server.ts.js-Bo_EsYXJ.js.map → _server.ts.js-Baz4gPRd.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/assets/delete/{_server.ts.js-DW4w0XAr.js → _server.ts.js-CnqdPxWQ.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/assets/delete/{_server.ts.js-DW4w0XAr.js.map → _server.ts.js-CnqdPxWQ.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/assets/move/{_server.ts.js-_MiNPnSy.js → _server.ts.js-bvrtSRDz.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/assets/move/{_server.ts.js-_MiNPnSy.js.map → _server.ts.js-bvrtSRDz.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/folders/_path_/{_server.ts.js-DwbrQnBc.js → _server.ts.js-cgYcVXgU.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/folders/_path_/{_server.ts.js-DwbrQnBc.js.map → _server.ts.js-cgYcVXgU.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/folders/{_server.ts.js-CEnHQf3b.js → _server.ts.js-DbXw3YEr.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/folders/{_server.ts.js-CEnHQf3b.js.map → _server.ts.js-DbXw3YEr.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/imports/{_server.ts.js-BZDuJZtF.js → _server.ts.js-D0PEYlzG.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/imports/{_server.ts.js-BZDuJZtF.js.map → _server.ts.js-D0PEYlzG.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/manifests/_name_/{_server.ts.js-DRgdpKKd.js → _server.ts.js-Dt9Wfgs7.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/manifests/_name_/{_server.ts.js-DRgdpKKd.js.map → _server.ts.js-Dt9Wfgs7.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/manifests/{_server.ts.js-CP5QyIhz.js → _server.ts.js-BBuZYakQ.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/manifests/{_server.ts.js-CP5QyIhz.js.map → _server.ts.js-BBuZYakQ.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/raw/adopt/{_server.ts.js-BKEvt065.js → _server.ts.js-DQ_CWMTu.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/raw/adopt/{_server.ts.js-BKEvt065.js.map → _server.ts.js-DQ_CWMTu.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/raw/edited/accept/{_server.ts.js-C_zihkDS.js → _server.ts.js-B3TVoDCl.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/raw/edited/accept/{_server.ts.js-C_zihkDS.js.map → _server.ts.js-B3TVoDCl.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/raw/edited/dismiss/{_server.ts.js-watkBmy6.js → _server.ts.js--2C2x6Q0.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/raw/edited/dismiss/{_server.ts.js-watkBmy6.js.map → _server.ts.js--2C2x6Q0.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/reconcile/{_server.ts.js-YtumLIou.js → _server.ts.js-DD2Hz15k.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/reconcile/{_server.ts.js-YtumLIou.js.map → _server.ts.js-DD2Hz15k.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/reveal/{_server.ts.js-Dkouuu-M.js → _server.ts.js-Ei98ilB5.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/reveal/{_server.ts.js-Dkouuu-M.js.map → _server.ts.js-Ei98ilB5.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/state/{_server.ts.js-DwsEQeuf.js → _server.ts.js-NNuDGwyK.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/state/{_server.ts.js-DwsEQeuf.js.map → _server.ts.js-NNuDGwyK.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/usage/{_server.ts.js-CdQxfhV3.js → _server.ts.js-6_Wl_k0H.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/usage/{_server.ts.js-CdQxfhV3.js.map → _server.ts.js-6_Wl_k0H.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/files/_...path_/{_server.ts.js-DDdMocWj.js → _server.ts.js-DkYQlG9U.js} +6 -6
- package/build/server/chunks/entries/endpoints/files/_...path_/{_server.ts.js-DDdMocWj.js.map → _server.ts.js-DkYQlG9U.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/files/proxy/_...path_/{_server.ts.js-DbzjbH32.js → _server.ts.js-Dft0Zgh3.js} +8 -8
- package/build/server/chunks/entries/endpoints/files/proxy/_...path_/{_server.ts.js-DbzjbH32.js.map → _server.ts.js-Dft0Zgh3.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/files/raw/_...path_/{_server.ts.js-K_JbXZsU.js → _server.ts.js-rlV0QRQS.js} +8 -8
- package/build/server/chunks/entries/endpoints/files/raw/_...path_/{_server.ts.js-K_JbXZsU.js.map → _server.ts.js-rlV0QRQS.js.map} +1 -1
- package/build/server/chunks/entries/{hooks.server.js-DgZAVFbQ.js → hooks.server.js-C345JVQ2.js} +7 -7
- package/build/server/chunks/entries/{hooks.server.js-DgZAVFbQ.js.map → hooks.server.js-C345JVQ2.js.map} +1 -1
- package/build/server/chunks/{handler-C4m7sKKb.js → handler-C_S3CtEF.js} +5 -5
- package/build/server/chunks/{handler-C4m7sKKb.js.map → handler-C_S3CtEF.js.map} +1 -1
- package/build/server/chunks/{index.js-pAnkrzRH.js → index.js-CSCxgyyg.js} +5 -5
- package/build/server/chunks/{index.js-pAnkrzRH.js.map → index.js-CSCxgyyg.js.map} +1 -1
- package/build/server/chunks/{manifest.js-CXQHeYnS.js → manifest.js-CO6AjAUm.js} +30 -30
- package/build/server/chunks/{manifest.js-CXQHeYnS.js.map → manifest.js-CO6AjAUm.js.map} +1 -1
- package/build/server/chunks/nodes/{0.js-lmQMhWZd.js → 0.js-CRc8onmc.js} +2 -2
- package/build/server/chunks/nodes/{0.js-lmQMhWZd.js.map → 0.js-CRc8onmc.js.map} +1 -1
- package/build/server/chunks/nodes/1.js-CZm_Doa7.js +7 -0
- package/build/server/chunks/nodes/{1.js-CdH3UJI2.js.map → 1.js-CZm_Doa7.js.map} +1 -1
- package/build/server/chunks/nodes/2.js-B92vn1Hu.js +7 -0
- package/build/server/chunks/nodes/2.js-B92vn1Hu.js.map +1 -0
- package/build/server/chunks/nodes/3.js-C14BP7Jm.js +7 -0
- package/build/server/chunks/nodes/3.js-C14BP7Jm.js.map +1 -0
- package/build/server/chunks/nodes/4.js-BLNdVCa1.js +7 -0
- package/build/server/chunks/nodes/{4.js-DtgDNAZF.js.map → 4.js-BLNdVCa1.js.map} +1 -1
- package/dist/config.d.ts +5 -3
- package/dist/config.js +3 -2
- package/dist/core/api-types.d.ts +7 -22
- package/dist/core/config.d.ts +8 -82
- package/dist/core/config.js +0 -9
- package/dist/core/dependencies.d.ts +52 -0
- package/dist/core/dependencies.js +56 -0
- package/dist/core/dependency-validation.d.ts +17 -0
- package/dist/core/dependency-validation.js +19 -0
- package/dist/core/index.d.ts +8 -10
- package/dist/core/index.js +4 -5
- package/dist/core/library.d.ts +0 -19
- package/dist/core/library.js +4 -4
- package/dist/core/manifest-membership.d.ts +2 -2
- package/dist/core/reference-graph.d.ts +3 -3
- package/dist/server/build.js +12 -26
- package/dist/server/check.d.ts +3 -13
- package/dist/server/check.js +33 -112
- package/dist/server/codegen.d.ts +1 -3
- package/dist/server/codegen.js +0 -18
- package/dist/server/config-loader.d.ts +10 -33
- package/dist/server/config-loader.js +87 -156
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/library-store.d.ts +1 -11
- package/dist/server/library-store.js +60 -42
- package/dist/server/operations.js +54 -161
- package/package.json +1 -1
- package/build/client/_app/immutable/assets/2.X44Wyac-.css +0 -1
- package/build/client/_app/immutable/assets/2.X44Wyac-.css.br +0 -0
- package/build/client/_app/immutable/assets/2.X44Wyac-.css.gz +0 -0
- package/build/client/_app/immutable/assets/3.66PJT3JC.css.br +0 -0
- package/build/client/_app/immutable/assets/3.66PJT3JC.css.gz +0 -0
- package/build/client/_app/immutable/assets/AssetSourceMenu.Buj2UxUg.css.br +0 -0
- package/build/client/_app/immutable/assets/AssetSourceMenu.Buj2UxUg.css.gz +0 -0
- package/build/client/_app/immutable/chunks/0SQyBKXe.js +0 -108
- package/build/client/_app/immutable/chunks/0SQyBKXe.js.br +0 -0
- package/build/client/_app/immutable/chunks/0SQyBKXe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DXiUbZ9S.js +0 -2
- package/build/client/_app/immutable/chunks/DXiUbZ9S.js.br +0 -0
- package/build/client/_app/immutable/chunks/DXiUbZ9S.js.gz +0 -0
- package/build/client/_app/immutable/chunks/R0o69z6O.js.br +0 -0
- package/build/client/_app/immutable/chunks/R0o69z6O.js.gz +0 -0
- package/build/client/_app/immutable/chunks/TrnW_5ju.js +0 -1
- package/build/client/_app/immutable/chunks/TrnW_5ju.js.br +0 -0
- package/build/client/_app/immutable/chunks/TrnW_5ju.js.gz +0 -0
- package/build/client/_app/immutable/chunks/jEVVu5G9.js.br +0 -0
- package/build/client/_app/immutable/chunks/jEVVu5G9.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.DxYfHxs-.js.br +0 -0
- package/build/client/_app/immutable/entry/app.DxYfHxs-.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.CdM7ozdO.js +0 -1
- package/build/client/_app/immutable/entry/start.CdM7ozdO.js.br +0 -0
- package/build/client/_app/immutable/entry/start.CdM7ozdO.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.Do0MsVUC.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.Do0MsVUC.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.DhfAdUbg.js.br +0 -1
- package/build/client/_app/immutable/nodes/1.DhfAdUbg.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.lLNAdU5s.js +0 -3
- package/build/client/_app/immutable/nodes/2.lLNAdU5s.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.lLNAdU5s.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.DA8xzCvA.js +0 -1
- package/build/client/_app/immutable/nodes/3.DA8xzCvA.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.DA8xzCvA.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.gPNAednG.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.gPNAednG.js.gz +0 -0
- package/build/server/chunks/chunks/context.js-Dh0ibRIF.js.map +0 -1
- package/build/server/chunks/chunks/contract.js-_LTMZBo2.js.map +0 -1
- package/build/server/chunks/chunks/core.js-CTyKR4bu.js.map +0 -1
- package/build/server/chunks/chunks/raw-reconciliation.js-CUH8IIJx.js.map +0 -1
- package/build/server/chunks/nodes/1.js-CdH3UJI2.js +0 -7
- package/build/server/chunks/nodes/2.js-BHnsJqcE.js +0 -7
- package/build/server/chunks/nodes/2.js-BHnsJqcE.js.map +0 -1
- package/build/server/chunks/nodes/3.js-cR9NdrYS.js +0 -7
- package/build/server/chunks/nodes/3.js-cR9NdrYS.js.map +0 -1
- package/build/server/chunks/nodes/4.js-DtgDNAZF.js +0 -7
- package/dist/core/library-validation.d.ts +0 -13
- package/dist/core/library-validation.js +0 -48
- package/dist/core/package-declaration.d.ts +0 -43
- package/dist/core/package-declaration.js +0 -80
- package/dist/core/package-merge.d.ts +0 -65
- package/dist/core/package-merge.js +0 -173
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { c as compareCodeUnits, h as folderOfRawPath, j as rawFileNameOfPath, g as canonicalizeParameters, n as normalizeFolderPath, H as typesForFileName, k as parentFolderPath, u as portableFolderPathKey
|
|
2
|
-
import {
|
|
3
|
-
import { c as collectAllReferences, a as assetIdError, b as computeLibraryMembership, d as allDeliveredAssetIds, i as isValidAssetId } from './manifest-membership.js-
|
|
4
|
-
import { v as
|
|
1
|
+
import { c as compareCodeUnits, h as folderOfRawPath, j as rawFileNameOfPath, g as canonicalizeParameters, n as normalizeFolderPath, H as typesForFileName, k as parentFolderPath, u as portableFolderPathKey } from './core.js-Bp-ReC60.js';
|
|
2
|
+
import { i as isRecord, s as serverPluginsByType, L as LibraryStore, d as descriptorsByType, m as manifestModuleFileName, l as locateGeneratedAssetDeclaration, a as serializeLibrary, b as serverPluginForType, S as SourceImportError, p as processAssets, g as generateManifestModules, r as readCurrentProxy, e as encodeRelativePathForUrl, c as invalidInput, f as parseLibrary } from './contract.js-B6KBK8D9.js';
|
|
3
|
+
import { c as collectAllReferences, a as assetIdError, b as computeLibraryMembership, d as allDeliveredAssetIds, i as isValidAssetId } from './manifest-membership.js-Dj3WwZgz.js';
|
|
4
|
+
import { v as validateDependencyList, f as formatRequiredBy } from './dependencies.js-pUkjICr5.js';
|
|
5
|
+
import { v as verifyStableRawFile, c as classifyRawDirectory } from './raw-reconciliation2.js-Bo1jJgvd.js';
|
|
5
6
|
import { createRequire } from 'node:module';
|
|
6
7
|
import { isAbsolute, resolve, join, dirname, extname, relative, sep } from 'node:path';
|
|
7
8
|
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
-
import { readFile, realpath } from 'node:fs/promises';
|
|
9
|
-
import { pathToFileURL } from 'node:url';
|
|
10
9
|
import { createJiti } from 'jiti';
|
|
10
|
+
import { readFile, realpath } from 'node:fs/promises';
|
|
11
11
|
import { execFile } from 'node:child_process';
|
|
12
12
|
import { isDeepStrictEqual, promisify } from 'node:util';
|
|
13
13
|
import sharp from 'sharp';
|
|
@@ -16,224 +16,6 @@ import { lookup } from 'node:dns/promises';
|
|
|
16
16
|
import { isIP } from 'node:net';
|
|
17
17
|
import { request } from 'node:https';
|
|
18
18
|
|
|
19
|
-
//#region src/lib/core/package-declaration.ts
|
|
20
|
-
function parsePackageAsset(origin, id, value) {
|
|
21
|
-
if (!isRecord$1(value)) throw new Error(`Package "${origin}" asset "${id}" must be an object.`);
|
|
22
|
-
if (typeof value.type !== "string" || value.type.length === 0) throw new Error(`Package "${origin}" asset "${id}" is missing a string "type".`);
|
|
23
|
-
if ("raw" in value || "rawHash" in value) throw new Error(`Package "${origin}" asset "${id}" declares "raw"/"rawHash"; Packages ship byte-less slots only.`);
|
|
24
|
-
if (!Array.isArray(value.manifests) || value.manifests.some((entry) => typeof entry !== "string")) throw new Error(`Package "${origin}" asset "${id}" must have a "manifests" array of strings.`);
|
|
25
|
-
const record = {
|
|
26
|
-
type: value.type,
|
|
27
|
-
parameters: "parameters" in value ? value.parameters : {},
|
|
28
|
-
manifests: value.manifests
|
|
29
|
-
};
|
|
30
|
-
if (value.importSource !== void 0) record.importSource = parseImportSource(id, value.importSource);
|
|
31
|
-
return record;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Parse and structurally validate a `fundus.package.json` (JSON text). Delegates
|
|
35
|
-
* to {@link validatePackageDeclaration} after `JSON.parse`.
|
|
36
|
-
*/
|
|
37
|
-
function parsePackageDeclaration(json, origin) {
|
|
38
|
-
let value;
|
|
39
|
-
try {
|
|
40
|
-
value = JSON.parse(json);
|
|
41
|
-
} catch (cause) {
|
|
42
|
-
throw new Error(`Package "${origin}" declaration is not valid JSON: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
43
|
-
}
|
|
44
|
-
return validatePackageDeclaration(value, origin);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Structurally validate an already-parsed package declaration — the shared core of
|
|
48
|
-
* both the JSON path ({@link parsePackageDeclaration}) and the TypeScript-module path
|
|
49
|
-
* (a `fundus.package.ts` default export loaded via jiti). Throws with a clear,
|
|
50
|
-
* origin-tagged message on any malformed part. Plugin parameter validation and
|
|
51
|
-
* id/manifest-name validity are separate steps that run over the merged
|
|
52
|
-
* (effective) library, not here — mirroring `parseLibrary`. `version` defaults to 1.
|
|
53
|
-
*/
|
|
54
|
-
function validatePackageDeclaration(value, origin) {
|
|
55
|
-
if (!isRecord$1(value)) throw new Error(`Package "${origin}" declaration must be an object.`);
|
|
56
|
-
if (value.version !== void 0 && value.version !== 1) throw new Error(`Package "${origin}" declaration has unsupported version ${JSON.stringify(value.version)} (expected 1).`);
|
|
57
|
-
if (!isRecord$1(value.assets)) throw new Error(`Package "${origin}" declaration "assets" must be an object.`);
|
|
58
|
-
if (value.manifests !== void 0 && !isRecord$1(value.manifests)) throw new Error(`Package "${origin}" declaration "manifests" must be an object.`);
|
|
59
|
-
const assets = {};
|
|
60
|
-
for (const [id, record] of Object.entries(value.assets)) {
|
|
61
|
-
assertSafeKey("asset", id);
|
|
62
|
-
assets[id] = parsePackageAsset(origin, id, record);
|
|
63
|
-
}
|
|
64
|
-
const manifests = {};
|
|
65
|
-
if (isRecord$1(value.manifests)) for (const [name, record] of Object.entries(value.manifests)) {
|
|
66
|
-
assertSafeKey("manifest", name);
|
|
67
|
-
if (!isRecord$1(record)) throw new Error(`Package "${origin}" manifest "${name}" must be an object.`);
|
|
68
|
-
manifests[name] = parseManifestRecord(name, record);
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
version: 1,
|
|
72
|
-
assets,
|
|
73
|
-
manifests
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
//#endregion
|
|
77
|
-
//#region src/lib/core/package-merge.ts
|
|
78
|
-
/**
|
|
79
|
-
* The pure Package merge: fold package-shipped partial libraries **under** the
|
|
80
|
-
* host library into one in-memory *effective* library. Host wins per-field
|
|
81
|
-
* (deep). No disk, no config — testable like `resolveConfig`. The effective
|
|
82
|
-
* library is never serialized (a host `Library` always carries `raw`/`rawHash`);
|
|
83
|
-
* `materializeLibrary` drops raw-less inert slots to hand a plain `Library` to
|
|
84
|
-
* processing/codegen once the slot/validation gates have passed.
|
|
85
|
-
*/
|
|
86
|
-
function sortDedupManifests(names) {
|
|
87
|
-
return [...new Set(names)].sort(compareCodeUnits);
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Deep-merge plugin `parameters` — overlay (host) wins. Recurses into plain
|
|
91
|
-
* objects only; arrays are replaced wholesale (host-replace) and `{ $asset }`
|
|
92
|
-
* reference markers are treated as atomic (never merged field-by-field). Applied
|
|
93
|
-
* to `parameters` only — the record-level `manifests` array is unioned by the
|
|
94
|
-
* caller, never routed through here.
|
|
95
|
-
*/
|
|
96
|
-
function deepMergeParameters(base, overlay) {
|
|
97
|
-
if (isRecord$1(base) && isRecord$1(overlay) && !isAssetReference(base) && !isAssetReference(overlay)) {
|
|
98
|
-
const result = { ...base };
|
|
99
|
-
for (const [key, value] of Object.entries(overlay)) result[key] = key in base ? deepMergeParameters(base[key], value) : value;
|
|
100
|
-
return result;
|
|
101
|
-
}
|
|
102
|
-
return overlay;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Merge `packages` under `host` (host wins, per-field deep). Returns the merged
|
|
106
|
-
* effective library, per-asset provenance, and merge findings. `host` is an
|
|
107
|
-
* `EffectiveLibrary` so a raw-less host override branch stays reachable/testable
|
|
108
|
-
* and v2-ready; a plain `Library` is assignable.
|
|
109
|
-
*/
|
|
110
|
-
function mergePackages(host, packages) {
|
|
111
|
-
const findings = [];
|
|
112
|
-
const pkgAssets = /* @__PURE__ */ new Map();
|
|
113
|
-
const pkgManifests = /* @__PURE__ */ new Map();
|
|
114
|
-
for (const { origin, declaration } of packages) {
|
|
115
|
-
for (const [id, decl] of Object.entries(declaration.assets)) {
|
|
116
|
-
const existing = pkgAssets.get(id);
|
|
117
|
-
if (existing) {
|
|
118
|
-
findings.push({
|
|
119
|
-
kind: "package-conflict",
|
|
120
|
-
assetId: id,
|
|
121
|
-
origins: [existing.origin, origin],
|
|
122
|
-
message: `Asset "${id}" is declared by two Packages ("${existing.origin}" and "${origin}"); Package ids must be unique.`
|
|
123
|
-
});
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
pkgAssets.set(id, {
|
|
127
|
-
origin,
|
|
128
|
-
decl
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
for (const [name, record] of Object.entries(declaration.manifests)) if (!pkgManifests.has(name)) pkgManifests.set(name, record);
|
|
132
|
-
}
|
|
133
|
-
const assets = {};
|
|
134
|
-
const provenance = {};
|
|
135
|
-
for (const [id, hostRecord] of Object.entries(host.assets)) {
|
|
136
|
-
const pkg = pkgAssets.get(id);
|
|
137
|
-
if (!pkg) {
|
|
138
|
-
assets[id] = { ...hostRecord };
|
|
139
|
-
provenance[id] = { source: "host" };
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
if (pkg.decl.type !== hostRecord.type) {
|
|
143
|
-
findings.push({
|
|
144
|
-
kind: "package-type-mismatch",
|
|
145
|
-
assetId: id,
|
|
146
|
-
origin: pkg.origin,
|
|
147
|
-
message: `Asset "${id}" overrides Package "${pkg.origin}" but changes its type from "${pkg.decl.type}" to "${hostRecord.type}"; changing the type is a different asset, not an override.`
|
|
148
|
-
});
|
|
149
|
-
assets[id] = { ...hostRecord };
|
|
150
|
-
provenance[id] = {
|
|
151
|
-
source: "override",
|
|
152
|
-
origin: pkg.origin
|
|
153
|
-
};
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
const merged = {
|
|
157
|
-
type: hostRecord.type,
|
|
158
|
-
parameters: deepMergeParameters(pkg.decl.parameters, hostRecord.parameters),
|
|
159
|
-
manifests: sortDedupManifests([...pkg.decl.manifests, ...hostRecord.manifests])
|
|
160
|
-
};
|
|
161
|
-
if (hostRecord.raw !== void 0 || hostRecord.importSource !== void 0) {
|
|
162
|
-
if (hostRecord.raw !== void 0) merged.raw = hostRecord.raw;
|
|
163
|
-
if (hostRecord.rawHash !== void 0) merged.rawHash = hostRecord.rawHash;
|
|
164
|
-
if (hostRecord.importSource !== void 0) merged.importSource = hostRecord.importSource;
|
|
165
|
-
} else if (pkg.decl.importSource !== void 0) merged.importSource = pkg.decl.importSource;
|
|
166
|
-
assets[id] = merged;
|
|
167
|
-
provenance[id] = {
|
|
168
|
-
source: "override",
|
|
169
|
-
origin: pkg.origin
|
|
170
|
-
};
|
|
171
|
-
findings.push({
|
|
172
|
-
kind: "package-overridden",
|
|
173
|
-
assetId: id,
|
|
174
|
-
origin: pkg.origin,
|
|
175
|
-
message: `Asset "${id}" from Package "${pkg.origin}" is overridden by the host library.`
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
for (const [id, { origin, decl }] of pkgAssets) {
|
|
179
|
-
if (Object.hasOwn(host.assets, id)) continue;
|
|
180
|
-
const record = {
|
|
181
|
-
type: decl.type,
|
|
182
|
-
parameters: decl.parameters,
|
|
183
|
-
manifests: sortDedupManifests(decl.manifests)
|
|
184
|
-
};
|
|
185
|
-
if (decl.importSource !== void 0) record.importSource = decl.importSource;
|
|
186
|
-
assets[id] = record;
|
|
187
|
-
provenance[id] = {
|
|
188
|
-
source: "package",
|
|
189
|
-
origin
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
const manifests = {};
|
|
193
|
-
for (const [name, record] of pkgManifests) manifests[name] = { ...record };
|
|
194
|
-
for (const [name, record] of Object.entries(host.manifests)) manifests[name] = {
|
|
195
|
-
...manifests[name],
|
|
196
|
-
...record
|
|
197
|
-
};
|
|
198
|
-
return {
|
|
199
|
-
library: {
|
|
200
|
-
version: Object.values(assets).some((record) => record.importSource !== void 0) ? 2 : host.version,
|
|
201
|
-
folders: host.folders,
|
|
202
|
-
assets,
|
|
203
|
-
manifests
|
|
204
|
-
},
|
|
205
|
-
provenance,
|
|
206
|
-
findings
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Drop raw-less (unfilled) slots from an effective library, yielding a plain
|
|
211
|
-
* `Library` for processing/codegen. Safe only after the slot/validation gates
|
|
212
|
-
* pass — every remaining delivered asset then has `raw`; dropped slots are
|
|
213
|
-
* provably inert (not delivered).
|
|
214
|
-
*/
|
|
215
|
-
function materializeLibrary(effective) {
|
|
216
|
-
const assets = {};
|
|
217
|
-
for (const [id, record] of Object.entries(effective.assets)) {
|
|
218
|
-
if (record.raw === void 0 || record.rawHash === void 0) continue;
|
|
219
|
-
const materialized = {
|
|
220
|
-
type: record.type,
|
|
221
|
-
raw: record.raw,
|
|
222
|
-
rawHash: record.rawHash,
|
|
223
|
-
parameters: record.parameters,
|
|
224
|
-
manifests: record.manifests
|
|
225
|
-
};
|
|
226
|
-
if (record.importSource !== void 0) materialized.importSource = record.importSource;
|
|
227
|
-
assets[id] = materialized;
|
|
228
|
-
}
|
|
229
|
-
return {
|
|
230
|
-
version: effective.version,
|
|
231
|
-
folders: effective.folders,
|
|
232
|
-
assets,
|
|
233
|
-
manifests: effective.manifests
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
//#endregion
|
|
237
19
|
//#region src/lib/core/propose-asset-id.ts
|
|
238
20
|
/**
|
|
239
21
|
* Propose a camelCase asset id from a file (or node) name: split on
|
|
@@ -252,6 +34,20 @@ function proposeAssetId(fileName) {
|
|
|
252
34
|
return withoutLeadingDigits.charAt(0).toLowerCase() + withoutLeadingDigits.slice(1);
|
|
253
35
|
}
|
|
254
36
|
//#endregion
|
|
37
|
+
//#region src/lib/core/dependency-validation.ts
|
|
38
|
+
function validateDependencies(dependencies, library) {
|
|
39
|
+
const findings = [];
|
|
40
|
+
for (const dependency of dependencies) {
|
|
41
|
+
if (!Object.hasOwn(library.assets, dependency.id)) {
|
|
42
|
+
findings.push({ message: `Missing ${dependency.type} "${dependency.id}" required by ${formatRequiredBy(dependency.sources)}.` });
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const record = library.assets[dependency.id];
|
|
46
|
+
if (record.type !== dependency.type) findings.push({ message: `Type mismatch for "${dependency.id}" required by ${formatRequiredBy(dependency.sources)}: expected ${dependency.type}, library has ${record.type}.` });
|
|
47
|
+
}
|
|
48
|
+
return findings;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
255
51
|
//#region src/lib/server/config-loader.ts
|
|
256
52
|
/**
|
|
257
53
|
* Loads and resolves the host's `fundus.config.ts` through jiti, validates
|
|
@@ -275,70 +71,6 @@ function configDefinitionsFor(registry) {
|
|
|
275
71
|
}
|
|
276
72
|
return [...byNamespace.values()];
|
|
277
73
|
}
|
|
278
|
-
/**
|
|
279
|
-
* A string `packages` entry is a *path* when it looks like one (starts with
|
|
280
|
-
* `.`/`/`, is absolute, or ends `.json`), or a bare relative path with a
|
|
281
|
-
* separator; otherwise it is a package *name*. A scoped name (`@scope/pkg`)
|
|
282
|
-
* contains a `/` but is a name.
|
|
283
|
-
*/
|
|
284
|
-
function classifyPackageSpec(spec) {
|
|
285
|
-
if (spec.startsWith(".") || spec.startsWith("/") || isAbsolute(spec)) return "path";
|
|
286
|
-
if (DECLARATION_FILE_RE.test(spec)) return "path";
|
|
287
|
-
if (spec.startsWith("@")) return "name";
|
|
288
|
-
if (spec.includes("/") || spec.includes("\\")) return "path";
|
|
289
|
-
return "name";
|
|
290
|
-
}
|
|
291
|
-
/** A declaration file is JSON or a JS/TS module (the latter loaded via jiti). */
|
|
292
|
-
var DECLARATION_FILE_RE = /\.(json|[mc]?[jt]s)$/;
|
|
293
|
-
/**
|
|
294
|
-
* Read a package declaration from its resolved file: a JSON `fundus.package.json`
|
|
295
|
-
* (parsed as text) or a JS/TS module (`fundus.package.ts`) whose default export is
|
|
296
|
-
* the declaration — loaded through the same jiti path as `fundus.config.ts`, which
|
|
297
|
-
* keeps the resource `type`s literal for the package's `PackageAssets<…>` derivation.
|
|
298
|
-
*/
|
|
299
|
-
async function loadPackageDeclaration(file, origin) {
|
|
300
|
-
if (/\.[mc]?[jt]s$/.test(file)) {
|
|
301
|
-
let module;
|
|
302
|
-
try {
|
|
303
|
-
module = await createJiti(import.meta.url, { interopDefault: false }).import(file);
|
|
304
|
-
} catch (cause) {
|
|
305
|
-
throw new Error(`Cannot load fundus package "${origin}" (${file}): ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
306
|
-
}
|
|
307
|
-
return validatePackageDeclaration(isRecord(module) && "default" in module ? module.default : module, origin);
|
|
308
|
-
}
|
|
309
|
-
let text;
|
|
310
|
-
try {
|
|
311
|
-
text = await readFile(file, "utf8");
|
|
312
|
-
} catch (cause) {
|
|
313
|
-
throw new Error(`Cannot read fundus package "${origin}" (${file}): ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
314
|
-
}
|
|
315
|
-
return parsePackageDeclaration(text, origin);
|
|
316
|
-
}
|
|
317
|
-
function normalizePackageSource(projectRoot, entry) {
|
|
318
|
-
let spec;
|
|
319
|
-
let rawDirOverride;
|
|
320
|
-
if (typeof entry === "string") spec = entry;
|
|
321
|
-
else if (isRecord(entry) && typeof entry.package === "string" && entry.package.length > 0) {
|
|
322
|
-
spec = entry.package;
|
|
323
|
-
if (entry.rawDir !== void 0) {
|
|
324
|
-
if (typeof entry.rawDir !== "string" || entry.rawDir.length === 0) throw new Error("fundus.config: a \"packages\" entry \"rawDir\" must be a non-empty string.");
|
|
325
|
-
rawDirOverride = entry.rawDir;
|
|
326
|
-
}
|
|
327
|
-
} else throw new Error("fundus.config: each \"packages\" entry must be a package name, a path string, or { package: string; rawDir?: string }.");
|
|
328
|
-
const kind = classifyPackageSpec(spec);
|
|
329
|
-
const reference = kind === "path" ? resolve(projectRoot, spec) : spec;
|
|
330
|
-
return {
|
|
331
|
-
origin: spec,
|
|
332
|
-
kind,
|
|
333
|
-
reference,
|
|
334
|
-
...rawDirOverride !== void 0 ? { rawDirOverride } : {}
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
function resolvePackageSources(projectRoot, value) {
|
|
338
|
-
if (value === void 0) return [];
|
|
339
|
-
if (!Array.isArray(value)) throw new Error("fundus.config: \"packages\" must be an array.");
|
|
340
|
-
return value.map((entry) => normalizePackageSource(projectRoot, entry));
|
|
341
|
-
}
|
|
342
74
|
/** Pure resolution step (testable without a config file on disk). */
|
|
343
75
|
function resolveConfig(projectRoot, value, registry = serverPluginsByType) {
|
|
344
76
|
if (!isRecord(value)) throw new Error("fundus.config must default-export a configuration object.");
|
|
@@ -361,6 +93,7 @@ function resolveConfig(projectRoot, value, registry = serverPluginsByType) {
|
|
|
361
93
|
if (!isRecord(defaults)) throw new Error("fundus.config: \"import.figma.defaults\" must be an object.");
|
|
362
94
|
const scale = defaults.scale === void 0 ? 2 : defaults.scale;
|
|
363
95
|
if (scale !== 1 && scale !== 2 && scale !== 3 && scale !== 4) throw new Error("fundus.config: \"import.figma.defaults.scale\" must be 1, 2, 3, or 4.");
|
|
96
|
+
dependencySpecs(value);
|
|
364
97
|
const usage = value.usage;
|
|
365
98
|
if (usage !== void 0 && !isRecord(usage)) throw new Error("fundus.config: \"usage\" must be an object.");
|
|
366
99
|
if (usage !== void 0 && typeof usage.referenceProvider !== "function") throw new Error("fundus.config: \"usage.referenceProvider\" must be a function.");
|
|
@@ -372,93 +105,92 @@ function resolveConfig(projectRoot, value, registry = serverPluginsByType) {
|
|
|
372
105
|
library: resolvePath(projectRoot, requiredString(value, "library")),
|
|
373
106
|
manifestsDir: resolvePath(projectRoot, requiredString(value, "manifestsDir")),
|
|
374
107
|
proxyBasePath,
|
|
108
|
+
dependencies: [],
|
|
375
109
|
plugins: resolvedPlugins,
|
|
376
110
|
import: { figma: {
|
|
377
111
|
...figma.token !== void 0 ? { token: figma.token } : {},
|
|
378
112
|
...figma.defaultFileKey !== void 0 ? { defaultFileKey: figma.defaultFileKey } : {},
|
|
379
113
|
defaults: { scale }
|
|
380
114
|
} },
|
|
381
|
-
usage: usage === void 0 ? null : usage
|
|
382
|
-
packageSources: resolvePackageSources(projectRoot, value.packages),
|
|
383
|
-
packages: []
|
|
115
|
+
usage: usage === void 0 ? null : usage
|
|
384
116
|
};
|
|
385
117
|
}
|
|
386
|
-
|
|
387
|
-
|
|
118
|
+
/** Validated dependency source specs (shape only; absent means none). */
|
|
119
|
+
function dependencySpecs(value) {
|
|
120
|
+
const specs = value.dependencies;
|
|
121
|
+
if (specs === void 0) return [];
|
|
122
|
+
if (!Array.isArray(specs) || specs.some((spec) => typeof spec !== "string" || spec.length === 0)) throw new Error("fundus.config: \"dependencies\" must be an array of non-empty strings.");
|
|
123
|
+
return specs;
|
|
124
|
+
}
|
|
125
|
+
/** Reject a `.json` dependency source: JSON carries no literal types (D4). */
|
|
126
|
+
function assertNotJson(spec, context) {
|
|
127
|
+
if (spec.endsWith(".json")) throw new Error(`Dependency ${context} "${spec}" must be a .ts or .js module; JSON is not supported.`);
|
|
128
|
+
}
|
|
129
|
+
/** A dependency spec is a path when it is relative/absolute or names a module file. */
|
|
130
|
+
function isPathSpec(spec) {
|
|
131
|
+
return spec.startsWith(".") || spec.startsWith("/") || spec.endsWith(".ts") || spec.endsWith(".js");
|
|
132
|
+
}
|
|
133
|
+
/** Walk up from `fromPath` to the nearest package.json whose `name` matches. */
|
|
134
|
+
function nearestPackageJson(fromPath, name) {
|
|
135
|
+
let dir = dirname(fromPath);
|
|
388
136
|
for (;;) {
|
|
389
137
|
const candidate = join(dir, "package.json");
|
|
390
138
|
if (existsSync(candidate)) try {
|
|
391
|
-
|
|
392
|
-
if (isRecord(pkg) && pkg.name === name) return {
|
|
393
|
-
dir,
|
|
394
|
-
pkg
|
|
395
|
-
};
|
|
139
|
+
if (JSON.parse(readFileSync(candidate, "utf8")).name === name) return candidate;
|
|
396
140
|
} catch {}
|
|
397
141
|
const parent = dirname(dir);
|
|
398
142
|
if (parent === dir) break;
|
|
399
143
|
dir = parent;
|
|
400
144
|
}
|
|
401
|
-
throw new Error(`Cannot
|
|
145
|
+
throw new Error(`Cannot resolve the package.json of dependency "${name}".`);
|
|
402
146
|
}
|
|
403
|
-
/**
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
* would throw `MODULE_NOT_FOUND`; resolve its `package.json` subpath first and
|
|
407
|
-
* only fall back to entry resolution when an `exports` map hides it.
|
|
408
|
-
*/
|
|
409
|
-
function resolvePackageRoot(require, reference, origin) {
|
|
410
|
-
try {
|
|
411
|
-
const manifestPath = require.resolve(`${reference}/package.json`);
|
|
412
|
-
const pkg = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
413
|
-
if (isRecord(pkg)) return {
|
|
414
|
-
dir: dirname(manifestPath),
|
|
415
|
-
pkg
|
|
416
|
-
};
|
|
417
|
-
} catch {}
|
|
418
|
-
let entry;
|
|
147
|
+
/** Resolve an npm-name dependency spec to its declared source module path. */
|
|
148
|
+
function resolveNpmDependencyModule(spec, require) {
|
|
149
|
+
let packageJsonPath;
|
|
419
150
|
try {
|
|
420
|
-
|
|
421
|
-
} catch {
|
|
422
|
-
|
|
151
|
+
packageJsonPath = require.resolve(`${spec}/package.json`);
|
|
152
|
+
} catch (cause) {
|
|
153
|
+
if (cause !== null && typeof cause === "object" && cause.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") packageJsonPath = nearestPackageJson(require.resolve(spec), spec);
|
|
154
|
+
else throw cause;
|
|
423
155
|
}
|
|
424
|
-
|
|
156
|
+
const field = JSON.parse(readFileSync(packageJsonPath, "utf8")).fundus?.dependencies;
|
|
157
|
+
if (typeof field !== "string" || field.length === 0) throw new Error(`Dependency "${spec}" is missing a non-empty "fundus".dependencies module path in its package.json.`);
|
|
158
|
+
assertNotJson(field, `package.json "fundus".dependencies field of "${spec}"`);
|
|
159
|
+
return resolve(dirname(packageJsonPath), field);
|
|
425
160
|
}
|
|
426
161
|
/**
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
* entries point directly at a `fundus.package.json`. Throws a clear,
|
|
431
|
-
* origin-tagged error on any resolution/read/parse failure — Package assembly
|
|
432
|
-
* failures are symmetric with a missing `fundus.config.ts`.
|
|
162
|
+
* Load and aggregate every configured dependency source (D3, D6). `requireAnchor`
|
|
163
|
+
* anchors npm-name resolution at the host project (injectable for tests). Flat:
|
|
164
|
+
* the dependencies of a referenced npm package are not resolved recursively.
|
|
433
165
|
*/
|
|
434
|
-
async function
|
|
435
|
-
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
166
|
+
async function resolveDependencies(projectRoot, specs, requireAnchor = join(resolve(projectRoot), "package.json")) {
|
|
167
|
+
if (specs.length === 0) return [];
|
|
168
|
+
const jiti = createJiti(import.meta.url, { interopDefault: false });
|
|
169
|
+
const require = createRequire(requireAnchor);
|
|
170
|
+
const aggregated = /* @__PURE__ */ new Map();
|
|
171
|
+
for (const spec of specs) {
|
|
172
|
+
assertNotJson(spec, "source");
|
|
173
|
+
const modulePath = isPathSpec(spec) ? resolve(resolve(projectRoot), spec) : resolveNpmDependencyModule(spec, require);
|
|
174
|
+
const loaded = await jiti.import(modulePath);
|
|
175
|
+
const value = loaded.default ?? loaded;
|
|
176
|
+
for (const dependency of validateDependencyList(spec, value)) {
|
|
177
|
+
const existing = aggregated.get(dependency.id);
|
|
178
|
+
if (existing === void 0) {
|
|
179
|
+
aggregated.set(dependency.id, {
|
|
180
|
+
type: dependency.type,
|
|
181
|
+
sources: [spec]
|
|
182
|
+
});
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (existing.type !== dependency.type) throw new Error(`Dependency "${dependency.id}" is declared as "${existing.type}" by "${existing.sources.join("\", \"")}" and as "${dependency.type}" by "${spec}".`);
|
|
186
|
+
if (!existing.sources.includes(spec)) existing.sources.push(spec);
|
|
451
187
|
}
|
|
452
|
-
const declaration = await loadPackageDeclaration(file, source.origin);
|
|
453
|
-
const rawDir = source.rawDirOverride !== void 0 ? resolve(projectRoot, source.rawDirOverride) : defaultRawDir;
|
|
454
|
-
packages.push({
|
|
455
|
-
origin: source.origin,
|
|
456
|
-
file,
|
|
457
|
-
rawDir,
|
|
458
|
-
declaration
|
|
459
|
-
});
|
|
460
188
|
}
|
|
461
|
-
return
|
|
189
|
+
return [...aggregated].map(([id, { type, sources }]) => ({
|
|
190
|
+
id,
|
|
191
|
+
type,
|
|
192
|
+
sources
|
|
193
|
+
}));
|
|
462
194
|
}
|
|
463
195
|
/** Load `fundus.config.ts` from the host project root. */
|
|
464
196
|
async function loadConfig(projectRoot) {
|
|
@@ -471,153 +203,14 @@ async function loadConfig(projectRoot) {
|
|
|
471
203
|
} catch (cause) {
|
|
472
204
|
throw new Error(`Cannot load fundus.config.ts: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
473
205
|
}
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
packages: await loadPackages(root, config.packageSources)
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
async function imageFingerprint(filePath, hashSize) {
|
|
481
|
-
const width = hashSize + 1;
|
|
482
|
-
const pixels = await sharp(filePath).rotate().trim({
|
|
483
|
-
background: {
|
|
484
|
-
r: 0,
|
|
485
|
-
g: 0,
|
|
486
|
-
b: 0,
|
|
487
|
-
alpha: 0
|
|
488
|
-
},
|
|
489
|
-
threshold: 0
|
|
490
|
-
}).resize({
|
|
491
|
-
width,
|
|
492
|
-
height: hashSize,
|
|
493
|
-
fit: "fill"
|
|
494
|
-
}).ensureAlpha().toColourspace("srgb").raw().toBuffer();
|
|
495
|
-
const hash = new Uint8Array(Math.ceil(hashSize * hashSize / 8));
|
|
496
|
-
const alphaHash = new Uint8Array(hash.length);
|
|
497
|
-
const colorTotals = [
|
|
498
|
-
0,
|
|
499
|
-
0,
|
|
500
|
-
0
|
|
501
|
-
];
|
|
502
|
-
let alphaTotal = 0;
|
|
503
|
-
let bit = 0;
|
|
504
|
-
for (let row = 0; row < hashSize; row++) for (let column = 0; column < hashSize; column++) {
|
|
505
|
-
const leftOffset = (row * width + column) * 4;
|
|
506
|
-
const rightOffset = leftOffset + 4;
|
|
507
|
-
const leftAlpha = pixels[leftOffset + 3] / 255;
|
|
508
|
-
const rightAlpha = pixels[rightOffset + 3] / 255;
|
|
509
|
-
if (visibleLuminance(pixels, leftOffset, leftAlpha) < visibleLuminance(pixels, rightOffset, rightAlpha)) hash[bit >> 3] |= 1 << 7 - (bit & 7);
|
|
510
|
-
if (leftAlpha < rightAlpha) alphaHash[bit >> 3] |= 1 << 7 - (bit & 7);
|
|
511
|
-
for (let channel = 0; channel < 3; channel++) colorTotals[channel] += pixels[leftOffset + channel] * leftAlpha;
|
|
512
|
-
alphaTotal += leftAlpha;
|
|
513
|
-
bit += 1;
|
|
514
|
-
}
|
|
515
|
-
const pixelCount = hashSize * hashSize;
|
|
206
|
+
const value = isRecord(module) && "default" in module ? module.default : module;
|
|
207
|
+
const resolved = resolveConfig(root, value);
|
|
208
|
+
const dependencies = await resolveDependencies(root, isRecord(value) ? dependencySpecs(value) : []);
|
|
516
209
|
return {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
meanColor: colorTotals.map((total) => alphaTotal === 0 ? 0 : total / alphaTotal),
|
|
520
|
-
meanAlpha: alphaTotal / pixelCount
|
|
210
|
+
...resolved,
|
|
211
|
+
dependencies
|
|
521
212
|
};
|
|
522
213
|
}
|
|
523
|
-
function visibleLuminance(pixels, offset, alpha) {
|
|
524
|
-
return (pixels[offset] * .2126 + pixels[offset + 1] * .7152 + pixels[offset + 2] * .0722) * alpha + 127 * (1 - alpha);
|
|
525
|
-
}
|
|
526
|
-
function colorDistance(left, right) {
|
|
527
|
-
return Math.hypot(left[0] - right[0], left[1] - right[1], left[2] - right[2]);
|
|
528
|
-
}
|
|
529
|
-
/** Count differing bits between two equally sized perceptual hashes. */
|
|
530
|
-
function hammingDistance(left, right) {
|
|
531
|
-
if (left.length !== right.length) throw new Error("Image hashes must have the same length.");
|
|
532
|
-
let distance = 0;
|
|
533
|
-
for (let index = 0; index < left.length; index++) {
|
|
534
|
-
let value = left[index] ^ right[index];
|
|
535
|
-
while (value !== 0) {
|
|
536
|
-
value &= value - 1;
|
|
537
|
-
distance += 1;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
return distance;
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* Stateful so the editor can reuse fingerprints by content hash between state
|
|
544
|
-
* snapshots. Unreadable raws are omitted: duplicate detection is advisory and
|
|
545
|
-
* must not hide the editor or replace the pipeline's canonical diagnostics.
|
|
546
|
-
*/
|
|
547
|
-
var ImageDuplicateDetector = class {
|
|
548
|
-
#fingerprints = /* @__PURE__ */ new Map();
|
|
549
|
-
async find(library, rawDir) {
|
|
550
|
-
const images = Object.entries(library.assets).filter(([, record]) => record.type === "image").sort(([left], [right]) => compareCodeUnits(left, right));
|
|
551
|
-
const activeHashes = new Set(images.map(([, record]) => record.rawHash));
|
|
552
|
-
for (const hash of this.#fingerprints.keys()) if (!activeHashes.has(hash)) this.#fingerprints.delete(hash);
|
|
553
|
-
const readable = [];
|
|
554
|
-
for (const [id, record] of images) {
|
|
555
|
-
let fingerprint = this.#fingerprints.get(record.rawHash);
|
|
556
|
-
if (!fingerprint) {
|
|
557
|
-
fingerprint = imageFingerprint(join(rawDir, record.raw), 8);
|
|
558
|
-
this.#fingerprints.set(record.rawHash, fingerprint);
|
|
559
|
-
}
|
|
560
|
-
try {
|
|
561
|
-
readable.push({
|
|
562
|
-
id,
|
|
563
|
-
fingerprint: await fingerprint
|
|
564
|
-
});
|
|
565
|
-
} catch {
|
|
566
|
-
this.#fingerprints.delete(record.rawHash);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
const duplicates = /* @__PURE__ */ new Map();
|
|
570
|
-
for (let leftIndex = 0; leftIndex < readable.length; leftIndex++) for (let rightIndex = leftIndex + 1; rightIndex < readable.length; rightIndex++) {
|
|
571
|
-
const left = readable[leftIndex];
|
|
572
|
-
const right = readable[rightIndex];
|
|
573
|
-
if (hammingDistance(left.fingerprint.hash, right.fingerprint.hash) > 5 || hammingDistance(left.fingerprint.alphaHash, right.fingerprint.alphaHash) > 5 || Math.abs(left.fingerprint.meanAlpha - right.fingerprint.meanAlpha) > .125 || colorDistance(left.fingerprint.meanColor, right.fingerprint.meanColor) > 32) continue;
|
|
574
|
-
const leftDuplicates = duplicates.get(left.id) ?? [];
|
|
575
|
-
leftDuplicates.push(right.id);
|
|
576
|
-
duplicates.set(left.id, leftDuplicates);
|
|
577
|
-
const rightDuplicates = duplicates.get(right.id) ?? [];
|
|
578
|
-
rightDuplicates.push(left.id);
|
|
579
|
-
duplicates.set(right.id, rightDuplicates);
|
|
580
|
-
}
|
|
581
|
-
return duplicates;
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
//#endregion
|
|
585
|
-
//#region src/lib/server/check.ts
|
|
586
|
-
/**
|
|
587
|
-
* The delivered-slot contract: a Package slot that is delivered (explicit member
|
|
588
|
-
* or in a delivered manifest's reference closure) but has no host-supplied bytes
|
|
589
|
-
* must be filled. A slot with an `importSource` is `slot-unmaterialized` (run
|
|
590
|
-
* import); a slot with nothing is `slot-unfilled`. Inert (undelivered) slots
|
|
591
|
-
* produce no finding.
|
|
592
|
-
*/
|
|
593
|
-
function packageSlotFindings(library, provenance, membership) {
|
|
594
|
-
const deliveringManifests = /* @__PURE__ */ new Map();
|
|
595
|
-
for (const [name, manifestMembership] of Object.entries(membership)) for (const assetId of manifestMembership.deliveredAssetIds) {
|
|
596
|
-
const names = deliveringManifests.get(assetId) ?? [];
|
|
597
|
-
names.push(name);
|
|
598
|
-
deliveringManifests.set(assetId, names);
|
|
599
|
-
}
|
|
600
|
-
const findings = [];
|
|
601
|
-
for (const [assetId, record] of Object.entries(library.assets)) {
|
|
602
|
-
if (record.raw !== void 0) continue;
|
|
603
|
-
const names = deliveringManifests.get(assetId);
|
|
604
|
-
if (!names || names.length === 0) continue;
|
|
605
|
-
const originRecord = provenance[assetId];
|
|
606
|
-
const origin = originRecord && originRecord.source !== "host" ? originRecord.origin : "a package";
|
|
607
|
-
const deliveredBy = [...names].sort(compareCodeUnits).map((name) => `"${name}"`).join(", ");
|
|
608
|
-
if (record.importSource !== void 0) findings.push({
|
|
609
|
-
kind: "slot-unmaterialized",
|
|
610
|
-
assetId,
|
|
611
|
-
message: `Slot "${assetId}" (from ${origin}) has an import source but no bytes yet — run import to fill it. Delivered by: ${deliveredBy}.`
|
|
612
|
-
});
|
|
613
|
-
else findings.push({
|
|
614
|
-
kind: "slot-unfilled",
|
|
615
|
-
assetId,
|
|
616
|
-
message: `Slot "${assetId}" (from ${origin}) has no bytes, import source, or host override. Delivered by: ${deliveredBy}.`
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
return findings;
|
|
620
|
-
}
|
|
621
214
|
//#endregion
|
|
622
215
|
//#region src/lib/server/raw-safety.ts
|
|
623
216
|
function rawSafetyIssueKey(issue) {
|
|
@@ -1678,6 +1271,110 @@ function pathsFromRoot(root, target, referencesByAsset, countMemo = /* @__PURE__
|
|
|
1678
1271
|
function usageSnapshotRevision(parts) {
|
|
1679
1272
|
return createHash("sha256").update(parts.join("\0")).digest("hex");
|
|
1680
1273
|
}
|
|
1274
|
+
async function imageFingerprint(filePath, hashSize) {
|
|
1275
|
+
const width = hashSize + 1;
|
|
1276
|
+
const pixels = await sharp(filePath).rotate().trim({
|
|
1277
|
+
background: {
|
|
1278
|
+
r: 0,
|
|
1279
|
+
g: 0,
|
|
1280
|
+
b: 0,
|
|
1281
|
+
alpha: 0
|
|
1282
|
+
},
|
|
1283
|
+
threshold: 0
|
|
1284
|
+
}).resize({
|
|
1285
|
+
width,
|
|
1286
|
+
height: hashSize,
|
|
1287
|
+
fit: "fill"
|
|
1288
|
+
}).ensureAlpha().toColourspace("srgb").raw().toBuffer();
|
|
1289
|
+
const hash = new Uint8Array(Math.ceil(hashSize * hashSize / 8));
|
|
1290
|
+
const alphaHash = new Uint8Array(hash.length);
|
|
1291
|
+
const colorTotals = [
|
|
1292
|
+
0,
|
|
1293
|
+
0,
|
|
1294
|
+
0
|
|
1295
|
+
];
|
|
1296
|
+
let alphaTotal = 0;
|
|
1297
|
+
let bit = 0;
|
|
1298
|
+
for (let row = 0; row < hashSize; row++) for (let column = 0; column < hashSize; column++) {
|
|
1299
|
+
const leftOffset = (row * width + column) * 4;
|
|
1300
|
+
const rightOffset = leftOffset + 4;
|
|
1301
|
+
const leftAlpha = pixels[leftOffset + 3] / 255;
|
|
1302
|
+
const rightAlpha = pixels[rightOffset + 3] / 255;
|
|
1303
|
+
if (visibleLuminance(pixels, leftOffset, leftAlpha) < visibleLuminance(pixels, rightOffset, rightAlpha)) hash[bit >> 3] |= 1 << 7 - (bit & 7);
|
|
1304
|
+
if (leftAlpha < rightAlpha) alphaHash[bit >> 3] |= 1 << 7 - (bit & 7);
|
|
1305
|
+
for (let channel = 0; channel < 3; channel++) colorTotals[channel] += pixels[leftOffset + channel] * leftAlpha;
|
|
1306
|
+
alphaTotal += leftAlpha;
|
|
1307
|
+
bit += 1;
|
|
1308
|
+
}
|
|
1309
|
+
const pixelCount = hashSize * hashSize;
|
|
1310
|
+
return {
|
|
1311
|
+
hash,
|
|
1312
|
+
alphaHash,
|
|
1313
|
+
meanColor: colorTotals.map((total) => alphaTotal === 0 ? 0 : total / alphaTotal),
|
|
1314
|
+
meanAlpha: alphaTotal / pixelCount
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
function visibleLuminance(pixels, offset, alpha) {
|
|
1318
|
+
return (pixels[offset] * .2126 + pixels[offset + 1] * .7152 + pixels[offset + 2] * .0722) * alpha + 127 * (1 - alpha);
|
|
1319
|
+
}
|
|
1320
|
+
function colorDistance(left, right) {
|
|
1321
|
+
return Math.hypot(left[0] - right[0], left[1] - right[1], left[2] - right[2]);
|
|
1322
|
+
}
|
|
1323
|
+
/** Count differing bits between two equally sized perceptual hashes. */
|
|
1324
|
+
function hammingDistance(left, right) {
|
|
1325
|
+
if (left.length !== right.length) throw new Error("Image hashes must have the same length.");
|
|
1326
|
+
let distance = 0;
|
|
1327
|
+
for (let index = 0; index < left.length; index++) {
|
|
1328
|
+
let value = left[index] ^ right[index];
|
|
1329
|
+
while (value !== 0) {
|
|
1330
|
+
value &= value - 1;
|
|
1331
|
+
distance += 1;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
return distance;
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* Stateful so the editor can reuse fingerprints by content hash between state
|
|
1338
|
+
* snapshots. Unreadable raws are omitted: duplicate detection is advisory and
|
|
1339
|
+
* must not hide the editor or replace the pipeline's canonical diagnostics.
|
|
1340
|
+
*/
|
|
1341
|
+
var ImageDuplicateDetector = class {
|
|
1342
|
+
#fingerprints = /* @__PURE__ */ new Map();
|
|
1343
|
+
async find(library, rawDir) {
|
|
1344
|
+
const images = Object.entries(library.assets).filter(([, record]) => record.type === "image").sort(([left], [right]) => compareCodeUnits(left, right));
|
|
1345
|
+
const activeHashes = new Set(images.map(([, record]) => record.rawHash));
|
|
1346
|
+
for (const hash of this.#fingerprints.keys()) if (!activeHashes.has(hash)) this.#fingerprints.delete(hash);
|
|
1347
|
+
const readable = [];
|
|
1348
|
+
for (const [id, record] of images) {
|
|
1349
|
+
let fingerprint = this.#fingerprints.get(record.rawHash);
|
|
1350
|
+
if (!fingerprint) {
|
|
1351
|
+
fingerprint = imageFingerprint(join(rawDir, record.raw), 8);
|
|
1352
|
+
this.#fingerprints.set(record.rawHash, fingerprint);
|
|
1353
|
+
}
|
|
1354
|
+
try {
|
|
1355
|
+
readable.push({
|
|
1356
|
+
id,
|
|
1357
|
+
fingerprint: await fingerprint
|
|
1358
|
+
});
|
|
1359
|
+
} catch {
|
|
1360
|
+
this.#fingerprints.delete(record.rawHash);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
1364
|
+
for (let leftIndex = 0; leftIndex < readable.length; leftIndex++) for (let rightIndex = leftIndex + 1; rightIndex < readable.length; rightIndex++) {
|
|
1365
|
+
const left = readable[leftIndex];
|
|
1366
|
+
const right = readable[rightIndex];
|
|
1367
|
+
if (hammingDistance(left.fingerprint.hash, right.fingerprint.hash) > 5 || hammingDistance(left.fingerprint.alphaHash, right.fingerprint.alphaHash) > 5 || Math.abs(left.fingerprint.meanAlpha - right.fingerprint.meanAlpha) > .125 || colorDistance(left.fingerprint.meanColor, right.fingerprint.meanColor) > 32) continue;
|
|
1368
|
+
const leftDuplicates = duplicates.get(left.id) ?? [];
|
|
1369
|
+
leftDuplicates.push(right.id);
|
|
1370
|
+
duplicates.set(left.id, leftDuplicates);
|
|
1371
|
+
const rightDuplicates = duplicates.get(right.id) ?? [];
|
|
1372
|
+
rightDuplicates.push(left.id);
|
|
1373
|
+
duplicates.set(right.id, rightDuplicates);
|
|
1374
|
+
}
|
|
1375
|
+
return duplicates;
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1681
1378
|
//#endregion
|
|
1682
1379
|
//#region src/lib/server/operations.ts
|
|
1683
1380
|
/**
|
|
@@ -2173,24 +1870,7 @@ var FundusOperations = class {
|
|
|
2173
1870
|
this.#validateImportedRaw(raw);
|
|
2174
1871
|
const fileName = raw.suggestedFileName ?? `${options.id}.${raw.extension}`;
|
|
2175
1872
|
const plugin = serverPluginForType(options.type, this.#registry);
|
|
2176
|
-
const
|
|
2177
|
-
if (packageBase && packageBase.type !== options.type) throw new SourceImportError("invalid-input", `Filling slot "${options.id}" requires the package type "${packageBase.type}", not "${options.type}".`);
|
|
2178
|
-
let slotOverride = {};
|
|
2179
|
-
if (packageBase) {
|
|
2180
|
-
const pixelRatio = figmaSlicePixelRatio(raw, options.type);
|
|
2181
|
-
if (pixelRatio !== void 0) slotOverride = mergeParameterPatch(slotOverride, { pixelRatio });
|
|
2182
|
-
if (options.parametersPatch !== void 0) slotOverride = mergeParameterPatch(slotOverride, options.parametersPatch);
|
|
2183
|
-
}
|
|
2184
|
-
const library = packageBase ? await this.#store.createAsset({
|
|
2185
|
-
fileName,
|
|
2186
|
-
bytes: raw.bytes,
|
|
2187
|
-
type: options.type,
|
|
2188
|
-
id: options.id,
|
|
2189
|
-
folder: options.folder,
|
|
2190
|
-
manifests: options.manifests,
|
|
2191
|
-
importSource: raw.importSource,
|
|
2192
|
-
parametersOverride: slotOverride
|
|
2193
|
-
}) : await this.#store.createAsset({
|
|
1873
|
+
const library = await this.#store.createAsset({
|
|
2194
1874
|
fileName,
|
|
2195
1875
|
bytes: raw.bytes,
|
|
2196
1876
|
type: options.type,
|
|
@@ -2225,8 +1905,7 @@ var FundusOperations = class {
|
|
|
2225
1905
|
const folder = normalizeFolderPath(options.folder ?? "");
|
|
2226
1906
|
if (folder !== "" && !library.folders.includes(folder)) throw new SourceImportError("invalid-input", `Unknown folder "${folder}".`);
|
|
2227
1907
|
if (options.manifests !== void 0 && (!Array.isArray(options.manifests) || options.manifests.some((value) => typeof value !== "string"))) throw new SourceImportError("invalid-input", "Import manifests must be an array of strings.");
|
|
2228
|
-
const
|
|
2229
|
-
for (const manifest of new Set(options.manifests ?? [])) if (!Object.hasOwn(validManifests, manifest)) throw new SourceImportError("invalid-input", `Unknown manifest "${manifest}".`);
|
|
1908
|
+
for (const manifest of new Set(options.manifests ?? [])) if (!Object.hasOwn(library.manifests, manifest)) throw new SourceImportError("invalid-input", `Unknown manifest "${manifest}".`);
|
|
2230
1909
|
}
|
|
2231
1910
|
#validateImportedRaw(raw, importerKind) {
|
|
2232
1911
|
if (!(raw.bytes instanceof Uint8Array) || !/^[a-z0-9]+$/.test(raw.extension)) throw new SourceImportError("invalid-response", "The source importer returned invalid raw data.");
|
|
@@ -2241,7 +1920,7 @@ var FundusOperations = class {
|
|
|
2241
1920
|
}
|
|
2242
1921
|
async #patchAsset(id, body) {
|
|
2243
1922
|
let library = await this.#store.read();
|
|
2244
|
-
this.#
|
|
1923
|
+
this.#requireAsset(library, id);
|
|
2245
1924
|
if (body.parameters !== void 0) library = await this.#store.updateParameters(id, body.parameters);
|
|
2246
1925
|
if (body.manifests !== void 0) {
|
|
2247
1926
|
if (!Array.isArray(body.manifests) || body.manifests.some((name) => typeof name !== "string")) throw new Error("\"manifests\" must be an array of manifest names.");
|
|
@@ -2443,13 +2122,11 @@ var FundusOperations = class {
|
|
|
2443
2122
|
async #runAfterMutation(library) {
|
|
2444
2123
|
const pipelineIssues = [];
|
|
2445
2124
|
const classification = await this.#classifyRawDirectory(library);
|
|
2446
|
-
const
|
|
2447
|
-
const materialized = materializeLibrary(effective);
|
|
2448
|
-
const ordinaryIssues = [...await this.#store.validate(library, { flatSpace: false }), ...this.#flatIssues(effective, provenance, mergeFindings)];
|
|
2125
|
+
const ordinaryIssues = await this.#store.validate(library);
|
|
2449
2126
|
const safetyIssues = this.#rawSafetyIssues(library, classification);
|
|
2450
2127
|
if (ordinaryIssues.length === 0 && safetyIssues.length === 0) try {
|
|
2451
|
-
const report = await processAssets(this.#config,
|
|
2452
|
-
await generateManifestModules(this.#config,
|
|
2128
|
+
const report = await processAssets(this.#config, library, this.#registry);
|
|
2129
|
+
await generateManifestModules(this.#config, library, report.proxies, this.#registry);
|
|
2453
2130
|
} catch (cause) {
|
|
2454
2131
|
pipelineIssues.push({ message: `Processing failed: ${cause instanceof Error ? cause.message : String(cause)}` });
|
|
2455
2132
|
}
|
|
@@ -2461,10 +2138,10 @@ var FundusOperations = class {
|
|
|
2461
2138
|
state: await this.#snapshotState(latestLibrary, latestClassification, pipelineIssues)
|
|
2462
2139
|
};
|
|
2463
2140
|
}
|
|
2464
|
-
async #buildState(
|
|
2465
|
-
const [gitBranch, changedGitAssets] = await Promise.all([currentGitBranch(this.#config.projectRoot), gitAssetChanges(this.#config.projectRoot, this.#config.library,
|
|
2141
|
+
async #buildState(library, issues, classification) {
|
|
2142
|
+
const [gitBranch, changedGitAssets] = await Promise.all([currentGitBranch(this.#config.projectRoot), gitAssetChanges(this.#config.projectRoot, this.#config.library, library)]);
|
|
2466
2143
|
const referencesByAsset = collectAllReferences(library, descriptorsByType(this.#registry));
|
|
2467
|
-
const duplicatesByAsset = await this.#duplicateDetector.find(
|
|
2144
|
+
const duplicatesByAsset = await this.#duplicateDetector.find(library, this.#config.rawDir);
|
|
2468
2145
|
const membershipByManifest = computeLibraryMembership(library, referencesByAsset);
|
|
2469
2146
|
const delivered = allDeliveredAssetIds(membershipByManifest);
|
|
2470
2147
|
const passiveManifestsByAsset = /* @__PURE__ */ new Map();
|
|
@@ -2485,24 +2162,17 @@ var FundusOperations = class {
|
|
|
2485
2162
|
});
|
|
2486
2163
|
incomingByAsset.set(reference.assetId, incoming);
|
|
2487
2164
|
}
|
|
2165
|
+
const requiredByAsset = /* @__PURE__ */ new Map();
|
|
2166
|
+
for (const dependency of this.#config.dependencies) requiredByAsset.set(dependency.id, [...dependency.sources]);
|
|
2488
2167
|
const assets = [];
|
|
2489
2168
|
for (const assetId of Object.keys(library.assets).sort(compareCodeUnits)) {
|
|
2490
2169
|
const record = library.assets[assetId];
|
|
2491
|
-
const prov = provenance[assetId] ?? { source: "host" };
|
|
2492
|
-
const origin = prov.source === "host" ? { kind: "host" } : prov.source === "package" ? {
|
|
2493
|
-
kind: "package",
|
|
2494
|
-
origin: prov.origin
|
|
2495
|
-
} : {
|
|
2496
|
-
kind: "override",
|
|
2497
|
-
origin: prov.origin
|
|
2498
|
-
};
|
|
2499
|
-
const isSlot = record.raw === void 0;
|
|
2500
2170
|
const warnings = [];
|
|
2501
2171
|
for (const issue of issues) if (issue.assetId === assetId) warnings.push(issue.message);
|
|
2502
|
-
if (record.manifests.length === 0 && !delivered.has(assetId)
|
|
2172
|
+
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.");
|
|
2503
2173
|
if (record.importSource && !this.#importers.has(record.importSource.importer)) warnings.push(`Importer "${record.importSource.importer}" is unavailable; the local raw file remains usable.`);
|
|
2504
2174
|
let proxy = null;
|
|
2505
|
-
if (delivered.has(assetId)
|
|
2175
|
+
if (delivered.has(assetId)) try {
|
|
2506
2176
|
const currentProxy = await readCurrentProxy(assetId, record, this.#config, this.#registry);
|
|
2507
2177
|
if (currentProxy) proxy = {
|
|
2508
2178
|
url: `/files/proxy/${encodeRelativePathForUrl(currentProxy.relativePath)}`,
|
|
@@ -2513,15 +2183,13 @@ var FundusOperations = class {
|
|
|
2513
2183
|
} catch (cause) {
|
|
2514
2184
|
warnings.push(cause instanceof Error ? cause.message : String(cause));
|
|
2515
2185
|
}
|
|
2516
|
-
const raw = record.raw ?? "";
|
|
2517
|
-
const rawHash = record.rawHash ?? "";
|
|
2518
2186
|
assets.push({
|
|
2519
2187
|
id: assetId,
|
|
2520
2188
|
type: record.type,
|
|
2521
|
-
raw,
|
|
2522
|
-
folder: folderOfRawPath(raw),
|
|
2523
|
-
rawUrl:
|
|
2524
|
-
rawHash,
|
|
2189
|
+
raw: record.raw,
|
|
2190
|
+
folder: folderOfRawPath(record.raw),
|
|
2191
|
+
rawUrl: `/files/raw/${encodeRelativePathForUrl(record.raw)}?v=${record.rawHash.slice(0, 12)}`,
|
|
2192
|
+
rawHash: record.rawHash,
|
|
2525
2193
|
gitStatus: changedGitAssets.get(assetId) ?? null,
|
|
2526
2194
|
importSource: record.importSource,
|
|
2527
2195
|
parameters: record.parameters,
|
|
@@ -2537,8 +2205,7 @@ var FundusOperations = class {
|
|
|
2537
2205
|
})),
|
|
2538
2206
|
incoming: incomingByAsset.get(assetId) ?? []
|
|
2539
2207
|
},
|
|
2540
|
-
|
|
2541
|
-
overridden: origin.kind === "override"
|
|
2208
|
+
requiredBy: requiredByAsset.get(assetId) ?? []
|
|
2542
2209
|
});
|
|
2543
2210
|
}
|
|
2544
2211
|
const proxySizeByAssetId = new Map(assets.filter((asset) => asset.proxy).map((asset) => [asset.id, asset.proxy?.fileSize ?? 0]));
|
|
@@ -2562,7 +2229,7 @@ var FundusOperations = class {
|
|
|
2562
2229
|
presetNames[type] = names;
|
|
2563
2230
|
presetCapabilities[type] = Object.fromEntries(names.map((name) => [name, plugin.presetCapabilities?.(presets[name]) ?? {}]));
|
|
2564
2231
|
}
|
|
2565
|
-
const rawIngestionQueue = this.#buildRawIngestionQueue(
|
|
2232
|
+
const rawIngestionQueue = this.#buildRawIngestionQueue(library, classification);
|
|
2566
2233
|
return {
|
|
2567
2234
|
gitBranch,
|
|
2568
2235
|
library,
|
|
@@ -2576,8 +2243,7 @@ var FundusOperations = class {
|
|
|
2576
2243
|
presetCapabilities,
|
|
2577
2244
|
manifestMemberships,
|
|
2578
2245
|
manifestDeliveredBytes,
|
|
2579
|
-
rawIngestionQueue
|
|
2580
|
-
packageOrigins: this.#config.packages.map((pkg) => pkg.origin).sort(compareCodeUnits)
|
|
2246
|
+
rawIngestionQueue
|
|
2581
2247
|
};
|
|
2582
2248
|
}
|
|
2583
2249
|
#compatibleTypes(path) {
|
|
@@ -2590,11 +2256,10 @@ var FundusOperations = class {
|
|
|
2590
2256
|
return rawSafetyIssues(library, classification, (path) => this.#compatibleTypes(path));
|
|
2591
2257
|
}
|
|
2592
2258
|
async #snapshotState(library, classification, extraIssues = []) {
|
|
2593
|
-
const { effective, provenance, mergeFindings } = this.#effectiveOf(library);
|
|
2594
2259
|
const issues = [
|
|
2595
|
-
...await this.#store.validate(library
|
|
2596
|
-
...this.#flatIssues(effective, provenance, mergeFindings),
|
|
2260
|
+
...await this.#store.validate(library),
|
|
2597
2261
|
...this.#rawSafetyIssues(library, classification),
|
|
2262
|
+
...validateDependencies(this.#config.dependencies, library),
|
|
2598
2263
|
...extraIssues
|
|
2599
2264
|
];
|
|
2600
2265
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2604,7 +2269,7 @@ var FundusOperations = class {
|
|
|
2604
2269
|
seen.add(key);
|
|
2605
2270
|
return true;
|
|
2606
2271
|
});
|
|
2607
|
-
return this.#buildState(library,
|
|
2272
|
+
return this.#buildState(library, uniqueIssues, classification);
|
|
2608
2273
|
}
|
|
2609
2274
|
#canAutoReconcile(classification, retry = false) {
|
|
2610
2275
|
return classification.complete && classification.blockers.length === 0 && classification.moves.length + classification.deletions.length > 0 && (!retry || classification.edited.length === 0 && classification.unmanaged.length === 0);
|
|
@@ -2693,59 +2358,6 @@ var FundusOperations = class {
|
|
|
2693
2358
|
#requireAsset(library, id) {
|
|
2694
2359
|
if (!Object.hasOwn(library.assets, id)) throw new Error(`Unknown asset "${id}".`);
|
|
2695
2360
|
}
|
|
2696
|
-
/** Merge the configured Packages under the host library (host wins). */
|
|
2697
|
-
#effectiveOf(host) {
|
|
2698
|
-
const { library, provenance, findings } = mergePackages(host, this.#config.packages ?? []);
|
|
2699
|
-
return {
|
|
2700
|
-
effective: library,
|
|
2701
|
-
provenance,
|
|
2702
|
-
mergeFindings: findings
|
|
2703
|
-
};
|
|
2704
|
-
}
|
|
2705
|
-
/**
|
|
2706
|
-
* The Package base record for `id` when `id` is a read-only Package asset the
|
|
2707
|
-
* host has not yet filled — i.e. this create is a *slot fill*. Returns null
|
|
2708
|
-
* for a plain new host asset.
|
|
2709
|
-
*/
|
|
2710
|
-
#packageBase(host, id) {
|
|
2711
|
-
if (Object.hasOwn(host.assets, id)) return null;
|
|
2712
|
-
const { effective, provenance } = this.#effectiveOf(host);
|
|
2713
|
-
if (provenance[id]?.source === "package") return { type: effective.assets[id].type };
|
|
2714
|
-
return null;
|
|
2715
|
-
}
|
|
2716
|
-
/**
|
|
2717
|
-
* Flat-space validation over the effective library: merge errors, id/type/
|
|
2718
|
-
* parameter/membership/appearance/reference checks, module collisions, and
|
|
2719
|
-
* delivered-slot findings. Disk/host checks stay in `store.validate(host,
|
|
2720
|
-
* { flatSpace: false })`.
|
|
2721
|
-
*/
|
|
2722
|
-
#flatIssues(effective, provenance, mergeFindings) {
|
|
2723
|
-
const membership = computeLibraryMembership(effective, collectAllReferences(effective, descriptorsByType(this.#registry)));
|
|
2724
|
-
return [
|
|
2725
|
-
...mergeFindings.filter((finding) => finding.kind !== "package-overridden").map((finding) => ({
|
|
2726
|
-
assetId: finding.assetId,
|
|
2727
|
-
message: finding.message
|
|
2728
|
-
})),
|
|
2729
|
-
...flatLibraryIssues(effective, descriptorsByType(this.#registry)),
|
|
2730
|
-
...manifestModuleCollisionIssues(effective.manifests),
|
|
2731
|
-
...packageSlotFindings(effective, provenance, membership).map((finding) => ({
|
|
2732
|
-
assetId: finding.assetId,
|
|
2733
|
-
message: finding.message
|
|
2734
|
-
}))
|
|
2735
|
-
];
|
|
2736
|
-
}
|
|
2737
|
-
/**
|
|
2738
|
-
* Whether an id is a read-only Package asset the host has not overridden.
|
|
2739
|
-
* Such ids can be filled/overridden (write a host record) but not mutated,
|
|
2740
|
-
* renamed, moved, or deleted in place.
|
|
2741
|
-
*/
|
|
2742
|
-
#assertHostAsset(host, id, action) {
|
|
2743
|
-
if (Object.hasOwn(host.assets, id)) return;
|
|
2744
|
-
const { provenance } = this.#effectiveOf(host);
|
|
2745
|
-
const prov = provenance[id];
|
|
2746
|
-
if (prov && prov.source !== "host") throw new Error(`Asset "${id}" is provided by package "${prov.origin}"; ${action} is not available. Override it by importing or uploading bytes with this id.`);
|
|
2747
|
-
throw new Error(`Unknown asset "${id}".`);
|
|
2748
|
-
}
|
|
2749
2361
|
/**
|
|
2750
2362
|
* Apply a CLI asset change to the store, validating the resulting library
|
|
2751
2363
|
* on an in-memory candidate first — nothing is persisted when the change
|
|
@@ -2794,4 +2406,4 @@ async function createFundusContext() {
|
|
|
2794
2406
|
}
|
|
2795
2407
|
|
|
2796
2408
|
export { getFundusContext as g, initializeFundusContext as i };
|
|
2797
|
-
//# sourceMappingURL=context.js-
|
|
2409
|
+
//# sourceMappingURL=context.js-BIgcUcEl.js.map
|