@fudanda/admin-antd 0.0.0-stage → 2.20261024.1-beta.1

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 (482) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -3
  3. package/THIRD_PARTY_NOTICES.md +55 -0
  4. package/dist/assets/libarchive-DxGirPmi.wasm +0 -0
  5. package/dist/assets/pdfium-BJ2Yip8Q.wasm +0 -0
  6. package/dist/assets/ppt-font-cjk-DxgKpThH.otf +0 -0
  7. package/dist/assets/ppt-native-Cz5DBbag.wasm +0 -0
  8. package/dist/assets/pptx.worker-CtaL8LO_.js +30 -0
  9. package/dist/assets/worker-C5LZNsKY.mjs +1650 -0
  10. package/dist/assets/worker-CDeo9jS-.js +40 -0
  11. package/dist/assets/worker-bundle-Dx5mKZOL.js +6 -0
  12. package/dist/automation.d.ts +3 -0
  13. package/dist/automation.js +15 -0
  14. package/dist/chunks/App-DNjXLysb.js +79 -0
  15. package/dist/chunks/AppModal-DJzQA6FR.js +1 -0
  16. package/dist/chunks/ArcBaseAdmin-BZrHGq2f.js +1 -0
  17. package/dist/chunks/ConfigurableTable-DzmZDd8F.js +55 -0
  18. package/dist/chunks/DashboardPage-BohGodSl.js +22 -0
  19. package/dist/chunks/DataScopePanel-B2-x8Jcz.js +1 -0
  20. package/dist/chunks/DateTimeText-CIt0Qy45.js +1 -0
  21. package/dist/chunks/DepartmentsPage-DMWY__Y_.js +1 -0
  22. package/dist/chunks/DictTag-2-adKbYg.js +1 -0
  23. package/dist/chunks/DictsPage-DILDyHi-.js +15 -0
  24. package/dist/chunks/EditFormModal-DNHOZHxM.js +1 -0
  25. package/dist/chunks/EmptyIllustration-DUC3RZmF.js +1 -0
  26. package/dist/chunks/EntityContextRuntime-DMklAv-k.js +1 -0
  27. package/dist/chunks/EntityContextRuntime-sslBZqYD.js +1 -0
  28. package/dist/chunks/EntityRelationButton-DWn1rC2J.js +8 -0
  29. package/dist/chunks/ExportButton-AzH4D0oW.js +1 -0
  30. package/dist/chunks/FileNameCell-DPyi64Rv.js +1 -0
  31. package/dist/chunks/FileStorageConfigsPage-CzuOgeK0.js +15 -0
  32. package/dist/chunks/FileTypeIcon-DIih3XQG.js +1 -0
  33. package/dist/chunks/FileViewerPreviewPanel-CMqVtGCr.js +41 -0
  34. package/dist/chunks/FilesPage-BaEBCOCs.js +43 -0
  35. package/dist/chunks/IdentitySecurityPage-BO7nY8id.js +1 -0
  36. package/dist/chunks/JsonPreviewPanel-Dhbza-Uu.js +1 -0
  37. package/dist/chunks/LogStatsScaffold-CLycj3da.js +1 -0
  38. package/dist/chunks/LoginLogsPage-DTmHi8u0.js +1 -0
  39. package/dist/chunks/LoginLogsTable-DVmHnC6V.js +1 -0
  40. package/dist/chunks/MarkdownPreviewPanel-DoiaAeRv.js +51 -0
  41. package/dist/chunks/MasterDetailLayout-sjPWw8BI.js +8 -0
  42. package/dist/chunks/MemberAssignmentSheet-Czbt6_zv.js +1 -0
  43. package/dist/chunks/MenuCommandPalette-BCOzf-Kq.js +8 -0
  44. package/dist/chunks/MenusPage-DN8DTGB1.js +1 -0
  45. package/dist/chunks/ModalFooter-RMlvqrO9.js +1 -0
  46. package/dist/chunks/MonacoPreviewPanel-Dnz7xpWP.js +1 -0
  47. package/dist/chunks/NavListPanel-vjIOIqK0.js +1 -0
  48. package/dist/chunks/OnlineSessionsPage-FoHYZKlR.js +1 -0
  49. package/dist/chunks/OperationLogsPage-BeRnGcBJ.js +1 -0
  50. package/dist/chunks/OperationLogsTable-COI-Lp-y.js +1 -0
  51. package/dist/chunks/PDFPreviewPanel-BIQuBnZZ.js +37 -0
  52. package/dist/chunks/PasswordInput-DGEJO9yx.js +1 -0
  53. package/dist/chunks/PositionsPage-DohI0luX.js +1 -0
  54. package/dist/chunks/PreferencesSheetBody-B9niQABW.js +43 -0
  55. package/dist/chunks/ProfilePage-CVTRv7xb.js +15 -0
  56. package/dist/chunks/RelationPanel-B1X6AVaM.js +36 -0
  57. package/dist/chunks/ResponsiveTableActions-y54aSdhs.js +1 -0
  58. package/dist/chunks/RolesPage-CtUw93L8.js +1 -0
  59. package/dist/chunks/ScrollArea-DqjJmHDN.js +11 -0
  60. package/dist/chunks/SearchToolbar-CvgYKUjr.js +1 -0
  61. package/dist/chunks/SessionClientTag-DIwnYodW.js +22 -0
  62. package/dist/chunks/SessionConflictModal-BLNuDsN_.js +1 -0
  63. package/dist/chunks/SettingRow-DVNmTJWC.js +1 -0
  64. package/dist/chunks/SettingsPage-BRnCxYQm.js +26 -0
  65. package/dist/chunks/StatCard-Czjfs0fa.js +4 -0
  66. package/dist/chunks/UTIF-QUtClmQd.js +1 -0
  67. package/dist/chunks/UserAvatar-B8CFnTCn.js +1 -0
  68. package/dist/chunks/UserDisplay-J0Re8z-7.js +1 -0
  69. package/dist/chunks/UserGroupsPage-CNwbejx-.js +1 -0
  70. package/dist/chunks/UserLogsPanels-BHeSxWrk.js +36 -0
  71. package/dist/chunks/UserTransferSelect-CAeyxdor.js +22 -0
  72. package/dist/chunks/UsersPage-BXt9fOru.js +36 -0
  73. package/dist/chunks/abnfDiagram-VCTEODGH-Z6OhNjoW.js +1 -0
  74. package/dist/chunks/activity-DBu4axwF.js +8 -0
  75. package/dist/chunks/arc-B3K1fDeF.js +1 -0
  76. package/dist/chunks/architecture-7GRP2DOG-CMtoOwin.js +1 -0
  77. package/dist/chunks/architectureDiagram-5GKGNRK7-V5A7S5fY.js +36 -0
  78. package/dist/chunks/archive-B_IKvysI.js +72 -0
  79. package/dist/chunks/array-BrHhzP_A.js +1 -0
  80. package/dist/chunks/arrow-left-CsxBMzKY.js +8 -0
  81. package/dist/chunks/avsc-C0VoJRmm.js +160 -0
  82. package/dist/chunks/blockDiagram-I7D4REHJ-CFKGJkc_.js +129 -0
  83. package/dist/chunks/browser-BKLM0ThC-mnGPrtB_.js +1 -0
  84. package/dist/chunks/browser-index-JqxD-45S.js +1 -0
  85. package/dist/chunks/builtin_esm-external-require-react-BsBndGeN.js +1 -0
  86. package/dist/chunks/bundle-DbfUnEV1.js +29 -0
  87. package/dist/chunks/c4Diagram-7LVT6UL2-BqYYoXPe.js +38 -0
  88. package/dist/chunks/channel-C9Dr7Z-W.js +1 -0
  89. package/dist/chunks/chart-data-DImT_Mzn.js +5 -0
  90. package/dist/chunks/chart-renderer-k-Rd8vdL.js +7 -0
  91. package/dist/chunks/chevron-down-mn2tSKQd.js +8 -0
  92. package/dist/chunks/chevron-right-EBApfX6q.js +15 -0
  93. package/dist/chunks/chevrons-up-down-2M6hY6wt.js +15 -0
  94. package/dist/chunks/chunk-2E4U76K2-DNbbdpCx.js +1 -0
  95. package/dist/chunks/chunk-2Q5K7J3B-CmAE3Vs0.js +1 -0
  96. package/dist/chunks/chunk-2ZTRR5NV-BjsSRgBv.js +2 -0
  97. package/dist/chunks/chunk-3Z5EZCMW-uYiqz-6y.js +1 -0
  98. package/dist/chunks/chunk-4HAMMTFA-Aw59LwS3.js +62 -0
  99. package/dist/chunks/chunk-5V3GS4D5-B_CVcJic.js +1 -0
  100. package/dist/chunks/chunk-5VM5RSS4-DMlsEAcl.js +15 -0
  101. package/dist/chunks/chunk-6AZGARVD-CgAiC5mV.js +1 -0
  102. package/dist/chunks/chunk-6EIED4P4-CXz5D9B0.js +1 -0
  103. package/dist/chunks/chunk-6K3QC6MW-DtaQ52mY.js +1 -0
  104. package/dist/chunks/chunk-6TQVIW2G-D0YDxefI.js +1 -0
  105. package/dist/chunks/chunk-747NJXEK-DGoElbDa.js +2 -0
  106. package/dist/chunks/chunk-75Z2AOVW-IO9R6faP.js +2 -0
  107. package/dist/chunks/chunk-CLGD4ZFX-tRS89bnq.js +1 -0
  108. package/dist/chunks/chunk-DU6HZSFF-Bx48E1rg.js +125 -0
  109. package/dist/chunks/chunk-F27PBJKO-DtLva7y0.js +1 -0
  110. package/dist/chunks/chunk-FOHPRMQF-B8MMrnxV.js +255 -0
  111. package/dist/chunks/chunk-GMAD6QVW-D41KnniX.js +72 -0
  112. package/dist/chunks/chunk-GVQU2GXP-CVzgM_ui.js +1 -0
  113. package/dist/chunks/chunk-I5DQTOEV-CoecQT42.js +1 -0
  114. package/dist/chunks/chunk-ICYGCRZG-lH3opfCY.js +1 -0
  115. package/dist/chunks/chunk-IH6LHLGP-tD-j3Rsy.js +1 -0
  116. package/dist/chunks/chunk-IMKFNOWR-CL9pLQhV.js +231 -0
  117. package/dist/chunks/chunk-JWPE2WC7-Wk0BVLn5.js +1 -0
  118. package/dist/chunks/chunk-KI3K4JFJ-C-3Y_9er.js +1 -0
  119. package/dist/chunks/chunk-L3NEJ4N5-CmvrS7Dt.js +1 -0
  120. package/dist/chunks/chunk-LNGE3PJU-BP1fsJRz.js +34 -0
  121. package/dist/chunks/chunk-OSK3NFVY-C9uWOXTC.js +10 -0
  122. package/dist/chunks/chunk-OUJLGHUK-Cm55l9bx.js +2 -0
  123. package/dist/chunks/chunk-P2QGCYS3-C9bc1yiM.js +1 -0
  124. package/dist/chunks/chunk-POPQ4Y6H-P1s5xaxM.js +1 -0
  125. package/dist/chunks/chunk-PWAF6VOD-IORmPx9D.js +1 -0
  126. package/dist/chunks/chunk-SHT3W25Y-Bip4melZ.js +168 -0
  127. package/dist/chunks/chunk-SVP7TREG-BKCgUOuy.js +88 -0
  128. package/dist/chunks/chunk-TICWLB2K-12W2EmSx.js +206 -0
  129. package/dist/chunks/chunk-TLUHSLCS-DsqF476v.js +1 -0
  130. package/dist/chunks/chunk-UY3FDG6J-71d_M6t3.js +1 -0
  131. package/dist/chunks/chunk-XHIXRSVI-C2X1-xC6.js +1 -0
  132. package/dist/chunks/chunk-XXDRQBXY-Bl6AoSZF.js +1 -0
  133. package/dist/chunks/chunk-Y2CYZVJY-DjEHBC-3.js +1 -0
  134. package/dist/chunks/circle-check-RKAno__V.js +8 -0
  135. package/dist/chunks/circle-x-BB5x-D-8.js +8 -0
  136. package/dist/chunks/classDiagram-ZZMXUADV-CZrpYcfK.js +1 -0
  137. package/dist/chunks/classDiagram-v2-VYDZK3BY-CZrpYcfK.js +1 -0
  138. package/dist/chunks/clipboard-ERcMSMRH.js +1 -0
  139. package/dist/chunks/clock-CniP1gZS.js +8 -0
  140. package/dist/chunks/confirm-BtBBEqk8.js +1 -0
  141. package/dist/chunks/controls-C5dPckUT.js +1 -0
  142. package/dist/chunks/copy-ofLPH1I0.js +8 -0
  143. package/dist/chunks/cose-bilkent-JH36ORCC-D9OUqkk5.js +1 -0
  144. package/dist/chunks/createLucideIcon-BtwfYE6A.js +83 -0
  145. package/dist/chunks/cynefin-OW5HDTMX-B8_kUynj.js +1 -0
  146. package/dist/chunks/cynefinDiagram-5FMLGOSQ-DhQChnCg.js +62 -0
  147. package/dist/chunks/cytoscape.esm-wDUnleWx.js +339 -0
  148. package/dist/chunks/dagre-GXQ25YYZ-CfbwC_a5.js +4 -0
  149. package/dist/chunks/dagre-ZVAWSfFw.js +1 -0
  150. package/dist/chunks/data-B05HzECj.js +28 -0
  151. package/dist/chunks/date-picker-CPUxgHVv.js +1 -0
  152. package/dist/chunks/defaultLocale-BvxIcb9Y.js +1 -0
  153. package/dist/chunks/deleteAction-CCocr5uV.js +1 -0
  154. package/dist/chunks/diagram-D9cwc7QH.js +5 -0
  155. package/dist/chunks/diagram-S7CK7UJ4-DVPbdtMm.js +30 -0
  156. package/dist/chunks/diagram-UQ7AKVKN-D_ZBhGLL.js +41 -0
  157. package/dist/chunks/diagram-VSXAHHWV-Dqypp-OX.js +3 -0
  158. package/dist/chunks/diagram-VX7I27RA-CbWJVJ_L.js +24 -0
  159. package/dist/chunks/diagram-Z3DM3KII-CUyP4-RY.js +24 -0
  160. package/dist/chunks/direct-engine-thps0u7R.js +5 -0
  161. package/dist/chunks/dist-Bauqz5on.js +1 -0
  162. package/dist/chunks/dist-CWj_XYki.js +1 -0
  163. package/dist/chunks/dist-D_KGQS7-.js +11 -0
  164. package/dist/chunks/dist-DdW4yNBK.js +1 -0
  165. package/dist/chunks/docx-preview-CPN81HCr.js +11 -0
  166. package/dist/chunks/download--5IybXxz.js +8 -0
  167. package/dist/chunks/drawing-D2Qrun-P.js +48 -0
  168. package/dist/chunks/ebnfDiagram-PWID7BFC-C5NMigjm.js +1 -0
  169. package/dist/chunks/ellipsis-Dux1Nxa5.js +8 -0
  170. package/dist/chunks/email-ByshRsFv.js +61 -0
  171. package/dist/chunks/emailHtml-BAKcRhSm.js +1 -0
  172. package/dist/chunks/erDiagram-RLTQ6QDP-B5rUHJPJ.js +99 -0
  173. package/dist/chunks/eventmodeling-NTZA5JFV-C74no5BH.js +1 -0
  174. package/dist/chunks/export-BkwewH6Q.js +1 -0
  175. package/dist/chunks/export-DlTz5dc2.js +341 -0
  176. package/dist/chunks/eye-off-BtJoIT5n.js +8 -0
  177. package/dist/chunks/feedback-BnjMKZpz.js +1 -0
  178. package/dist/chunks/file-utils-DyvnVEoH.js +1 -0
  179. package/dist/chunks/fit-CsnhEncA.js +1 -0
  180. package/dist/chunks/flowDiagram-HODETNUW-BuMvaSeo.js +1 -0
  181. package/dist/chunks/form-CQutQFiD.js +1 -0
  182. package/dist/chunks/funnel-BwQjQI4Y.js +8 -0
  183. package/dist/chunks/ganttDiagram-EL5Y4UJY-DIAlbvVg.js +292 -0
  184. package/dist/chunks/geo-DR0fL7r2.js +38 -0
  185. package/dist/chunks/gitGraph-4MIJSDKK-Ce5mOfp1.js +1 -0
  186. package/dist/chunks/gitGraphDiagram-WWUBYQGX-DN3G9xiQ.js +106 -0
  187. package/dist/chunks/graphlib-CYBMTUbW.js +1 -0
  188. package/dist/chunks/icons-CbRx5Om7.js +1 -0
  189. package/dist/chunks/illustrations-DT1eq6jI.js +1 -0
  190. package/dist/chunks/image-ez9hvzKT.js +17 -0
  191. package/dist/chunks/index.es-OAWlVkoK.js +16 -0
  192. package/dist/chunks/info-A6RAGUB7-BP6lMBIR.js +1 -0
  193. package/dist/chunks/info-BQa8C31Y.js +8 -0
  194. package/dist/chunks/infoDiagram-27XIBGKW-BhQtr_Ti.js +2 -0
  195. package/dist/chunks/init-Ca_Ibf4y.js +1 -0
  196. package/dist/chunks/ishikawaDiagram-5VMMS53U-CLR6CAi4.js +70 -0
  197. package/dist/chunks/journeyDiagram-3NMN7TZE-_-Q7sjsP.js +139 -0
  198. package/dist/chunks/json-viewer-DHYRjY8I.js +1 -0
  199. package/dist/chunks/jszip.min-hNOoGCeG.js +14 -0
  200. package/dist/chunks/kanban-definition-UXKFOSKX-D97mHeUZ.js +89 -0
  201. package/dist/chunks/katex-D5qu7EYh.js +257 -0
  202. package/dist/chunks/layout-grid-Bp9bwiQZ.js +8 -0
  203. package/dist/chunks/lib-BlRm3nk1.js +15 -0
  204. package/dist/chunks/lib-C1nFUu19.js +4 -0
  205. package/dist/chunks/lib-CqYXBtHb.js +1 -0
  206. package/dist/chunks/libarchive-DRzzJvQl.js +7 -0
  207. package/dist/chunks/line-BV7qVRkM.js +1 -0
  208. package/dist/chunks/line-qVHaOdPp.js +1 -0
  209. package/dist/chunks/linear-DXABSWHW.js +1 -0
  210. package/dist/chunks/list-0CbyOlT9.js +1 -0
  211. package/dist/chunks/list-DCcWnjUg.js +8 -0
  212. package/dist/chunks/listTableProps-DDynsnLF.js +1 -0
  213. package/dist/chunks/log-in-OzbNes8i.js +8 -0
  214. package/dist/chunks/lucide-react-VfAPsQQ5.js +8 -0
  215. package/dist/chunks/maplibre-gl-Bxi83GUP.js +819 -0
  216. package/dist/chunks/maplibre-shared-Oo0L8Lll.js +6 -0
  217. package/dist/chunks/maximize-CnmQ11E7.js +8 -0
  218. package/dist/chunks/media-DoGe_p4O.js +1 -0
  219. package/dist/chunks/menu-mQgsexFx.js +15 -0
  220. package/dist/chunks/mermaid-parser.core-DvCAQkzY.js +3 -0
  221. package/dist/chunks/mermaid.core-CxOC6yPr.js +15 -0
  222. package/dist/chunks/messages-CFyOVxEM.js +1 -0
  223. package/dist/chunks/mindmap-definition-YA3MSWOX-A2UgnMwx.js +96 -0
  224. package/dist/chunks/minimize-Bpau_zCe.js +8 -0
  225. package/dist/chunks/msg-BzZbudMm.js +7 -0
  226. package/dist/chunks/ofd-C7DKqJ6Z.js +33 -0
  227. package/dist/chunks/ofd-DrJyXIpS.js +14 -0
  228. package/dist/chunks/openDocument-DGzqlyJg.js +12 -0
  229. package/dist/chunks/options-B65xkxOY.js +1 -0
  230. package/dist/chunks/ordinal-NuFkISw7.js +1 -0
  231. package/dist/chunks/packet-AYTQ26CC-DS6h3a5l.js +1 -0
  232. package/dist/chunks/panzoom.es-DnuzxUQi.js +1 -0
  233. package/dist/chunks/parse-6ZQGx714.js +1 -0
  234. package/dist/chunks/parser-DC3PvpL4.js +72 -0
  235. package/dist/chunks/path-VUNELGFR.js +1 -0
  236. package/dist/chunks/pegDiagram-XKGWAZYB-DxQqpKfh.js +1 -0
  237. package/dist/chunks/pie-WAS4IAKB-BsaegmNA.js +1 -0
  238. package/dist/chunks/pieDiagram-E7YTZNPT-BUsnkTkJ.js +39 -0
  239. package/dist/chunks/postal-mime-DMcA5b7k.js +28 -0
  240. package/dist/chunks/ppt-B0WY5Gks.js +30 -0
  241. package/dist/chunks/ppt-BIiNnCyj.js +1 -0
  242. package/dist/chunks/pptx-DX5KDFZ7.js +109 -0
  243. package/dist/chunks/preload-helper-C-73SErw.js +1 -0
  244. package/dist/chunks/print-mask-Dguzv0rv.js +17 -0
  245. package/dist/chunks/printLayout-oeudvFkr.js +34 -0
  246. package/dist/chunks/printMask-LefOTJqk.js +8 -0
  247. package/dist/chunks/psd-hjeNFQZ-.js +36 -0
  248. package/dist/chunks/purify.es-BsWMI_aG.js +5 -0
  249. package/dist/chunks/quadrantDiagram-AXDQQJYC-BmQNSzhY.js +7 -0
  250. package/dist/chunks/radar-RG4KPBEZ-BoHdw2h7.js +1 -0
  251. package/dist/chunks/railroad-74A4TZTK-BifJffb4.js +1 -0
  252. package/dist/chunks/railroad-abnf-HS5TGJTU-CMEPumRO.js +1 -0
  253. package/dist/chunks/railroad-ebnf-LZEXJU2U-B06BgAeN.js +1 -0
  254. package/dist/chunks/railroad-peg-WCYAUIDC-CMjriUEs.js +1 -0
  255. package/dist/chunks/railroadDiagram-O6MQD6OU-B2t5KY26.js +1 -0
  256. package/dist/chunks/react-runtime-x2lFbSKq.js +11 -0
  257. package/dist/chunks/refresh-cw-Dz8O9-Hp.js +8 -0
  258. package/dist/chunks/rendered-slot-YhfmcMJr.js +1 -0
  259. package/dist/chunks/requirementDiagram-BXWQKSXE-CBBfNOAp.js +84 -0
  260. package/dist/chunks/rolldown-runtime-BKuNeK48.js +1 -0
  261. package/dist/chunks/rotate-ccw-D2__Zisi.js +8 -0
  262. package/dist/chunks/rotate-cw-BSTVLlWY.js +8 -0
  263. package/dist/chunks/rough.esm-CVrpq1dW.js +1 -0
  264. package/dist/chunks/sankeyDiagram-P5KCCOFB-Cp8SrFyb.js +40 -0
  265. package/dist/chunks/save-w-NwiMMY.js +8 -0
  266. package/dist/chunks/search-DYZU68h1.js +8 -0
  267. package/dist/chunks/search-filters-CRIhZ0gL.js +1 -0
  268. package/dist/chunks/sequenceDiagram-WJ2MYXX4-PDtVfEoj.js +162 -0
  269. package/dist/chunks/shield-alert-De_Hx56I.js +8 -0
  270. package/dist/chunks/sizeCapture-INFHLROL-DA-kAaXB.js +1 -0
  271. package/dist/chunks/skeleton-CrjMjJNr.js +1 -0
  272. package/dist/chunks/spreadsheet-BzbBEhmY.js +1 -0
  273. package/dist/chunks/spreadsheet-LR3SOG-x.js +58 -0
  274. package/dist/chunks/sql-wasm-browser-CFddXd9f.js +2 -0
  275. package/dist/chunks/src-C1iDJpBK.js +1 -0
  276. package/dist/chunks/src-vLpLkuQx.js +1 -0
  277. package/dist/chunks/stateDiagram-D77RDMKH-C1Sx8KUD.js +1 -0
  278. package/dist/chunks/stateDiagram-v2-MP3YSRHH-7wYLSzBX.js +1 -0
  279. package/dist/chunks/swimlanes-42K2YHIH-BmybX9eL.js +1 -0
  280. package/dist/chunks/swimlanesDiagram-VR7AAH4N-DxhXklfm.js +8 -0
  281. package/dist/chunks/tabs-BobA_IcO.js +1 -0
  282. package/dist/chunks/theme-controller-D-ATwFal.js +1 -0
  283. package/dist/chunks/timeline-definition-24CTP7MA-QS9QNm2i.js +120 -0
  284. package/dist/chunks/tinycolor-CG1wnM-U.js +1 -0
  285. package/dist/chunks/togeojson.es-BE8iM7U6.js +1 -0
  286. package/dist/chunks/toolbar-controls-CThS0xuP.js +15 -0
  287. package/dist/chunks/trash-tHBT8Mpw.js +8 -0
  288. package/dist/chunks/treeView-Q6P3EWNA-CN0l7whJ.js +1 -0
  289. package/dist/chunks/treemap-WGGIJYW6-C4P1fQxS.js +1 -0
  290. package/dist/chunks/typography-DKK_iHcj.js +1 -0
  291. package/dist/chunks/ui-BFsHoY7a.js +1 -0
  292. package/dist/chunks/ui-utils-ClxYogUQ.js +1 -0
  293. package/dist/chunks/upload-M-n6woFv.js +8 -0
  294. package/dist/chunks/useCrudOperationColumn-D935tixd.js +1 -0
  295. package/dist/chunks/useListPage-CbcOQG4m.js +1 -0
  296. package/dist/chunks/useModalViewport-HF7te75S.js +1 -0
  297. package/dist/chunks/useRowSelection-4GOMFmjG.js +1 -0
  298. package/dist/chunks/useStatusToggle-B2qZaoc-.js +1 -0
  299. package/dist/chunks/user-round-kYfBkPNu.js +15 -0
  300. package/dist/chunks/users-BXZLb4TY.js +8 -0
  301. package/dist/chunks/vennDiagram-4TSXK5OY-CVd73ycc.js +34 -0
  302. package/dist/chunks/view-B8ZvC8z3.js +1 -0
  303. package/dist/chunks/viewer-Ct88ypIL.js +24 -0
  304. package/dist/chunks/wardley-WFR3VGLG-cG9pRFwD.js +1 -0
  305. package/dist/chunks/wardleyDiagram-VM6X3IG4-B42d0Gqz.js +78 -0
  306. package/dist/chunks/wordDoc-BZY3ZnxN.js +152 -0
  307. package/dist/chunks/wordDocx-Bt2mlB3C.js +77 -0
  308. package/dist/chunks/wordMl-Y_ghyTZ8.js +1 -0
  309. package/dist/chunks/worker-engine-B4e92GsN.js +17369 -0
  310. package/dist/chunks/x-Ak9hw1R9.js +8 -0
  311. package/dist/chunks/xmind-CF9YwkOD.js +58 -0
  312. package/dist/chunks/xychartDiagram-S5SC5T6Z-B_Owv9Ho.js +7 -0
  313. package/dist/file-viewer/flyfish-viewer-assets.json +46 -0
  314. package/dist/file-viewer/vendor/docx/docx.worker.js +5 -0
  315. package/dist/file-viewer/vendor/docx/jszip.min.js +13 -0
  316. package/dist/file-viewer/vendor/xlsx/sheet.worker.js +107 -0
  317. package/dist/file-viewer/wasm/data/sql-wasm.wasm +0 -0
  318. package/dist/index.d.ts +5 -0
  319. package/dist/index.js +1 -0
  320. package/dist/public/avatars/avatar-01.svg +1 -0
  321. package/dist/public/avatars/avatar-02.svg +1 -0
  322. package/dist/public/avatars/avatar-03.svg +1 -0
  323. package/dist/public/avatars/avatar-04.svg +1 -0
  324. package/dist/public/avatars/avatar-05.svg +1 -0
  325. package/dist/public/avatars/avatar-06.svg +1 -0
  326. package/dist/public/avatars/avatar-07.svg +1 -0
  327. package/dist/public/avatars/avatar-08.svg +1 -0
  328. package/dist/public/avatars/avatar-09.svg +1 -0
  329. package/dist/public/avatars/avatar-10.svg +1 -0
  330. package/dist/public/avatars/avatar-11.svg +1 -0
  331. package/dist/public/avatars/avatar-12.svg +1 -0
  332. package/dist/public/monaco/vs/abap-D-t0cyap.js +1 -0
  333. package/dist/public/monaco/vs/apex-CcIm7xu6.js +1 -0
  334. package/dist/public/monaco/vs/assets/css.worker-URu8fCFR.js +97 -0
  335. package/dist/public/monaco/vs/assets/editor.worker-lj3bdIIn.js +30 -0
  336. package/dist/public/monaco/vs/assets/editorWebWorkerMain-CA_vMoUU.js +30 -0
  337. package/dist/public/monaco/vs/assets/html.worker-D1SL3iM8.js +474 -0
  338. package/dist/public/monaco/vs/assets/json.worker-CoJx_OPf.js +62 -0
  339. package/dist/public/monaco/vs/assets/ts.worker-BWKtMYOk.js +67722 -0
  340. package/dist/public/monaco/vs/azcli-BA0tQDCg.js +1 -0
  341. package/dist/public/monaco/vs/basic-languages/monaco.contribution.js +1 -0
  342. package/dist/public/monaco/vs/bat-C397hTD6.js +1 -0
  343. package/dist/public/monaco/vs/bicep-DF5aW17k.js +2 -0
  344. package/dist/public/monaco/vs/cameligo-plsz8qhj.js +1 -0
  345. package/dist/public/monaco/vs/clojure-Y2auQMzK.js +1 -0
  346. package/dist/public/monaco/vs/coffee-Bu45yuWE.js +1 -0
  347. package/dist/public/monaco/vs/cpp-CkKPQIni.js +1 -0
  348. package/dist/public/monaco/vs/csharp-CX28MZyh.js +1 -0
  349. package/dist/public/monaco/vs/csp-D8uWnyxW.js +1 -0
  350. package/dist/public/monaco/vs/css-CaeNmE3S.js +3 -0
  351. package/dist/public/monaco/vs/css.worker-CyhWkhHo.js +1 -0
  352. package/dist/public/monaco/vs/cssMode-CV6Ay48H.js +1 -0
  353. package/dist/public/monaco/vs/cypher-DVThT8BS.js +1 -0
  354. package/dist/public/monaco/vs/dart-CmGfCvrO.js +1 -0
  355. package/dist/public/monaco/vs/dockerfile-CZqqYdch.js +1 -0
  356. package/dist/public/monaco/vs/ecl-30fUercY.js +1 -0
  357. package/dist/public/monaco/vs/editor/editor.main.css +1 -0
  358. package/dist/public/monaco/vs/editor/editor.main.js +1 -0
  359. package/dist/public/monaco/vs/editor-KLE6jdfb.js +831 -0
  360. package/dist/public/monaco/vs/editor.js +1 -0
  361. package/dist/public/monaco/vs/editorWorkerHost-fVE1cjcC.js +35 -0
  362. package/dist/public/monaco/vs/elixir-xjPaIfzF.js +1 -0
  363. package/dist/public/monaco/vs/flow9-DqtmStfK.js +1 -0
  364. package/dist/public/monaco/vs/freemarker2-FWreY7v7.js +3 -0
  365. package/dist/public/monaco/vs/fsharp-BOMdg4U1.js +1 -0
  366. package/dist/public/monaco/vs/go-D_hbi-Jt.js +1 -0
  367. package/dist/public/monaco/vs/graphql-CKUU4kLG.js +1 -0
  368. package/dist/public/monaco/vs/handlebars-CZi4pHCH.js +1 -0
  369. package/dist/public/monaco/vs/hcl-DTaboeZW.js +1 -0
  370. package/dist/public/monaco/vs/html-j_7ZTNRU.js +1 -0
  371. package/dist/public/monaco/vs/html.worker-CA3iAimZ.js +1 -0
  372. package/dist/public/monaco/vs/htmlMode-27by_KM4.js +1 -0
  373. package/dist/public/monaco/vs/index-049xrXrp.js +1 -0
  374. package/dist/public/monaco/vs/index-CBVt3dzv.js +5 -0
  375. package/dist/public/monaco/vs/index.js +1 -0
  376. package/dist/public/monaco/vs/ini-CsNwO04R.js +1 -0
  377. package/dist/public/monaco/vs/initialize-DL0l1TGY.js +1 -0
  378. package/dist/public/monaco/vs/java-CI4ZMsH9.js +1 -0
  379. package/dist/public/monaco/vs/javascript-DTJl4Jn1.js +1 -0
  380. package/dist/public/monaco/vs/json.worker-BizpAl9O.js +1 -0
  381. package/dist/public/monaco/vs/jsonMode-DLUiMUrI.js +1 -0
  382. package/dist/public/monaco/vs/julia-BwzEvaQw.js +1 -0
  383. package/dist/public/monaco/vs/kotlin-IUYPiTV8.js +1 -0
  384. package/dist/public/monaco/vs/language/css/monaco.contribution.js +1 -0
  385. package/dist/public/monaco/vs/language/html/monaco.contribution.js +1 -0
  386. package/dist/public/monaco/vs/language/json/monaco.contribution.js +1 -0
  387. package/dist/public/monaco/vs/language/typescript/monaco.contribution.js +1 -0
  388. package/dist/public/monaco/vs/less-C0eDYdqa.js +2 -0
  389. package/dist/public/monaco/vs/lexon-iON-Kj97.js +1 -0
  390. package/dist/public/monaco/vs/liquid-CLJYelW6.js +1 -0
  391. package/dist/public/monaco/vs/loader.js +1368 -0
  392. package/dist/public/monaco/vs/lspLanguageFeatures-BIkJOWLw.js +2 -0
  393. package/dist/public/monaco/vs/lua-DtygF91M.js +1 -0
  394. package/dist/public/monaco/vs/m3-CsR4AuFi.js +1 -0
  395. package/dist/public/monaco/vs/main-BEx-Fmlo.js +15 -0
  396. package/dist/public/monaco/vs/main-DsK8pnKg.js +3 -0
  397. package/dist/public/monaco/vs/markdown-C_rD0bIw.js +1 -0
  398. package/dist/public/monaco/vs/mdx-CpzZIPHF.js +1 -0
  399. package/dist/public/monaco/vs/mips-CiYP61RB.js +1 -0
  400. package/dist/public/monaco/vs/monaco.contribution-9cKT3C7t.js +1 -0
  401. package/dist/public/monaco/vs/monaco.contribution-BE88ZNGY.js +1 -0
  402. package/dist/public/monaco/vs/monaco.contribution-BPhsneLd.js +1 -0
  403. package/dist/public/monaco/vs/monaco.contribution-BgRy6xDf.js +1 -0
  404. package/dist/public/monaco/vs/msdax-C38-sJlp.js +1 -0
  405. package/dist/public/monaco/vs/mysql-CdtbpvbG.js +1 -0
  406. package/dist/public/monaco/vs/nls/lang/cs.d.ts +1 -0
  407. package/dist/public/monaco/vs/nls/lang/cs.js +9 -0
  408. package/dist/public/monaco/vs/nls/lang/de.d.ts +1 -0
  409. package/dist/public/monaco/vs/nls/lang/de.js +9 -0
  410. package/dist/public/monaco/vs/nls/lang/es.d.ts +1 -0
  411. package/dist/public/monaco/vs/nls/lang/es.js +9 -0
  412. package/dist/public/monaco/vs/nls/lang/fr.d.ts +1 -0
  413. package/dist/public/monaco/vs/nls/lang/fr.js +9 -0
  414. package/dist/public/monaco/vs/nls/lang/it.d.ts +1 -0
  415. package/dist/public/monaco/vs/nls/lang/it.js +9 -0
  416. package/dist/public/monaco/vs/nls/lang/ja.d.ts +1 -0
  417. package/dist/public/monaco/vs/nls/lang/ja.js +9 -0
  418. package/dist/public/monaco/vs/nls/lang/ko.d.ts +1 -0
  419. package/dist/public/monaco/vs/nls/lang/ko.js +9 -0
  420. package/dist/public/monaco/vs/nls/lang/pl.d.ts +1 -0
  421. package/dist/public/monaco/vs/nls/lang/pl.js +9 -0
  422. package/dist/public/monaco/vs/nls/lang/pt-br.d.ts +1 -0
  423. package/dist/public/monaco/vs/nls/lang/pt-br.js +9 -0
  424. package/dist/public/monaco/vs/nls/lang/ru.d.ts +1 -0
  425. package/dist/public/monaco/vs/nls/lang/ru.js +9 -0
  426. package/dist/public/monaco/vs/nls/lang/tr.d.ts +1 -0
  427. package/dist/public/monaco/vs/nls/lang/tr.js +9 -0
  428. package/dist/public/monaco/vs/nls/lang/zh-cn.d.ts +1 -0
  429. package/dist/public/monaco/vs/nls/lang/zh-cn.js +9 -0
  430. package/dist/public/monaco/vs/nls/lang/zh-tw.d.ts +1 -0
  431. package/dist/public/monaco/vs/nls/lang/zh-tw.js +9 -0
  432. package/dist/public/monaco/vs/nls.messages-loader.js +1 -0
  433. package/dist/public/monaco/vs/objective-c-CntZFaHX.js +1 -0
  434. package/dist/public/monaco/vs/pascal-r6kuqfl_.js +1 -0
  435. package/dist/public/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
  436. package/dist/public/monaco/vs/perl-DABw_TcH.js +1 -0
  437. package/dist/public/monaco/vs/pgsql-me_jFXeX.js +1 -0
  438. package/dist/public/monaco/vs/php-D_kh-9LK.js +1 -0
  439. package/dist/public/monaco/vs/pla-VfZjczW0.js +1 -0
  440. package/dist/public/monaco/vs/postiats-BBSzz8Pk.js +1 -0
  441. package/dist/public/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
  442. package/dist/public/monaco/vs/powershell-B-7ap1zc.js +1 -0
  443. package/dist/public/monaco/vs/protobuf-BmtuEB1A.js +2 -0
  444. package/dist/public/monaco/vs/pug-BRpRNeEb.js +1 -0
  445. package/dist/public/monaco/vs/python-CqWUUgfu.js +1 -0
  446. package/dist/public/monaco/vs/qsharp-BzsFaUU9.js +1 -0
  447. package/dist/public/monaco/vs/r-f8dDdrp4.js +1 -0
  448. package/dist/public/monaco/vs/razor-hok5y9Km.js +1 -0
  449. package/dist/public/monaco/vs/redis-fvZQY4PI.js +1 -0
  450. package/dist/public/monaco/vs/redshift-45Et0LQi.js +1 -0
  451. package/dist/public/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
  452. package/dist/public/monaco/vs/ruby-CZO8zYTz.js +1 -0
  453. package/dist/public/monaco/vs/rust-Bfetafyc.js +1 -0
  454. package/dist/public/monaco/vs/sb-3GYllVck.js +1 -0
  455. package/dist/public/monaco/vs/scala-foMgrKo1.js +1 -0
  456. package/dist/public/monaco/vs/scheme-CHdMtr7p.js +1 -0
  457. package/dist/public/monaco/vs/scss-C1cmLt9V.js +3 -0
  458. package/dist/public/monaco/vs/shell-ClXCKCEW.js +1 -0
  459. package/dist/public/monaco/vs/solidity-MZ6ExpPy.js +1 -0
  460. package/dist/public/monaco/vs/sophia-DWkuSsPQ.js +1 -0
  461. package/dist/public/monaco/vs/sparql-AUGFYSyk.js +1 -0
  462. package/dist/public/monaco/vs/sql-32GpJSV2.js +1 -0
  463. package/dist/public/monaco/vs/st-CuDFIVZ_.js +1 -0
  464. package/dist/public/monaco/vs/swift-t-PfMj7W.js +1 -0
  465. package/dist/public/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
  466. package/dist/public/monaco/vs/tcl-D74tq1nH.js +1 -0
  467. package/dist/public/monaco/vs/toggleHighContrast-qGX7E9o7.js +61 -0
  468. package/dist/public/monaco/vs/ts.worker-2QLmBukE.js +1 -0
  469. package/dist/public/monaco/vs/tsMode-B0S_kp2q.js +11 -0
  470. package/dist/public/monaco/vs/twig-C6taOxMV.js +1 -0
  471. package/dist/public/monaco/vs/typescript-_2t_511t.js +1 -0
  472. package/dist/public/monaco/vs/typespec-8OfoLt6R.js +1 -0
  473. package/dist/public/monaco/vs/vb-Dyb2648j.js +1 -0
  474. package/dist/public/monaco/vs/wgsl-BhLXMOR0.js +298 -0
  475. package/dist/public/monaco/vs/workers-BBttULjf.js +1 -0
  476. package/dist/public/monaco/vs/xml-cZjNDqDT.js +1 -0
  477. package/dist/public/monaco/vs/yaml-A1fOIdH6.js +1 -0
  478. package/dist/src-LbWcrSWe.js +3 -0
  479. package/dist/styles.css +2 -0
  480. package/dist/styles.d.ts +1 -0
  481. package/dist/types.d.ts +1 -0
  482. package/package.json +113 -4
@@ -0,0 +1,1650 @@
1
+ /**
2
+ * Bounded, best-effort cache for final watermarked PNG frames.
3
+ *
4
+ * This module is intentionally storage-only. It does not parse PPT data, inspect
5
+ * font assets, or transform renderer output. Every storage failure degrades to a
6
+ * cache miss so IndexedDB can never become a rendering dependency.
7
+ */
8
+
9
+ const DB_VERSION = 1;
10
+ const FRAME_STORE = "frames";
11
+ const META_STORE = "meta";
12
+ const DOCUMENT_INDEX = "byDocument";
13
+ const ACCESS_INDEX = "byLastAccess";
14
+ const USAGE_KEY = "usage";
15
+
16
+ const MIB = 1024 * 1024;
17
+ const DEFAULT_DB_NAME = "flyfish-ppt-frame-cache-v1";
18
+ const DEFAULT_MAX_BYTES = 256 * MIB;
19
+ const DEFAULT_MAX_ENTRIES = 256;
20
+ const DEFAULT_MAX_ITEM_BYTES = 32 * MIB;
21
+ const MAX_DATABASE_NAME_LENGTH = 128;
22
+ const MAX_DOCUMENT_ID_LENGTH = 256;
23
+ const MAX_VARIANT_LENGTH = 256;
24
+ const MAX_PAGE_INDEX = 10_000_000;
25
+ const MAX_DIMENSION = 65_535;
26
+ const OPEN_TIMEOUT_MS = 1_000;
27
+
28
+ function clampInteger(value, fallback, minimum, maximum) {
29
+ let numeric;
30
+ try {
31
+ numeric = Number(value);
32
+ } catch {
33
+ return fallback;
34
+ }
35
+ if (!Number.isFinite(numeric)) {
36
+ return fallback;
37
+ }
38
+ return Math.min(maximum, Math.max(minimum, Math.trunc(numeric)));
39
+ }
40
+
41
+ function normalizeBoundedString(value, maximumLength, { trim = false } = {}) {
42
+ if (typeof value !== "string") {
43
+ return null;
44
+ }
45
+ const normalized = trim ? value.trim() : value;
46
+ if (normalized.length === 0 || normalized.length > maximumLength) {
47
+ return null;
48
+ }
49
+ return normalized;
50
+ }
51
+
52
+ /**
53
+ * Pure limit normalization used by both production code and unit tests.
54
+ */
55
+ function normalizeFrameCacheLimits(options = {}) {
56
+ const source = options && typeof options === "object" ? options : {};
57
+ const maxBytes = clampInteger(source.maxBytes, DEFAULT_MAX_BYTES, 0, 2 * 1024 * MIB);
58
+ const maxEntries = clampInteger(source.maxEntries, DEFAULT_MAX_ENTRIES, 0, 4_096);
59
+ const defaultItemBytes = Math.min(DEFAULT_MAX_ITEM_BYTES, maxBytes);
60
+ const configuredItemBytes = source.maxItemBytes ?? source.maxEntryBytes;
61
+ const maxItemBytes = maxBytes === 0
62
+ ? 0
63
+ : clampInteger(configuredItemBytes, defaultItemBytes, 0, maxBytes);
64
+ return Object.freeze({ maxBytes, maxEntries, maxItemBytes });
65
+ }
66
+
67
+ /**
68
+ * Pure cache-key normalization. Invalid or potentially collision-prone inputs
69
+ * return null instead of being truncated.
70
+ */
71
+ function normalizeFrameCacheKey(input, pageIndex, variant = "") {
72
+ const source = input && typeof input === "object"
73
+ ? input
74
+ : { documentId: input, pageIndex, variant };
75
+
76
+ const documentId = normalizeBoundedString(source.documentId, MAX_DOCUMENT_ID_LENGTH, { trim: true });
77
+ let normalizedPageIndex;
78
+ let normalizedVariant;
79
+ try {
80
+ normalizedPageIndex = Number(source.pageIndex);
81
+ normalizedVariant = source.variant == null ? "" : String(source.variant);
82
+ } catch {
83
+ return null;
84
+ }
85
+
86
+ if (
87
+ documentId == null
88
+ || !Number.isSafeInteger(normalizedPageIndex)
89
+ || normalizedPageIndex < 0
90
+ || normalizedPageIndex > MAX_PAGE_INDEX
91
+ || normalizedVariant.length > MAX_VARIANT_LENGTH
92
+ ) {
93
+ return null;
94
+ }
95
+
96
+ // Length-prefixing prevents separators inside opaque identifiers from
97
+ // creating collisions.
98
+ const key = `v1:${documentId.length}:${documentId}:${normalizedPageIndex}:${normalizedVariant.length}:${normalizedVariant}`;
99
+ return Object.freeze({
100
+ key,
101
+ documentId,
102
+ pageIndex: normalizedPageIndex,
103
+ variant: normalizedVariant,
104
+ });
105
+ }
106
+
107
+ function createFrameCacheKey(documentId, pageIndex, variant = "") {
108
+ return normalizeFrameCacheKey(documentId, pageIndex, variant)?.key ?? null;
109
+ }
110
+
111
+ function normalizeDatabaseName(value) {
112
+ return normalizeBoundedString(value, MAX_DATABASE_NAME_LENGTH, { trim: true }) ?? DEFAULT_DB_NAME;
113
+ }
114
+
115
+ function isPngBlob(blob) {
116
+ return Boolean(
117
+ blob
118
+ && typeof blob === "object"
119
+ && Number.isSafeInteger(blob.size)
120
+ && blob.size > 0
121
+ && typeof blob.arrayBuffer === "function"
122
+ && typeof blob.type === "string"
123
+ && blob.type.toLowerCase() === "image/png",
124
+ );
125
+ }
126
+
127
+ function normalizeDimension(value) {
128
+ let numeric;
129
+ try {
130
+ numeric = Number(value);
131
+ } catch {
132
+ return null;
133
+ }
134
+ return Number.isSafeInteger(numeric) && numeric > 0 && numeric <= MAX_DIMENSION
135
+ ? numeric
136
+ : null;
137
+ }
138
+
139
+ function normalizePutArguments(keyInput, frameInput, limits) {
140
+ const frame = frameInput && typeof frameInput === "object" ? frameInput : keyInput;
141
+ const key = normalizeFrameCacheKey(keyInput);
142
+ const width = normalizeDimension(frame?.width);
143
+ const height = normalizeDimension(frame?.height);
144
+ const blob = frame?.blob;
145
+
146
+ if (key == null || width == null || height == null || !isPngBlob(blob)) {
147
+ return null;
148
+ }
149
+ if (blob.size > limits.maxItemBytes || blob.size > limits.maxBytes) {
150
+ return null;
151
+ }
152
+ return { ...key, blob, width, height, byteSize: blob.size };
153
+ }
154
+
155
+ function requestResult(request) {
156
+ return new Promise((resolve, reject) => {
157
+ request.onsuccess = () => resolve(request.result);
158
+ request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
159
+ });
160
+ }
161
+
162
+ function transactionError(transaction, fallbackMessage) {
163
+ return transaction.error ?? new Error(fallbackMessage);
164
+ }
165
+
166
+ function openDatabase(factory, dbName) {
167
+ return new Promise((resolve, reject) => {
168
+ let settled = false;
169
+ let request;
170
+ let timer = null;
171
+
172
+ const settle = (callback, value) => {
173
+ if (settled) {
174
+ if (value && typeof value.close === "function") {
175
+ value.close();
176
+ }
177
+ return;
178
+ }
179
+ settled = true;
180
+ if (timer != null) {
181
+ clearTimeout(timer);
182
+ }
183
+ callback(value);
184
+ };
185
+
186
+ try {
187
+ request = factory.open(dbName, DB_VERSION);
188
+ } catch (error) {
189
+ settle(reject, error);
190
+ return;
191
+ }
192
+
193
+ request.onupgradeneeded = () => {
194
+ const database = request.result;
195
+ let frameStore;
196
+ if (!database.objectStoreNames.contains(FRAME_STORE)) {
197
+ frameStore = database.createObjectStore(FRAME_STORE, { keyPath: "key" });
198
+ } else {
199
+ frameStore = request.transaction.objectStore(FRAME_STORE);
200
+ }
201
+ if (!frameStore.indexNames.contains(DOCUMENT_INDEX)) {
202
+ frameStore.createIndex(DOCUMENT_INDEX, "documentId", { unique: false });
203
+ }
204
+ if (!frameStore.indexNames.contains(ACCESS_INDEX)) {
205
+ frameStore.createIndex(ACCESS_INDEX, "lastAccess", { unique: false });
206
+ }
207
+ if (!database.objectStoreNames.contains(META_STORE)) {
208
+ database.createObjectStore(META_STORE, { keyPath: "key" });
209
+ }
210
+ };
211
+ request.onsuccess = () => settle(resolve, request.result);
212
+ request.onerror = () => settle(reject, request.error ?? new Error("Unable to open IndexedDB"));
213
+ request.onblocked = () => settle(reject, new Error("IndexedDB open was blocked"));
214
+
215
+ if (typeof setTimeout === "function") {
216
+ timer = setTimeout(() => {
217
+ settle(reject, new Error("IndexedDB open timed out"));
218
+ }, OPEN_TIMEOUT_MS);
219
+ }
220
+ });
221
+ }
222
+
223
+ function isStoredFrameValid(record) {
224
+ return Boolean(
225
+ record
226
+ && typeof record === "object"
227
+ && typeof record.key === "string"
228
+ && typeof record.documentId === "string"
229
+ && Number.isSafeInteger(record.pageIndex)
230
+ && normalizeDimension(record.width) != null
231
+ && normalizeDimension(record.height) != null
232
+ && Number.isSafeInteger(record.byteSize)
233
+ && record.byteSize > 0
234
+ && isPngBlob(record.blob)
235
+ && record.blob.size === record.byteSize,
236
+ );
237
+ }
238
+
239
+ function reconcileUsage(database, limits) {
240
+ return new Promise((resolve, reject) => {
241
+ let transaction;
242
+ try {
243
+ transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
244
+ } catch (error) {
245
+ reject(error);
246
+ return;
247
+ }
248
+
249
+ const frames = transaction.objectStore(FRAME_STORE);
250
+ const meta = transaction.objectStore(META_STORE);
251
+ let totalBytes = 0;
252
+ let totalEntries = 0;
253
+
254
+ const writeUsage = () => {
255
+ meta.put({
256
+ key: USAGE_KEY,
257
+ totalBytes,
258
+ totalEntries,
259
+ updatedAt: Date.now(),
260
+ });
261
+ };
262
+
263
+ const withinLimits = () => (
264
+ totalBytes <= limits.maxBytes
265
+ && totalEntries <= limits.maxEntries
266
+ );
267
+
268
+ const trimOldest = () => {
269
+ if (withinLimits()) {
270
+ writeUsage();
271
+ return;
272
+ }
273
+ const trimRequest = frames.index(ACCESS_INDEX).openCursor();
274
+ trimRequest.onsuccess = () => {
275
+ const cursor = trimRequest.result;
276
+ if (cursor == null) {
277
+ totalBytes = 0;
278
+ totalEntries = 0;
279
+ writeUsage();
280
+ return;
281
+ }
282
+ const record = cursor.value;
283
+ cursor.delete();
284
+ if (isStoredFrameValid(record)) {
285
+ totalBytes = Math.max(0, totalBytes - record.byteSize);
286
+ totalEntries = Math.max(0, totalEntries - 1);
287
+ }
288
+ if (withinLimits()) {
289
+ writeUsage();
290
+ } else {
291
+ cursor.continue();
292
+ }
293
+ };
294
+ };
295
+
296
+ const cursorRequest = frames.openCursor();
297
+ cursorRequest.onsuccess = () => {
298
+ const cursor = cursorRequest.result;
299
+ if (cursor == null) {
300
+ trimOldest();
301
+ return;
302
+ }
303
+ const record = cursor.value;
304
+ if (isStoredFrameValid(record) && record.byteSize <= limits.maxItemBytes) {
305
+ totalBytes += record.byteSize;
306
+ totalEntries += 1;
307
+ } else {
308
+ cursor.delete();
309
+ }
310
+ cursor.continue();
311
+ };
312
+
313
+ transaction.oncomplete = () => resolve({ totalBytes, totalEntries });
314
+ transaction.onerror = () => reject(transactionError(transaction, "IndexedDB reconciliation failed"));
315
+ transaction.onabort = () => reject(transactionError(transaction, "IndexedDB reconciliation was aborted"));
316
+ });
317
+ }
318
+
319
+ function readUsageRecord(value) {
320
+ const totalBytes = Number.isSafeInteger(value?.totalBytes) && value.totalBytes >= 0
321
+ ? value.totalBytes
322
+ : 0;
323
+ const totalEntries = Number.isSafeInteger(value?.totalEntries) && value.totalEntries >= 0
324
+ ? value.totalEntries
325
+ : 0;
326
+ return { totalBytes, totalEntries };
327
+ }
328
+
329
+ function putFrame(database, record, limits) {
330
+ return new Promise((resolve, reject) => {
331
+ let transaction;
332
+ try {
333
+ transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
334
+ } catch (error) {
335
+ reject(error);
336
+ return;
337
+ }
338
+
339
+ const frames = transaction.objectStore(FRAME_STORE);
340
+ const meta = transaction.objectStore(META_STORE);
341
+ let existing;
342
+ let usage;
343
+ let existingReady = false;
344
+ let usageReady = false;
345
+ let started = false;
346
+
347
+ const failRequest = () => {
348
+ try {
349
+ transaction.abort();
350
+ } catch {
351
+ // The transaction may already have been aborted by the browser.
352
+ }
353
+ };
354
+
355
+ const finalizeWrite = () => {
356
+ const now = record.lastAccess;
357
+ frames.put(record);
358
+ meta.put({
359
+ key: USAGE_KEY,
360
+ totalBytes: usage.totalBytes,
361
+ totalEntries: usage.totalEntries,
362
+ updatedAt: now,
363
+ });
364
+ };
365
+
366
+ const evictIfNeeded = () => {
367
+ if (started || !existingReady || !usageReady) {
368
+ return;
369
+ }
370
+ started = true;
371
+
372
+ const oldBytes = isStoredFrameValid(existing) ? existing.byteSize : 0;
373
+ const oldEntries = isStoredFrameValid(existing) ? 1 : 0;
374
+ usage.totalBytes = Math.max(0, usage.totalBytes - oldBytes) + record.byteSize;
375
+ usage.totalEntries = Math.max(0, usage.totalEntries - oldEntries) + 1;
376
+
377
+ const withinLimits = () => (
378
+ usage.totalBytes <= limits.maxBytes
379
+ && usage.totalEntries <= limits.maxEntries
380
+ );
381
+
382
+ if (withinLimits()) {
383
+ finalizeWrite();
384
+ return;
385
+ }
386
+
387
+ const cursorRequest = frames.index(ACCESS_INDEX).openCursor();
388
+ cursorRequest.onsuccess = () => {
389
+ const cursor = cursorRequest.result;
390
+ if (cursor == null) {
391
+ if (withinLimits()) {
392
+ finalizeWrite();
393
+ } else {
394
+ failRequest();
395
+ }
396
+ return;
397
+ }
398
+
399
+ const candidate = cursor.value;
400
+ if (candidate?.key !== record.key && isStoredFrameValid(candidate)) {
401
+ cursor.delete();
402
+ usage.totalBytes = Math.max(0, usage.totalBytes - candidate.byteSize);
403
+ usage.totalEntries = Math.max(0, usage.totalEntries - 1);
404
+ } else if (candidate?.key !== record.key) {
405
+ cursor.delete();
406
+ }
407
+
408
+ if (withinLimits()) {
409
+ finalizeWrite();
410
+ } else {
411
+ cursor.continue();
412
+ }
413
+ };
414
+ cursorRequest.onerror = failRequest;
415
+ };
416
+
417
+ const existingRequest = frames.get(record.key);
418
+ existingRequest.onsuccess = () => {
419
+ existing = existingRequest.result;
420
+ existingReady = true;
421
+ evictIfNeeded();
422
+ };
423
+ existingRequest.onerror = failRequest;
424
+
425
+ const usageRequest = meta.get(USAGE_KEY);
426
+ usageRequest.onsuccess = () => {
427
+ usage = readUsageRecord(usageRequest.result);
428
+ usageReady = true;
429
+ evictIfNeeded();
430
+ };
431
+ usageRequest.onerror = failRequest;
432
+
433
+ transaction.oncomplete = () => resolve(true);
434
+ transaction.onerror = () => reject(transactionError(transaction, "IndexedDB frame write failed"));
435
+ transaction.onabort = () => reject(transactionError(transaction, "IndexedDB frame write was aborted"));
436
+ });
437
+ }
438
+
439
+ function getFrame(database, key, nextAccess) {
440
+ return new Promise((resolve, reject) => {
441
+ let transaction;
442
+ try {
443
+ transaction = database.transaction(FRAME_STORE, "readwrite");
444
+ } catch (error) {
445
+ reject(error);
446
+ return;
447
+ }
448
+
449
+ const store = transaction.objectStore(FRAME_STORE);
450
+ let result = null;
451
+ const request = store.get(key.key);
452
+ request.onsuccess = () => {
453
+ const record = request.result;
454
+ if (!isStoredFrameValid(record)) {
455
+ if (record != null) {
456
+ store.delete(key.key);
457
+ }
458
+ return;
459
+ }
460
+ record.lastAccess = nextAccess();
461
+ store.put(record);
462
+ result = {
463
+ blob: record.blob,
464
+ width: record.width,
465
+ height: record.height,
466
+ byteSize: record.byteSize,
467
+ lastAccess: record.lastAccess,
468
+ };
469
+ };
470
+
471
+ transaction.oncomplete = () => resolve(result);
472
+ transaction.onerror = () => reject(transactionError(transaction, "IndexedDB frame read failed"));
473
+ transaction.onabort = () => reject(transactionError(transaction, "IndexedDB frame read was aborted"));
474
+ });
475
+ }
476
+
477
+ function deleteFrame(database, key) {
478
+ return new Promise((resolve, reject) => {
479
+ let transaction;
480
+ try {
481
+ transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
482
+ } catch (error) {
483
+ reject(error);
484
+ return;
485
+ }
486
+
487
+ const frames = transaction.objectStore(FRAME_STORE);
488
+ const meta = transaction.objectStore(META_STORE);
489
+ let deleted = false;
490
+ const getRequest = frames.get(key.key);
491
+ getRequest.onsuccess = () => {
492
+ const existing = getRequest.result;
493
+ if (existing == null) {
494
+ return;
495
+ }
496
+ deleted = true;
497
+ const existingIsValid = isStoredFrameValid(existing);
498
+ const usageRequest = meta.get(USAGE_KEY);
499
+ usageRequest.onsuccess = () => {
500
+ const usage = readUsageRecord(usageRequest.result);
501
+ frames.delete(key.key);
502
+ meta.put({
503
+ key: USAGE_KEY,
504
+ totalBytes: Math.max(0, usage.totalBytes - (existingIsValid ? existing.byteSize : 0)),
505
+ totalEntries: Math.max(0, usage.totalEntries - (existingIsValid ? 1 : 0)),
506
+ updatedAt: Date.now(),
507
+ });
508
+ };
509
+ };
510
+
511
+ transaction.oncomplete = () => resolve(deleted);
512
+ transaction.onerror = () => reject(transactionError(transaction, "IndexedDB frame delete failed"));
513
+ transaction.onabort = () => reject(transactionError(transaction, "IndexedDB frame delete was aborted"));
514
+ });
515
+ }
516
+
517
+ function clearDocumentFrames(database, documentId) {
518
+ return new Promise((resolve, reject) => {
519
+ let transaction;
520
+ try {
521
+ transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
522
+ } catch (error) {
523
+ reject(error);
524
+ return;
525
+ }
526
+
527
+ const frames = transaction.objectStore(FRAME_STORE);
528
+ const meta = transaction.objectStore(META_STORE);
529
+ let usage = null;
530
+ let cursorFinished = false;
531
+ let deletedEntries = 0;
532
+ let deletedBytes = 0;
533
+ let finalized = false;
534
+
535
+ const maybeFinalize = () => {
536
+ if (finalized || usage == null || !cursorFinished) {
537
+ return;
538
+ }
539
+ finalized = true;
540
+ meta.put({
541
+ key: USAGE_KEY,
542
+ totalBytes: Math.max(0, usage.totalBytes - deletedBytes),
543
+ totalEntries: Math.max(0, usage.totalEntries - deletedEntries),
544
+ updatedAt: Date.now(),
545
+ });
546
+ };
547
+
548
+ const usageRequest = meta.get(USAGE_KEY);
549
+ usageRequest.onsuccess = () => {
550
+ usage = readUsageRecord(usageRequest.result);
551
+ maybeFinalize();
552
+ };
553
+
554
+ const cursorRequest = frames.index(DOCUMENT_INDEX).openCursor(documentId);
555
+ cursorRequest.onsuccess = () => {
556
+ const cursor = cursorRequest.result;
557
+ if (cursor == null) {
558
+ cursorFinished = true;
559
+ maybeFinalize();
560
+ return;
561
+ }
562
+ const record = cursor.value;
563
+ if (isStoredFrameValid(record)) {
564
+ deletedEntries += 1;
565
+ deletedBytes += record.byteSize;
566
+ }
567
+ cursor.delete();
568
+ cursor.continue();
569
+ };
570
+
571
+ transaction.oncomplete = () => resolve(deletedEntries);
572
+ transaction.onerror = () => reject(transactionError(transaction, "IndexedDB document clear failed"));
573
+ transaction.onabort = () => reject(transactionError(transaction, "IndexedDB document clear was aborted"));
574
+ });
575
+ }
576
+
577
+ /**
578
+ * Create a cache facade that is safe in Window and DedicatedWorkerGlobalScope.
579
+ * The facade is synchronous; all storage methods are asynchronous and never
580
+ * throw for storage availability, quota, cloning, or transaction failures.
581
+ */
582
+ function createFrameCache(options = {}) {
583
+ const source = options && typeof options === "object" ? options : {};
584
+ const limits = normalizeFrameCacheLimits(source);
585
+ const dbName = normalizeDatabaseName(source.dbName);
586
+ const factory = source.indexedDB ?? globalThis.indexedDB;
587
+ const enabled = source.enabled !== false;
588
+ let closed = false;
589
+ let disabledReason = !enabled
590
+ ? "disabled"
591
+ : factory && typeof factory.open === "function"
592
+ ? null
593
+ : "unavailable";
594
+ let databasePromise = null;
595
+ let lastAccess = 0;
596
+
597
+ const nextAccess = () => {
598
+ lastAccess = Math.max(Date.now(), lastAccess + 1);
599
+ return lastAccess;
600
+ };
601
+
602
+ const disable = (error) => {
603
+ if (disabledReason == null) {
604
+ disabledReason = typeof error?.name === "string" && error.name
605
+ ? error.name
606
+ : "storage-error";
607
+ }
608
+ if (databasePromise != null) {
609
+ databasePromise.then((database) => database?.close()).catch(() => {});
610
+ }
611
+ };
612
+
613
+ const getDatabase = async () => {
614
+ if (closed || disabledReason != null) {
615
+ return null;
616
+ }
617
+ if (databasePromise == null) {
618
+ databasePromise = openDatabase(factory, dbName)
619
+ .then(async (database) => {
620
+ database.onversionchange = () => {
621
+ database.close();
622
+ disable({ name: "version-change" });
623
+ };
624
+ await reconcileUsage(database, limits);
625
+ return database;
626
+ })
627
+ .catch((error) => {
628
+ disable(error);
629
+ return null;
630
+ });
631
+ }
632
+ return databasePromise;
633
+ };
634
+
635
+ const run = async (operation, fallback) => {
636
+ if (closed || disabledReason != null) {
637
+ return fallback;
638
+ }
639
+ const database = await getDatabase();
640
+ if (database == null) {
641
+ return fallback;
642
+ }
643
+ try {
644
+ return await operation(database);
645
+ } catch (error) {
646
+ // QuotaExceededError, Safari's InvalidStateError / TransactionInactiveError,
647
+ // private-mode failures, and structured-clone failures all become misses.
648
+ disable(error);
649
+ return fallback;
650
+ }
651
+ };
652
+
653
+ return Object.freeze({
654
+ async get(keyInput) {
655
+ const key = normalizeFrameCacheKey(keyInput);
656
+ if (key == null) {
657
+ return null;
658
+ }
659
+ return run((database) => getFrame(database, key, nextAccess), null);
660
+ },
661
+
662
+ async put(keyInput, frameInput) {
663
+ const input = normalizePutArguments(keyInput, frameInput, limits);
664
+ if (input == null) {
665
+ return false;
666
+ }
667
+ const record = {
668
+ ...input,
669
+ lastAccess: nextAccess(),
670
+ };
671
+ return run((database) => putFrame(database, record, limits), false);
672
+ },
673
+
674
+ async delete(keyInput) {
675
+ const key = normalizeFrameCacheKey(keyInput);
676
+ if (key == null) {
677
+ return false;
678
+ }
679
+ return run((database) => deleteFrame(database, key), false);
680
+ },
681
+
682
+ async clearDocument(documentId) {
683
+ const normalized = normalizeBoundedString(documentId, MAX_DOCUMENT_ID_LENGTH, { trim: true });
684
+ if (normalized == null) {
685
+ return 0;
686
+ }
687
+ return run((database) => clearDocumentFrames(database, normalized), 0);
688
+ },
689
+
690
+ async stats() {
691
+ const unavailable = () => ({
692
+ available: false,
693
+ disabledReason: closed ? "closed" : disabledReason ?? "unavailable",
694
+ entries: 0,
695
+ totalBytes: 0,
696
+ ...limits,
697
+ });
698
+ if (closed || disabledReason != null) {
699
+ return unavailable();
700
+ }
701
+ const result = await run(async (database) => {
702
+ let transaction;
703
+ try {
704
+ transaction = database.transaction(META_STORE, "readonly");
705
+ } catch (error) {
706
+ throw error;
707
+ }
708
+ const value = await requestResult(transaction.objectStore(META_STORE).get(USAGE_KEY));
709
+ const usage = readUsageRecord(value);
710
+ return {
711
+ available: true,
712
+ disabledReason: null,
713
+ entries: usage.totalEntries,
714
+ totalBytes: usage.totalBytes,
715
+ ...limits,
716
+ };
717
+ }, null);
718
+ return result ?? unavailable();
719
+ },
720
+
721
+ close() {
722
+ if (closed) {
723
+ return;
724
+ }
725
+ closed = true;
726
+ if (databasePromise != null) {
727
+ databasePromise.then((database) => database?.close()).catch(() => {});
728
+ }
729
+ },
730
+ });
731
+ }
732
+
733
+ const WASM_EXPORTS = Object.freeze([
734
+ 'memory',
735
+ 'ppt_input_alloc',
736
+ 'ppt_input_free',
737
+ 'ppt_font_pack_install',
738
+ 'ppt_font_pack_is_installed',
739
+ 'ppt_document_open',
740
+ 'ppt_document_close',
741
+ 'ppt_slide_count',
742
+ 'ppt_slide_width',
743
+ 'ppt_slide_height',
744
+ 'ppt_render_slide_rgba',
745
+ 'ppt_frame_ptr',
746
+ 'ppt_frame_len',
747
+ 'ppt_frame_width',
748
+ 'ppt_frame_height',
749
+ 'ppt_frame_stride',
750
+ 'ppt_frame_free',
751
+ 'ppt_last_error_code'
752
+ ]);
753
+
754
+ const CFB_SIGNATURE = Object.freeze([0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1]);
755
+ const MAX_ASSET_BYTES = 64 * 1024 * 1024;
756
+ const MAX_DOCUMENT_BYTES = 256 * 1024 * 1024;
757
+ const CACHE_VARIANT_VERSION = 'flyfish-ppt-final-watermarked-png-v1';
758
+
759
+ let runtime = null;
760
+ let requestQueue = Promise.resolve();
761
+ let sessionEpoch = 0;
762
+ const activationIntents = new Map();
763
+ const pendingRequestIds = new Set();
764
+ const activeAbortControllers = new Set();
765
+
766
+ const counters = {
767
+ cacheHits: 0,
768
+ cacheMisses: 0,
769
+ cacheWrites: 0,
770
+ nativeRenders: 0,
771
+ cancellations: 0
772
+ };
773
+
774
+ const workerScope = globalThis;
775
+ if (typeof workerScope.addEventListener === 'function' && typeof workerScope.postMessage === 'function') {
776
+ workerScope.addEventListener('message', (event) => enqueueRequest(event.data));
777
+ }
778
+
779
+ function enqueueRequest(message) {
780
+ const fallbackId = isRecord(message) && isRequestId(message.id) ? message.id : null;
781
+ let request;
782
+ try {
783
+ request = prepareRequest(message);
784
+ } catch (error) {
785
+ postResponse(fallbackId, false, serializeError(error));
786
+ return;
787
+ }
788
+
789
+ const requestKey = idKey(request.id);
790
+ if (pendingRequestIds.has(requestKey)) {
791
+ postResponse(request.id, false, serializeError(workerError(
792
+ 'duplicate-request-id',
793
+ 'Worker request ids must remain unique until their responses are delivered.'
794
+ )));
795
+ return;
796
+ }
797
+ pendingRequestIds.add(requestKey);
798
+
799
+ requestQueue = requestQueue.then(async () => {
800
+ try {
801
+ const result = await dispatchRequest(request);
802
+ postResponse(request.id, true, result);
803
+ } catch (error) {
804
+ if (error instanceof CancelledOperation) {
805
+ counters.cancellations += 1;
806
+ postResponse(request.id, true, Object.freeze({ cancelled: true }));
807
+ } else {
808
+ postResponse(request.id, false, serializeError(error));
809
+ }
810
+ } finally {
811
+ pendingRequestIds.delete(requestKey);
812
+ }
813
+ });
814
+ }
815
+
816
+ function prepareRequest(message) {
817
+ if (!isRecord(message)) throw workerError('request-invalid', 'Worker requests must be objects.');
818
+ if (!isRequestId(message.id)) {
819
+ throw workerError('request-id-invalid', 'Worker requests require a finite number or non-empty string id.');
820
+ }
821
+ if (typeof message.type !== 'string' || message.type.length === 0) {
822
+ throw workerError('request-type-invalid', 'Worker requests require a non-empty type.');
823
+ }
824
+ if (!['init', 'open', 'attach', 'activate', 'deactivate', 'cacheStats', 'close'].includes(message.type)) {
825
+ throw workerError('request-type-unsupported', `Unsupported worker request type: ${message.type}`);
826
+ }
827
+
828
+ if (message.type === 'init' || message.type === 'close') {
829
+ sessionEpoch += 1;
830
+ activationIntents.clear();
831
+ abortActiveOperations();
832
+ }
833
+
834
+ let intentRevision = null;
835
+ if (message.type === 'activate' || message.type === 'deactivate') {
836
+ const slideIndex = requireSlideIndex(message.slideIndex, false);
837
+ const previous = activationIntents.get(slideIndex) || { revision: 0, active: false };
838
+ const next = {
839
+ revision: previous.revision + 1,
840
+ active: message.type === 'activate'
841
+ };
842
+ activationIntents.set(slideIndex, next);
843
+ intentRevision = next.revision;
844
+ }
845
+
846
+ return Object.freeze({
847
+ id: message.id,
848
+ type: message.type,
849
+ message,
850
+ epoch: sessionEpoch,
851
+ intentRevision
852
+ });
853
+ }
854
+
855
+ async function dispatchRequest(request) {
856
+ assertCurrent(request);
857
+ switch (request.type) {
858
+ case 'init':
859
+ return initialize(request);
860
+ case 'open':
861
+ return openDocument(request);
862
+ case 'attach':
863
+ return attachCanvas(request);
864
+ case 'activate':
865
+ return activateCanvas(request);
866
+ case 'deactivate':
867
+ return deactivateCanvas(request);
868
+ case 'cacheStats':
869
+ return cacheStats(request);
870
+ case 'close':
871
+ return closeRuntime(request);
872
+ default:
873
+ throw workerError('request-type-unsupported', `Unsupported worker request type: ${request.type}`);
874
+ }
875
+ }
876
+
877
+ async function initialize(request) {
878
+ await releaseRuntime();
879
+ assertCurrent(request);
880
+ resetCounters();
881
+
882
+ const manifest = normalizeManifest(request.message.manifest);
883
+ const wasmUrl = normalizeAssetUrl(request.message.wasmUrl, 'wasmUrl');
884
+ const fontUrl = normalizeAssetUrl(request.message.fontUrl, 'fontUrl');
885
+ const cacheOptions = normalizeCacheOptions(request.message.cacheOptions);
886
+ requireWebCrypto();
887
+
888
+ const controller = new AbortController();
889
+ activeAbortControllers.add(controller);
890
+ let cache = null;
891
+ try {
892
+ const fontPromise = downloadVerifiedAsset(
893
+ fontUrl,
894
+ manifest.fontPack.bytes,
895
+ manifest.fontPack.sha256,
896
+ 'PPT native font pack',
897
+ controller.signal
898
+ );
899
+ void fontPromise.catch(() => {});
900
+ const wasmBytes = await downloadVerifiedAsset(
901
+ wasmUrl,
902
+ manifest.wasmBytes,
903
+ manifest.wasmSha256,
904
+ 'PPT native WASM',
905
+ controller.signal
906
+ );
907
+ assertCurrent(request);
908
+
909
+ // Security invariant: no unverified bytes are presented to the WebAssembly
910
+ // compiler. Streaming compilation and compile-before-hash are deliberately
911
+ // not used by this worker.
912
+ const module = await WebAssembly.compile(wasmBytes);
913
+ assertCurrent(request);
914
+ validateModule(module);
915
+ const instance = await WebAssembly.instantiate(module, {});
916
+ assertCurrent(request);
917
+ validateEngine(instance.exports);
918
+ const fontBytes = await fontPromise;
919
+ assertCurrent(request);
920
+ installFontPack(instance.exports, fontBytes);
921
+
922
+ cache = createFrameCache(cacheOptions);
923
+ runtime = {
924
+ manifest,
925
+ instance,
926
+ api: instance.exports,
927
+ cache,
928
+ document: null,
929
+ attachments: new Map()
930
+ };
931
+
932
+ const cacheSnapshot = await safeCacheStats(cache);
933
+ assertCurrent(request);
934
+ return Object.freeze({
935
+ initialized: true,
936
+ wasmSha256: manifest.wasmSha256,
937
+ wasmBytes: manifest.wasmBytes,
938
+ fontPackSha256: manifest.fontPack.sha256,
939
+ fontPackBytes: manifest.fontPack.bytes,
940
+ fontPackInstalled: true,
941
+ cache: cacheSnapshot
942
+ });
943
+ } catch (error) {
944
+ controller.abort();
945
+ if (cache) cache.close();
946
+ runtime = null;
947
+ if (!isCurrent(request) || error?.name === 'AbortError') throw new CancelledOperation();
948
+ throw error;
949
+ } finally {
950
+ activeAbortControllers.delete(controller);
951
+ }
952
+ }
953
+
954
+ async function openDocument(request) {
955
+ const current = requireRuntime();
956
+ if (current.document) {
957
+ throw workerError('document-already-open', 'Close the current PPT document before opening another one.');
958
+ }
959
+ const input = request.message.input;
960
+ if (!(input instanceof ArrayBuffer) || typeof SharedArrayBuffer !== 'undefined' && input instanceof SharedArrayBuffer) {
961
+ throw workerError('document-input-invalid', 'open requires a transferable ArrayBuffer in the input field.');
962
+ }
963
+ const bytes = new Uint8Array(input);
964
+ if (bytes.byteLength < CFB_SIGNATURE.length || bytes.byteLength > MAX_DOCUMENT_BYTES) {
965
+ throw workerError('document-size-invalid', 'The PPT input length is outside the supported range.');
966
+ }
967
+ if (!CFB_SIGNATURE.every((value, index) => bytes[index] === value)) {
968
+ throw workerError('document-signature-invalid', 'Input is not a PowerPoint 97-2003 compound document.');
969
+ }
970
+
971
+ const documentHashPromise = sha256Hex(bytes);
972
+ let handle = 0;
973
+ try {
974
+ handle = copyAndOpenDocument(current.api, bytes);
975
+ if (!handle) throw engineError(current.api, 'The native PPT parser rejected the document.');
976
+ const slideCount = Number(current.api.ppt_slide_count(handle));
977
+ const width = Number(current.api.ppt_slide_width(handle, 1000));
978
+ const height = Number(current.api.ppt_slide_height(handle, 1000));
979
+ if (!Number.isInteger(slideCount) || slideCount < 1 || slideCount > 10_000
980
+ || !Number.isInteger(width) || width < 1
981
+ || !Number.isInteger(height) || height < 1) {
982
+ throw engineError(current.api, 'The native PPT parser returned invalid document metadata.');
983
+ }
984
+ const sha256 = await documentHashPromise;
985
+ assertCurrent(request);
986
+ current.document = Object.freeze({ handle, sha256, slideCount, width, height });
987
+ handle = 0;
988
+ return Object.freeze({
989
+ documentId: sha256,
990
+ sha256,
991
+ slideCount,
992
+ width,
993
+ height
994
+ });
995
+ } catch (error) {
996
+ await documentHashPromise.catch(() => {});
997
+ if (handle) current.api.ppt_document_close(handle);
998
+ if (!isCurrent(request)) throw new CancelledOperation();
999
+ throw error;
1000
+ }
1001
+ }
1002
+
1003
+ function attachCanvas(request) {
1004
+ const current = requireOpenDocument();
1005
+ const slideIndex = requireSlideIndex(request.message.slideIndex, true, current.document.slideCount);
1006
+ const canvas = request.message.canvas;
1007
+ if (typeof OffscreenCanvas !== 'function' || !(canvas instanceof OffscreenCanvas)) {
1008
+ throw workerError('canvas-invalid', 'attach requires a transferred OffscreenCanvas in the canvas field.');
1009
+ }
1010
+ const renderOptions = normalizeRenderOptions(request.message.scale, request.message.pixelRatio);
1011
+ const context = canvas.getContext('2d', { alpha: false, desynchronized: false });
1012
+ if (!context || typeof context.putImageData !== 'function' || typeof context.drawImage !== 'function') {
1013
+ throw workerError('canvas-context-unavailable', 'A Worker-compatible Canvas 2D context is required.');
1014
+ }
1015
+
1016
+ const existing = current.attachments.get(slideIndex);
1017
+ if (existing) releaseCanvasBacking(existing.canvas);
1018
+ releaseCanvasBacking(canvas);
1019
+ const attachment = {
1020
+ slideIndex,
1021
+ canvas,
1022
+ context,
1023
+ scale: renderOptions.scale,
1024
+ pixelRatio: renderOptions.pixelRatio,
1025
+ active: false,
1026
+ rendered: null
1027
+ };
1028
+ current.attachments.set(slideIndex, attachment);
1029
+ return Object.freeze({
1030
+ attached: true,
1031
+ slideIndex,
1032
+ scale: attachment.scale,
1033
+ pixelRatio: attachment.pixelRatio
1034
+ });
1035
+ }
1036
+
1037
+ async function activateCanvas(request) {
1038
+ const current = requireOpenDocument();
1039
+ const slideIndex = requireSlideIndex(request.message.slideIndex, true, current.document.slideCount);
1040
+ const attachment = current.attachments.get(slideIndex);
1041
+ if (!attachment) throw workerError('canvas-not-attached', `Slide ${slideIndex} has no attached OffscreenCanvas.`);
1042
+ assertActivationCurrent(request, slideIndex, true);
1043
+
1044
+ const renderOptions = normalizeRenderOptions(request.message.scale, request.message.pixelRatio);
1045
+ attachment.scale = renderOptions.scale;
1046
+ attachment.pixelRatio = renderOptions.pixelRatio;
1047
+ const dimensions = slideDimensions(current.api, current.document.handle, renderOptions.scaleMilli);
1048
+ const cacheKey = frameCacheKey(current, slideIndex, renderOptions.scaleMilli, dimensions);
1049
+
1050
+ const cached = await current.cache.get(cacheKey);
1051
+ assertCurrent(request);
1052
+ assertActivationCurrent(request, slideIndex, true);
1053
+ if (validCachedFrame(cached, dimensions)) {
1054
+ const drawn = await drawCachedFrame(attachment, cached.blob, dimensions, request);
1055
+ if (drawn) {
1056
+ counters.cacheHits += 1;
1057
+ attachment.active = true;
1058
+ attachment.rendered = renderMetadata(
1059
+ slideIndex,
1060
+ renderOptions,
1061
+ dimensions,
1062
+ cacheKey,
1063
+ 'indexeddb'
1064
+ );
1065
+ return Object.freeze({ ...attachment.rendered, cancelled: false });
1066
+ }
1067
+ await current.cache.delete(cacheKey);
1068
+ } else if (cached) {
1069
+ await current.cache.delete(cacheKey);
1070
+ }
1071
+ counters.cacheMisses += 1;
1072
+
1073
+ assertCurrent(request);
1074
+ assertActivationCurrent(request, slideIndex, true);
1075
+ drawNativeFrame(current.api, current.document.handle, slideIndex, renderOptions.scaleMilli, dimensions, attachment);
1076
+ counters.nativeRenders += 1;
1077
+ attachment.active = true;
1078
+ attachment.rendered = renderMetadata(
1079
+ slideIndex,
1080
+ renderOptions,
1081
+ dimensions,
1082
+ cacheKey,
1083
+ 'native'
1084
+ );
1085
+ return Object.freeze({ ...attachment.rendered, cancelled: false });
1086
+ }
1087
+
1088
+ async function deactivateCanvas(request) {
1089
+ const current = requireOpenDocument();
1090
+ const slideIndex = requireSlideIndex(request.message.slideIndex, true, current.document.slideCount);
1091
+ const attachment = current.attachments.get(slideIndex);
1092
+ if (!attachment) throw workerError('canvas-not-attached', `Slide ${slideIndex} has no attached OffscreenCanvas.`);
1093
+ assertActivationCurrent(request, slideIndex, false);
1094
+
1095
+ let stored = false;
1096
+ if (attachment.rendered
1097
+ && attachment.rendered.source !== 'indexeddb'
1098
+ && attachment.canvas.width > 1
1099
+ && attachment.canvas.height > 1) {
1100
+ if (typeof attachment.canvas.convertToBlob !== 'function') {
1101
+ throw workerError('canvas-blob-unavailable', 'OffscreenCanvas PNG encoding is unavailable in this Worker.');
1102
+ }
1103
+ const blob = await attachment.canvas.convertToBlob({ type: 'image/png' });
1104
+ assertCurrent(request);
1105
+ assertActivationCurrent(request, slideIndex, false);
1106
+ if (!(blob instanceof Blob) || blob.type !== 'image/png' || blob.size === 0) {
1107
+ throw workerError('canvas-png-invalid', 'OffscreenCanvas did not produce a valid final-frame PNG.');
1108
+ }
1109
+ stored = await current.cache.put(attachment.rendered.cacheKey, {
1110
+ blob,
1111
+ width: attachment.rendered.width,
1112
+ height: attachment.rendered.height
1113
+ });
1114
+ if (stored) counters.cacheWrites += 1;
1115
+ assertCurrent(request);
1116
+ assertActivationCurrent(request, slideIndex, false);
1117
+ }
1118
+
1119
+ attachment.active = false;
1120
+ releaseCanvasBacking(attachment.canvas);
1121
+ return Object.freeze({
1122
+ deactivated: true,
1123
+ slideIndex,
1124
+ cached: stored,
1125
+ width: 1,
1126
+ height: 1
1127
+ });
1128
+ }
1129
+
1130
+ async function cacheStats(request) {
1131
+ assertCurrent(request);
1132
+ const current = requireRuntime();
1133
+ const persisted = await safeCacheStats(current.cache);
1134
+ assertCurrent(request);
1135
+ return Object.freeze({
1136
+ enabled: persisted.disabledReason !== 'disabled',
1137
+ available: persisted.available === true,
1138
+ disabledReason: persisted.disabledReason ?? null,
1139
+ entries: Number(persisted.entries) || 0,
1140
+ bytes: Number(persisted.totalBytes) || 0,
1141
+ maxBytes: Number(persisted.maxBytes) || 0,
1142
+ maxEntries: Number(persisted.maxEntries) || 0,
1143
+ maxEntryBytes: Number(persisted.maxItemBytes) || 0,
1144
+ hits: counters.cacheHits,
1145
+ misses: counters.cacheMisses,
1146
+ writes: counters.cacheWrites,
1147
+ nativeRenders: counters.nativeRenders,
1148
+ cancellations: counters.cancellations,
1149
+ attachedCanvases: current.attachments.size,
1150
+ activeCanvases: Array.from(current.attachments.values()).filter((item) => item.active).length,
1151
+ wasmMemoryBytes: current.api.memory.buffer.byteLength
1152
+ });
1153
+ }
1154
+
1155
+ async function closeRuntime(request) {
1156
+ releaseDocument(requireRuntime());
1157
+ assertCurrent(request);
1158
+ return Object.freeze({ closed: true });
1159
+ }
1160
+
1161
+ async function releaseRuntime() {
1162
+ const current = runtime;
1163
+ runtime = null;
1164
+ if (!current) return;
1165
+
1166
+ let closeError = null;
1167
+ try {
1168
+ releaseDocument(current);
1169
+ } catch (error) {
1170
+ closeError = error;
1171
+ }
1172
+ try {
1173
+ current.cache.close();
1174
+ } catch (error) {
1175
+ closeError ||= error;
1176
+ }
1177
+ if (closeError) throw closeError;
1178
+ }
1179
+
1180
+ function releaseDocument(current) {
1181
+ let closeError = null;
1182
+ if (current.document) {
1183
+ try {
1184
+ if (Number(current.api.ppt_document_close(current.document.handle)) !== 1) {
1185
+ closeError = engineError(current.api, 'Unable to close the native PPT document.');
1186
+ }
1187
+ } catch (error) {
1188
+ closeError = error;
1189
+ }
1190
+ }
1191
+ current.document = null;
1192
+ for (const attachment of current.attachments.values()) releaseCanvasBacking(attachment.canvas);
1193
+ current.attachments.clear();
1194
+ activationIntents.clear();
1195
+ if (closeError) throw closeError;
1196
+ }
1197
+
1198
+ async function downloadVerifiedAsset(url, expectedBytes, expectedSha256, label, signal) {
1199
+ const response = await fetch(url, { signal, cache: 'default', credentials: 'same-origin' });
1200
+ if (!response.ok) {
1201
+ throw workerError('asset-request-failed', `${label} request failed with HTTP ${response.status}.`);
1202
+ }
1203
+
1204
+ const encoding = response.headers.get('content-encoding');
1205
+ const contentLength = response.headers.get('content-length');
1206
+ if (!encoding && contentLength && Number(contentLength) !== expectedBytes) {
1207
+ throw workerError('asset-length-invalid', `${label} Content-Length did not match its manifest.`);
1208
+ }
1209
+
1210
+ const bytes = await readExactResponseBytes(response, expectedBytes, label, signal);
1211
+ const actualSha256 = await sha256Hex(bytes);
1212
+ if (actualSha256 !== expectedSha256) {
1213
+ throw workerError('asset-integrity-invalid', `${label} failed its SHA-256 integrity check.`);
1214
+ }
1215
+ return bytes;
1216
+ }
1217
+
1218
+ async function readExactResponseBytes(response, expectedBytes, label, signal) {
1219
+ if (!response.body || typeof response.body.getReader !== 'function') {
1220
+ const buffer = await response.arrayBuffer();
1221
+ if (buffer.byteLength !== expectedBytes) {
1222
+ throw workerError('asset-length-invalid', `${label} byte length did not match its manifest.`);
1223
+ }
1224
+ return new Uint8Array(buffer);
1225
+ }
1226
+
1227
+ const output = new Uint8Array(expectedBytes);
1228
+ const reader = response.body.getReader();
1229
+ let offset = 0;
1230
+ try {
1231
+ while (true) {
1232
+ if (signal.aborted) throw new DOMException('The operation was aborted.', 'AbortError');
1233
+ const { done, value } = await reader.read();
1234
+ if (done) break;
1235
+ if (!(value instanceof Uint8Array) || offset + value.byteLength > expectedBytes) {
1236
+ await reader.cancel();
1237
+ throw workerError('asset-length-invalid', `${label} exceeded its manifest byte length.`);
1238
+ }
1239
+ output.set(value, offset);
1240
+ offset += value.byteLength;
1241
+ }
1242
+ } finally {
1243
+ reader.releaseLock();
1244
+ }
1245
+ if (offset !== expectedBytes) {
1246
+ throw workerError('asset-length-invalid', `${label} byte length did not match its manifest.`);
1247
+ }
1248
+ return output;
1249
+ }
1250
+
1251
+ function validateModule(module) {
1252
+ const imports = WebAssembly.Module.imports(module);
1253
+ if (imports.length !== 0) {
1254
+ throw workerError('wasm-imports-rejected', 'The PPT rendering engine must not import browser or host functions.');
1255
+ }
1256
+ const actual = WebAssembly.Module.exports(module)
1257
+ .map(({ name, kind }) => `${kind}:${name}`)
1258
+ .sort();
1259
+ const expected = WASM_EXPORTS
1260
+ .map((name) => `${name === 'memory' ? 'memory' : 'function'}:${name}`)
1261
+ .sort();
1262
+ if (actual.length !== expected.length || actual.some((value, index) => value !== expected[index])) {
1263
+ throw workerError('wasm-abi-invalid', 'The PPT rendering engine has an unexpected public ABI.');
1264
+ }
1265
+ }
1266
+
1267
+ function validateEngine(api) {
1268
+ const actual = Object.keys(api).sort();
1269
+ const expected = [...WASM_EXPORTS].sort();
1270
+ if (actual.length !== expected.length || actual.some((name, index) => name !== expected[index])) {
1271
+ throw workerError('wasm-abi-invalid', 'The PPT rendering engine instance has an unexpected public ABI.');
1272
+ }
1273
+ if (!(api.memory instanceof WebAssembly.Memory)) {
1274
+ throw workerError('wasm-memory-invalid', 'The PPT rendering engine did not export its bounded memory.');
1275
+ }
1276
+ for (const name of WASM_EXPORTS) {
1277
+ if (name !== 'memory' && typeof api[name] !== 'function') {
1278
+ throw workerError('wasm-abi-invalid', `The PPT rendering engine is missing ${name}.`);
1279
+ }
1280
+ }
1281
+ }
1282
+
1283
+ function installFontPack(api, bytes) {
1284
+ if (Number(api.ppt_font_pack_is_installed()) !== 0) {
1285
+ throw workerError('font-pack-state-invalid', 'The native font pack was unexpectedly installed before initialization.');
1286
+ }
1287
+ const pointer = Number(api.ppt_input_alloc(bytes.byteLength));
1288
+ if (!pointer) throw engineError(api, 'Unable to allocate native font-pack memory.');
1289
+ let consumed = false;
1290
+ try {
1291
+ new Uint8Array(api.memory.buffer, pointer, bytes.byteLength).set(bytes);
1292
+ const installed = Number(api.ppt_font_pack_install(pointer, bytes.byteLength));
1293
+ if (installed !== 1) throw engineError(api, 'The native engine rejected the verified font pack.');
1294
+ // A successful install transfers allocation ownership to native code. It
1295
+ // must not be passed to ppt_input_free afterwards.
1296
+ consumed = true;
1297
+ if (Number(api.ppt_font_pack_is_installed()) !== 1) {
1298
+ throw workerError('font-pack-state-invalid', 'The native font pack did not enter the installed state.');
1299
+ }
1300
+ } finally {
1301
+ if (!consumed && Number(api.ppt_input_free(pointer, bytes.byteLength)) !== 1) {
1302
+ throw engineError(api, 'Unable to release rejected native font-pack memory.');
1303
+ }
1304
+ }
1305
+ }
1306
+
1307
+ function copyAndOpenDocument(api, bytes) {
1308
+ const pointer = Number(api.ppt_input_alloc(bytes.byteLength));
1309
+ if (!pointer) throw engineError(api, 'Unable to allocate native PPT input memory.');
1310
+ let handle = 0;
1311
+ let openErrorCode = 0;
1312
+ let primaryError = null;
1313
+ try {
1314
+ new Uint8Array(api.memory.buffer, pointer, bytes.byteLength).set(bytes);
1315
+ handle = Number(api.ppt_document_open(pointer, bytes.byteLength));
1316
+ if (!handle) openErrorCode = Number(api.ppt_last_error_code()) || 0;
1317
+ } catch (error) {
1318
+ primaryError = error;
1319
+ }
1320
+ const released = Number(api.ppt_input_free(pointer, bytes.byteLength));
1321
+ if (primaryError) throw primaryError;
1322
+ if (released !== 1) {
1323
+ const releaseError = engineError(api, 'Unable to release native PPT input memory.');
1324
+ if (handle) api.ppt_document_close(handle);
1325
+ throw releaseError;
1326
+ }
1327
+ if (!handle) {
1328
+ throw workerError(
1329
+ `native-${openErrorCode || 'unknown'}`,
1330
+ `The native PPT parser rejected the document. (native error ${openErrorCode || 'unknown'})`
1331
+ );
1332
+ }
1333
+ return handle;
1334
+ }
1335
+
1336
+ function slideDimensions(api, documentHandle, scaleMilli) {
1337
+ const width = Number(api.ppt_slide_width(documentHandle, scaleMilli));
1338
+ const height = Number(api.ppt_slide_height(documentHandle, scaleMilli));
1339
+ if (!Number.isInteger(width) || width < 1 || !Number.isInteger(height) || height < 1) {
1340
+ throw engineError(api, 'The native engine returned invalid slide dimensions.');
1341
+ }
1342
+ return Object.freeze({ width, height });
1343
+ }
1344
+
1345
+ function drawNativeFrame(api, documentHandle, slideIndex, scaleMilli, dimensions, attachment) {
1346
+ const frame = Number(api.ppt_render_slide_rgba(documentHandle, slideIndex, scaleMilli));
1347
+ if (!frame) throw engineError(api, `Unable to render slide ${slideIndex + 1}.`);
1348
+ let primaryError = null;
1349
+ try {
1350
+ const width = Number(api.ppt_frame_width(frame));
1351
+ const height = Number(api.ppt_frame_height(frame));
1352
+ const stride = Number(api.ppt_frame_stride(frame));
1353
+ const length = Number(api.ppt_frame_len(frame));
1354
+ const pointer = Number(api.ppt_frame_ptr(frame));
1355
+ const expectedLength = dimensions.width * dimensions.height * 4;
1356
+ if (width !== dimensions.width || height !== dimensions.height || stride !== width * 4
1357
+ || length !== expectedLength || !pointer || pointer + length > api.memory.buffer.byteLength) {
1358
+ throw workerError('wasm-frame-invalid', 'The native engine returned an invalid final RGBA frame.');
1359
+ }
1360
+
1361
+ attachment.canvas.width = width;
1362
+ attachment.canvas.height = height;
1363
+ const pixels = new Uint8ClampedArray(api.memory.buffer, pointer, length);
1364
+ let imageData;
1365
+ if (typeof ImageData === 'function') {
1366
+ imageData = new ImageData(pixels, width, height);
1367
+ } else {
1368
+ imageData = attachment.context.createImageData(width, height);
1369
+ imageData.data.set(pixels);
1370
+ }
1371
+ attachment.context.putImageData(imageData, 0, 0);
1372
+ } catch (error) {
1373
+ primaryError = error;
1374
+ }
1375
+ const released = Number(api.ppt_frame_free(frame));
1376
+ if (primaryError) throw primaryError;
1377
+ if (released !== 1) throw engineError(api, 'Unable to release the native final RGBA frame.');
1378
+ }
1379
+
1380
+ async function drawCachedFrame(attachment, blob, dimensions, request) {
1381
+ if (typeof createImageBitmap !== 'function') return false;
1382
+ let bitmap;
1383
+ try {
1384
+ bitmap = await createImageBitmap(blob);
1385
+ assertCurrent(request);
1386
+ assertActivationCurrent(request, attachment.slideIndex, true);
1387
+ if (bitmap.width !== dimensions.width || bitmap.height !== dimensions.height) return false;
1388
+ attachment.canvas.width = dimensions.width;
1389
+ attachment.canvas.height = dimensions.height;
1390
+ attachment.context.drawImage(bitmap, 0, 0, dimensions.width, dimensions.height);
1391
+ return true;
1392
+ } catch (error) {
1393
+ if (error instanceof CancelledOperation) throw error;
1394
+ return false;
1395
+ } finally {
1396
+ if (bitmap && typeof bitmap.close === 'function') bitmap.close();
1397
+ }
1398
+ }
1399
+
1400
+ function frameCacheKey(current, slideIndex, scaleMilli, dimensions) {
1401
+ return Object.freeze({
1402
+ documentId: current.document.sha256,
1403
+ pageIndex: slideIndex,
1404
+ variant: [
1405
+ CACHE_VARIANT_VERSION,
1406
+ current.manifest.wasmSha256,
1407
+ current.manifest.fontPack.sha256,
1408
+ `s${scaleMilli}`,
1409
+ `w${dimensions.width}`,
1410
+ `h${dimensions.height}`
1411
+ ].join(':')
1412
+ });
1413
+ }
1414
+
1415
+ function validCachedFrame(entry, dimensions) {
1416
+ return isRecord(entry)
1417
+ && entry.blob instanceof Blob
1418
+ && entry.blob.type === 'image/png'
1419
+ && entry.blob.size > 0
1420
+ && entry.width === dimensions.width
1421
+ && entry.height === dimensions.height;
1422
+ }
1423
+
1424
+ function renderMetadata(slideIndex, options, dimensions, cacheKey, source) {
1425
+ return Object.freeze({
1426
+ slideIndex,
1427
+ width: dimensions.width,
1428
+ height: dimensions.height,
1429
+ scale: options.scale,
1430
+ pixelRatio: options.pixelRatio,
1431
+ source,
1432
+ cacheKey
1433
+ });
1434
+ }
1435
+
1436
+ function normalizeManifest(value) {
1437
+ if (!isRecord(value)) throw workerError('manifest-invalid', 'init requires a manifest object.');
1438
+ if (value.watermarkRequired !== true || value.watermarkEnforcement !== 'native-final-frame') {
1439
+ throw workerError('manifest-policy-invalid', 'The Worker only accepts mandatory native-final-frame watermark builds.');
1440
+ }
1441
+ if (value.edition !== 'public-watermarked'
1442
+ || value.renderer !== 'native-wasm-worker-offscreen-canvas') {
1443
+ throw workerError('manifest-policy-invalid', 'The Worker only accepts the public native OffscreenCanvas edition.');
1444
+ }
1445
+
1446
+ const wasmBytes = requireAssetLength(value.wasmBytes, 'manifest.wasmBytes');
1447
+ const wasmSha256 = requireSha256(value.wasmSha256, 'manifest.wasmSha256');
1448
+ const fontPack = isRecord(value.fontPack) ? value.fontPack : {
1449
+ file: value.fontPackFile,
1450
+ bytes: value.fontPackBytes,
1451
+ sha256: value.fontPackSha256
1452
+ };
1453
+ const fontBytes = requireAssetLength(fontPack.bytes, 'manifest.fontPack.bytes');
1454
+ const fontSha256 = requireSha256(fontPack.sha256, 'manifest.fontPack.sha256');
1455
+ return Object.freeze({
1456
+ ...value,
1457
+ wasmBytes,
1458
+ wasmSha256,
1459
+ fontPack: Object.freeze({
1460
+ file: typeof fontPack.file === 'string' ? fontPack.file : '',
1461
+ bytes: fontBytes,
1462
+ sha256: fontSha256
1463
+ })
1464
+ });
1465
+ }
1466
+
1467
+ function normalizeAssetUrl(value, label) {
1468
+ if (!(typeof value === 'string' && value.length > 0) && !(value instanceof URL)) {
1469
+ throw workerError('asset-url-invalid', `init requires a valid ${label}.`);
1470
+ }
1471
+ const url = new URL(value instanceof URL ? value.href : value, import.meta.url);
1472
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
1473
+ throw workerError('asset-url-invalid', `${label} must use HTTP or HTTPS; blob/data assets are not accepted.`);
1474
+ }
1475
+ return url;
1476
+ }
1477
+
1478
+ function normalizeCacheOptions(value) {
1479
+ if (value === undefined) return Object.freeze({});
1480
+ if (!isRecord(value)) throw workerError('cache-options-invalid', 'cacheOptions must be an object when provided.');
1481
+ const normalized = { ...value };
1482
+ if (value.maxEntryBytes !== undefined) normalized.maxItemBytes = value.maxEntryBytes;
1483
+ delete normalized.maxEntryBytes;
1484
+ // `enabled: false` is intentionally preserved. createFrameCache treats it as
1485
+ // a hard disable and never opens, reads, or writes IndexedDB.
1486
+ return Object.freeze(normalized);
1487
+ }
1488
+
1489
+ function normalizeRenderOptions(scaleValue, pixelRatioValue) {
1490
+ const scale = finitePositive(scaleValue, 'scale');
1491
+ const pixelRatio = finitePositive(pixelRatioValue, 'pixelRatio');
1492
+ const nativeScale = scale * pixelRatio;
1493
+ if (nativeScale < 0.1 || nativeScale > 8) {
1494
+ throw workerError('render-scale-invalid', 'scale * pixelRatio must be between 0.1 and 8.');
1495
+ }
1496
+ return Object.freeze({ scale, pixelRatio, scaleMilli: Math.round(nativeScale * 1000) });
1497
+ }
1498
+
1499
+ function finitePositive(value, label) {
1500
+ const number = Number(value);
1501
+ if (!Number.isFinite(number) || number <= 0) {
1502
+ throw workerError('render-scale-invalid', `${label} must be a finite positive number.`);
1503
+ }
1504
+ return number;
1505
+ }
1506
+
1507
+ function requireSlideIndex(value, validateRange, slideCount = 0) {
1508
+ if (!Number.isInteger(value) || value < 0 || value > 9_999) {
1509
+ throw workerError('slide-index-invalid', 'slideIndex must be an integer between 0 and 9999.');
1510
+ }
1511
+ if (validateRange && value >= slideCount) {
1512
+ throw workerError('slide-index-invalid', `slideIndex must be between 0 and ${slideCount - 1}.`);
1513
+ }
1514
+ return value;
1515
+ }
1516
+
1517
+ function requireAssetLength(value, label) {
1518
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_ASSET_BYTES) {
1519
+ throw workerError('manifest-length-invalid', `${label} must be an exact positive byte length no larger than ${MAX_ASSET_BYTES}.`);
1520
+ }
1521
+ return value;
1522
+ }
1523
+
1524
+ function requireSha256(value, label) {
1525
+ if (typeof value !== 'string' || !/^[0-9a-f]{64}$/i.test(value)) {
1526
+ throw workerError('manifest-sha256-invalid', `${label} must be a 64-character hexadecimal SHA-256 digest.`);
1527
+ }
1528
+ return value.toLowerCase();
1529
+ }
1530
+
1531
+ function requireRuntime() {
1532
+ if (!runtime) throw workerError('worker-not-initialized', 'Initialize the PPT Worker before using it.');
1533
+ return runtime;
1534
+ }
1535
+
1536
+ function requireOpenDocument() {
1537
+ const current = requireRuntime();
1538
+ if (!current.document) throw workerError('document-not-open', 'Open a PPT document before attaching or rendering slides.');
1539
+ return current;
1540
+ }
1541
+
1542
+ function assertActivationCurrent(request, slideIndex, expectedActive) {
1543
+ assertCurrent(request);
1544
+ const intent = activationIntents.get(slideIndex);
1545
+ if (!intent || intent.revision !== request.intentRevision || intent.active !== expectedActive) {
1546
+ throw new CancelledOperation();
1547
+ }
1548
+ }
1549
+
1550
+ function assertCurrent(request) {
1551
+ if (!isCurrent(request)) throw new CancelledOperation();
1552
+ }
1553
+
1554
+ function isCurrent(request) {
1555
+ return request.epoch === sessionEpoch;
1556
+ }
1557
+
1558
+ function abortActiveOperations() {
1559
+ for (const controller of activeAbortControllers) controller.abort();
1560
+ }
1561
+
1562
+ function resetCounters() {
1563
+ counters.cacheHits = 0;
1564
+ counters.cacheMisses = 0;
1565
+ counters.cacheWrites = 0;
1566
+ counters.nativeRenders = 0;
1567
+ counters.cancellations = 0;
1568
+ }
1569
+
1570
+ function releaseCanvasBacking(canvas) {
1571
+ try {
1572
+ canvas.width = 1;
1573
+ canvas.height = 1;
1574
+ } catch {
1575
+ // A detached or already-disposed OffscreenCanvas has no remaining backing
1576
+ // store to release.
1577
+ }
1578
+ }
1579
+
1580
+ async function safeCacheStats(cache) {
1581
+ try {
1582
+ return Object.freeze({ ...(await cache.stats()) });
1583
+ } catch {
1584
+ return Object.freeze({ available: false, entries: 0, totalBytes: 0 });
1585
+ }
1586
+ }
1587
+
1588
+ async function sha256Hex(bytes) {
1589
+ const subtle = requireWebCrypto();
1590
+ const digest = new Uint8Array(await subtle.digest('SHA-256', bytes));
1591
+ return Array.from(digest, (byte) => byte.toString(16).padStart(2, '0')).join('');
1592
+ }
1593
+
1594
+ function requireWebCrypto() {
1595
+ const subtle = globalThis.crypto?.subtle;
1596
+ if (!subtle || typeof subtle.digest !== 'function') {
1597
+ throw workerError('web-crypto-unavailable', 'Web Crypto SHA-256 support is required in the PPT Worker.');
1598
+ }
1599
+ return subtle;
1600
+ }
1601
+
1602
+ function engineError(api, fallback) {
1603
+ const nativeCode = Number(api.ppt_last_error_code()) || 0;
1604
+ return workerError(`native-${nativeCode || 'unknown'}`, `${fallback} (native error ${nativeCode || 'unknown'})`);
1605
+ }
1606
+
1607
+ function workerError(code, message) {
1608
+ const error = new Error(message);
1609
+ error.name = 'FlyfishPptWorkerError';
1610
+ Object.defineProperty(error, 'code', { value: code, enumerable: true });
1611
+ return error;
1612
+ }
1613
+
1614
+ function serializeError(error) {
1615
+ return Object.freeze({
1616
+ name: typeof error?.name === 'string' ? error.name : 'Error',
1617
+ code: typeof error?.code === 'string' ? error.code : 'worker-failure',
1618
+ message: error instanceof Error ? error.message : String(error)
1619
+ });
1620
+ }
1621
+
1622
+ function postResponse(id, ok, payload) {
1623
+ try {
1624
+ workerScope.postMessage(ok
1625
+ ? { id, ok: true, result: payload }
1626
+ : { id, ok: false, error: payload });
1627
+ } catch {
1628
+ // There is no secondary channel on which a failed structured-clone response
1629
+ // can be reported. All normal results intentionally contain cloneable data.
1630
+ }
1631
+ }
1632
+
1633
+ function isRecord(value) {
1634
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
1635
+ }
1636
+
1637
+ function isRequestId(value) {
1638
+ return typeof value === 'string' ? value.length > 0 : typeof value === 'number' && Number.isFinite(value);
1639
+ }
1640
+
1641
+ function idKey(value) {
1642
+ return `${typeof value}:${String(value)}`;
1643
+ }
1644
+
1645
+ class CancelledOperation extends Error {
1646
+ constructor() {
1647
+ super('The Worker operation was superseded by newer state.');
1648
+ this.name = 'CancelledOperation';
1649
+ }
1650
+ }