fundus 0.15.0 → 0.17.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.
Files changed (231) hide show
  1. package/README.md +158 -1
  2. package/build/client/_app/immutable/assets/2.X44Wyac-.css +1 -0
  3. package/build/client/_app/immutable/assets/2.X44Wyac-.css.br +0 -0
  4. package/build/client/_app/immutable/assets/2.X44Wyac-.css.gz +0 -0
  5. package/build/client/_app/immutable/assets/{3.C6xo25uI.css → 3.66PJT3JC.css} +1 -1
  6. package/build/client/_app/immutable/assets/3.66PJT3JC.css.br +0 -0
  7. package/build/client/_app/immutable/assets/3.66PJT3JC.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/{AssetSourceMenu.IjDdjx3o.css → AssetSourceMenu.Buj2UxUg.css} +1 -1
  9. package/build/client/_app/immutable/assets/AssetSourceMenu.Buj2UxUg.css.br +0 -0
  10. package/build/client/_app/immutable/assets/AssetSourceMenu.Buj2UxUg.css.gz +0 -0
  11. package/build/client/_app/immutable/chunks/{VX-Uq_b9.js → 5fq8ySvR.js} +1 -1
  12. package/build/client/_app/immutable/chunks/5fq8ySvR.js.br +0 -0
  13. package/build/client/_app/immutable/chunks/5fq8ySvR.js.gz +0 -0
  14. package/build/client/_app/immutable/chunks/BcVZHIBD.js +1 -0
  15. package/build/client/_app/immutable/chunks/BcVZHIBD.js.br +0 -0
  16. package/build/client/_app/immutable/chunks/BcVZHIBD.js.gz +0 -0
  17. package/build/client/_app/immutable/chunks/DXiUbZ9S.js +2 -0
  18. package/build/client/_app/immutable/chunks/DXiUbZ9S.js.br +0 -0
  19. package/build/client/_app/immutable/chunks/DXiUbZ9S.js.gz +0 -0
  20. package/build/client/_app/immutable/chunks/H5KnxQLQ.js +108 -0
  21. package/build/client/_app/immutable/chunks/H5KnxQLQ.js.br +0 -0
  22. package/build/client/_app/immutable/chunks/H5KnxQLQ.js.gz +0 -0
  23. package/build/client/_app/immutable/chunks/{-8MKoIIe.js → jEVVu5G9.js} +1 -1
  24. package/build/client/_app/immutable/chunks/jEVVu5G9.js.br +0 -0
  25. package/build/client/_app/immutable/chunks/jEVVu5G9.js.gz +0 -0
  26. package/build/client/_app/immutable/entry/{app.CJpgt8H5.js → app.Z9n2k33I.js} +2 -2
  27. package/build/client/_app/immutable/entry/app.Z9n2k33I.js.br +0 -0
  28. package/build/client/_app/immutable/entry/app.Z9n2k33I.js.gz +0 -0
  29. package/build/client/_app/immutable/entry/start.DGo1uhI2.js +1 -0
  30. package/build/client/_app/immutable/entry/start.DGo1uhI2.js.br +0 -0
  31. package/build/client/_app/immutable/entry/start.DGo1uhI2.js.gz +0 -0
  32. package/build/client/_app/immutable/nodes/0.DiZpkhxP.js +1 -0
  33. package/build/client/_app/immutable/nodes/0.DiZpkhxP.js.br +0 -0
  34. package/build/client/_app/immutable/nodes/0.DiZpkhxP.js.gz +0 -0
  35. package/build/client/_app/immutable/nodes/{1.D6OhgXcC.js → 1.rgoSlmPu.js} +1 -1
  36. package/build/client/_app/immutable/nodes/1.rgoSlmPu.js.br +2 -0
  37. package/build/client/_app/immutable/nodes/1.rgoSlmPu.js.gz +0 -0
  38. package/build/client/_app/immutable/nodes/2.Dzp3a3be.js +3 -0
  39. package/build/client/_app/immutable/nodes/2.Dzp3a3be.js.br +0 -0
  40. package/build/client/_app/immutable/nodes/2.Dzp3a3be.js.gz +0 -0
  41. package/build/client/_app/immutable/nodes/3.mSsa2TDI.js +1 -0
  42. package/build/client/_app/immutable/nodes/3.mSsa2TDI.js.br +0 -0
  43. package/build/client/_app/immutable/nodes/3.mSsa2TDI.js.gz +0 -0
  44. package/build/client/_app/immutable/nodes/4.4oRGPYr4.js +2 -0
  45. package/build/client/_app/immutable/nodes/4.4oRGPYr4.js.br +0 -0
  46. package/build/client/_app/immutable/nodes/4.4oRGPYr4.js.gz +0 -0
  47. package/build/client/_app/version.json +1 -1
  48. package/build/client/_app/version.json.br +0 -0
  49. package/build/client/_app/version.json.gz +0 -0
  50. package/build/handler.js +8 -7
  51. package/build/handler.js.map +1 -1
  52. package/build/index.js +8 -7
  53. package/build/index.js.map +1 -1
  54. package/build/server/chunks/chunks/{context.js-CVuTSPjH.js → context.js-Dh0ibRIF.js} +818 -136
  55. package/build/server/chunks/chunks/context.js-Dh0ibRIF.js.map +1 -0
  56. package/build/server/chunks/chunks/{contract.js-itFN0Gon.js → contract.js-_LTMZBo2.js} +156 -58
  57. package/build/server/chunks/chunks/contract.js-_LTMZBo2.js.map +1 -0
  58. package/build/server/chunks/chunks/{core.js-CABVXpby.js → core.js-CTyKR4bu.js} +145 -156
  59. package/build/server/chunks/chunks/core.js-CTyKR4bu.js.map +1 -0
  60. package/build/server/chunks/chunks/{exports.js-VRV1_yEb.js → exports.js-gz2aNXzz.js} +2 -2
  61. package/build/server/chunks/chunks/{exports.js-VRV1_yEb.js.map → exports.js-gz2aNXzz.js.map} +1 -1
  62. package/build/server/chunks/chunks/{http.js-ChQRRKfZ.js → http.js-BiqUcAuu.js} +3 -2
  63. package/build/server/chunks/chunks/http.js-BiqUcAuu.js.map +1 -0
  64. package/build/server/chunks/chunks/{internal.js-qXxDe7VN.js → internal.js-DoH0cN5N.js} +5 -3
  65. package/build/server/chunks/chunks/internal.js-DoH0cN5N.js.map +1 -0
  66. package/build/server/chunks/chunks/internal2.js-BlXt2rfE.js.map +1 -1
  67. package/build/server/chunks/chunks/{manifest-membership.js-BnSECWpJ.js → manifest-membership.js-at1ixQdW.js} +10 -3
  68. package/build/server/chunks/chunks/manifest-membership.js-at1ixQdW.js.map +1 -0
  69. package/build/server/chunks/chunks/{raw-reconciliation.js-ZEOCk_jA.js → raw-reconciliation.js-CUH8IIJx.js} +3 -3
  70. package/build/server/chunks/chunks/raw-reconciliation.js-CUH8IIJx.js.map +1 -0
  71. package/build/server/chunks/chunks/{raw-reconciliation2.js-CscuoBC2.js → raw-reconciliation2.js-z4xl5zw2.js} +2 -2
  72. package/build/server/chunks/chunks/{raw-reconciliation2.js-CscuoBC2.js.map → raw-reconciliation2.js-z4xl5zw2.js.map} +1 -1
  73. package/build/server/chunks/chunks/{shared.js-DnEOHbgT.js → shared.js-CI-ZkPQn.js} +2 -2
  74. package/build/server/chunks/chunks/{shared.js-DnEOHbgT.js.map → shared.js-CI-ZkPQn.js.map} +1 -1
  75. package/build/server/chunks/chunks/{utils.js-lNH0hKSx.js → utils.js-gXYLxRG9.js} +3 -3
  76. package/build/server/chunks/chunks/{utils.js-lNH0hKSx.js.map → utils.js-gXYLxRG9.js.map} +1 -1
  77. package/build/server/chunks/entries/endpoints/api/_...path_/{_server.ts.js-z988EDp2.js → _server.ts.js-CdDjuW0r.js} +6 -6
  78. package/build/server/chunks/entries/endpoints/api/_...path_/{_server.ts.js-z988EDp2.js.map → _server.ts.js-CdDjuW0r.js.map} +1 -1
  79. package/build/server/chunks/entries/endpoints/api/assets/_id_/{_server.ts.js-C68ru6gS.js → _server.ts.js-OWM1eORG.js} +9 -7
  80. package/build/server/chunks/entries/endpoints/api/assets/_id_/{_server.ts.js-C68ru6gS.js.map → _server.ts.js-OWM1eORG.js.map} +1 -1
  81. package/build/server/chunks/entries/endpoints/api/assets/_id_/raw/{_server.ts.js-C0tk6RFk.js → _server.ts.js-DoG-7ZpZ.js} +9 -7
  82. package/build/server/chunks/entries/endpoints/api/assets/_id_/raw/{_server.ts.js-C0tk6RFk.js.map → _server.ts.js-DoG-7ZpZ.js.map} +1 -1
  83. package/build/server/chunks/entries/endpoints/api/assets/_id_/reimport/{_server.ts.js-I03oZuo8.js → _server.ts.js-CAWjVeGd.js} +9 -7
  84. package/build/server/chunks/entries/endpoints/api/assets/_id_/reimport/{_server.ts.js-I03oZuo8.js.map → _server.ts.js-CAWjVeGd.js.map} +1 -1
  85. package/build/server/chunks/entries/endpoints/api/assets/_id_/retag/_server.ts.js-CqS4aALY.js +38 -0
  86. package/build/server/chunks/entries/endpoints/api/assets/_id_/retag/_server.ts.js-CqS4aALY.js.map +1 -0
  87. package/build/server/chunks/entries/endpoints/api/assets/{_server.ts.js-BsQB8YDq.js → _server.ts.js-Bo_EsYXJ.js} +9 -7
  88. package/build/server/chunks/entries/endpoints/api/assets/{_server.ts.js-BsQB8YDq.js.map → _server.ts.js-Bo_EsYXJ.js.map} +1 -1
  89. package/build/server/chunks/entries/endpoints/api/assets/delete/{_server.ts.js-CJuFE6Fb.js → _server.ts.js-DW4w0XAr.js} +9 -7
  90. package/build/server/chunks/entries/endpoints/api/assets/delete/{_server.ts.js-CJuFE6Fb.js.map → _server.ts.js-DW4w0XAr.js.map} +1 -1
  91. package/build/server/chunks/entries/endpoints/api/assets/move/{_server.ts.js-DuOZRRiA.js → _server.ts.js-_MiNPnSy.js} +9 -7
  92. package/build/server/chunks/entries/endpoints/api/assets/move/{_server.ts.js-DuOZRRiA.js.map → _server.ts.js-_MiNPnSy.js.map} +1 -1
  93. package/build/server/chunks/entries/endpoints/api/folders/_path_/{_server.ts.js-DGzYpQbv.js → _server.ts.js-DwbrQnBc.js} +9 -7
  94. package/build/server/chunks/entries/endpoints/api/folders/_path_/{_server.ts.js-DGzYpQbv.js.map → _server.ts.js-DwbrQnBc.js.map} +1 -1
  95. package/build/server/chunks/entries/endpoints/api/folders/{_server.ts.js-B045QoCA.js → _server.ts.js-CEnHQf3b.js} +9 -7
  96. package/build/server/chunks/entries/endpoints/api/folders/{_server.ts.js-B045QoCA.js.map → _server.ts.js-CEnHQf3b.js.map} +1 -1
  97. package/build/server/chunks/entries/endpoints/api/imports/{_server.ts.js-HUkVdz19.js → _server.ts.js-BZDuJZtF.js} +9 -7
  98. package/build/server/chunks/entries/endpoints/api/imports/{_server.ts.js-HUkVdz19.js.map → _server.ts.js-BZDuJZtF.js.map} +1 -1
  99. package/build/server/chunks/entries/endpoints/api/manifests/_name_/{_server.ts.js-ry509mom.js → _server.ts.js-DRgdpKKd.js} +9 -7
  100. package/build/server/chunks/entries/endpoints/api/manifests/_name_/{_server.ts.js-ry509mom.js.map → _server.ts.js-DRgdpKKd.js.map} +1 -1
  101. package/build/server/chunks/entries/endpoints/api/manifests/{_server.ts.js-DU0J7U25.js → _server.ts.js-CP5QyIhz.js} +9 -7
  102. package/build/server/chunks/entries/endpoints/api/manifests/{_server.ts.js-DU0J7U25.js.map → _server.ts.js-CP5QyIhz.js.map} +1 -1
  103. package/build/server/chunks/entries/endpoints/api/raw/adopt/{_server.ts.js-AZIV2PIn.js → _server.ts.js-BKEvt065.js} +9 -7
  104. package/build/server/chunks/entries/endpoints/api/raw/adopt/{_server.ts.js-AZIV2PIn.js.map → _server.ts.js-BKEvt065.js.map} +1 -1
  105. package/build/server/chunks/entries/endpoints/api/raw/edited/accept/{_server.ts.js-CDL0hCfM.js → _server.ts.js-C_zihkDS.js} +9 -7
  106. package/build/server/chunks/entries/endpoints/api/raw/edited/accept/{_server.ts.js-CDL0hCfM.js.map → _server.ts.js-C_zihkDS.js.map} +1 -1
  107. package/build/server/chunks/entries/endpoints/api/raw/edited/dismiss/{_server.ts.js-B13c17fq.js → _server.ts.js-watkBmy6.js} +9 -7
  108. package/build/server/chunks/entries/endpoints/api/raw/edited/dismiss/{_server.ts.js-B13c17fq.js.map → _server.ts.js-watkBmy6.js.map} +1 -1
  109. package/build/server/chunks/entries/endpoints/api/reconcile/{_server.ts.js-BCxjyAGC.js → _server.ts.js-YtumLIou.js} +9 -7
  110. package/build/server/chunks/entries/endpoints/api/reconcile/{_server.ts.js-BCxjyAGC.js.map → _server.ts.js-YtumLIou.js.map} +1 -1
  111. package/build/server/chunks/entries/endpoints/api/reveal/{_server.ts.js-BveeMZc2.js → _server.ts.js-Dkouuu-M.js} +9 -7
  112. package/build/server/chunks/entries/endpoints/api/reveal/{_server.ts.js-BveeMZc2.js.map → _server.ts.js-Dkouuu-M.js.map} +1 -1
  113. package/build/server/chunks/entries/endpoints/api/state/{_server.ts.js-BZjTd9a0.js → _server.ts.js-DwsEQeuf.js} +9 -7
  114. package/build/server/chunks/entries/endpoints/api/state/{_server.ts.js-BZjTd9a0.js.map → _server.ts.js-DwsEQeuf.js.map} +1 -1
  115. package/build/server/chunks/entries/endpoints/api/usage/{_server.ts.js-BbTfPvC9.js → _server.ts.js-CdQxfhV3.js} +9 -7
  116. package/build/server/chunks/entries/endpoints/api/usage/{_server.ts.js-BbTfPvC9.js.map → _server.ts.js-CdQxfhV3.js.map} +1 -1
  117. package/build/server/chunks/entries/endpoints/files/_...path_/{_server.ts.js-8VPJMLBk.js → _server.ts.js-DDdMocWj.js} +6 -6
  118. package/build/server/chunks/entries/endpoints/files/_...path_/{_server.ts.js-8VPJMLBk.js.map → _server.ts.js-DDdMocWj.js.map} +1 -1
  119. package/build/server/chunks/entries/endpoints/files/proxy/_...path_/{_server.ts.js-BqR2J2sB.js → _server.ts.js-DbzjbH32.js} +9 -7
  120. package/build/server/chunks/entries/endpoints/files/proxy/_...path_/{_server.ts.js-BqR2J2sB.js.map → _server.ts.js-DbzjbH32.js.map} +1 -1
  121. package/build/server/chunks/entries/endpoints/files/raw/_...path_/{_server.ts.js-DbA28dCY.js → _server.ts.js-K_JbXZsU.js} +9 -7
  122. package/build/server/chunks/entries/endpoints/files/raw/_...path_/{_server.ts.js-DbA28dCY.js.map → _server.ts.js-K_JbXZsU.js.map} +1 -1
  123. package/build/server/chunks/entries/{hooks.server.js-9PBc_3Jh.js → hooks.server.js-DgZAVFbQ.js} +8 -6
  124. package/build/server/chunks/entries/{hooks.server.js-9PBc_3Jh.js.map → hooks.server.js-DgZAVFbQ.js.map} +1 -1
  125. package/build/server/chunks/{handler-BHt7eOOX.js → handler-CFkKak8t.js} +5 -5
  126. package/build/server/chunks/{handler-BHt7eOOX.js.map → handler-CFkKak8t.js.map} +1 -1
  127. package/build/server/chunks/{index.js-DcVaL-Ja.js → index.js-B1IroJH5.js} +5 -5
  128. package/build/server/chunks/{index.js-DcVaL-Ja.js.map → index.js-B1IroJH5.js.map} +1 -1
  129. package/build/server/chunks/{manifest.js-DgjSU4wg.js → manifest.js-DNDBsrEU.js} +36 -29
  130. package/build/server/chunks/manifest.js-DNDBsrEU.js.map +1 -0
  131. package/build/server/chunks/nodes/{0.js-BgTB-_Zt.js → 0.js-CZ3mZUZl.js} +2 -2
  132. package/build/server/chunks/nodes/{0.js-BgTB-_Zt.js.map → 0.js-CZ3mZUZl.js.map} +1 -1
  133. package/build/server/chunks/nodes/1.js-BmDzLKxV.js +7 -0
  134. package/build/server/chunks/nodes/{1.js-DNabcIPP.js.map → 1.js-BmDzLKxV.js.map} +1 -1
  135. package/build/server/chunks/nodes/2.js-Dirm-bY-.js +7 -0
  136. package/build/server/chunks/nodes/2.js-Dirm-bY-.js.map +1 -0
  137. package/build/server/chunks/nodes/3.js-DOqHmSWt.js +7 -0
  138. package/build/server/chunks/nodes/3.js-DOqHmSWt.js.map +1 -0
  139. package/build/server/chunks/nodes/4.js-C8pmF8IP.js +7 -0
  140. package/build/server/chunks/nodes/{4.js-BE7ZG9vA.js.map → 4.js-C8pmF8IP.js.map} +1 -1
  141. package/dist/config.d.ts +3 -3
  142. package/dist/config.js +2 -2
  143. package/dist/core/api-types.d.ts +24 -3
  144. package/dist/core/config.d.ts +84 -0
  145. package/dist/core/config.js +9 -0
  146. package/dist/core/index.d.ts +10 -5
  147. package/dist/core/index.js +5 -2
  148. package/dist/core/ingest.d.ts +1 -6
  149. package/dist/core/ingest.js +4 -21
  150. package/dist/core/library-validation.d.ts +13 -0
  151. package/dist/core/library-validation.js +48 -0
  152. package/dist/core/library.d.ts +19 -0
  153. package/dist/core/library.js +4 -4
  154. package/dist/core/manifest-membership.d.ts +2 -2
  155. package/dist/core/package-declaration.d.ts +43 -0
  156. package/dist/core/package-declaration.js +80 -0
  157. package/dist/core/package-merge.d.ts +65 -0
  158. package/dist/core/package-merge.js +173 -0
  159. package/dist/core/propose-asset-id.d.ts +10 -0
  160. package/dist/core/propose-asset-id.js +25 -0
  161. package/dist/core/reference-graph.d.ts +3 -3
  162. package/dist/server/build.js +26 -11
  163. package/dist/server/check.d.ts +13 -3
  164. package/dist/server/check.js +112 -24
  165. package/dist/server/cli-commands.d.ts +2 -2
  166. package/dist/server/cli-commands.js +213 -29
  167. package/dist/server/codegen.d.ts +3 -1
  168. package/dist/server/codegen.js +18 -0
  169. package/dist/server/config-loader.d.ts +36 -1
  170. package/dist/server/config-loader.js +190 -4
  171. package/dist/server/http.js +1 -0
  172. package/dist/server/importers/figma.d.ts +26 -3
  173. package/dist/server/importers/figma.js +114 -1
  174. package/dist/server/library-store.d.ts +20 -1
  175. package/dist/server/library-store.js +121 -60
  176. package/dist/server/operations.d.ts +12 -0
  177. package/dist/server/operations.js +283 -48
  178. package/package.json +1 -1
  179. package/build/client/_app/immutable/assets/2.C-1MfvLQ.css +0 -1
  180. package/build/client/_app/immutable/assets/2.C-1MfvLQ.css.br +0 -0
  181. package/build/client/_app/immutable/assets/2.C-1MfvLQ.css.gz +0 -0
  182. package/build/client/_app/immutable/assets/3.C6xo25uI.css.br +0 -0
  183. package/build/client/_app/immutable/assets/3.C6xo25uI.css.gz +0 -0
  184. package/build/client/_app/immutable/assets/AssetSourceMenu.IjDdjx3o.css.br +0 -0
  185. package/build/client/_app/immutable/assets/AssetSourceMenu.IjDdjx3o.css.gz +0 -0
  186. package/build/client/_app/immutable/chunks/-8MKoIIe.js.br +0 -0
  187. package/build/client/_app/immutable/chunks/-8MKoIIe.js.gz +0 -0
  188. package/build/client/_app/immutable/chunks/D1wFzWdi.js +0 -108
  189. package/build/client/_app/immutable/chunks/D1wFzWdi.js.br +0 -0
  190. package/build/client/_app/immutable/chunks/D1wFzWdi.js.gz +0 -0
  191. package/build/client/_app/immutable/chunks/DmQb0SN8.js +0 -2
  192. package/build/client/_app/immutable/chunks/DmQb0SN8.js.br +0 -0
  193. package/build/client/_app/immutable/chunks/DmQb0SN8.js.gz +0 -0
  194. package/build/client/_app/immutable/chunks/N1X6Qzcl.js +0 -1
  195. package/build/client/_app/immutable/chunks/N1X6Qzcl.js.br +0 -0
  196. package/build/client/_app/immutable/chunks/N1X6Qzcl.js.gz +0 -0
  197. package/build/client/_app/immutable/chunks/VX-Uq_b9.js.br +0 -1
  198. package/build/client/_app/immutable/chunks/VX-Uq_b9.js.gz +0 -0
  199. package/build/client/_app/immutable/entry/app.CJpgt8H5.js.br +0 -0
  200. package/build/client/_app/immutable/entry/app.CJpgt8H5.js.gz +0 -0
  201. package/build/client/_app/immutable/entry/start.DToPJitz.js +0 -1
  202. package/build/client/_app/immutable/entry/start.DToPJitz.js.br +0 -1
  203. package/build/client/_app/immutable/entry/start.DToPJitz.js.gz +0 -0
  204. package/build/client/_app/immutable/nodes/0.Co4Hh8k6.js +0 -1
  205. package/build/client/_app/immutable/nodes/0.Co4Hh8k6.js.br +0 -0
  206. package/build/client/_app/immutable/nodes/0.Co4Hh8k6.js.gz +0 -0
  207. package/build/client/_app/immutable/nodes/1.D6OhgXcC.js.br +0 -3
  208. package/build/client/_app/immutable/nodes/1.D6OhgXcC.js.gz +0 -0
  209. package/build/client/_app/immutable/nodes/2.sBDjyIQu.js +0 -3
  210. package/build/client/_app/immutable/nodes/2.sBDjyIQu.js.br +0 -0
  211. package/build/client/_app/immutable/nodes/2.sBDjyIQu.js.gz +0 -0
  212. package/build/client/_app/immutable/nodes/3.DDt73kMC.js +0 -1
  213. package/build/client/_app/immutable/nodes/3.DDt73kMC.js.br +0 -0
  214. package/build/client/_app/immutable/nodes/3.DDt73kMC.js.gz +0 -0
  215. package/build/client/_app/immutable/nodes/4.FsXXhVSP.js +0 -2
  216. package/build/client/_app/immutable/nodes/4.FsXXhVSP.js.br +0 -0
  217. package/build/client/_app/immutable/nodes/4.FsXXhVSP.js.gz +0 -0
  218. package/build/server/chunks/chunks/context.js-CVuTSPjH.js.map +0 -1
  219. package/build/server/chunks/chunks/contract.js-itFN0Gon.js.map +0 -1
  220. package/build/server/chunks/chunks/core.js-CABVXpby.js.map +0 -1
  221. package/build/server/chunks/chunks/http.js-ChQRRKfZ.js.map +0 -1
  222. package/build/server/chunks/chunks/internal.js-qXxDe7VN.js.map +0 -1
  223. package/build/server/chunks/chunks/manifest-membership.js-BnSECWpJ.js.map +0 -1
  224. package/build/server/chunks/chunks/raw-reconciliation.js-ZEOCk_jA.js.map +0 -1
  225. package/build/server/chunks/manifest.js-DgjSU4wg.js.map +0 -1
  226. package/build/server/chunks/nodes/1.js-DNabcIPP.js +0 -7
  227. package/build/server/chunks/nodes/2.js-CcVBvLSR.js +0 -7
  228. package/build/server/chunks/nodes/2.js-CcVBvLSR.js.map +0 -1
  229. package/build/server/chunks/nodes/3.js-DreG5rig.js +0 -7
  230. package/build/server/chunks/nodes/3.js-DreG5rig.js.map +0 -1
  231. package/build/server/chunks/nodes/4.js-BE7ZG9vA.js +0 -7
@@ -7,9 +7,10 @@
7
7
  */
8
8
  import { readFile } from 'node:fs/promises';
9
9
  import { join } from 'node:path';
10
- import { assetIdError, allDeliveredAssetIds, canonicalizeParameters, collectAllReferences, compareCodeUnits, computeLibraryMembership, folderOfRawPath, normalizeFolderPath, parentFolderPath, portableFolderPathKey, proposeAssetId, rawFileNameOfPath, serializeLibrary, typesForFileName } from '../core/index.js';
10
+ import { assetIdError, allDeliveredAssetIds, canonicalizeParameters, collectAllReferences, compareCodeUnits, computeLibraryMembership, flatLibraryIssues, folderOfRawPath, materializeLibrary, mergePackages, normalizeFolderPath, parentFolderPath, portableFolderPathKey, proposeAssetId, rawFileNameOfPath, serializeLibrary, typesForFileName } from '../core/index.js';
11
11
  import { LibraryStore } from './library-store.js';
12
- import { generateManifestModules, locateGeneratedAssetDeclaration, manifestModuleFileName } from './codegen.js';
12
+ import { generateManifestModules, locateGeneratedAssetDeclaration, manifestModuleCollisionIssues, manifestModuleFileName } from './codegen.js';
13
+ import { packageSlotFindings } from './check.js';
13
14
  import { descriptorsByType, serverPluginForType, serverPluginsByType } from './plugins.js';
14
15
  import { processAssets, readCurrentProxy } from './processing/processor.js';
15
16
  import { encodeRelativePathForUrl } from './folder-filesystem.js';
@@ -52,6 +53,18 @@ function figmaSlicePixelRatio(raw, type) {
52
53
  return undefined;
53
54
  return validateFigmaSourceParameters(raw.importSource.parameters).scale;
54
55
  }
56
+ /**
57
+ * The Fundus tag of a Figma tag-mode import source, else null. In tag mode the
58
+ * tag IS the asset id, so this is the single seam that ties provenance to
59
+ * identity — used to assert id equality on import/reimport and to forbid
60
+ * renaming a tag-referenced asset. Only Figma sources are inspected.
61
+ */
62
+ function figmaTagOf(importSource) {
63
+ if (importSource?.importer !== 'figma')
64
+ return null;
65
+ const params = validateFigmaSourceParameters(importSource.parameters);
66
+ return params.mode === 'tag' ? params.fundusTag : null;
67
+ }
55
68
  export class FundusOperations {
56
69
  #config;
57
70
  #registry;
@@ -358,6 +371,10 @@ export class FundusOperations {
358
371
  });
359
372
  return this.#enqueueOperation(async () => {
360
373
  this.#validateImportedRaw(raw, options.importer);
374
+ const tag = figmaTagOf(raw.importSource);
375
+ if (tag !== null && tag !== options.id) {
376
+ throw new SourceImportError('invalid-input', `A Figma tag import must use its tag as the asset id: the tag is "${tag}", not "${options.id}".`);
377
+ }
361
378
  return this.#createImportedAsset(raw, options);
362
379
  });
363
380
  }
@@ -398,6 +415,10 @@ export class FundusOperations {
398
415
  }
399
416
  return this.#enqueueOperation(async () => {
400
417
  this.#validateImportedRaw(raw, snapshot.importer.kind);
418
+ const tag = figmaTagOf(raw.importSource);
419
+ if (tag !== null && tag !== id) {
420
+ throw new SourceImportError('invalid-input', `A Figma tag reimport may not retarget asset "${id}" to a different tag "${tag}".`);
421
+ }
401
422
  const plugin = serverPluginForType(snapshot.expected.type, this.#registry);
402
423
  if (!plugin.descriptor.accepts.includes(raw.extension)) {
403
424
  throw new SourceImportError('invalid-response', `The ${snapshot.expected.type} type does not accept ".${raw.extension}" files.`);
@@ -457,6 +478,10 @@ export class FundusOperations {
457
478
  const importSource = raw.importSource;
458
479
  return this.#enqueueOperation(async () => {
459
480
  this.#validateImportedRaw(raw, preflight.importer.kind);
481
+ const tag = figmaTagOf(importSource);
482
+ if (tag !== null && tag !== id) {
483
+ throw new SourceImportError('invalid-input', `A Figma tag replacement must use its own tag as the asset id: the tag is "${tag}", not "${id}".`);
484
+ }
460
485
  const plugin = serverPluginForType(preflight.expected.type, this.#registry);
461
486
  if (!plugin.descriptor.accepts.includes(raw.extension)) {
462
487
  throw new SourceImportError('invalid-response', `The ${preflight.expected.type} type does not accept ".${raw.extension}" files.`);
@@ -485,40 +510,155 @@ export class FundusOperations {
485
510
  }
486
511
  });
487
512
  }
513
+ /**
514
+ * Edit a Figma tag asset's tag, fileKey, and/or scale in place. Because in tag
515
+ * mode the tag IS the asset id, changing the tag renames the asset (moves the
516
+ * library key); changing only fileKey/scale is an in-place re-point. Mirrors
517
+ * `reimportAsset`'s three phases: preflight in the queue, materialize outside
518
+ * it, then commit atomically through `store.repointTagAsset`.
519
+ */
520
+ async retagFigmaAsset(id, input) {
521
+ const snapshot = await this.#enqueueOperation(async () => {
522
+ const library = await this.#store.read();
523
+ this.#requireAsset(library, id);
524
+ const record = library.assets[id];
525
+ const currentTag = figmaTagOf(record.importSource);
526
+ if (currentTag === null || !record.importSource) {
527
+ throw new SourceImportError('invalid-input', `Asset "${id}" is not a Figma tag import.`);
528
+ }
529
+ const current = validateFigmaSourceParameters(record.importSource.parameters);
530
+ const newTag = input.tag ?? currentTag;
531
+ const fileKey = input.fileKey ?? current.fileKey;
532
+ const scale = input.scale ?? current.scale;
533
+ if (newTag !== id) {
534
+ const problem = assetIdError(newTag);
535
+ if (problem)
536
+ throw new SourceImportError('invalid-input', problem);
537
+ if (Object.hasOwn(library.assets, newTag)) {
538
+ throw new SourceImportError('invalid-input', `An asset with id "${newTag}" already exists.`);
539
+ }
540
+ // A tag change renames the asset; reject one that would dangle references.
541
+ const candidate = structuredClone(library);
542
+ candidate.assets[newTag] = candidate.assets[id];
543
+ delete candidate.assets[id];
544
+ await this.#assertNoIntroducedIssues(library, candidate);
545
+ }
546
+ try {
547
+ await verifyStableRawFile(join(this.#config.rawDir, record.raw), record.rawHash);
548
+ }
549
+ catch {
550
+ throw new SourceImportError('stale-import', 'The local raw file changed. Apply or discard that edit before retagging.');
551
+ }
552
+ const importer = this.#importers.require('figma');
553
+ return {
554
+ importer,
555
+ input: importer.validateInput({ mode: 'tag', tag: newTag, fileKey, scale, format: 'png' }),
556
+ newTag,
557
+ expected: {
558
+ raw: record.raw,
559
+ rawHash: record.rawHash,
560
+ type: record.type,
561
+ canonicalSource: canonicalizeParameters(record.importSource)
562
+ }
563
+ };
564
+ });
565
+ const raw = await snapshot.importer.importRaw(snapshot.input, {
566
+ config: this.#config,
567
+ fetch: globalThis.fetch
568
+ });
569
+ if (!raw.importSource) {
570
+ throw new SourceImportError('invalid-response', 'The Figma importer did not return provenance for the retagged source.');
571
+ }
572
+ const importSource = raw.importSource;
573
+ return this.#enqueueOperation(async () => {
574
+ this.#validateImportedRaw(raw, snapshot.importer.kind);
575
+ if (figmaTagOf(importSource) !== snapshot.newTag) {
576
+ throw new SourceImportError('invalid-response', `The Figma importer resolved a different tag than "${snapshot.newTag}".`);
577
+ }
578
+ const plugin = serverPluginForType(snapshot.expected.type, this.#registry);
579
+ if (!plugin.descriptor.accepts.includes(raw.extension)) {
580
+ throw new SourceImportError('invalid-response', `The ${snapshot.expected.type} type does not accept ".${raw.extension}" files.`);
581
+ }
582
+ // A retag may change the export scale, so always sync a slice's pixel ratio.
583
+ const pixelRatio = figmaSlicePixelRatio(raw, snapshot.expected.type);
584
+ let library;
585
+ try {
586
+ library = await this.#store.repointTagAsset(id, snapshot.newTag, raw.bytes, snapshot.expected, importSource, pixelRatio === undefined
587
+ ? undefined
588
+ : (parameters) => plugin.descriptor.validateParameters(mergeParameterPatch(parameters, { pixelRatio })));
589
+ }
590
+ catch (cause) {
591
+ if (cause instanceof Error && cause.message === 'stale-import') {
592
+ throw new SourceImportError('stale-import', 'The asset or local raw file changed while Figma was exporting. Nothing was changed.');
593
+ }
594
+ throw cause;
595
+ }
596
+ return this.#afterMutation(library);
597
+ });
598
+ }
488
599
  async #createImportedAsset(raw, options) {
489
600
  this.#validateImportedRaw(raw);
490
601
  const fileName = raw.suggestedFileName ?? `${options.id}.${raw.extension}`;
491
602
  const plugin = serverPluginForType(options.type, this.#registry);
492
- const library = await this.#store.createAsset({
493
- fileName,
494
- bytes: raw.bytes,
495
- type: options.type,
496
- id: options.id,
497
- folder: options.folder,
498
- manifests: options.manifests,
499
- importSource: raw.importSource
500
- }, async ({ rawPath, rawFileName, parameters }) => {
501
- let next = parameters;
502
- if (plugin.seedIngestParameters) {
503
- const seeded = await plugin.seedIngestParameters({
504
- rawPath,
505
- rawFileName,
506
- parameters: next,
507
- config: this.#config
508
- });
509
- if (seeded !== undefined)
510
- next = seeded;
511
- }
512
- // Source scale is a default: an explicit parametersPatch below still wins.
603
+ // Filling a Package slot writes a host override that inherits the Package's
604
+ // parameters via the deep merge, so the override is partial. Byte-derived
605
+ // fields the Package can't author — the slice pixelRatio from the import
606
+ // scale — must still be supplied here; an explicit patch then wins.
607
+ const packageBase = this.#packageBase(await this.#store.read(), options.id);
608
+ if (packageBase && packageBase.type !== options.type) {
609
+ throw new SourceImportError('invalid-input', `Filling slot "${options.id}" requires the package type "${packageBase.type}", not "${options.type}".`);
610
+ }
611
+ let slotOverride = {};
612
+ if (packageBase) {
513
613
  const pixelRatio = figmaSlicePixelRatio(raw, options.type);
514
614
  if (pixelRatio !== undefined) {
515
- next = mergeParameterPatch(next, { pixelRatio });
615
+ slotOverride = mergeParameterPatch(slotOverride, { pixelRatio });
516
616
  }
517
617
  if (options.parametersPatch !== undefined) {
518
- next = mergeParameterPatch(next, options.parametersPatch);
618
+ slotOverride = mergeParameterPatch(slotOverride, options.parametersPatch);
519
619
  }
520
- return plugin.descriptor.validateParameters(next);
521
- });
620
+ }
621
+ const library = packageBase
622
+ ? await this.#store.createAsset({
623
+ fileName,
624
+ bytes: raw.bytes,
625
+ type: options.type,
626
+ id: options.id,
627
+ folder: options.folder,
628
+ manifests: options.manifests,
629
+ importSource: raw.importSource,
630
+ parametersOverride: slotOverride
631
+ })
632
+ : await this.#store.createAsset({
633
+ fileName,
634
+ bytes: raw.bytes,
635
+ type: options.type,
636
+ id: options.id,
637
+ folder: options.folder,
638
+ manifests: options.manifests,
639
+ importSource: raw.importSource
640
+ }, async ({ rawPath, rawFileName, parameters }) => {
641
+ let next = parameters;
642
+ if (plugin.seedIngestParameters) {
643
+ const seeded = await plugin.seedIngestParameters({
644
+ rawPath,
645
+ rawFileName,
646
+ parameters: next,
647
+ config: this.#config
648
+ });
649
+ if (seeded !== undefined)
650
+ next = seeded;
651
+ }
652
+ // Source scale is a default: an explicit parametersPatch below still wins.
653
+ const pixelRatio = figmaSlicePixelRatio(raw, options.type);
654
+ if (pixelRatio !== undefined) {
655
+ next = mergeParameterPatch(next, { pixelRatio });
656
+ }
657
+ if (options.parametersPatch !== undefined) {
658
+ next = mergeParameterPatch(next, options.parametersPatch);
659
+ }
660
+ return plugin.descriptor.validateParameters(next);
661
+ });
522
662
  return this.#afterMutation(library);
523
663
  }
524
664
  #validateImportTarget(options, library) {
@@ -543,8 +683,10 @@ export class FundusOperations {
543
683
  options.manifests.some((value) => typeof value !== 'string'))) {
544
684
  throw new SourceImportError('invalid-input', 'Import manifests must be an array of strings.');
545
685
  }
686
+ // A placement may target a Package-introduced manifest (host + package union).
687
+ const validManifests = this.#effectiveOf(library).effective.manifests;
546
688
  for (const manifest of new Set(options.manifests ?? [])) {
547
- if (!Object.hasOwn(library.manifests, manifest)) {
689
+ if (!Object.hasOwn(validManifests, manifest)) {
548
690
  throw new SourceImportError('invalid-input', `Unknown manifest "${manifest}".`);
549
691
  }
550
692
  }
@@ -568,7 +710,9 @@ export class FundusOperations {
568
710
  }
569
711
  async #patchAsset(id, body) {
570
712
  let library = await this.#store.read();
571
- this.#requireAsset(library, id);
713
+ // A pure Package asset is read-only; fill/override it by importing bytes
714
+ // with its id. Host assets and existing overrides patch normally.
715
+ this.#assertHostAsset(library, id, 'editing it');
572
716
  if (body.parameters !== undefined) {
573
717
  library = await this.#store.updateParameters(id, body.parameters);
574
718
  }
@@ -689,6 +833,9 @@ export class FundusOperations {
689
833
  async #renameAsset(id, newId) {
690
834
  const library = await this.#store.read();
691
835
  this.#requireAsset(library, id);
836
+ if (figmaTagOf(library.assets[id].importSource) !== null) {
837
+ throw new SourceImportError('invalid-input', 'This asset is referenced by a Figma tag and cannot be renamed; re-import with a new tag instead.');
838
+ }
692
839
  // A collision or invalid new id is the store's own (clearer) error; the
693
840
  // candidate check covers what the store cannot see: broken references.
694
841
  if (newId !== id && !Object.hasOwn(library.assets, newId)) {
@@ -787,12 +934,19 @@ export class FundusOperations {
787
934
  async #runAfterMutation(library) {
788
935
  const pipelineIssues = [];
789
936
  const classification = await this.#classifyRawDirectory(library);
790
- const ordinaryIssues = await this.#store.validate(library);
937
+ const { effective, provenance, mergeFindings } = this.#effectiveOf(library);
938
+ const materialized = materializeLibrary(effective);
939
+ const ordinaryIssues = [
940
+ ...(await this.#store.validate(library, { flatSpace: false })),
941
+ ...this.#flatIssues(effective, provenance, mergeFindings)
942
+ ];
791
943
  const safetyIssues = this.#rawSafetyIssues(library, classification);
792
944
  if (ordinaryIssues.length === 0 && safetyIssues.length === 0) {
793
945
  try {
794
- const report = await processAssets(this.#config, library, this.#registry);
795
- await generateManifestModules(this.#config, library, report.proxies, this.#registry);
946
+ // Codegen runs over the merged, materialized library so the dev server
947
+ // writes the same modules `fundus build`/`fundus check` expect.
948
+ const report = await processAssets(this.#config, materialized, this.#registry);
949
+ await generateManifestModules(this.#config, materialized, report.proxies, this.#registry);
796
950
  }
797
951
  catch (cause) {
798
952
  pipelineIssues.push({
@@ -808,13 +962,15 @@ export class FundusOperations {
808
962
  state: await this.#snapshotState(latestLibrary, latestClassification, pipelineIssues)
809
963
  };
810
964
  }
811
- async #buildState(library, issues, classification) {
965
+ async #buildState(host, library, provenance, issues, classification) {
812
966
  const [gitBranch, changedGitAssets] = await Promise.all([
813
967
  currentGitBranch(this.#config.projectRoot),
814
- gitAssetChanges(this.#config.projectRoot, this.#config.library, library)
968
+ // Git diff over the host library only — Package assets are not host-owned
969
+ // and would otherwise all read as "new".
970
+ gitAssetChanges(this.#config.projectRoot, this.#config.library, host)
815
971
  ]);
816
972
  const referencesByAsset = collectAllReferences(library, descriptorsByType(this.#registry));
817
- const duplicatesByAsset = await this.#duplicateDetector.find(library, this.#config.rawDir);
973
+ const duplicatesByAsset = await this.#duplicateDetector.find(host, this.#config.rawDir);
818
974
  const membershipByManifest = computeLibraryMembership(library, referencesByAsset);
819
975
  const delivered = allDeliveredAssetIds(membershipByManifest);
820
976
  // Per asset: the manifests it is a passive member of, with attribution.
@@ -837,6 +993,14 @@ export class FundusOperations {
837
993
  const assets = [];
838
994
  for (const assetId of Object.keys(library.assets).sort(compareCodeUnits)) {
839
995
  const record = library.assets[assetId];
996
+ const prov = provenance[assetId] ?? { source: 'host' };
997
+ const origin = prov.source === 'host'
998
+ ? { kind: 'host' }
999
+ : prov.source === 'package'
1000
+ ? { kind: 'package', origin: prov.origin }
1001
+ : { kind: 'override', origin: prov.origin };
1002
+ // An unfilled Package slot carries no bytes.
1003
+ const isSlot = record.raw === undefined;
840
1004
  const warnings = [];
841
1005
  for (const issue of issues) {
842
1006
  if (issue.assetId === assetId)
@@ -844,8 +1008,9 @@ export class FundusOperations {
844
1008
  }
845
1009
  // Unreachable: no explicit membership AND no passive membership in any
846
1010
  // manifest — nothing delivers the asset. A passively delivered asset is
847
- // fine (it ships inlined into its referrers) and must not warn.
848
- if (record.manifests.length === 0 && !delivered.has(assetId)) {
1011
+ // fine (it ships inlined into its referrers) and must not warn. An inert
1012
+ // unfilled Package slot is not a host mistake and must not warn.
1013
+ if (record.manifests.length === 0 && !delivered.has(assetId) && !isSlot) {
849
1014
  warnings.push('In no manifest and not referenced by any delivered asset — ' +
850
1015
  'nothing is processed or generated for it.');
851
1016
  }
@@ -853,7 +1018,7 @@ export class FundusOperations {
853
1018
  warnings.push(`Importer "${record.importSource.importer}" is unavailable; the local raw file remains usable.`);
854
1019
  }
855
1020
  let proxy = null;
856
- if (delivered.has(assetId)) {
1021
+ if (delivered.has(assetId) && !isSlot) {
857
1022
  try {
858
1023
  const currentProxy = await readCurrentProxy(assetId, record, this.#config, this.#registry);
859
1024
  if (currentProxy) {
@@ -871,13 +1036,17 @@ export class FundusOperations {
871
1036
  warnings.push(cause instanceof Error ? cause.message : String(cause));
872
1037
  }
873
1038
  }
1039
+ const raw = record.raw ?? '';
1040
+ const rawHash = record.rawHash ?? '';
874
1041
  assets.push({
875
1042
  id: assetId,
876
1043
  type: record.type,
877
- raw: record.raw,
878
- folder: folderOfRawPath(record.raw),
879
- rawUrl: `/files/raw/${encodeRelativePathForUrl(record.raw)}?v=${record.rawHash.slice(0, 12)}`,
880
- rawHash: record.rawHash,
1044
+ raw,
1045
+ folder: folderOfRawPath(raw),
1046
+ rawUrl: isSlot
1047
+ ? ''
1048
+ : `/files/raw/${encodeRelativePathForUrl(raw)}?v=${rawHash.slice(0, 12)}`,
1049
+ rawHash,
881
1050
  gitStatus: changedGitAssets.get(assetId) ?? null,
882
1051
  importSource: record.importSource,
883
1052
  parameters: record.parameters,
@@ -892,7 +1061,9 @@ export class FundusOperations {
892
1061
  assetId: reference.assetId
893
1062
  })),
894
1063
  incoming: incomingByAsset.get(assetId) ?? []
895
- }
1064
+ },
1065
+ origin,
1066
+ overridden: origin.kind === 'override'
896
1067
  });
897
1068
  }
898
1069
  // Per manifest: the membership picture for the manifests view, and the
@@ -923,18 +1094,26 @@ export class FundusOperations {
923
1094
  presetNames[type] = names;
924
1095
  presetCapabilities[type] = Object.fromEntries(names.map((name) => [name, plugin.presetCapabilities?.(presets[name]) ?? {}]));
925
1096
  }
926
- const rawIngestionQueue = this.#buildRawIngestionQueue(library, classification);
1097
+ const rawIngestionQueue = this.#buildRawIngestionQueue(host, classification);
927
1098
  return {
928
1099
  gitBranch,
929
1100
  library,
930
1101
  assets,
931
- importDefaults: { figma: { scale: this.#config.import.figma.defaults.scale } },
1102
+ importDefaults: {
1103
+ figma: {
1104
+ scale: this.#config.import.figma.defaults.scale,
1105
+ ...(this.#config.import.figma.defaultFileKey !== undefined
1106
+ ? { defaultFileKey: this.#config.import.figma.defaultFileKey }
1107
+ : {})
1108
+ }
1109
+ },
932
1110
  issues,
933
1111
  presetNames,
934
1112
  presetCapabilities,
935
1113
  manifestMemberships,
936
1114
  manifestDeliveredBytes,
937
- rawIngestionQueue
1115
+ rawIngestionQueue,
1116
+ packageOrigins: this.#config.packages.map((pkg) => pkg.origin).sort(compareCodeUnits)
938
1117
  };
939
1118
  }
940
1119
  #compatibleTypes(path) {
@@ -947,8 +1126,10 @@ export class FundusOperations {
947
1126
  return rawSafetyIssues(library, classification, (path) => this.#compatibleTypes(path));
948
1127
  }
949
1128
  async #snapshotState(library, classification, extraIssues = []) {
1129
+ const { effective, provenance, mergeFindings } = this.#effectiveOf(library);
950
1130
  const issues = [
951
- ...(await this.#store.validate(library)),
1131
+ ...(await this.#store.validate(library, { flatSpace: false })),
1132
+ ...this.#flatIssues(effective, provenance, mergeFindings),
952
1133
  ...this.#rawSafetyIssues(library, classification),
953
1134
  ...extraIssues
954
1135
  ];
@@ -960,7 +1141,7 @@ export class FundusOperations {
960
1141
  seen.add(key);
961
1142
  return true;
962
1143
  });
963
- return this.#buildState(library, uniqueIssues, classification);
1144
+ return this.#buildState(library, effective, provenance, uniqueIssues, classification);
964
1145
  }
965
1146
  #canAutoReconcile(classification, retry = false) {
966
1147
  return (classification.complete &&
@@ -1066,6 +1247,60 @@ export class FundusOperations {
1066
1247
  throw new Error(`Unknown asset "${id}".`);
1067
1248
  }
1068
1249
  }
1250
+ /** Merge the configured Packages under the host library (host wins). */
1251
+ #effectiveOf(host) {
1252
+ const { library, provenance, findings } = mergePackages(host, this.#config.packages ?? []);
1253
+ return { effective: library, provenance, mergeFindings: findings };
1254
+ }
1255
+ /**
1256
+ * The Package base record for `id` when `id` is a read-only Package asset the
1257
+ * host has not yet filled — i.e. this create is a *slot fill*. Returns null
1258
+ * for a plain new host asset.
1259
+ */
1260
+ #packageBase(host, id) {
1261
+ if (Object.hasOwn(host.assets, id))
1262
+ return null;
1263
+ const { effective, provenance } = this.#effectiveOf(host);
1264
+ if (provenance[id]?.source === 'package')
1265
+ return { type: effective.assets[id].type };
1266
+ return null;
1267
+ }
1268
+ /**
1269
+ * Flat-space validation over the effective library: merge errors, id/type/
1270
+ * parameter/membership/appearance/reference checks, module collisions, and
1271
+ * delivered-slot findings. Disk/host checks stay in `store.validate(host,
1272
+ * { flatSpace: false })`.
1273
+ */
1274
+ #flatIssues(effective, provenance, mergeFindings) {
1275
+ const referencesByAsset = collectAllReferences(effective, descriptorsByType(this.#registry));
1276
+ const membership = computeLibraryMembership(effective, referencesByAsset);
1277
+ return [
1278
+ ...mergeFindings
1279
+ .filter((finding) => finding.kind !== 'package-overridden')
1280
+ .map((finding) => ({ assetId: finding.assetId, message: finding.message })),
1281
+ ...flatLibraryIssues(effective, descriptorsByType(this.#registry)),
1282
+ ...manifestModuleCollisionIssues(effective.manifests),
1283
+ ...packageSlotFindings(effective, provenance, membership).map((finding) => ({
1284
+ assetId: finding.assetId,
1285
+ message: finding.message
1286
+ }))
1287
+ ];
1288
+ }
1289
+ /**
1290
+ * Whether an id is a read-only Package asset the host has not overridden.
1291
+ * Such ids can be filled/overridden (write a host record) but not mutated,
1292
+ * renamed, moved, or deleted in place.
1293
+ */
1294
+ #assertHostAsset(host, id, action) {
1295
+ if (Object.hasOwn(host.assets, id))
1296
+ return;
1297
+ const { provenance } = this.#effectiveOf(host);
1298
+ const prov = provenance[id];
1299
+ if (prov && prov.source !== 'host') {
1300
+ 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.`);
1301
+ }
1302
+ throw new Error(`Unknown asset "${id}".`);
1303
+ }
1069
1304
  /**
1070
1305
  * Apply a CLI asset change to the store, validating the resulting library
1071
1306
  * on an in-memory candidate first — nothing is persisted when the change
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fundus",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- .submenu-anchor.svelte-13hq4tl{position:relative}button.svelte-13hq4tl{width:100%;color:var(--text);font:inherit;text-align:left;white-space:nowrap;background:0 0;border:0;border-radius:4px;padding:6px 8px}button.svelte-13hq4tl:hover,button.svelte-13hq4tl:focus-visible{background:var(--accent-soft);outline:none}.submenu-anchor.svelte-13hq4tl:has(.submenu:where(.svelte-13hq4tl))>.submenu-trigger:where(.svelte-13hq4tl){background:var(--accent-soft);outline:none}button.svelte-13hq4tl:disabled{color:var(--text-faint);background:0 0}.submenu-trigger.svelte-13hq4tl{justify-content:space-between;align-items:center;gap:12px;display:flex}.arrow.svelte-13hq4tl{color:var(--text-faint);font-size:16px;line-height:12px}.submenu.svelte-13hq4tl{z-index:1;background:var(--panel-raised);border:1px solid var(--border);border-radius:6px;min-width:168px;max-width:320px;padding:4px;position:absolute;top:-5px;left:calc(100% - 4px);overflow-y:auto;box-shadow:0 8px 24px #00000073}.submenu.opens-left.svelte-13hq4tl{left:auto;right:calc(100% - 4px)}.submenu.svelte-13hq4tl button:where(.svelte-13hq4tl){text-overflow:ellipsis;overflow:hidden}hr.svelte-13hq4tl{background:var(--border);border:0;height:1px;margin:4px 8px}.context-menu.svelte-109nkvw{z-index:200;background:var(--panel-raised);border:1px solid var(--border);border-radius:6px;width:168px;padding:4px;position:fixed;box-shadow:0 8px 24px #00000073}button.svelte-109nkvw{width:100%;color:var(--text);font:inherit;text-align:left;background:0 0;border:0;border-radius:4px;padding:6px 8px}button.svelte-109nkvw:hover,button.svelte-109nkvw:focus-visible{background:var(--accent-soft);outline:none}button.danger.svelte-109nkvw{color:var(--danger)}hr.svelte-109nkvw{background:var(--border);border:0;height:1px;margin:4px 8px}.manifest-label.svelte-1b4m5oj{align-items:center;gap:4px;min-width:0;display:inline-flex}.emoji.svelte-1b4m5oj{flex:none;line-height:1}.name.svelte-1b4m5oj{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.chip.svelte-1b4m5oj{background:color-mix(in srgb, var(--manifest-color) 20%, transparent);color:var(--manifest-color);border-radius:4px;padding:0 5px;font-size:10px}.chip.passive.svelte-1b4m5oj{border:1px dashed var(--manifest-color);background:0 0}.browse-select.svelte-dr99ka{border-radius:4px;align-items:center;min-width:0;height:24px;padding:0 6px 0 0;display:inline-flex}.browse-select.svelte-dr99ka:focus-within{border-color:var(--accent)}.browse-select.filter-active.svelte-dr99ka{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}.browse-select.filter-active.svelte-dr99ka .icon-slot:where(.svelte-dr99ka){color:var(--accent)}.icon-slot.svelte-dr99ka{width:24px;height:24px;color:var(--text-dim);-webkit-user-select:none;user-select:none;flex:none;justify-content:center;align-items:center;display:flex}select.svelte-dr99ka{background:0 0;border:0;outline:none;min-width:0;height:100%;margin:0;padding:0 6px 0 0}.filter-field .popover-anchor{width:100%}.multi-select-trigger.svelte-1yxb8yh{text-align:left;border-radius:4px;align-items:center;gap:5px;width:100%;min-width:0;height:24px;padding:0 6px 0 0;display:flex}.multi-select-trigger.filter-active.svelte-1yxb8yh{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}.icon-slot.svelte-1yxb8yh{width:24px;height:24px;color:var(--text-dim);flex:none;place-items:center;display:grid}.filter-active.svelte-1yxb8yh .icon-slot:where(.svelte-1yxb8yh){color:var(--accent)}.summary.svelte-1yxb8yh{min-width:0;color:var(--text);text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.filter-active.svelte-1yxb8yh .summary:where(.svelte-1yxb8yh){color:var(--accent)}.selected-count.svelte-1yxb8yh{background:var(--accent);min-width:15px;height:15px;color:var(--text);border-radius:999px;flex:none;place-items:center;padding:0 4px;font-size:9px;font-weight:700;display:grid}.multi-select-menu.svelte-1yxb8yh{width:max(160px, var(--multi-select-width,100%));min-width:160px}.menu-header.svelte-1yxb8yh{border-bottom:1px solid var(--border-soft);color:var(--text-dim);justify-content:space-between;align-items:center;gap:12px;padding:1px 4px 6px;font-size:10px;display:flex}.menu-header.svelte-1yxb8yh button:where(.svelte-1yxb8yh){color:var(--accent);font:inherit;background:0 0;border:0;padding:1px 2px}.menu-header.svelte-1yxb8yh button:where(.svelte-1yxb8yh):disabled{opacity:.4;cursor:default}.options.svelte-1yxb8yh{max-height:224px;padding-top:4px;overflow-y:auto}.options.svelte-1yxb8yh label:where(.svelte-1yxb8yh){border-radius:var(--radius-small);min-width:0;height:26px;color:var(--text);cursor:pointer;align-items:center;gap:7px;padding:0 5px;display:flex}.options.svelte-1yxb8yh label:where(.svelte-1yxb8yh):hover,.options.svelte-1yxb8yh label:where(.svelte-1yxb8yh):focus-within{background:var(--accent-soft)}.options.svelte-1yxb8yh label.selected:where(.svelte-1yxb8yh){color:var(--accent)}.options.svelte-1yxb8yh input:where(.svelte-1yxb8yh){width:12px;height:12px;accent-color:var(--accent);flex:none;margin:0}.options.svelte-1yxb8yh span:where(.svelte-1yxb8yh){text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.browse-checkbox.svelte-sa6meb{cursor:pointer;align-items:center;min-width:0;height:24px;display:inline-flex}.browse-checkbox.svelte-sa6meb:focus-within .value:where(.svelte-sa6meb){color:var(--accent)}.icon-slot.svelte-sa6meb{-webkit-user-select:none;user-select:none;flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:flex}.value.svelte-sa6meb{min-width:0;color:var(--text);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:11px;line-height:14px;overflow:hidden}input.svelte-sa6meb{width:12px;height:12px;accent-color:var(--accent);margin:0}.library-view.svelte-1uha8ag{flex:1;min-height:0;display:flex}.page.svelte-1uha8ag{flex:1;min-height:0;padding:16px;position:relative;overflow-y:auto}.library-toolbar.svelte-1uha8ag{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:16px;display:flex}.library-toolbar.svelte-1uha8ag .control{border-radius:var(--radius-small);height:24px}.selection-controls.svelte-1uha8ag{align-items:center;gap:8px;display:inline-flex}.selection-action.svelte-1uha8ag:disabled{opacity:.45;cursor:default}.selection-action.svelte-1uha8ag{justify-content:center;align-items:center;display:inline-flex}.selection-summary.svelte-1uha8ag{color:var(--accent);white-space:nowrap;font-weight:600}.preview-size-control.svelte-1uha8ag{height:24px;color:var(--text-dim);cursor:default;align-items:center;gap:6px;margin-left:auto;padding:0 7px;display:inline-flex}.preview-size-icon.svelte-1uha8ag{fill:currentColor;flex:none;width:14px;height:14px}.preview-size-icon.dense.svelte-1uha8ag{color:var(--text-faint)}.preview-size-icon.dense.svelte-1uha8ag rect:where(.svelte-1uha8ag){rx:.75px;width:3px;height:3px}.preview-size-icon.roomy.svelte-1uha8ag rect:where(.svelte-1uha8ag){rx:1.25px}.preview-size-range.svelte-1uha8ag{appearance:none;cursor:pointer;background:0 0;flex:none;width:104px;height:14px;margin:0;padding:0}.preview-size-range.svelte-1uha8ag::-webkit-slider-runnable-track{background:linear-gradient(to right, var(--accent) 0 var(--preview-size-progress), var(--border) var(--preview-size-progress) 100%);border-radius:999px;height:3px}.preview-size-range.svelte-1uha8ag::-moz-range-track{background:var(--border);border-radius:999px;height:3px}.preview-size-range.svelte-1uha8ag::-moz-range-progress{background:var(--accent);border-radius:999px;height:3px}.preview-size-range.svelte-1uha8ag::-webkit-slider-thumb{border:2px solid var(--panel-raised);appearance:none;background:var(--accent);width:12px;height:12px;box-shadow:0 0 0 1px var(--accent);border-radius:50%;margin-top:-4.5px}.preview-size-range.svelte-1uha8ag::-moz-range-thumb{border:2px solid var(--panel-raised);background:var(--accent);width:8px;height:8px;box-shadow:0 0 0 1px var(--accent);border-radius:50%}.preview-size-range.svelte-1uha8ag:focus-visible{outline:none}.preview-size-range.svelte-1uha8ag:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 1px var(--accent), 0 0 0 4px var(--accent-soft)}.preview-size-range.svelte-1uha8ag:focus-visible::-moz-range-thumb{box-shadow:0 0 0 1px var(--accent), 0 0 0 4px var(--accent-soft)}.search.svelte-1uha8ag{flex:0 0 240px;align-items:center;gap:4px;width:240px;min-width:200px;height:24px;padding:0 6px 0 0;display:flex}.search.svelte-1uha8ag:focus-within{border-color:var(--accent)}.search.filter-active.svelte-1uha8ag{border-color:var(--accent);background:var(--accent-soft)}.search.filter-active.svelte-1uha8ag .search-icon-slot:where(.svelte-1uha8ag),.search.filter-active.svelte-1uha8ag kbd:where(.svelte-1uha8ag){color:var(--accent)}.search.filter-active.svelte-1uha8ag kbd:where(.svelte-1uha8ag){border-color:var(--accent)}.search-icon-slot.svelte-1uha8ag{width:24px;height:24px;color:var(--text-dim);flex:none;justify-content:center;align-items:center;display:flex}.search-icon.svelte-1uha8ag{fill:none;stroke:currentColor;stroke-width:1.5px;stroke-linecap:round;flex:none;width:14px;height:14px}.search-input.svelte-1uha8ag{min-width:0;height:100%;color:var(--text);font:inherit;background:0 0;border:0;outline:none;flex:1;padding:0}.search-input.svelte-1uha8ag::-webkit-search-cancel-button{appearance:none;background:var(--text-dim);cursor:pointer;width:12px;height:12px;margin:0;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='m3 3 8 8m0-8-8 8' fill='none' stroke='black' stroke-linecap='round' stroke-width='2.25'/%3E%3C/svg%3E") 50%/12px 12px no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='m3 3 8 8m0-8-8 8' fill='none' stroke='black' stroke-linecap='round' stroke-width='2.25'/%3E%3C/svg%3E") 50%/12px 12px no-repeat}.search.filter-active.svelte-1uha8ag .search-input:where(.svelte-1uha8ag)::-webkit-search-cancel-button{background:var(--accent)}.search.svelte-1uha8ag kbd:where(.svelte-1uha8ag){border:1px solid var(--border);color:var(--text-faint);border-radius:3px;flex:none;padding:1px 4px;font:9px/14px system-ui,sans-serif}.toolbar-button.svelte-1uha8ag,.import-trigger.svelte-1uha8ag{white-space:nowrap;justify-content:center;align-items:center;gap:6px;display:inline-flex}.toolbar-button.active.svelte-1uha8ag{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}.filter-count.svelte-1uha8ag{background:var(--accent);min-width:16px;height:16px;color:var(--text);border-radius:999px;place-items:center;padding:0 4px;font-size:10px;font-weight:700;display:inline-grid}.filters-popover.svelte-1uha8ag{width:min(480px,100vw - 24px)}.popover-header.svelte-1uha8ag{border-bottom:1px solid var(--border-soft);justify-content:space-between;align-items:center;gap:16px;padding:2px 2px 10px;display:flex}.popover-header.svelte-1uha8ag strong:where(.svelte-1uha8ag){color:var(--text);font-size:11px;font-weight:400}.clear-filters.svelte-1uha8ag{color:var(--accent);font:inherit;background:0 0;border:0;padding:2px 4px;font-size:11px}.clear-filters.svelte-1uha8ag:disabled{opacity:.4;cursor:default}.filter-grid.svelte-1uha8ag{grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;padding:10px 2px;display:grid}.filter-field.svelte-1uha8ag{flex-direction:column;gap:4px;min-width:0;display:flex}.filter-field.svelte-1uha8ag>span:where(.svelte-1uha8ag){color:#ffffffb2;letter-spacing:.27px;-webkit-user-select:none;user-select:none;font-size:9px;font-weight:500;line-height:14px}.filter-field.svelte-1uha8ag .browse-select,.filter-field.svelte-1uha8ag .browse-checkbox{width:100%}.filter-field.svelte-1uha8ag .browse-select select{flex:1;width:100%}.filter-options-grid.svelte-1uha8ag{padding-top:0;padding-bottom:2px}.filter-options-grid.svelte-1uha8ag .browse-checkbox,.filter-options-grid.svelte-1uha8ag .browse-checkbox .icon-slot{height:14px}.filter-options-grid.svelte-1uha8ag .browse-checkbox .icon-slot{justify-content:flex-start;align-items:flex-start;width:18px}@media (width<=560px){.filter-grid.svelte-1uha8ag{grid-template-columns:1fr}}@media (width<=1056px){.search.svelte-1uha8ag{flex-basis:100%;order:10;width:100%}}.section.svelte-1uha8ag{margin-bottom:24px}.section.svelte-1uha8ag:last-child{margin-bottom:0}.section-emoji.svelte-1uha8ag{margin-right:6px}.grid.svelte-1uha8ag,.folder-grid.svelte-1uha8ag{gap:8px;display:grid}.grid.svelte-1uha8ag{grid-template-columns:repeat(auto-fill, minmax(min(100%, var(--preview-card-width)), 1fr))}.folder-grid.svelte-1uha8ag{grid-template-columns:repeat(auto-fill,minmax(160px,1fr))}.folder-card.svelte-1uha8ag{background:var(--panel);border:1px solid var(--border-soft);min-width:0;height:60px;color:var(--text);text-align:left;border-radius:8px;align-items:center;gap:10px;padding:8px 10px;display:flex}.folder-card.svelte-1uha8ag:hover,.folder-card.svelte-1uha8ag:focus-visible{border-color:var(--accent);outline:none}.folder-card.drop-target.svelte-1uha8ag{border-color:var(--accent);background:var(--accent-soft);box-shadow:0 0 0 1px var(--accent)}.folder-card.dragging-folder.svelte-1uha8ag{opacity:.55}.folder-card-icon.svelte-1uha8ag{color:var(--text-dim);flex:none;align-items:center;display:flex}.folder-card-details.svelte-1uha8ag{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.folder-card-details.svelte-1uha8ag strong:where(.svelte-1uha8ag){text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.folder-card-details.svelte-1uha8ag span:where(.svelte-1uha8ag),.folder-card-arrow.svelte-1uha8ag{color:var(--text-faint)}.folder-card-arrow.svelte-1uha8ag{flex:none;font-size:18px}.card.svelte-1uha8ag{background:var(--panel);border:1px solid var(--border-soft);border-radius:8px;flex-direction:column;gap:clamp(4px,5cqi,8px);padding:clamp(4px,5cqi,8px);display:flex;position:relative;container-type:inline-size}.card.selected.svelte-1uha8ag{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}.asset-select.svelte-1uha8ag{z-index:1;width:16px;height:16px;accent-color:var(--accent);position:absolute;top:clamp(6px,8cqi,12px);left:clamp(6px,8cqi,12px)}.card.svelte-1uha8ag:hover{border-color:var(--accent)}.thumbnail.svelte-1uha8ag{width:100%;height:min(var(--preview-card-height), 66.667cqi);border-radius:var(--radius);justify-content:center;align-items:center;display:flex;overflow:hidden}.meta.svelte-1uha8ag{align-items:center;gap:6px;min-width:0;display:flex}.id.svelte-1uha8ag{text-overflow:ellipsis;white-space:nowrap;font-weight:600;overflow:hidden}.type-badge.svelte-1uha8ag{color:var(--text-dim);border:1px solid var(--border);border-radius:4px;flex:none;margin-left:auto;padding:0 5px;font-size:10px}.badges.svelte-1uha8ag{flex-wrap:wrap;gap:4px;min-height:16px;display:flex}.badge.svelte-1uha8ag{border-radius:4px;padding:0 5px;font-size:10px}.badge.warning.svelte-1uha8ag{background:var(--warning-soft);color:var(--warning)}@container (width<=109px){.type-badge.svelte-1uha8ag{display:none}.badges.svelte-1uha8ag{flex-wrap:nowrap;overflow:hidden}}@container (width<=79px){.card.svelte-1uha8ag>.overlay{background:var(--accent);border:0;width:6px;height:6px;padding:0;font-size:0;top:5px;left:auto;right:5px;transform:none}.card.svelte-1uha8ag>.overlay.edited{background:var(--warning)}.asset-select.svelte-1uha8ag{width:8px;height:8px;top:0;left:0;transform:translate(-8%,8%)}.meta.svelte-1uha8ag,.badges.svelte-1uha8ag{display:none}}.empty.svelte-1uha8ag{color:var(--text-dim);text-align:center;padding:48px}.dialog-row.svelte-1uha8ag{align-items:center;gap:8px;display:flex}.dialog-row.svelte-1uha8ag span:where(.svelte-1uha8ag){width:44px;color:var(--text-dim)}.dialog-row.svelte-1uha8ag input:where(.svelte-1uha8ag){flex:1}.dialog-text.svelte-1uha8ag,.dialog-warning.svelte-1uha8ag{margin:8px 0 0}.dialog-warning.svelte-1uha8ag{color:var(--warning)}.drop-hint.svelte-1uha8ag{border:2px dashed var(--accent);color:var(--accent);pointer-events:none;background:#0d99ff14;border-radius:12px;justify-content:center;align-items:center;font-size:14px;display:flex;position:fixed;inset:48px 8px 8px}