framefields 2.14.0 → 2.15.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 (334) hide show
  1. package/NOTICE.md +5 -1
  2. package/dist/audio/index.d.mts +3 -3
  3. package/dist/audio/index.mjs +10 -10
  4. package/dist/{audio-DFwRbID_.mjs → audio-6TfPlfl4.mjs} +3 -3
  5. package/dist/{audio-DFwRbID_.mjs.map → audio-6TfPlfl4.mjs.map} +1 -1
  6. package/dist/{audio-CdCuGK5d.d.mts → audio-7oqTUi4G.d.mts} +2 -2
  7. package/dist/{audio-CdCuGK5d.d.mts.map → audio-7oqTUi4G.d.mts.map} +1 -1
  8. package/dist/cli/check-worker.mjs +44 -44
  9. package/dist/cli.mjs +1 -1
  10. package/dist/cloud/index.d.mts.map +1 -1
  11. package/dist/cloud/index.mjs +1 -1
  12. package/dist/{cloud-Cj1TIme8.mjs → cloud-jnk1hPYf.mjs} +2 -2
  13. package/dist/{cloud-Cj1TIme8.mjs.map → cloud-jnk1hPYf.mjs.map} +1 -1
  14. package/dist/components/index.d.mts +11 -11
  15. package/dist/components/index.mjs +43 -43
  16. package/dist/{dist-Kbf-JTry.mjs → dist-BtI6ukB5.mjs} +2 -2
  17. package/dist/{dist-Kbf-JTry.mjs.map → dist-BtI6ukB5.mjs.map} +1 -1
  18. package/dist/{dist-B8Nby2CU.mjs → dist-COOpgG9G.mjs} +4 -3
  19. package/dist/{dist-B8Nby2CU.mjs.map → dist-COOpgG9G.mjs.map} +1 -1
  20. package/dist/{dist--Uu5bQ_6.mjs → dist-XqlFM2a8.mjs} +13733 -5323
  21. package/dist/dist-XqlFM2a8.mjs.map +1 -0
  22. package/dist/{dist-CiTgmfUw.mjs → dist-f1zkl69f.mjs} +4 -4
  23. package/dist/dist-f1zkl69f.mjs.map +1 -0
  24. package/dist/{dist-B_rSWeOz.mjs → dist-umQOWz0a.mjs} +1 -1
  25. package/dist/effects/index.d.mts +4 -4
  26. package/dist/effects/index.mjs +35 -35
  27. package/dist/{effects-WMgv8ZaD.mjs → effects-DlRMovU5.mjs} +2 -2
  28. package/dist/{effects-WMgv8ZaD.mjs.map → effects-DlRMovU5.mjs.map} +1 -1
  29. package/dist/fonts/index.d.mts +1 -1
  30. package/dist/fonts/index.mjs +2 -2
  31. package/dist/{fonts-OW3yAfO5.mjs → fonts-BWYcXjyK.mjs} +3 -3
  32. package/dist/fonts-BWYcXjyK.mjs.map +1 -0
  33. package/dist/{gpu-R4T2Tndu.mjs → gpu-CH1PdM4T.mjs} +2 -2
  34. package/dist/{gpu-R4T2Tndu.mjs.map → gpu-CH1PdM4T.mjs.map} +1 -1
  35. package/dist/{index-CEKxvGY-.d.mts → index-BHTycml5.d.mts} +2 -2
  36. package/dist/{index-CEKxvGY-.d.mts.map → index-BHTycml5.d.mts.map} +1 -1
  37. package/dist/{index-DoP6EiHj.d.mts → index-BcxxxwhV.d.mts} +4 -4
  38. package/dist/{index-DoP6EiHj.d.mts.map → index-BcxxxwhV.d.mts.map} +1 -1
  39. package/dist/{index-Bv7gxGK1.d.mts → index-BnB_Ou2y.d.mts} +2 -2
  40. package/dist/index-BnB_Ou2y.d.mts.map +1 -0
  41. package/dist/index-C-V6CAhP.d.mts.map +1 -1
  42. package/dist/{index-D1FqV1eu.d.mts → index-CMhkkc56.d.mts} +43 -11
  43. package/dist/index-CMhkkc56.d.mts.map +1 -0
  44. package/dist/{index-B0Vq8Bwf.d.mts → index-CYVpYGM-.d.mts} +2 -2
  45. package/dist/{index-B0Vq8Bwf.d.mts.map → index-CYVpYGM-.d.mts.map} +1 -1
  46. package/dist/{index-C7-p9zwU.d.mts → index-DhL7ckvs.d.mts} +5 -5
  47. package/dist/index-DhL7ckvs.d.mts.map +1 -0
  48. package/dist/{index-9xte4JgL.d.mts → index-DkAjKnhW.d.mts} +1464 -559
  49. package/dist/index-DkAjKnhW.d.mts.map +1 -0
  50. package/dist/{index-GA9_Z8Fn.d.mts → index-RILu3ULT.d.mts} +2 -2
  51. package/dist/{index-GA9_Z8Fn.d.mts.map → index-RILu3ULT.d.mts.map} +1 -1
  52. package/dist/{index-C5sgRLlG.d.mts → index-TCtdSXd7.d.mts} +3 -1
  53. package/dist/index-TCtdSXd7.d.mts.map +1 -0
  54. package/dist/{index-CRaydvLi.d.mts → index-s2qQ8ifZ.d.mts} +886 -51
  55. package/dist/index-s2qQ8ifZ.d.mts.map +1 -0
  56. package/dist/index.d.mts +13 -13
  57. package/dist/index.mjs +52 -52
  58. package/dist/preview/index.d.mts +3 -3
  59. package/dist/preview/index.mjs +10 -10
  60. package/dist/preview-BeGF1Bb1.mjs +1002 -0
  61. package/dist/preview-BeGF1Bb1.mjs.map +1 -0
  62. package/dist/preview-engine/audio.mjs +1 -1
  63. package/dist/preview-engine/{chunk-64L4GUOF.mjs → chunk-4F3DG6YB.mjs} +2 -2
  64. package/dist/preview-engine/chunk-A2OTOW3B.mjs +4694 -0
  65. package/dist/preview-engine/{chunk-GNDE3OXQ.mjs → chunk-BR56TQBP.mjs} +1 -1
  66. package/dist/preview-engine/{chunk-ADLIF544.mjs → chunk-H2XKXXAU.mjs} +1 -1
  67. package/dist/preview-engine/chunk-NDUODAY2.mjs +3 -0
  68. package/dist/preview-engine/{chunk-FZ4RD7HV.mjs → chunk-QAQJSWUT.mjs} +1 -1
  69. package/dist/preview-engine/chunk-SWRGQTVC.mjs +138 -0
  70. package/dist/preview-engine/{chunk-52X7SURQ.mjs → chunk-TEA3GVBJ.mjs} +1 -1
  71. package/dist/preview-engine/chunk-VM2ZBPLM.mjs +644 -0
  72. package/dist/preview-engine/{chunk-UBY2UYEL.mjs → chunk-XSHNQJ7L.mjs} +1 -1
  73. package/dist/preview-engine/components.mjs +1 -1
  74. package/dist/preview-engine/effects.mjs +1 -1
  75. package/dist/preview-engine/fonts.mjs +1 -1
  76. package/dist/preview-engine/framefields.mjs +1 -1
  77. package/dist/preview-engine/player.mjs +2 -2
  78. package/dist/preview-engine/{renderers-DU7KPFVV.mjs → renderers-6C7NWWDX.mjs} +1 -1
  79. package/dist/preview-engine/renderers-HHVGNMSJ.mjs +206 -0
  80. package/dist/preview-engine/{src-YXNX4MLK.mjs → src-RCNEKIRP.mjs} +1 -1
  81. package/dist/preview-page/index.html +19 -0
  82. package/dist/preview-page/main.css +1 -0
  83. package/dist/preview-page/main.js +327 -0
  84. package/dist/{program-tFKCWU2j.mjs → program-CMigyfso.mjs} +829 -52
  85. package/dist/program-CMigyfso.mjs.map +1 -0
  86. package/dist/renderer/index.d.mts +2 -2
  87. package/dist/renderer/index.mjs +2 -2
  88. package/dist/{renderer-DkOuQi84.mjs → renderer-0GMEL_Zi.mjs} +3 -3
  89. package/dist/{renderer-DkOuQi84.mjs.map → renderer-0GMEL_Zi.mjs.map} +1 -1
  90. package/dist/{renderer-BGp0An5A.mjs → renderer-3Wv2ZBJG.mjs} +3 -3
  91. package/dist/{renderer-BGp0An5A.mjs.map → renderer-3Wv2ZBJG.mjs.map} +1 -1
  92. package/dist/{renderer-BVIXKfbC.mjs → renderer-4nXkaAWu.mjs} +1178 -199
  93. package/dist/renderer-4nXkaAWu.mjs.map +1 -0
  94. package/dist/{renderer-Cw6_NL2i.mjs → renderer-6SnfLXeg.mjs} +3 -3
  95. package/dist/{renderer-Cw6_NL2i.mjs.map → renderer-6SnfLXeg.mjs.map} +1 -1
  96. package/dist/{renderer-BVU22lBS.mjs → renderer-8gHw3O0P.mjs} +2 -2
  97. package/dist/{renderer-BVU22lBS.mjs.map → renderer-8gHw3O0P.mjs.map} +1 -1
  98. package/dist/{renderer-BjDddtw9.mjs → renderer-AOBglZHC.mjs} +2 -2
  99. package/dist/{renderer-D-KHHWQD.mjs → renderer-B0bSARK3.mjs} +3 -3
  100. package/dist/{renderer-D-KHHWQD.mjs.map → renderer-B0bSARK3.mjs.map} +1 -1
  101. package/dist/{renderer-CCxk-RJR.mjs → renderer-B2_tuRfl.mjs} +2 -2
  102. package/dist/{renderer-CCxk-RJR.mjs.map → renderer-B2_tuRfl.mjs.map} +1 -1
  103. package/dist/{renderer-k5d7JSbs.mjs → renderer-B82FhkEr.mjs} +3 -3
  104. package/dist/{renderer-k5d7JSbs.mjs.map → renderer-B82FhkEr.mjs.map} +1 -1
  105. package/dist/{renderer-I0Hh9cLK.mjs → renderer-B9lzA0PY.mjs} +3 -3
  106. package/dist/{renderer-I0Hh9cLK.mjs.map → renderer-B9lzA0PY.mjs.map} +1 -1
  107. package/dist/{renderer-Dwwnx7Dk.mjs → renderer-BBSIWSry.mjs} +2 -2
  108. package/dist/{renderer-Dwwnx7Dk.mjs.map → renderer-BBSIWSry.mjs.map} +1 -1
  109. package/dist/{renderer-_pC-jB9O.mjs → renderer-BEKDMxbi.mjs} +2 -2
  110. package/dist/{renderer-_pC-jB9O.mjs.map → renderer-BEKDMxbi.mjs.map} +1 -1
  111. package/dist/renderer-BERGAxqA.mjs +5 -0
  112. package/dist/{renderer-raxwsiGI.mjs → renderer-BF960HY8.mjs} +3 -3
  113. package/dist/{renderer-raxwsiGI.mjs.map → renderer-BF960HY8.mjs.map} +1 -1
  114. package/dist/{renderer-Dr0tXA4k.mjs → renderer-BFwyVxCu.mjs} +3 -3
  115. package/dist/{renderer-Dr0tXA4k.mjs.map → renderer-BFwyVxCu.mjs.map} +1 -1
  116. package/dist/{renderer-DEjo6dw_.mjs → renderer-BNiwcI3-.mjs} +2 -2
  117. package/dist/{renderer-DEjo6dw_.mjs.map → renderer-BNiwcI3-.mjs.map} +1 -1
  118. package/dist/{renderer-DIEeHiQA.mjs → renderer-BPbVb2Q4.mjs} +2 -2
  119. package/dist/{renderer-DIEeHiQA.mjs.map → renderer-BPbVb2Q4.mjs.map} +1 -1
  120. package/dist/renderer-BQ_YkBMt.mjs +6 -0
  121. package/dist/{renderer-BBMtmxks.mjs → renderer-BUWxlA8T.mjs} +3 -3
  122. package/dist/{renderer-BBMtmxks.mjs.map → renderer-BUWxlA8T.mjs.map} +1 -1
  123. package/dist/renderer-BW0Tjsv9.mjs +5 -0
  124. package/dist/{renderer-Dgj46uEU.mjs → renderer-BX8liu-e.mjs} +2 -2
  125. package/dist/{renderer-ZnrEfkYh.mjs → renderer-BXIwDAr_.mjs} +2 -2
  126. package/dist/{renderer-ZnrEfkYh.mjs.map → renderer-BXIwDAr_.mjs.map} +1 -1
  127. package/dist/{renderer-DA8YEo_d.mjs → renderer-B_Hy1W-g.mjs} +3 -3
  128. package/dist/{renderer-DA8YEo_d.mjs.map → renderer-B_Hy1W-g.mjs.map} +1 -1
  129. package/dist/{renderer-iMiYStcW.mjs → renderer-Bb6cvSgh.mjs} +2 -2
  130. package/dist/{renderer-iMiYStcW.mjs.map → renderer-Bb6cvSgh.mjs.map} +1 -1
  131. package/dist/{renderer-BacY4nh8.mjs → renderer-BdppwWC9.mjs} +2 -2
  132. package/dist/{renderer-BacY4nh8.mjs.map → renderer-BdppwWC9.mjs.map} +1 -1
  133. package/dist/{renderer-CrxwW6VQ.mjs → renderer-Bhc24HVe.mjs} +3 -3
  134. package/dist/{renderer-CrxwW6VQ.mjs.map → renderer-Bhc24HVe.mjs.map} +1 -1
  135. package/dist/{renderer-BH7UCMPQ.mjs → renderer-BiNA2wF0.mjs} +2 -2
  136. package/dist/{renderer-BH7UCMPQ.mjs.map → renderer-BiNA2wF0.mjs.map} +1 -1
  137. package/dist/{renderer-DVPgWHZw.mjs → renderer-BmoBgTp5.mjs} +3 -3
  138. package/dist/{renderer-DVPgWHZw.mjs.map → renderer-BmoBgTp5.mjs.map} +1 -1
  139. package/dist/{renderer-C20efMI0.mjs → renderer-BmqFmCWS.mjs} +3 -3
  140. package/dist/{renderer-C20efMI0.mjs.map → renderer-BmqFmCWS.mjs.map} +1 -1
  141. package/dist/{renderer-B0yVUOPP.mjs → renderer-BnVwAObV.mjs} +2 -2
  142. package/dist/{renderer-B0yVUOPP.mjs.map → renderer-BnVwAObV.mjs.map} +1 -1
  143. package/dist/{renderer-CP8wLzTU.mjs → renderer-BxttZHme.mjs} +2 -2
  144. package/dist/{renderer-CP8wLzTU.mjs.map → renderer-BxttZHme.mjs.map} +1 -1
  145. package/dist/renderer-BzyPdUD1.mjs +5 -0
  146. package/dist/renderer-C0hM-mtY.mjs +5 -0
  147. package/dist/renderer-C6cyUTvk.mjs +5 -0
  148. package/dist/{renderer-BOSZAdgF.mjs → renderer-C8E4XsSg.mjs} +2 -2
  149. package/dist/{renderer-BOSZAdgF.mjs.map → renderer-C8E4XsSg.mjs.map} +1 -1
  150. package/dist/renderer-C8zY3pzk.mjs +5 -0
  151. package/dist/{renderer-DWq9gYRw.mjs → renderer-C9U-LY50.mjs} +3 -3
  152. package/dist/{renderer-DWq9gYRw.mjs.map → renderer-C9U-LY50.mjs.map} +1 -1
  153. package/dist/{renderer-Dj2H5JPR.mjs → renderer-CB2JVu5x.mjs} +3 -3
  154. package/dist/{renderer-Dj2H5JPR.mjs.map → renderer-CB2JVu5x.mjs.map} +1 -1
  155. package/dist/{renderer-Bcu3UrI-.mjs → renderer-CC4YBJ8Z.mjs} +3 -3
  156. package/dist/{renderer-Bcu3UrI-.mjs.map → renderer-CC4YBJ8Z.mjs.map} +1 -1
  157. package/dist/renderer-CEkSOyKu.mjs +5 -0
  158. package/dist/{renderer-DzLrvCB2.mjs → renderer-CIycc5O-.mjs} +2 -2
  159. package/dist/{renderer-DzLrvCB2.mjs.map → renderer-CIycc5O-.mjs.map} +1 -1
  160. package/dist/renderer-CJYtfa4x.mjs +5 -0
  161. package/dist/{renderer-BeNl_6EG.mjs → renderer-CJraQlV-.mjs} +2 -2
  162. package/dist/{renderer-BeNl_6EG.mjs.map → renderer-CJraQlV-.mjs.map} +1 -1
  163. package/dist/renderer-CKMtHGZh.mjs +5 -0
  164. package/dist/renderer-CLzicoiy.mjs +5 -0
  165. package/dist/renderer-CM2A4BHd.mjs +5 -0
  166. package/dist/{renderer-DtMVitEF.mjs → renderer-COWGWtob.mjs} +2 -2
  167. package/dist/{renderer-DtMVitEF.mjs.map → renderer-COWGWtob.mjs.map} +1 -1
  168. package/dist/{renderer-CT3zkfbf.mjs → renderer-COxG2XGf.mjs} +2 -2
  169. package/dist/{renderer-CT3zkfbf.mjs.map → renderer-COxG2XGf.mjs.map} +1 -1
  170. package/dist/{renderer-DNxWOz8Q.mjs → renderer-CQDCIsQm.mjs} +2 -2
  171. package/dist/{renderer-DNxWOz8Q.mjs.map → renderer-CQDCIsQm.mjs.map} +1 -1
  172. package/dist/{renderer-C5AoaymD.mjs → renderer-CRUeag8i.mjs} +3 -3
  173. package/dist/{renderer-C5AoaymD.mjs.map → renderer-CRUeag8i.mjs.map} +1 -1
  174. package/dist/{renderer-ngmYIIob.mjs → renderer-CWVput06.mjs} +3 -3
  175. package/dist/{renderer-ngmYIIob.mjs.map → renderer-CWVput06.mjs.map} +1 -1
  176. package/dist/renderer-CZlHjcxr.mjs +5 -0
  177. package/dist/{renderer-0rveCDm-.mjs → renderer-CbbnBLOB.mjs} +3 -3
  178. package/dist/{renderer-0rveCDm-.mjs.map → renderer-CbbnBLOB.mjs.map} +1 -1
  179. package/dist/renderer-CbimvSU8.mjs +5 -0
  180. package/dist/renderer-Ccvc63yd.mjs +5 -0
  181. package/dist/renderer-Cdp-SGfq.mjs +5 -0
  182. package/dist/renderer-CeTcSs3e.mjs +5 -0
  183. package/dist/{renderer-Brmbl12Y.mjs → renderer-CfLZein2.mjs} +3 -3
  184. package/dist/{renderer-Brmbl12Y.mjs.map → renderer-CfLZein2.mjs.map} +1 -1
  185. package/dist/{renderer-BJ8ea92W.mjs → renderer-Ch-q1O-q.mjs} +3 -3
  186. package/dist/{renderer-BJ8ea92W.mjs.map → renderer-Ch-q1O-q.mjs.map} +1 -1
  187. package/dist/{renderer-CP108ABB.mjs → renderer-Ch5JvJWl.mjs} +2 -2
  188. package/dist/{renderer-CP108ABB.mjs.map → renderer-Ch5JvJWl.mjs.map} +1 -1
  189. package/dist/{renderer-47y12Z37.mjs → renderer-ChtEzq-R.mjs} +2 -2
  190. package/dist/{renderer-47y12Z37.mjs.map → renderer-ChtEzq-R.mjs.map} +1 -1
  191. package/dist/{renderer-DhyMfG1v.mjs → renderer-Cj9nTC5l.mjs} +3 -3
  192. package/dist/{renderer-DhyMfG1v.mjs.map → renderer-Cj9nTC5l.mjs.map} +1 -1
  193. package/dist/{renderer-BDzn1AKF.mjs → renderer-CqT8HsSS.mjs} +2 -2
  194. package/dist/{renderer-BDzn1AKF.mjs.map → renderer-CqT8HsSS.mjs.map} +1 -1
  195. package/dist/{renderer-B7G1KohJ.mjs → renderer-CuQjMhdV.mjs} +2 -2
  196. package/dist/renderer-CvNuu52U.mjs +5 -0
  197. package/dist/renderer-CwciC0oI.mjs +5 -0
  198. package/dist/renderer-CysLUbIr.mjs +5 -0
  199. package/dist/{renderer-Cm0tsbQH.mjs → renderer-Cz30EVws.mjs} +2 -2
  200. package/dist/{renderer-Cm0tsbQH.mjs.map → renderer-Cz30EVws.mjs.map} +1 -1
  201. package/dist/renderer-D3A22Vxb.mjs +5 -0
  202. package/dist/renderer-D5SY9EmA.mjs +5 -0
  203. package/dist/renderer-D8h3ZvaE.mjs +5 -0
  204. package/dist/renderer-DE-B6N9n.mjs +5 -0
  205. package/dist/renderer-DETZTI7t.mjs +5 -0
  206. package/dist/{renderer-nHS3Sius.mjs → renderer-DHoX-5U_.mjs} +3 -3
  207. package/dist/{renderer-nHS3Sius.mjs.map → renderer-DHoX-5U_.mjs.map} +1 -1
  208. package/dist/{renderer-BWSRryIA.mjs → renderer-DOkm0Ycd.mjs} +2 -2
  209. package/dist/{renderer-BWSRryIA.mjs.map → renderer-DOkm0Ycd.mjs.map} +1 -1
  210. package/dist/{renderer-BHYJlK6H.d.mts → renderer-DU3f6ZrS.d.mts} +2 -2
  211. package/dist/{renderer-BHYJlK6H.d.mts.map → renderer-DU3f6ZrS.d.mts.map} +1 -1
  212. package/dist/{renderer-BpVOk9ux.mjs → renderer-DUzv-shq.mjs} +2 -2
  213. package/dist/{renderer-BpVOk9ux.mjs.map → renderer-DUzv-shq.mjs.map} +1 -1
  214. package/dist/renderer-DWnDj0IM.mjs +5 -0
  215. package/dist/renderer-DcGUIbQF.mjs +5 -0
  216. package/dist/renderer-Dfq6FoNO.mjs +5 -0
  217. package/dist/renderer-DhasXW6S.mjs +3 -0
  218. package/dist/{renderer-NRMlYkX6.mjs → renderer-DhnOWnEA.mjs} +3 -3
  219. package/dist/{renderer-NRMlYkX6.mjs.map → renderer-DhnOWnEA.mjs.map} +1 -1
  220. package/dist/{renderer-COgwYqev.mjs → renderer-Dhy1XHzz.mjs} +3 -3
  221. package/dist/{renderer-COgwYqev.mjs.map → renderer-Dhy1XHzz.mjs.map} +1 -1
  222. package/dist/renderer-DjCvpsV_.mjs +5 -0
  223. package/dist/{renderer-BfZNIiSv.mjs → renderer-DjJshz9Y.mjs} +2 -2
  224. package/dist/{renderer-BfZNIiSv.mjs.map → renderer-DjJshz9Y.mjs.map} +1 -1
  225. package/dist/{renderer-CKo7VR8x.mjs → renderer-DmTUIdus.mjs} +3 -3
  226. package/dist/{renderer-CKo7VR8x.mjs.map → renderer-DmTUIdus.mjs.map} +1 -1
  227. package/dist/{renderer-Baw6Utxi.mjs → renderer-Dq7AioJa.mjs} +2 -2
  228. package/dist/{renderer-Baw6Utxi.mjs.map → renderer-Dq7AioJa.mjs.map} +1 -1
  229. package/dist/renderer-DrAaM6JD.mjs +5 -0
  230. package/dist/{renderer-D-GWBoVT.mjs → renderer-Dt4sqNEu.mjs} +2 -2
  231. package/dist/{renderer-D-GWBoVT.mjs.map → renderer-Dt4sqNEu.mjs.map} +1 -1
  232. package/dist/{renderer-FYOL5Za6.mjs → renderer-Dtcs4idV.mjs} +3 -3
  233. package/dist/{renderer-FYOL5Za6.mjs.map → renderer-Dtcs4idV.mjs.map} +1 -1
  234. package/dist/renderer-Dxlv8LYm.mjs +5 -0
  235. package/dist/{renderer-D-RhYvVl.mjs → renderer-Gj8SrE2W.mjs} +2 -2
  236. package/dist/{renderer-D-RhYvVl.mjs.map → renderer-Gj8SrE2W.mjs.map} +1 -1
  237. package/dist/{renderer-D_j1WKMD.mjs → renderer-KfnXDJS0.mjs} +3 -3
  238. package/dist/{renderer-D_j1WKMD.mjs.map → renderer-KfnXDJS0.mjs.map} +1 -1
  239. package/dist/{renderer-Bpm145BW.mjs → renderer-MXVlg4p5.mjs} +3 -3
  240. package/dist/{renderer-Bpm145BW.mjs.map → renderer-MXVlg4p5.mjs.map} +1 -1
  241. package/dist/{renderer-Nnmi8Gt6.mjs → renderer-N2b6QZ1E.mjs} +3 -3
  242. package/dist/{renderer-Nnmi8Gt6.mjs.map → renderer-N2b6QZ1E.mjs.map} +1 -1
  243. package/dist/renderer-Pb43OO2t.mjs +5 -0
  244. package/dist/{renderer-Ca1KjNCO.mjs → renderer-Q7gDzm8c.mjs} +2 -2
  245. package/dist/{renderer-Ca1KjNCO.mjs.map → renderer-Q7gDzm8c.mjs.map} +1 -1
  246. package/dist/{renderer-D2wNFNRf.mjs → renderer-RCiANtRV.mjs} +2 -2
  247. package/dist/{renderer-D2wNFNRf.mjs.map → renderer-RCiANtRV.mjs.map} +1 -1
  248. package/dist/{renderer-Cqb7PGrI.mjs → renderer-Sig9nZcI.mjs} +2 -2
  249. package/dist/renderer-VQbm-cGr.mjs +5 -0
  250. package/dist/{renderer-W1bVNVR6.mjs → renderer-fabBgwQX.mjs} +3 -3
  251. package/dist/{renderer-W1bVNVR6.mjs.map → renderer-fabBgwQX.mjs.map} +1 -1
  252. package/dist/{renderer-zRq0j6Xy.mjs → renderer-g-0PCNoo.mjs} +3 -3
  253. package/dist/{renderer-zRq0j6Xy.mjs.map → renderer-g-0PCNoo.mjs.map} +1 -1
  254. package/dist/{renderer-2PjR3w-q.mjs → renderer-gmHKIbKI.mjs} +3 -3
  255. package/dist/{renderer-2PjR3w-q.mjs.map → renderer-gmHKIbKI.mjs.map} +1 -1
  256. package/dist/{renderer-03mYJLgX.mjs → renderer-kVZwiRoK.mjs} +3 -3
  257. package/dist/{renderer-03mYJLgX.mjs.map → renderer-kVZwiRoK.mjs.map} +1 -1
  258. package/dist/renderer-oPMypDM1.mjs +5 -0
  259. package/dist/{renderer-DcAKDAnS.mjs → renderer-p7tgxP-A.mjs} +3 -3
  260. package/dist/{renderer-DcAKDAnS.mjs.map → renderer-p7tgxP-A.mjs.map} +1 -1
  261. package/dist/{renderer-jUKdkmG5.mjs → renderer-tvYj306A.mjs} +81 -78
  262. package/dist/renderer-tvYj306A.mjs.map +1 -0
  263. package/dist/renderer-xvWGpVyp.mjs +5 -0
  264. package/dist/renderer-zafZbD6Q.mjs +5 -0
  265. package/dist/{renderers-CP8CFWDs-CshljORp.mjs → renderers-CP8CFWDs-DLjtjrwx.mjs} +2 -2
  266. package/dist/{renderers-CP8CFWDs-CshljORp.mjs.map → renderers-CP8CFWDs-DLjtjrwx.mjs.map} +1 -1
  267. package/dist/sam/index.d.mts +2 -2
  268. package/dist/sam/index.mjs +1 -1
  269. package/dist/signals/index.d.mts +4 -4
  270. package/dist/signals/index.mjs +4 -4
  271. package/dist/{src-BU6vm9sP-DdTHmCr4.mjs → src-B23p_eh7-Cj6-lvV6.mjs} +293 -6
  272. package/dist/src-B23p_eh7-Cj6-lvV6.mjs.map +1 -0
  273. package/dist/{src-Dy4gnc6w.mjs → src-CoHAjviq.mjs} +1349 -177
  274. package/dist/src-CoHAjviq.mjs.map +1 -0
  275. package/dist/storage/index.mjs +1 -1
  276. package/package.json +63 -60
  277. package/dist/dist--Uu5bQ_6.mjs.map +0 -1
  278. package/dist/dist-CiTgmfUw.mjs.map +0 -1
  279. package/dist/fonts-OW3yAfO5.mjs.map +0 -1
  280. package/dist/index-9xte4JgL.d.mts.map +0 -1
  281. package/dist/index-Bv7gxGK1.d.mts.map +0 -1
  282. package/dist/index-C5sgRLlG.d.mts.map +0 -1
  283. package/dist/index-C7-p9zwU.d.mts.map +0 -1
  284. package/dist/index-CRaydvLi.d.mts.map +0 -1
  285. package/dist/index-D1FqV1eu.d.mts.map +0 -1
  286. package/dist/preview-D7BGmE1E.mjs +0 -2446
  287. package/dist/preview-D7BGmE1E.mjs.map +0 -1
  288. package/dist/preview-engine/chunk-5DZTPUMH.mjs +0 -2568
  289. package/dist/preview-engine/chunk-NCQHOGZK.mjs +0 -3
  290. package/dist/preview-engine/chunk-PH3UUX6A.mjs +0 -138
  291. package/dist/preview-engine/chunk-UPZURPJY.mjs +0 -2227
  292. package/dist/preview-engine/renderers-DLJOA3BM.mjs +0 -228
  293. package/dist/program-tFKCWU2j.mjs.map +0 -1
  294. package/dist/renderer-6_bzbbXt.mjs +0 -5
  295. package/dist/renderer-8M-9G6F_.mjs +0 -5
  296. package/dist/renderer-B5OzKvF8.mjs +0 -5
  297. package/dist/renderer-BBCZ2qbE.mjs +0 -5
  298. package/dist/renderer-BChbxCux.mjs +0 -5
  299. package/dist/renderer-BGeMPr8C.mjs +0 -5
  300. package/dist/renderer-BPQ8Pkjb.mjs +0 -5
  301. package/dist/renderer-BTRpA3HD.mjs +0 -5
  302. package/dist/renderer-BVIXKfbC.mjs.map +0 -1
  303. package/dist/renderer-BVsECSn-.mjs +0 -5
  304. package/dist/renderer-Bgos68gc.mjs +0 -6
  305. package/dist/renderer-BjHOvoqO.mjs +0 -5
  306. package/dist/renderer-BjXMPPlV.mjs +0 -5
  307. package/dist/renderer-Byobxqkv.mjs +0 -5
  308. package/dist/renderer-CKrsg3EG.mjs +0 -5
  309. package/dist/renderer-Cj875NuH.mjs +0 -5
  310. package/dist/renderer-CnmzJoMv.mjs +0 -5
  311. package/dist/renderer-CtklDaMg.mjs +0 -5
  312. package/dist/renderer-D1tK3in_.mjs +0 -5
  313. package/dist/renderer-D2yc9P61.mjs +0 -5
  314. package/dist/renderer-D4v-JvSr.mjs +0 -5
  315. package/dist/renderer-D5yp74NL.mjs +0 -3
  316. package/dist/renderer-D7WRWDwB.mjs +0 -5
  317. package/dist/renderer-DGvA0tdB.mjs +0 -5
  318. package/dist/renderer-DO7v5Sdm.mjs +0 -5
  319. package/dist/renderer-DRVvt7-V.mjs +0 -5
  320. package/dist/renderer-DYMCd3jL.mjs +0 -5
  321. package/dist/renderer-DmHKw-MM.mjs +0 -5
  322. package/dist/renderer-DoDsuZ6G.mjs +0 -5
  323. package/dist/renderer-EpgclS70.mjs +0 -5
  324. package/dist/renderer-GroKiYyK.mjs +0 -5
  325. package/dist/renderer-MQ5K_xIS.mjs +0 -5
  326. package/dist/renderer-U43SflML.mjs +0 -5
  327. package/dist/renderer-UqOmBgCv.mjs +0 -5
  328. package/dist/renderer-XLULgJM0.mjs +0 -5
  329. package/dist/renderer-jUKdkmG5.mjs.map +0 -1
  330. package/dist/renderer-lNjxY1GG.mjs +0 -5
  331. package/dist/renderer-ukufL7pl.mjs +0 -5
  332. package/dist/renderer-wb0NCKdF.mjs +0 -5
  333. package/dist/src-BU6vm9sP-DdTHmCr4.mjs.map +0 -1
  334. package/dist/src-Dy4gnc6w.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"dist-CiTgmfUw.mjs","names":["path"],"sources":["../../storage/dist/index.mjs"],"sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport { mkdir, open, readFile, rename, rm } from \"node:fs/promises\";\nimport { AwsClient } from \"aws4fetch\";\nimport { createReadStream, createWriteStream, existsSync } from \"node:fs\";\nimport { dirname, join, relative, sep } from \"node:path\";\nimport { Readable, Transform } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\n\n//#region src/files.ts\n/**\n* Hashing and verified downloads: every byte an asset contributes is checked\n* against the sha256 its manifest entry pins.\n*/\nvar AssetError = class extends Error {\n\tname = \"AssetError\";\n\tconstructor(code, message, options) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t}\n};\nasync function hashFile(path) {\n\tconst hash = createHash(\"sha256\");\n\tlet size = 0;\n\tfor await (const chunk of createReadStream(path)) {\n\t\thash.update(chunk);\n\t\tsize += chunk.length;\n\t}\n\treturn {\n\t\tsha256: hash.digest(\"hex\"),\n\t\tsize\n\t};\n}\n/**\n* Downloads `url` to `dest` through a temporary file, and only renames it\n* into place once its size and sha256 match `expected`.\n*/\nasync function downloadVerified(url, dest, expected, options = {}) {\n\tconst attempts = options.attempts ?? 3;\n\tfor (let attempt = 1;; attempt++) try {\n\t\tawait downloadOnce(url, dest, expected, options);\n\t\treturn;\n\t} catch (err) {\n\t\tif (!(err instanceof AssetError ? err.code === \"ASSET_DOWNLOAD_FAILED\" : !options.signal?.aborted) || attempt >= attempts) throw err;\n\t\tawait new Promise((r) => setTimeout(r, 500 * 2 ** attempt));\n\t}\n}\nasync function downloadOnce(url, dest, expected, options) {\n\tconst shown = redactQuery(url);\n\tconst res = await (options.fetch ?? fetch)(url, { signal: options.signal });\n\tif (!res.ok || !res.body) {\n\t\tawait res.body?.cancel();\n\t\tif (res.status === 404) throw new AssetError(\"ASSET_NOT_FOUND\", `${shown} returned 404`);\n\t\tif (res.status === 401 || res.status === 403) throw new AssetError(\"ASSET_FORBIDDEN\", `${shown} returned ${res.status}: the bucket isn't public there, or the signed URL expired`);\n\t\tthrow new AssetError(\"ASSET_DOWNLOAD_FAILED\", `${shown} returned ${res.status}`);\n\t}\n\tawait mkdir(dirname(dest), { recursive: true });\n\tconst temp = `${dest}.${randomBytes(4).toString(\"hex\")}.part`;\n\tconst hash = createHash(\"sha256\");\n\tlet size = 0;\n\tconst tap = new Transform({ transform(chunk, _encoding, done) {\n\t\tsize += chunk.length;\n\t\tif (size > expected.size) return done(new AssetError(\"ASSET_HASH_MISMATCH\", `${shown} is larger than the ${expected.size} bytes framefields.json pins`));\n\t\thash.update(chunk);\n\t\tdone(null, chunk);\n\t} });\n\ttry {\n\t\tawait pipeline(Readable.fromWeb(res.body), tap, createWriteStream(temp), { signal: options.signal }).catch((err) => {\n\t\t\tif (err instanceof AssetError || options.signal?.aborted) throw err;\n\t\t\tthrow new AssetError(\"ASSET_DOWNLOAD_FAILED\", `${shown}: ${err.message}`, { cause: err });\n\t\t});\n\t\tconst sha256 = hash.digest(\"hex\");\n\t\tif (size !== expected.size || sha256 !== expected.sha256) throw new AssetError(\"ASSET_HASH_MISMATCH\", `${shown} is not the file framefields.json pins (got ${size} bytes, sha256 ${sha256.slice(0, 12)}…; expected ${expected.size} bytes, ${expected.sha256.slice(0, 12)}…)`);\n\t\tawait rename(temp, dest);\n\t} finally {\n\t\tawait rm(temp, { force: true });\n\t}\n}\n/** Signed URLs carry credentials in the query: never print them. */\nfunction redactQuery(url) {\n\tconst q = url.indexOf(\"?\");\n\treturn q < 0 ? url : `${url.slice(0, q)}?…`;\n}\nconst TYPES = {\n\tmp4: \"video/mp4\",\n\tm4v: \"video/mp4\",\n\tmov: \"video/quicktime\",\n\twebm: \"video/webm\",\n\tmkv: \"video/x-matroska\",\n\tmp3: \"audio/mpeg\",\n\tm4a: \"audio/mp4\",\n\taac: \"audio/aac\",\n\twav: \"audio/wav\",\n\tflac: \"audio/flac\",\n\togg: \"audio/ogg\",\n\tpng: \"image/png\",\n\tjpg: \"image/jpeg\",\n\tjpeg: \"image/jpeg\",\n\twebp: \"image/webp\",\n\tavif: \"image/avif\",\n\tgif: \"image/gif\",\n\tsvg: \"image/svg+xml\",\n\tjson: \"application/json\",\n\tlottie: \"application/zip\",\n\tglb: \"model/gltf-binary\",\n\tgltf: \"model/gltf+json\",\n\tttf: \"font/ttf\",\n\totf: \"font/otf\",\n\twoff2: \"font/woff2\",\n\tcube: \"text/plain\",\n\tsrt: \"text/plain\",\n\tvtt: \"text/vtt\"\n};\n/** The Content-Type a CDN serves the file with. */\nfunction contentType(path) {\n\treturn TYPES[path.slice(path.lastIndexOf(\".\") + 1).toLowerCase()] ?? \"application/octet-stream\";\n}\n\n//#endregion\n//#region src/manifest.ts\nconst REMOTE_NAME = /^[A-Za-z0-9][\\w-]{0,63}$/;\nconst SHA256 = /^[0-9a-f]{64}$/;\nconst FILE$1 = \"framefields.json\";\nvar ManifestError = class extends Error {\n\tname = \"ManifestError\";\n};\n/** Validates `storage`; errors name the remote and field at fault. */\nfunction parseStorage(value) {\n\tif (!isRecord(value) || !isRecord(value.remotes)) throw new ManifestError(`${FILE$1}: \"storage\" needs \"remotes\", e.g. { \"remotes\": { \"media\": { \"endpoint\": \"https://<account>.r2.cloudflarestorage.com\", \"bucket\": \"films\" } } }`);\n\tconst remotes = {};\n\tfor (const [name, spec] of Object.entries(value.remotes)) remotes[name] = parseRemote(name, spec);\n\tconst names = Object.keys(remotes);\n\tif (names.length === 0) throw new ManifestError(`${FILE$1}: \"storage.remotes\" is empty`);\n\tif (value.default !== void 0 && !names.includes(value.default)) throw new ManifestError(`${FILE$1}: \"storage.default\" must name a remote (${names.join(\", \")})`);\n\treturn {\n\t\t...typeof value.default === \"string\" && { default: value.default },\n\t\tremotes\n\t};\n}\nfunction parseRemote(name, spec) {\n\tconst fail = (message) => {\n\t\tthrow new ManifestError(`${FILE$1}: storage.remotes.${name} ${message}`);\n\t};\n\tif (!REMOTE_NAME.test(name)) fail(\"has an invalid name: use letters, digits, - and _ (at most 64)\");\n\tif (!isRecord(spec)) fail(\"must be an object with an endpoint and a bucket\");\n\tconst s = spec;\n\tif (!isHttpUrl(s.endpoint)) fail(\"needs \\\"endpoint\\\": the S3 API URL, e.g. \\\"https://<account>.r2.cloudflarestorage.com\\\"\");\n\tif (typeof s.bucket !== \"string\" || !/^[a-z0-9][a-z0-9.-]{1,62}$/.test(s.bucket)) fail(\"needs \\\"bucket\\\": the bucket name\");\n\tif (s.region !== void 0 && typeof s.region !== \"string\") fail(\"\\\"region\\\" must be a string\");\n\tif (s.prefix !== void 0 && (typeof s.prefix !== \"string\" || s.prefix.startsWith(\"/\") || s.prefix.split(\"/\").includes(\"..\"))) fail(\"\\\"prefix\\\" must be a key prefix such as \\\"films/launch/\\\"\");\n\tif (s.publicUrl !== void 0 && !isHttpUrl(s.publicUrl)) fail(\"\\\"publicUrl\\\" must be an http(s) URL, e.g. \\\"https://media.example.com\\\"\");\n\treturn {\n\t\tendpoint: s.endpoint,\n\t\tbucket: s.bucket,\n\t\t...s.region !== void 0 && { region: s.region },\n\t\t...typeof s.prefix === \"string\" && s.prefix && { prefix: normalizePrefix(s.prefix) },\n\t\t...s.publicUrl !== void 0 && { publicUrl: s.publicUrl }\n\t};\n}\n/** Validates `assets`; errors name the path and field at fault. */\nfunction parseAssets(value, storage) {\n\tif (!isRecord(value)) throw new ManifestError(`${FILE$1}: \"assets\" must map project paths to { \"sha256\", \"size\" }`);\n\tconst out = {};\n\tfor (const [path, entry] of Object.entries(value)) {\n\t\tconst fail = (message) => {\n\t\t\tthrow new ManifestError(`${FILE$1}: assets[\"${path}\"] ${message}`);\n\t\t};\n\t\tif (!isAssetPath(path)) fail(\"must be a path inside the project, e.g. assets/footage/intro.mp4\");\n\t\tif (!isRecord(entry)) fail(\"must be { \\\"sha256\\\", \\\"size\\\" }\");\n\t\tconst e = entry;\n\t\tif (typeof e.sha256 !== \"string\" || !SHA256.test(e.sha256)) fail(\"needs \\\"sha256\\\": 64 lowercase hex digits\");\n\t\tif (typeof e.size !== \"number\" || !Number.isSafeInteger(e.size) || e.size < 0) fail(\"needs \\\"size\\\" in bytes\");\n\t\tif (e.url !== void 0 && !isHttpUrl(e.url)) fail(\"\\\"url\\\" must be an http(s) URL\");\n\t\tif (e.remote !== void 0) {\n\t\t\tif (typeof e.remote !== \"string\" || !storage?.remotes[e.remote]) fail(`\"remote\" must name a remote in \"storage.remotes\"`);\n\t\t} else if (e.url === void 0 && !storage) fail(\"needs a \\\"url\\\", or a \\\"storage\\\" section with a remote to hold it\");\n\t\tout[path] = {\n\t\t\tsha256: e.sha256,\n\t\t\tsize: e.size,\n\t\t\t...e.remote !== void 0 && { remote: e.remote },\n\t\t\t...e.url !== void 0 && { url: e.url }\n\t\t};\n\t}\n\treturn out;\n}\n/** The remote an asset (or a new one, without `name`) belongs to. */\nfunction pickRemote(storage, name) {\n\tconst names = Object.keys(storage?.remotes ?? {});\n\tconst chosen = name ?? storage?.default ?? (names.length === 1 ? names[0] : void 0);\n\tif (!storage || names.length === 0) throw new ManifestError(`${FILE$1} has no \"storage\" remotes: add one (an R2 or S3 bucket) first`);\n\tif (!chosen) throw new ManifestError(`${FILE$1}: name the remote (${names.join(\", \")}), or set \"storage.default\"`);\n\tconst remote = storage.remotes[chosen];\n\tif (!remote) throw new ManifestError(`${FILE$1}: no remote named \"${chosen}\" (${names.join(\", \")})`);\n\treturn {\n\t\tname: chosen,\n\t\tremote\n\t};\n}\n/** The object key holding `sha256`: `<prefix>sha256/ab/<hash>`. */\nfunction objectKey(sha256, prefix = \"\") {\n\treturn `${prefix}sha256/${sha256.slice(0, 2)}/${sha256}`;\n}\n/** The asset's URL on the remote's public domain, if it has one. */\nfunction publicUrl(remote, sha256) {\n\tif (!remote.publicUrl) return void 0;\n\treturn `${remote.publicUrl.replace(/\\/+$/, \"\")}/${objectKey(sha256, remote.prefix)}`;\n}\n/**\n* Where to download an asset without credentials: a signed URL handed in\n* (`signed`, by sha256), its own `url`, or its remote's public domain.\n* Undefined means the asset is on a private remote and needs a signature.\n*/\nfunction readUrl(entry, storage, signed) {\n\tconst given = signed?.[entry.sha256];\n\tif (given) return given;\n\tif (entry.url) return entry.url;\n\tif (!storage) return void 0;\n\treturn publicUrl(pickRemote(storage, entry.remote).remote, entry.sha256);\n}\nfunction isAssetPath(path) {\n\treturn path.length > 0 && path.length <= 1024 && !path.startsWith(\"/\") && !path.includes(\"\\\\\") && !path.split(\"/\").some((part) => part === \"\" || part === \".\" || part === \"..\");\n}\nfunction normalizePrefix(prefix) {\n\treturn prefix.endsWith(\"/\") ? prefix : `${prefix}/`;\n}\nfunction isHttpUrl(value) {\n\tif (typeof value !== \"string\") return false;\n\ttry {\n\t\tconst { protocol } = new URL(value);\n\t\treturn protocol === \"https:\" || protocol === \"http:\";\n\t} catch {\n\t\treturn false;\n\t}\n}\nfunction isRecord(value) {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n//#endregion\n//#region src/bucket.ts\n/**\n* The few S3 calls asset storage needs (HEAD, PUT, multipart upload,\n* presigned GET), signed with SigV4 by aws4fetch. Works with any\n* S3-compatible service; R2 is the one to pick, since it charges no egress.\n*/\n/**\n* Keys for `remote` from the environment:\n* `FRAMEFIELDS_STORAGE_<REMOTE>_ACCESS_KEY_ID` / `…_SECRET_ACCESS_KEY`\n* (the remote's name upper-cased, `-` as `_`), else the standard\n* `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`.\n*/\nfunction credentialsFromEnv(remote, env = process.env) {\n\tconst scope = `FRAMEFIELDS_STORAGE_${remote.toUpperCase().replace(/-/g, \"_\")}`;\n\tconst own = env[`${scope}_ACCESS_KEY_ID`];\n\tconst ownSecret = env[`${scope}_SECRET_ACCESS_KEY`];\n\tif (own && ownSecret) return {\n\t\taccessKeyId: own,\n\t\tsecretAccessKey: ownSecret\n\t};\n\tconst id = env.AWS_ACCESS_KEY_ID;\n\tconst secret = env.AWS_SECRET_ACCESS_KEY;\n\tif (!id || !secret) return void 0;\n\treturn {\n\t\taccessKeyId: id,\n\t\tsecretAccessKey: secret,\n\t\t...env.AWS_SESSION_TOKEN && { sessionToken: env.AWS_SESSION_TOKEN }\n\t};\n}\n/** The env vars `credentialsFromEnv` reads for `remote`, for messages. */\nfunction credentialEnvNames(remote) {\n\tconst scope = `FRAMEFIELDS_STORAGE_${remote.toUpperCase().replace(/-/g, \"_\")}`;\n\treturn [`${scope}_ACCESS_KEY_ID`, `${scope}_SECRET_ACCESS_KEY`];\n}\nvar StorageError = class extends Error {\n\tname = \"StorageError\";\n\tconstructor(message, status) {\n\t\tsuper(message);\n\t\tthis.status = status;\n\t}\n};\nconst MiB = 1024 * 1024;\n/**\n* Content-addressed objects never change: CDNs and browsers may keep them\n* forever, which is what makes a custom domain in front of the bucket cheap.\n*/\nconst IMMUTABLE = \"public, max-age=31536000, immutable\";\n/** One remote's bucket, signed with `credentials`. */\nvar Bucket = class {\n\taws;\n\tfetch;\n\tconstructor(remote, credentials, options = {}) {\n\t\tthis.remote = remote;\n\t\tthis.options = options;\n\t\tthis.aws = new AwsClient({\n\t\t\t...credentials,\n\t\t\tservice: \"s3\",\n\t\t\tregion: remote.region ?? \"auto\",\n\t\t\tretries: 3\n\t\t});\n\t\tthis.fetch = options.fetch ?? fetch;\n\t}\n\tkeyFor(sha256) {\n\t\treturn objectKey(sha256, this.remote.prefix);\n\t}\n\t/** Whether the bucket holds `sha256` at the expected size. */\n\tasync has(sha256, size) {\n\t\tconst res = await this.send(this.keyFor(sha256), { method: \"HEAD\" });\n\t\tif (res.status === 404) return false;\n\t\tif (!res.ok) throw await this.failure(\"HEAD\", res);\n\t\treturn Number(res.headers.get(\"content-length\")) === size;\n\t}\n\t/**\n\t* Uploads `file` (already hashed) under its content key. The bucket\n\t* checks every byte against the sha256 sent with it.\n\t*/\n\tasync upload(file, digest, onProgress) {\n\t\tconst key = this.keyFor(digest.sha256);\n\t\tconst headers = {\n\t\t\t\"content-type\": contentType(file),\n\t\t\t\"cache-control\": IMMUTABLE\n\t\t};\n\t\tconst threshold = this.options.multipartThreshold ?? 64 * MiB;\n\t\tif (digest.size <= threshold) {\n\t\t\tconst handle = await open(file);\n\t\t\ttry {\n\t\t\t\tconst body = await handle.readFile();\n\t\t\t\tawait this.put(key, body, digest.sha256, headers);\n\t\t\t} finally {\n\t\t\t\tawait handle.close();\n\t\t\t}\n\t\t\tonProgress?.({\n\t\t\t\tsent: digest.size,\n\t\t\t\ttotal: digest.size\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tawait this.uploadParts(file, key, digest.size, headers, onProgress);\n\t}\n\t/** A GET URL anyone can use until it expires (at most 7 days). */\n\tasync presign(sha256, expiresSec = 86400) {\n\t\tconst url = new URL(this.url(this.keyFor(sha256)));\n\t\turl.searchParams.set(\"X-Amz-Expires\", String(Math.min(expiresSec, 604800)));\n\t\treturn (await this.aws.sign(url, {\n\t\t\tmethod: \"GET\",\n\t\t\taws: { signQuery: true }\n\t\t})).url;\n\t}\n\tasync put(key, body, sha256, headers, query = \"\") {\n\t\tconst res = await this.send(key, {\n\t\t\tmethod: \"PUT\",\n\t\t\tbody,\n\t\t\theaders: {\n\t\t\t\t...headers,\n\t\t\t\t\"x-amz-content-sha256\": sha256\n\t\t\t},\n\t\t\tquery\n\t\t});\n\t\tif (!res.ok) throw await this.failure(\"PUT\", res);\n\t\treturn res;\n\t}\n\tasync uploadParts(file, key, size, headers, onProgress) {\n\t\tconst partSize = Math.max(this.options.partSize ?? 16 * MiB, Math.ceil(size / 1e4), 5 * MiB);\n\t\tconst created = await this.send(key, {\n\t\t\tmethod: \"POST\",\n\t\t\tquery: \"uploads=\",\n\t\t\theaders\n\t\t});\n\t\tif (!created.ok) throw await this.failure(\"CreateMultipartUpload\", created);\n\t\tconst uploadId = /<UploadId>([^<]+)<\\/UploadId>/.exec(await created.text())?.[1];\n\t\tif (!uploadId) throw new StorageError(\"CreateMultipartUpload returned no UploadId\");\n\t\tconst id = encodeURIComponent(uploadId);\n\t\tconst count = Math.ceil(size / partSize);\n\t\tconst etags = new Array(count);\n\t\tconst handle = await open(file);\n\t\tlet next = 0;\n\t\tlet sent = 0;\n\t\tconst worker = async () => {\n\t\t\twhile (next < count) {\n\t\t\t\tconst index = next++;\n\t\t\t\tconst length = Math.min(partSize, size - index * partSize);\n\t\t\t\tconst chunk = Buffer.alloc(length);\n\t\t\t\tawait handle.read(chunk, 0, length, index * partSize);\n\t\t\t\tconst sha = createHash(\"sha256\").update(chunk).digest(\"hex\");\n\t\t\t\tetags[index] = (await this.put(key, chunk, sha, {}, `partNumber=${index + 1}&uploadId=${id}`)).headers.get(\"etag\") ?? \"\";\n\t\t\t\tsent += length;\n\t\t\t\tonProgress?.({\n\t\t\t\t\tsent,\n\t\t\t\t\ttotal: size\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\ttry {\n\t\t\tawait Promise.all(Array.from({ length: Math.min(this.options.concurrency ?? 4, count) }, worker));\n\t\t\tconst body = `<CompleteMultipartUpload>${etags.map((etag, i) => `<Part><PartNumber>${i + 1}</PartNumber><ETag>${escapeXml(etag)}</ETag></Part>`).join(\"\")}</CompleteMultipartUpload>`;\n\t\t\tconst done = await this.send(key, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tquery: `uploadId=${id}`,\n\t\t\t\tbody,\n\t\t\t\theaders: { \"content-type\": \"application/xml\" }\n\t\t\t});\n\t\t\tconst text = await done.text();\n\t\t\tif (!done.ok || text.includes(\"<Error>\")) throw new StorageError(`CompleteMultipartUpload failed (${done.status}): ${errorCode(text)}`, done.status);\n\t\t} catch (err) {\n\t\t\tawait this.send(key, {\n\t\t\t\tmethod: \"DELETE\",\n\t\t\t\tquery: `uploadId=${id}`\n\t\t\t}).catch(() => void 0);\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tawait handle.close();\n\t\t}\n\t}\n\turl(key, query = \"\") {\n\t\tconst base = this.remote.endpoint.replace(/\\/+$/, \"\");\n\t\tconst path = key.split(\"/\").map(encodeURIComponent).join(\"/\");\n\t\treturn `${base}/${this.remote.bucket}/${path}${query ? `?${query}` : \"\"}`;\n\t}\n\tasync send(key, init) {\n\t\tconst signed = await this.aws.sign(this.url(key, init.query), {\n\t\t\tmethod: init.method,\n\t\t\theaders: init.headers,\n\t\t\tbody: init.body\n\t\t});\n\t\treturn this.fetch(signed);\n\t}\n\tasync failure(what, res) {\n\t\tconst text = await res.text().catch(() => \"\");\n\t\tconst hint = res.status === 403 ? \": check the remote's keys and that they may write to the bucket\" : res.status === 404 ? \": check the remote's endpoint and bucket\" : \"\";\n\t\treturn new StorageError(`${what} ${this.remote.bucket} failed (${res.status} ${errorCode(text)})${hint}`, res.status);\n\t}\n};\nfunction errorCode(xml) {\n\treturn /<Code>([^<]+)<\\/Code>/.exec(xml)?.[1] ?? \"no error code\";\n}\nfunction escapeXml(text) {\n\treturn text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/\"/g, \"&quot;\");\n}\n\n//#endregion\n//#region src/locate.ts\n/**\n* Finding a project's pinned assets from file paths: what a preview or an\n* engine asks for is an absolute path, and a pinned file that isn't on disk\n* is read from its bucket instead.\n*/\nconst FILE = \"framefields.json\";\n/** The nearest folder at or above `dir` holding a framefields.json. */\nfunction findProjectDir(dir) {\n\tfor (let at = dir;; at = dirname(at)) {\n\t\tif (existsSync(join(at, FILE))) return at;\n\t\tif (dirname(at) === at) return void 0;\n\t}\n}\n/** The `storage` and `assets` of the project at `dir`; undefined without assets. */\nasync function readProjectManifest(dir) {\n\tconst file = join(dir, FILE);\n\tif (!existsSync(file)) return void 0;\n\tlet raw;\n\ttry {\n\t\traw = JSON.parse(await readFile(file, \"utf8\"));\n\t} catch (err) {\n\t\tthrow new ManifestError(`${FILE} is not valid JSON: ${err.message}`);\n\t}\n\tif (raw.assets === void 0) return void 0;\n\tconst storage = raw.storage === void 0 ? void 0 : parseStorage(raw.storage);\n\treturn {\n\t\tstorage,\n\t\tassets: parseAssets(raw.assets, storage)\n\t};\n}\n/** Signatures last 6 h and are reused for 5, so long sessions keep working. */\nconst SIGNED_SEC = 6 * 3600;\nconst REUSE_MS = 5 * 3600 * 1e3;\n/**\n* Pinned-asset lookup for the project at or above `dir`, or undefined when\n* it pins none.\n*/\nasync function openAssetLocator(dir, options = {}) {\n\tconst root = findProjectDir(dir);\n\tconst manifest = root && await readProjectManifest(root);\n\tif (!root || !manifest) return void 0;\n\tconst signed = /* @__PURE__ */ new Map();\n\tconst entry = (file) => {\n\t\tconst rel = relative(root, file).split(sep).join(\"/\");\n\t\treturn rel.startsWith(\"../\") ? void 0 : manifest.assets[rel];\n\t};\n\treturn {\n\t\troot,\n\t\tentry,\n\t\tasync url(file) {\n\t\t\tconst pinned = entry(file);\n\t\t\tif (!pinned) return void 0;\n\t\t\tconst open$1 = readUrl(pinned, manifest.storage);\n\t\t\tif (open$1) return open$1;\n\t\t\tconst cached = signed.get(pinned.sha256);\n\t\t\tif (cached && Date.now() - cached.at < REUSE_MS) return cached.url;\n\t\t\tconst { name, remote } = pickRemote(manifest.storage, pinned.remote);\n\t\t\tconst keys = credentialsFromEnv(name, options.env);\n\t\t\tif (!keys) return void 0;\n\t\t\tconst url = await new Bucket(remote, keys, { fetch: options.fetch }).presign(pinned.sha256, SIGNED_SEC);\n\t\t\tsigned.set(pinned.sha256, {\n\t\t\t\turl,\n\t\t\t\tat: Date.now()\n\t\t\t});\n\t\t\treturn url;\n\t\t}\n\t};\n}\n\n//#endregion\nexport { AssetError, Bucket, ManifestError, REMOTE_NAME, SHA256, StorageError, contentType, credentialEnvNames, credentialsFromEnv, downloadVerified, findProjectDir, hashFile, isAssetPath, objectKey, openAssetLocator, parseAssets, parseStorage, pickRemote, publicUrl, readProjectManifest, readUrl, redactQuery };\n//# sourceMappingURL=index.mjs.map"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fonts-OW3yAfO5.mjs","names":[],"sources":["../src/fonts/manager.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n\tregisterHeadlessFont,\n\tSlugFontCache,\n\tSlugGeometry,\n\tsetRegisteredFontSource,\n} from \"@framefields/webgpu-renderers\";\nimport * as fontkit from \"fontkit\";\n\nexport interface RegisterFontOptions {\n\tfamily?: string;\n\tsource: string | Uint8Array;\n\tweight?: number | string;\n\tstyle?: \"normal\" | \"italic\" | \"oblique\";\n}\n\nexport interface RegisteredFont {\n\tfamily: string;\n\tsource: string | Uint8Array;\n\tfilePath?: string;\n\tformat: \"truetype\" | \"opentype\";\n\tpostscriptName?: string;\n\tunitsPerEm?: number;\n\tweight?: number | string;\n\tstyle?: string;\n}\n\ninterface ResolvedSource {\n\tbuffer: Uint8Array;\n\tfilePath?: string;\n}\n\nconst SFNT_TRUETYPE_1 = 0x00010000;\nconst SFNT_TRUETYPE_TRUE = 0x74727565; // 'true'\nconst SFNT_TRUETYPE_TYP1 = 0x74797031; // 'typ1'\nconst SFNT_OPENTYPE_CFF = 0x4f54544f; // 'OTTO'\nconst SFNT_COLLECTION = 0x74746366; // 'ttcf'\n\nfunction validateFontBinaryHeader(\n\tbytes: Uint8Array,\n\tsourceLabel: string,\n): \"truetype\" | \"opentype\" {\n\tif (bytes.length < 12) {\n\t\tthrow new Error(\n\t\t\t`Invalid font binary for \"${sourceLabel}\": File size (${bytes.length} bytes) is too small to be a valid TrueType or OpenType font.`,\n\t\t);\n\t}\n\n\tconst tag =\n\t\t((bytes[0] ?? 0) << 24) |\n\t\t((bytes[1] ?? 0) << 16) |\n\t\t((bytes[2] ?? 0) << 8) |\n\t\t(bytes[3] ?? 0);\n\n\tif (\n\t\ttag === SFNT_TRUETYPE_1 ||\n\t\ttag === SFNT_TRUETYPE_TRUE ||\n\t\ttag === SFNT_TRUETYPE_TYP1 ||\n\t\ttag === SFNT_COLLECTION\n\t) {\n\t\treturn \"truetype\";\n\t}\n\n\tif (tag === SFNT_OPENTYPE_CFF) {\n\t\treturn \"opentype\";\n\t}\n\n\tconst hexTag = (tag >>> 0).toString(16).padStart(8, \"0\");\n\tthrow new Error(\n\t\t`Invalid font format for \"${sourceLabel}\": Expected a valid TrueType (.ttf) or OpenType (.otf) font binary. Found header tag: 0x${hexTag}.`,\n\t);\n}\n\nasync function resolveSourceBuffer(\n\tsource: string | Uint8Array,\n): Promise<ResolvedSource> {\n\tif (source instanceof Uint8Array) {\n\t\treturn { buffer: source };\n\t}\n\n\tif (typeof source !== \"string\") {\n\t\tthrow new TypeError(\n\t\t\t`Font source must be a file path string or Uint8Array, received: ${typeof source}`,\n\t\t);\n\t}\n\n\tlet cleanPath = source;\n\tif (cleanPath.startsWith(\"http://\") || cleanPath.startsWith(\"https://\")) {\n\t\tconst res = await fetch(cleanPath);\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to download font from \"${cleanPath}\": HTTP ${res.status} ${res.statusText}`,\n\t\t\t);\n\t\t}\n\t\tconst arrayBuffer = await res.arrayBuffer();\n\t\treturn {\n\t\t\tbuffer: new Uint8Array(arrayBuffer),\n\t\t\tfilePath: cleanPath,\n\t\t};\n\t}\n\n\tif (cleanPath.startsWith(\"file://\")) {\n\t\ttry {\n\t\t\t// A URL path is percent-encoded (\"My%20Film\"); files aren't. On\n\t\t\t// Windows \"/C:/…\" loses its leading slash.\n\t\t\tcleanPath = decodeURIComponent(new URL(cleanPath).pathname).replace(\n\t\t\t\t/^\\/([A-Za-z]:)/,\n\t\t\t\t\"$1\",\n\t\t\t);\n\t\t} catch {\n\t\t\tcleanPath = cleanPath.replace(/^file:\\/\\//, \"\");\n\t\t}\n\t}\n\n\tconst candidates: string[] = [\n\t\tcleanPath,\n\t\tpath.resolve(process.cwd(), cleanPath),\n\t\tpath.resolve(process.cwd(), \"assets/fonts\", cleanPath),\n\t\tpath.resolve(process.cwd(), \"assets/fonts\", path.basename(cleanPath)),\n\t];\n\n\t// Upward traversal to locate fonts in parent monorepo roots\n\tlet currentDir = process.cwd();\n\tfor (let i = 0; i < 5; i++) {\n\t\tcandidates.push(path.resolve(currentDir, cleanPath));\n\t\tcandidates.push(\n\t\t\tpath.resolve(currentDir, \"assets/fonts\", path.basename(cleanPath)),\n\t\t);\n\t\tconst parent = path.dirname(currentDir);\n\t\tif (parent === currentDir) break;\n\t\tcurrentDir = parent;\n\t}\n\n\tlet resolvedPath: string | null = null;\n\tlet fileBuffer: Buffer | null = null;\n\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst stat = await fs.stat(candidate);\n\t\t\tif (stat.isFile()) {\n\t\t\t\tresolvedPath = candidate;\n\t\t\t\tfileBuffer = await fs.readFile(candidate);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Continue searching next candidate\n\t\t}\n\t}\n\n\tif (!resolvedPath || !fileBuffer) {\n\t\tthrow new Error(\n\t\t\t`Font file not found: \"${source}\". Checked candidate locations:\\n - ${candidates.join(\"\\n - \")}`,\n\t\t);\n\t}\n\n\treturn {\n\t\tbuffer: new Uint8Array(\n\t\t\tfileBuffer.buffer,\n\t\t\tfileBuffer.byteOffset,\n\t\t\tfileBuffer.byteLength,\n\t\t),\n\t\tfilePath: resolvedPath,\n\t};\n}\n\n/**\n * Central singleton manager for font registration, TTF validation, and compositor typography binding.\n */\nexport interface MeasureTextOptions {\n\tfontFamily: string;\n\tfontSize?: number;\n\tfontWeight?: string | number;\n\t/** Extra px between characters, as on `Layer.text`. */\n\tletterSpacing?: number;\n\t/** Multiplier of fontSize when < 10, else px. Default 1.2. */\n\tlineHeight?: number;\n\t/** Wrap width in px; omit for one line per `\\n`. */\n\twidth?: number;\n\talign?: \"left\" | \"center\" | \"right\";\n\t/** Paragraph base direction, as on `Layer.text`. Default \"auto\". */\n\tdirection?: \"ltr\" | \"rtl\" | \"auto\";\n}\n\nexport interface MeasuredGlyph {\n\tchar: string;\n\t/** Index into the string (code units), matching `text.slice`. */\n\tindex: number;\n\t/** Left edge of the glyph, relative to the text box. */\n\tx: number;\n\t/** Baseline-relative top of the line box. */\n\ty: number;\n\t/** Advance width in px. */\n\twidth: number;\n\tline: number;\n\t/** Part of a right-to-left run: reading continues to the left. */\n\trtl?: boolean;\n}\n\nexport interface TextMetrics {\n\twidth: number;\n\theight: number;\n\tlines: number;\n\t/** Line box height in px. */\n\tlineHeight: number;\n\tglyphs: MeasuredGlyph[];\n\t/**\n\t * X of a caret placed after `count` characters (0 = before the first),\n\t * relative to the text box. In right-to-left text the caret sits on the\n\t * left of the last character. Pair with a `.keys(\"text\", …)` reveal to make\n\t * a cursor follow typing exactly.\n\t */\n\tcaretX(count: number): number;\n\t/** Width of the first `count` characters (same as `caretX` on one line). */\n\twidthOf(count: number): number;\n}\n\nexport class FontManager {\n\tprivate static instance: FontManager | null = null;\n\tprivate readonly fonts = new Map<string, RegisteredFont>();\n\n\tprivate constructor() {}\n\n\t/**\n\t * Returns the singleton FontManager instance.\n\t */\n\tpublic static getInstance(): FontManager {\n\t\tif (!FontManager.instance) {\n\t\t\tFontManager.instance = new FontManager();\n\t\t}\n\t\treturn FontManager.instance;\n\t}\n\n\t/**\n\t * Registers a TrueType/OpenType font into the Framefields engine with validation.\n\t */\n\tpublic static async register(\n\t\toptionsOrFamilyOrSource: RegisterFontOptions | string,\n\t\tsource?: string | Uint8Array,\n\t): Promise<RegisteredFont> {\n\t\treturn FontManager.getInstance().register(optionsOrFamilyOrSource, source);\n\t}\n\n\t/**\n\t * Sets the color emoji font text draws emoji with, for the preview and the\n\t * export alike: a CBDT/CBLC bitmap font such as Noto Color Emoji, as a file\n\t * path, URL or bytes. framefields ships none; without one, exports draw\n\t * nothing for emoji.\n\t */\n\tpublic static async registerEmojiFont(\n\t\tsource: string | Uint8Array,\n\t): Promise<void> {\n\t\tconst { buffer, filePath } = await resolveSourceBuffer(source);\n\t\tconst label =\n\t\t\tfilePath ?? (typeof source === \"string\" ? source : \"Uint8Array\");\n\t\tvalidateFontBinaryHeader(buffer, label);\n\t\tSlugFontCache.setEmojiFont(buffer, filePath);\n\t}\n\n\t/** Whether a color emoji font is registered (or set to load from a path / URL). */\n\tpublic static hasEmojiFont(): boolean {\n\t\treturn SlugFontCache.hasEmojiFont();\n\t}\n\n\t/**\n\t * Measures text with the real font, exactly as `Layer.text` lays it out:\n\t * box size, line count, per-glyph positions and caret offsets. Use it to\n\t * size containers, place cursors, underline a word or center by ink\n\t * instead of guessing advances. The family must be registered first.\n\t *\n\t * ```ts\n\t * const m = FontManager.measure(\"Hello\", { fontFamily: \"Inter\", fontSize: 60 });\n\t * m.width; m.caretX(3); m.glyphs[1].x\n\t * ```\n\t */\n\tpublic static measure(\n\t\ttext: string,\n\t\toptions: MeasureTextOptions,\n\t): TextMetrics {\n\t\tconst fontSize = options.fontSize ?? 48;\n\t\tconst font = SlugFontCache.getFont(\n\t\t\toptions.fontFamily,\n\t\t\toptions.fontWeight,\n\t\t\tnull,\n\t\t\tundefined,\n\t\t\tfontSize,\n\t\t);\n\t\tif (!font) {\n\t\t\tthrow new Error(\n\t\t\t\t`FontManager.measure: font \"${options.fontFamily}\" is not registered. ` +\n\t\t\t\t\t\"Call `await FontManager.register(...)` first.\",\n\t\t\t);\n\t\t}\n\t\tconst lineHeight =\n\t\t\toptions.lineHeight !== undefined && options.lineHeight < 10\n\t\t\t\t? options.lineHeight * fontSize\n\t\t\t\t: (options.lineHeight ?? fontSize * 1.2);\n\t\tconst letterSpacing = options.letterSpacing ?? 0;\n\t\tconst { width, height, layout } = SlugGeometry.measure(\n\t\t\ttext,\n\t\t\tfont,\n\t\t\tfontSize,\n\t\t\tletterSpacing,\n\t\t\tlineHeight,\n\t\t\toptions.width,\n\t\t\tundefined,\n\t\t\toptions.direction,\n\t\t);\n\t\tconst scale = fontSize / font.unitsPerEm;\n\t\t// One entry per cluster (a letter with its marks, or a ligature), in\n\t\t// reading order; textIndex maps it back to the string.\n\t\tconst glyphs: MeasuredGlyph[] = [];\n\t\tconst seen = new Set<number>();\n\t\tlet cursor = 0;\n\t\tfor (const g of layout.glyphs) {\n\t\t\tlet index = g.textIndex;\n\t\t\tif (index === undefined) {\n\t\t\t\tconst at = text.indexOf(g.char, cursor);\n\t\t\t\tindex = at >= 0 ? at : cursor;\n\t\t\t}\n\t\t\tif (seen.has(index)) continue;\n\t\t\tseen.add(index);\n\t\t\tcursor = index + g.char.length;\n\t\t\tconst advance =\n\t\t\t\tg.clusterAdvance ?? g.cp.advanceWidth * (g.fontScale ?? scale);\n\t\t\tglyphs.push({\n\t\t\t\tchar: g.char,\n\t\t\t\tindex,\n\t\t\t\tx: g.clusterX ?? g.x,\n\t\t\t\ty: g.y,\n\t\t\t\twidth: advance + letterSpacing,\n\t\t\t\tline: g.lineIndex,\n\t\t\t\t...(g.rtl && { rtl: true }),\n\t\t\t});\n\t\t}\n\t\tconst caretX = (count: number): number => {\n\t\t\tif (count <= 0 || glyphs.length === 0) {\n\t\t\t\tconst first = glyphs[0];\n\t\t\t\tif (!first) return 0;\n\t\t\t\treturn first.rtl ? first.x + first.width - letterSpacing : first.x;\n\t\t\t}\n\t\t\tconst before = glyphs.filter((g) => g.index < count);\n\t\t\tconst last = before[before.length - 1];\n\t\t\tif (!last) return 0;\n\t\t\treturn last.rtl ? last.x : last.x + last.width - letterSpacing;\n\t\t};\n\t\treturn {\n\t\t\twidth,\n\t\t\theight,\n\t\t\tlines: layout.linesCount,\n\t\t\tlineHeight,\n\t\t\tglyphs,\n\t\t\tcaretX,\n\t\t\twidthOf: (count: number) => caretX(count) - (glyphs[0]?.x ?? 0),\n\t\t};\n\t}\n\n\t/**\n\t * Retrieves registered font metadata by family name.\n\t */\n\tpublic static get(family: string): RegisteredFont | undefined {\n\t\treturn FontManager.getInstance().get(family);\n\t}\n\n\t/**\n\t * Checks if a font family has been registered.\n\t */\n\tpublic static has(family: string): boolean {\n\t\treturn FontManager.getInstance().has(family);\n\t}\n\n\t/**\n\t * Returns all currently registered fonts.\n\t */\n\tpublic static getAll(): RegisteredFont[] {\n\t\treturn FontManager.getInstance().getAll();\n\t}\n\n\t/**\n\t * Returns relative or absolute file paths of all registered fonts for composition spec serialization.\n\t */\n\tpublic static getRegisteredFontPaths(): string[] {\n\t\treturn FontManager.getInstance().getRegisteredFontPaths();\n\t}\n\n\t/**\n\t * Clears all registered fonts from the manager.\n\t */\n\tpublic static clear(): void {\n\t\tFontManager.getInstance().clear();\n\t}\n\n\t/**\n\t * Instance registration method with format validation and Slug WebGPU cache population.\n\t */\n\tpublic async register(\n\t\toptionsOrFamilyOrSource: RegisterFontOptions | string,\n\t\tsource?: string | Uint8Array,\n\t): Promise<RegisteredFont> {\n\t\tlet family: string | undefined;\n\t\tlet rawSource: string | Uint8Array;\n\t\tlet weight: number | string | undefined;\n\t\tlet style: \"normal\" | \"italic\" | \"oblique\" | undefined;\n\n\t\tif (\n\t\t\ttypeof optionsOrFamilyOrSource === \"object\" &&\n\t\t\toptionsOrFamilyOrSource !== null\n\t\t) {\n\t\t\tfamily = optionsOrFamilyOrSource.family;\n\t\t\trawSource = optionsOrFamilyOrSource.source;\n\t\t\tweight = optionsOrFamilyOrSource.weight;\n\t\t\tstyle = optionsOrFamilyOrSource.style;\n\t\t} else if (\n\t\t\ttypeof optionsOrFamilyOrSource === \"string\" &&\n\t\t\tsource !== undefined\n\t\t) {\n\t\t\tfamily = optionsOrFamilyOrSource;\n\t\t\trawSource = source;\n\t\t} else if (typeof optionsOrFamilyOrSource === \"string\") {\n\t\t\tfamily = undefined;\n\t\t\trawSource = optionsOrFamilyOrSource;\n\t\t} else {\n\t\t\tthrow new TypeError(\"Invalid arguments passed to FontManager.register\");\n\t\t}\n\n\t\tconst { buffer, filePath } = await resolveSourceBuffer(rawSource);\n\t\tconst sourceLabel =\n\t\t\tfilePath ?? (typeof rawSource === \"string\" ? rawSource : \"Uint8Array\");\n\t\tconst format = validateFontBinaryHeader(buffer, sourceLabel);\n\n\t\tlet parsedFontkit: fontkit.Font;\n\t\ttry {\n\t\t\tconst parsed = fontkit.create(buffer as unknown as Buffer);\n\t\t\tif (\n\t\t\t\tparsed &&\n\t\t\t\t\"fonts\" in parsed &&\n\t\t\t\tArray.isArray(parsed.fonts) &&\n\t\t\t\tparsed.fonts.length > 0\n\t\t\t) {\n\t\t\t\tparsedFontkit = parsed.fonts[0] as fontkit.Font;\n\t\t\t} else {\n\t\t\t\tparsedFontkit = parsed as fontkit.Font;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to parse TrueType/OpenType font binary for \"${sourceLabel}\": ${msg}`,\n\t\t\t);\n\t\t}\n\n\t\tconst detectedFamily =\n\t\t\tparsedFontkit.familyName ||\n\t\t\tparsedFontkit.postscriptName ||\n\t\t\tpath.parse(sourceLabel).name;\n\t\tconst resolvedFamily = family?.trim() || detectedFamily;\n\n\t\tconst registered: RegisteredFont = {\n\t\t\tfamily: resolvedFamily,\n\t\t\tsource: rawSource,\n\t\t\tfilePath,\n\t\t\tformat,\n\t\t\tpostscriptName: parsedFontkit.postscriptName,\n\t\t\tunitsPerEm: parsedFontkit.unitsPerEm,\n\t\t\tweight,\n\t\t\tstyle,\n\t\t};\n\n\t\tthis.fonts.set(resolvedFamily, registered);\n\n\t\tsetRegisteredFontSource(resolvedFamily, filePath ?? rawSource);\n\t\t// Populate headless font registries\n\t\tif (filePath) {\n\t\t\tawait registerHeadlessFont(resolvedFamily, filePath);\n\t\t}\n\t\tSlugFontCache.setParsed(resolvedFamily, parsedFontkit);\n\n\t\treturn registered;\n\t}\n\n\tpublic get(family: string): RegisteredFont | undefined {\n\t\treturn this.fonts.get(family);\n\t}\n\n\tpublic has(family: string): boolean {\n\t\treturn this.fonts.has(family);\n\t}\n\n\tpublic getAll(): RegisteredFont[] {\n\t\treturn Array.from(this.fonts.values());\n\t}\n\n\tpublic getRegisteredFontPaths(): string[] {\n\t\tconst paths: string[] = [];\n\t\tfor (const font of this.fonts.values()) {\n\t\t\tif (font.filePath) {\n\t\t\t\tpaths.push(font.filePath);\n\t\t\t} else if (typeof font.source === \"string\") {\n\t\t\t\tpaths.push(font.source);\n\t\t\t}\n\t\t}\n\t\treturn paths;\n\t}\n\n\tpublic clear(): void {\n\t\tthis.fonts.clear();\n\t}\n}\n"],"mappings":"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"}