@ryanyahya/opendoc 0.4.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 (789) hide show
  1. package/.agents/skills/opendoc-apply-comments/SKILL.md +30 -0
  2. package/.agents/skills/opendoc-apply-comments/agents/openai.yaml +4 -0
  3. package/.agents/skills/opendoc-create/SKILL.md +63 -0
  4. package/.agents/skills/opendoc-create/agents/openai.yaml +6 -0
  5. package/.agents/skills/opendoc-create-template/SKILL.md +50 -0
  6. package/.agents/skills/opendoc-create-template/agents/openai.yaml +4 -0
  7. package/.agents/skills/opendoc-create-template/references/structured-reports.md +11 -0
  8. package/.agents/skills/opendoc-create-theme/SKILL.md +40 -0
  9. package/.agents/skills/opendoc-create-theme/agents/openai.yaml +4 -0
  10. package/.agents/skills/opendoc-current-document/SKILL.md +32 -0
  11. package/.agents/skills/opendoc-current-document/agents/openai.yaml +4 -0
  12. package/.agents/skills/opendoc-current-document/references/context-fields.md +20 -0
  13. package/.agents/skills/opendoc-review-document/SKILL.md +60 -0
  14. package/.agents/skills/opendoc-review-document/agents/openai.yaml +4 -0
  15. package/AGENTS.md +69 -0
  16. package/CONTRIBUTING.md +38 -0
  17. package/LICENSE +21 -0
  18. package/README.md +179 -0
  19. package/SECURITY.md +9 -0
  20. package/THIRD_PARTY.md +49 -0
  21. package/VALIDATION.md +99 -0
  22. package/bin/opendoc.mjs +6 -0
  23. package/dist/assets/Markdown-sNZyjJi7.js +29 -0
  24. package/dist/assets/OpenDocSerif-Regular-D3OXs9A9.ttf +0 -0
  25. package/dist/assets/OpenDocSerif-Semibold-CjL9oDRo.ttf +0 -0
  26. package/dist/assets/geist-latin-ext-wght-italic-XgKbg5n7.woff2 +0 -0
  27. package/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  28. package/dist/assets/geist-latin-wght-italic-dTnRTFFJ.woff2 +0 -0
  29. package/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  30. package/dist/assets/index-DdrZ6ozO.css +1 -0
  31. package/dist/assets/index-DgNBz7mL.js +39 -0
  32. package/dist/assets/pdf-B7Emtyld.js +54 -0
  33. package/dist/assets/pdf.worker.min-Dswkl-cV.mjs +29 -0
  34. package/dist/assets/wordmark-DsqLlZpb.png +0 -0
  35. package/dist/index.html +17 -0
  36. package/docs/APPEARANCE.md +21 -0
  37. package/docs/ASSETS.md +176 -0
  38. package/docs/AUTHORING.md +178 -0
  39. package/docs/HEADLESS.md +120 -0
  40. package/docs/MEDIA.md +112 -0
  41. package/docs/PROJECTS.md +55 -0
  42. package/docs/PROSE.md +15 -0
  43. package/docs/SELECTION.md +59 -0
  44. package/docs/TEMPLATES.md +55 -0
  45. package/docs/THEMES.md +106 -0
  46. package/node_modules/@formepdf/core/LICENSE +21 -0
  47. package/node_modules/@formepdf/core/README.md +53 -0
  48. package/node_modules/@formepdf/core/dist/attachments.d.ts +55 -0
  49. package/node_modules/@formepdf/core/dist/attachments.js +59 -0
  50. package/node_modules/@formepdf/core/dist/extract.d.ts +8 -0
  51. package/node_modules/@formepdf/core/dist/extract.js +56 -0
  52. package/node_modules/@formepdf/core/dist/index.d.ts +311 -0
  53. package/node_modules/@formepdf/core/dist/index.js +167 -0
  54. package/node_modules/@formepdf/core/dist/layout.d.ts +132 -0
  55. package/node_modules/@formepdf/core/dist/layout.js +240 -0
  56. package/node_modules/@formepdf/core/dist/shared/browserHelpers.d.ts +19 -0
  57. package/node_modules/@formepdf/core/dist/shared/browserHelpers.js +128 -0
  58. package/node_modules/@formepdf/core/package.json +35 -0
  59. package/node_modules/@formepdf/core/pkg-node/LICENSE +21 -0
  60. package/node_modules/@formepdf/core/pkg-node/README.md +84 -0
  61. package/node_modules/@formepdf/core/pkg-node/forme.d.ts +39 -0
  62. package/node_modules/@formepdf/core/pkg-node/forme.js +394 -0
  63. package/node_modules/@formepdf/core/pkg-node/forme_bg.wasm +0 -0
  64. package/node_modules/@formepdf/core/pkg-node/forme_bg.wasm.d.ts +21 -0
  65. package/node_modules/@formepdf/core/pkg-node/package.json +25 -0
  66. package/node_modules/@formepdf/react/README.md +70 -0
  67. package/node_modules/@formepdf/react/dist/charts.d.ts +72 -0
  68. package/node_modules/@formepdf/react/dist/charts.js +338 -0
  69. package/node_modules/@formepdf/react/dist/components.d.ts +533 -0
  70. package/node_modules/@formepdf/react/dist/components.js +608 -0
  71. package/node_modules/@formepdf/react/dist/expr.d.ts +20 -0
  72. package/node_modules/@formepdf/react/dist/expr.js +39 -0
  73. package/node_modules/@formepdf/react/dist/font.d.ts +2 -0
  74. package/node_modules/@formepdf/react/dist/font.js +1 -0
  75. package/node_modules/@formepdf/react/dist/index.d.ts +11 -0
  76. package/node_modules/@formepdf/react/dist/index.js +15 -0
  77. package/node_modules/@formepdf/react/dist/render.d.ts +12 -0
  78. package/node_modules/@formepdf/react/dist/render.js +15 -0
  79. package/node_modules/@formepdf/react/dist/serialize.d.ts +12 -0
  80. package/node_modules/@formepdf/react/dist/serialize.js +1470 -0
  81. package/node_modules/@formepdf/react/dist/stylesheet.d.ts +4 -0
  82. package/node_modules/@formepdf/react/dist/stylesheet.js +5 -0
  83. package/node_modules/@formepdf/react/dist/template-proxy.d.ts +38 -0
  84. package/node_modules/@formepdf/react/dist/template-proxy.js +100 -0
  85. package/node_modules/@formepdf/react/dist/types.d.ts +287 -0
  86. package/node_modules/@formepdf/react/dist/types.js +1 -0
  87. package/node_modules/@formepdf/react/package.json +41 -0
  88. package/node_modules/@formepdf/shared/README.md +7 -0
  89. package/node_modules/@formepdf/shared/dist/canvas.d.ts +6 -0
  90. package/node_modules/@formepdf/shared/dist/canvas.js +43 -0
  91. package/node_modules/@formepdf/shared/dist/charts.d.ts +100 -0
  92. package/node_modules/@formepdf/shared/dist/charts.js +98 -0
  93. package/node_modules/@formepdf/shared/dist/encode.d.ts +27 -0
  94. package/node_modules/@formepdf/shared/dist/encode.js +93 -0
  95. package/node_modules/@formepdf/shared/dist/font.d.ts +13 -0
  96. package/node_modules/@formepdf/shared/dist/font.js +52 -0
  97. package/node_modules/@formepdf/shared/dist/index.d.ts +10 -0
  98. package/node_modules/@formepdf/shared/dist/index.js +15 -0
  99. package/node_modules/@formepdf/shared/dist/parser.d.ts +30 -0
  100. package/node_modules/@formepdf/shared/dist/parser.js +756 -0
  101. package/node_modules/@formepdf/shared/dist/semantics.d.ts +15 -0
  102. package/node_modules/@formepdf/shared/dist/semantics.js +44 -0
  103. package/node_modules/@formepdf/shared/dist/style.d.ts +7 -0
  104. package/node_modules/@formepdf/shared/dist/style.js +1024 -0
  105. package/node_modules/@formepdf/shared/dist/types.d.ts +743 -0
  106. package/node_modules/@formepdf/shared/dist/types.js +2 -0
  107. package/node_modules/@formepdf/shared/package.json +35 -0
  108. package/node_modules/@types/node/LICENSE +21 -0
  109. package/node_modules/@types/node/README.md +15 -0
  110. package/node_modules/@types/node/assert/strict.d.ts +111 -0
  111. package/node_modules/@types/node/assert.d.ts +1078 -0
  112. package/node_modules/@types/node/async_hooks.d.ts +603 -0
  113. package/node_modules/@types/node/buffer.buffer.d.ts +472 -0
  114. package/node_modules/@types/node/buffer.d.ts +1934 -0
  115. package/node_modules/@types/node/child_process.d.ts +1476 -0
  116. package/node_modules/@types/node/cluster.d.ts +578 -0
  117. package/node_modules/@types/node/compatibility/disposable.d.ts +14 -0
  118. package/node_modules/@types/node/compatibility/index.d.ts +9 -0
  119. package/node_modules/@types/node/compatibility/indexable.d.ts +20 -0
  120. package/node_modules/@types/node/compatibility/iterators.d.ts +20 -0
  121. package/node_modules/@types/node/console.d.ts +452 -0
  122. package/node_modules/@types/node/constants.d.ts +21 -0
  123. package/node_modules/@types/node/crypto.d.ts +4545 -0
  124. package/node_modules/@types/node/dgram.d.ts +600 -0
  125. package/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
  126. package/node_modules/@types/node/dns/promises.d.ts +503 -0
  127. package/node_modules/@types/node/dns.d.ts +923 -0
  128. package/node_modules/@types/node/domain.d.ts +170 -0
  129. package/node_modules/@types/node/events.d.ts +976 -0
  130. package/node_modules/@types/node/fs/promises.d.ts +1306 -0
  131. package/node_modules/@types/node/fs.d.ts +4463 -0
  132. package/node_modules/@types/node/globals.d.ts +172 -0
  133. package/node_modules/@types/node/globals.typedarray.d.ts +38 -0
  134. package/node_modules/@types/node/http.d.ts +2097 -0
  135. package/node_modules/@types/node/http2.d.ts +2843 -0
  136. package/node_modules/@types/node/https.d.ts +579 -0
  137. package/node_modules/@types/node/index.d.ts +98 -0
  138. package/node_modules/@types/node/inspector.d.ts +253 -0
  139. package/node_modules/@types/node/inspector.generated.d.ts +4052 -0
  140. package/node_modules/@types/node/module.d.ts +891 -0
  141. package/node_modules/@types/node/net.d.ts +1076 -0
  142. package/node_modules/@types/node/os.d.ts +506 -0
  143. package/node_modules/@types/node/package.json +145 -0
  144. package/node_modules/@types/node/path.d.ts +200 -0
  145. package/node_modules/@types/node/perf_hooks.d.ts +968 -0
  146. package/node_modules/@types/node/process.d.ts +2084 -0
  147. package/node_modules/@types/node/punycode.d.ts +117 -0
  148. package/node_modules/@types/node/querystring.d.ts +152 -0
  149. package/node_modules/@types/node/readline/promises.d.ts +161 -0
  150. package/node_modules/@types/node/readline.d.ts +594 -0
  151. package/node_modules/@types/node/repl.d.ts +428 -0
  152. package/node_modules/@types/node/sea.d.ts +162 -0
  153. package/node_modules/@types/node/sqlite.d.ts +722 -0
  154. package/node_modules/@types/node/stream/consumers.d.ts +38 -0
  155. package/node_modules/@types/node/stream/promises.d.ts +90 -0
  156. package/node_modules/@types/node/stream/web.d.ts +573 -0
  157. package/node_modules/@types/node/stream.d.ts +1694 -0
  158. package/node_modules/@types/node/string_decoder.d.ts +67 -0
  159. package/node_modules/@types/node/test.d.ts +2265 -0
  160. package/node_modules/@types/node/timers/promises.d.ts +108 -0
  161. package/node_modules/@types/node/timers.d.ts +287 -0
  162. package/node_modules/@types/node/tls.d.ts +1319 -0
  163. package/node_modules/@types/node/trace_events.d.ts +197 -0
  164. package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +468 -0
  165. package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +34 -0
  166. package/node_modules/@types/node/ts5.6/index.d.ts +98 -0
  167. package/node_modules/@types/node/tty.d.ts +208 -0
  168. package/node_modules/@types/node/url.d.ts +984 -0
  169. package/node_modules/@types/node/util.d.ts +2606 -0
  170. package/node_modules/@types/node/v8.d.ts +920 -0
  171. package/node_modules/@types/node/vm.d.ts +1053 -0
  172. package/node_modules/@types/node/wasi.d.ts +181 -0
  173. package/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
  174. package/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  175. package/node_modules/@types/node/web-globals/events.d.ts +97 -0
  176. package/node_modules/@types/node/web-globals/fetch.d.ts +55 -0
  177. package/node_modules/@types/node/web-globals/navigator.d.ts +22 -0
  178. package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
  179. package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
  180. package/node_modules/@types/node/worker_threads.d.ts +819 -0
  181. package/node_modules/@types/node/zlib.d.ts +747 -0
  182. package/node_modules/@types/react/LICENSE +21 -0
  183. package/node_modules/@types/react/README.md +15 -0
  184. package/node_modules/@types/react/canary.d.ts +129 -0
  185. package/node_modules/@types/react/compiler-runtime.d.ts +4 -0
  186. package/node_modules/@types/react/experimental.d.ts +184 -0
  187. package/node_modules/@types/react/global.d.ts +166 -0
  188. package/node_modules/@types/react/index.d.ts +4378 -0
  189. package/node_modules/@types/react/jsx-dev-runtime.d.ts +33 -0
  190. package/node_modules/@types/react/jsx-runtime.d.ts +24 -0
  191. package/node_modules/@types/react/package.json +210 -0
  192. package/node_modules/@types/react/ts5.0/canary.d.ts +129 -0
  193. package/node_modules/@types/react/ts5.0/experimental.d.ts +184 -0
  194. package/node_modules/@types/react/ts5.0/global.d.ts +166 -0
  195. package/node_modules/@types/react/ts5.0/index.d.ts +4365 -0
  196. package/node_modules/@types/react/ts5.0/jsx-dev-runtime.d.ts +33 -0
  197. package/node_modules/@types/react/ts5.0/jsx-runtime.d.ts +24 -0
  198. package/node_modules/csstype/LICENSE +19 -0
  199. package/node_modules/csstype/README.md +291 -0
  200. package/node_modules/csstype/index.d.ts +22569 -0
  201. package/node_modules/csstype/index.js.flow +6863 -0
  202. package/node_modules/csstype/package.json +70 -0
  203. package/node_modules/entities/LICENSE +11 -0
  204. package/node_modules/entities/decode.d.ts +1 -0
  205. package/node_modules/entities/decode.js +3 -0
  206. package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts +19 -0
  207. package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts.map +1 -0
  208. package/node_modules/entities/dist/commonjs/decode-codepoint.js +77 -0
  209. package/node_modules/entities/dist/commonjs/decode-codepoint.js.map +1 -0
  210. package/node_modules/entities/dist/commonjs/decode.d.ts +209 -0
  211. package/node_modules/entities/dist/commonjs/decode.d.ts.map +1 -0
  212. package/node_modules/entities/dist/commonjs/decode.js +511 -0
  213. package/node_modules/entities/dist/commonjs/decode.js.map +1 -0
  214. package/node_modules/entities/dist/commonjs/encode.d.ts +22 -0
  215. package/node_modules/entities/dist/commonjs/encode.d.ts.map +1 -0
  216. package/node_modules/entities/dist/commonjs/encode.js +73 -0
  217. package/node_modules/entities/dist/commonjs/encode.js.map +1 -0
  218. package/node_modules/entities/dist/commonjs/escape.d.ts +43 -0
  219. package/node_modules/entities/dist/commonjs/escape.d.ts.map +1 -0
  220. package/node_modules/entities/dist/commonjs/escape.js +121 -0
  221. package/node_modules/entities/dist/commonjs/escape.js.map +1 -0
  222. package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts +2 -0
  223. package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts.map +1 -0
  224. package/node_modules/entities/dist/commonjs/generated/decode-data-html.js +10 -0
  225. package/node_modules/entities/dist/commonjs/generated/decode-data-html.js.map +1 -0
  226. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts +2 -0
  227. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts.map +1 -0
  228. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js +10 -0
  229. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js.map +1 -0
  230. package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts +8 -0
  231. package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts.map +1 -0
  232. package/node_modules/entities/dist/commonjs/generated/encode-html.js +13 -0
  233. package/node_modules/entities/dist/commonjs/generated/encode-html.js.map +1 -0
  234. package/node_modules/entities/dist/commonjs/index.d.ts +96 -0
  235. package/node_modules/entities/dist/commonjs/index.d.ts.map +1 -0
  236. package/node_modules/entities/dist/commonjs/index.js +131 -0
  237. package/node_modules/entities/dist/commonjs/index.js.map +1 -0
  238. package/node_modules/entities/dist/commonjs/package.json +3 -0
  239. package/node_modules/entities/dist/esm/decode-codepoint.d.ts +19 -0
  240. package/node_modules/entities/dist/esm/decode-codepoint.d.ts.map +1 -0
  241. package/node_modules/entities/dist/esm/decode-codepoint.js +72 -0
  242. package/node_modules/entities/dist/esm/decode-codepoint.js.map +1 -0
  243. package/node_modules/entities/dist/esm/decode.d.ts +209 -0
  244. package/node_modules/entities/dist/esm/decode.d.ts.map +1 -0
  245. package/node_modules/entities/dist/esm/decode.js +497 -0
  246. package/node_modules/entities/dist/esm/decode.js.map +1 -0
  247. package/node_modules/entities/dist/esm/encode.d.ts +22 -0
  248. package/node_modules/entities/dist/esm/encode.d.ts.map +1 -0
  249. package/node_modules/entities/dist/esm/encode.js +69 -0
  250. package/node_modules/entities/dist/esm/encode.js.map +1 -0
  251. package/node_modules/entities/dist/esm/escape.d.ts +43 -0
  252. package/node_modules/entities/dist/esm/escape.d.ts.map +1 -0
  253. package/node_modules/entities/dist/esm/escape.js +117 -0
  254. package/node_modules/entities/dist/esm/escape.js.map +1 -0
  255. package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts +2 -0
  256. package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts.map +1 -0
  257. package/node_modules/entities/dist/esm/generated/decode-data-html.js +7 -0
  258. package/node_modules/entities/dist/esm/generated/decode-data-html.js.map +1 -0
  259. package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts +2 -0
  260. package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts.map +1 -0
  261. package/node_modules/entities/dist/esm/generated/decode-data-xml.js +7 -0
  262. package/node_modules/entities/dist/esm/generated/decode-data-xml.js.map +1 -0
  263. package/node_modules/entities/dist/esm/generated/encode-html.d.ts +8 -0
  264. package/node_modules/entities/dist/esm/generated/encode-html.d.ts.map +1 -0
  265. package/node_modules/entities/dist/esm/generated/encode-html.js +10 -0
  266. package/node_modules/entities/dist/esm/generated/encode-html.js.map +1 -0
  267. package/node_modules/entities/dist/esm/index.d.ts +96 -0
  268. package/node_modules/entities/dist/esm/index.d.ts.map +1 -0
  269. package/node_modules/entities/dist/esm/index.js +107 -0
  270. package/node_modules/entities/dist/esm/index.js.map +1 -0
  271. package/node_modules/entities/dist/esm/package.json +3 -0
  272. package/node_modules/entities/escape.d.ts +1 -0
  273. package/node_modules/entities/escape.js +3 -0
  274. package/node_modules/entities/package.json +118 -0
  275. package/node_modules/entities/readme.md +122 -0
  276. package/node_modules/entities/src/decode-codepoint.ts +81 -0
  277. package/node_modules/entities/src/decode.spec.ts +320 -0
  278. package/node_modules/entities/src/decode.ts +620 -0
  279. package/node_modules/entities/src/encode.spec.ts +78 -0
  280. package/node_modules/entities/src/encode.ts +77 -0
  281. package/node_modules/entities/src/escape.spec.ts +14 -0
  282. package/node_modules/entities/src/escape.ts +148 -0
  283. package/node_modules/entities/src/generated/.eslintrc.json +10 -0
  284. package/node_modules/entities/src/generated/decode-data-html.ts +8 -0
  285. package/node_modules/entities/src/generated/decode-data-xml.ts +8 -0
  286. package/node_modules/entities/src/generated/encode-html.ts +17 -0
  287. package/node_modules/entities/src/index.spec.ts +125 -0
  288. package/node_modules/entities/src/index.ts +188 -0
  289. package/node_modules/parse5/LICENSE +19 -0
  290. package/node_modules/parse5/README.md +38 -0
  291. package/node_modules/parse5/dist/cjs/common/doctype.d.ts +4 -0
  292. package/node_modules/parse5/dist/cjs/common/doctype.js +118 -0
  293. package/node_modules/parse5/dist/cjs/common/error-codes.d.ts +67 -0
  294. package/node_modules/parse5/dist/cjs/common/error-codes.js +66 -0
  295. package/node_modules/parse5/dist/cjs/common/foreign-content.d.ts +9 -0
  296. package/node_modules/parse5/dist/cjs/common/foreign-content.js +237 -0
  297. package/node_modules/parse5/dist/cjs/common/html.d.ts +289 -0
  298. package/node_modules/parse5/dist/cjs/common/html.js +528 -0
  299. package/node_modules/parse5/dist/cjs/common/token.d.ts +84 -0
  300. package/node_modules/parse5/dist/cjs/common/token.js +24 -0
  301. package/node_modules/parse5/dist/cjs/common/unicode.d.ts +42 -0
  302. package/node_modules/parse5/dist/cjs/common/unicode.js +70 -0
  303. package/node_modules/parse5/dist/cjs/index.d.ts +71 -0
  304. package/node_modules/parse5/dist/cjs/index.js +54 -0
  305. package/node_modules/parse5/dist/cjs/package.json +1 -0
  306. package/node_modules/parse5/dist/cjs/parser/formatting-element-list.d.ts +36 -0
  307. package/node_modules/parse5/dist/cjs/parser/formatting-element-list.js +114 -0
  308. package/node_modules/parse5/dist/cjs/parser/index.d.ts +221 -0
  309. package/node_modules/parse5/dist/cjs/parser/index.js +3240 -0
  310. package/node_modules/parse5/dist/cjs/parser/open-element-stack.d.ts +53 -0
  311. package/node_modules/parse5/dist/cjs/parser/open-element-stack.js +328 -0
  312. package/node_modules/parse5/dist/cjs/serializer/index.d.ts +60 -0
  313. package/node_modules/parse5/dist/cjs/serializer/index.js +172 -0
  314. package/node_modules/parse5/dist/cjs/tokenizer/index.d.ts +247 -0
  315. package/node_modules/parse5/dist/cjs/tokenizer/index.js +2714 -0
  316. package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.d.ts +36 -0
  317. package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.js +200 -0
  318. package/node_modules/parse5/dist/cjs/tree-adapters/default.d.ts +84 -0
  319. package/node_modules/parse5/dist/cjs/tree-adapters/default.js +176 -0
  320. package/node_modules/parse5/dist/cjs/tree-adapters/interface.d.ts +255 -0
  321. package/node_modules/parse5/dist/cjs/tree-adapters/interface.js +2 -0
  322. package/node_modules/parse5/dist/common/doctype.d.ts +4 -0
  323. package/node_modules/parse5/dist/common/doctype.js +114 -0
  324. package/node_modules/parse5/dist/common/error-codes.d.ts +67 -0
  325. package/node_modules/parse5/dist/common/error-codes.js +63 -0
  326. package/node_modules/parse5/dist/common/foreign-content.d.ts +9 -0
  327. package/node_modules/parse5/dist/common/foreign-content.js +228 -0
  328. package/node_modules/parse5/dist/common/html.d.ts +289 -0
  329. package/node_modules/parse5/dist/common/html.js +523 -0
  330. package/node_modules/parse5/dist/common/token.d.ts +84 -0
  331. package/node_modules/parse5/dist/common/token.js +20 -0
  332. package/node_modules/parse5/dist/common/unicode.d.ts +42 -0
  333. package/node_modules/parse5/dist/common/unicode.js +62 -0
  334. package/node_modules/parse5/dist/index.d.ts +71 -0
  335. package/node_modules/parse5/dist/index.js +42 -0
  336. package/node_modules/parse5/dist/parser/formatting-element-list.d.ts +36 -0
  337. package/node_modules/parse5/dist/parser/formatting-element-list.js +110 -0
  338. package/node_modules/parse5/dist/parser/index.d.ts +221 -0
  339. package/node_modules/parse5/dist/parser/index.js +3245 -0
  340. package/node_modules/parse5/dist/parser/open-element-stack.d.ts +53 -0
  341. package/node_modules/parse5/dist/parser/open-element-stack.js +324 -0
  342. package/node_modules/parse5/dist/serializer/index.d.ts +60 -0
  343. package/node_modules/parse5/dist/serializer/index.js +168 -0
  344. package/node_modules/parse5/dist/tokenizer/index.d.ts +247 -0
  345. package/node_modules/parse5/dist/tokenizer/index.js +2710 -0
  346. package/node_modules/parse5/dist/tokenizer/preprocessor.d.ts +36 -0
  347. package/node_modules/parse5/dist/tokenizer/preprocessor.js +196 -0
  348. package/node_modules/parse5/dist/tree-adapters/default.d.ts +84 -0
  349. package/node_modules/parse5/dist/tree-adapters/default.js +173 -0
  350. package/node_modules/parse5/dist/tree-adapters/interface.d.ts +255 -0
  351. package/node_modules/parse5/dist/tree-adapters/interface.js +1 -0
  352. package/node_modules/parse5/package.json +50 -0
  353. package/node_modules/undici-types/LICENSE +21 -0
  354. package/node_modules/undici-types/README.md +6 -0
  355. package/node_modules/undici-types/agent.d.ts +31 -0
  356. package/node_modules/undici-types/api.d.ts +43 -0
  357. package/node_modules/undici-types/balanced-pool.d.ts +29 -0
  358. package/node_modules/undici-types/cache.d.ts +36 -0
  359. package/node_modules/undici-types/client.d.ts +108 -0
  360. package/node_modules/undici-types/connector.d.ts +34 -0
  361. package/node_modules/undici-types/content-type.d.ts +21 -0
  362. package/node_modules/undici-types/cookies.d.ts +28 -0
  363. package/node_modules/undici-types/diagnostics-channel.d.ts +66 -0
  364. package/node_modules/undici-types/dispatcher.d.ts +256 -0
  365. package/node_modules/undici-types/env-http-proxy-agent.d.ts +21 -0
  366. package/node_modules/undici-types/errors.d.ts +149 -0
  367. package/node_modules/undici-types/eventsource.d.ts +61 -0
  368. package/node_modules/undici-types/fetch.d.ts +209 -0
  369. package/node_modules/undici-types/file.d.ts +39 -0
  370. package/node_modules/undici-types/filereader.d.ts +54 -0
  371. package/node_modules/undici-types/formdata.d.ts +108 -0
  372. package/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  373. package/node_modules/undici-types/global-origin.d.ts +7 -0
  374. package/node_modules/undici-types/handlers.d.ts +15 -0
  375. package/node_modules/undici-types/header.d.ts +4 -0
  376. package/node_modules/undici-types/index.d.ts +71 -0
  377. package/node_modules/undici-types/interceptors.d.ts +17 -0
  378. package/node_modules/undici-types/mock-agent.d.ts +50 -0
  379. package/node_modules/undici-types/mock-client.d.ts +25 -0
  380. package/node_modules/undici-types/mock-errors.d.ts +12 -0
  381. package/node_modules/undici-types/mock-interceptor.d.ts +93 -0
  382. package/node_modules/undici-types/mock-pool.d.ts +25 -0
  383. package/node_modules/undici-types/package.json +55 -0
  384. package/node_modules/undici-types/patch.d.ts +33 -0
  385. package/node_modules/undici-types/pool-stats.d.ts +19 -0
  386. package/node_modules/undici-types/pool.d.ts +39 -0
  387. package/node_modules/undici-types/proxy-agent.d.ts +28 -0
  388. package/node_modules/undici-types/readable.d.ts +65 -0
  389. package/node_modules/undici-types/retry-agent.d.ts +8 -0
  390. package/node_modules/undici-types/retry-handler.d.ts +116 -0
  391. package/node_modules/undici-types/util.d.ts +18 -0
  392. package/node_modules/undici-types/webidl.d.ts +228 -0
  393. package/node_modules/undici-types/websocket.d.ts +150 -0
  394. package/package.json +80 -0
  395. package/scripts/rebuild-forme.mjs +61 -0
  396. package/src/app/AppearanceControl.tsx +44 -0
  397. package/src/app/AssetThemeDefaults.tsx +87 -0
  398. package/src/app/AssetsBrowser.tsx +273 -0
  399. package/src/app/CommentDock.tsx +108 -0
  400. package/src/app/CreateDocumentDialog.tsx +51 -0
  401. package/src/app/DocumentActions.tsx +69 -0
  402. package/src/app/DocumentCard.tsx +50 -0
  403. package/src/app/DocumentViewControl.tsx +31 -0
  404. package/src/app/DocumentsBrowser.tsx +70 -0
  405. package/src/app/ExportHistoryDialog.tsx +86 -0
  406. package/src/app/ExportMenu.tsx +127 -0
  407. package/src/app/GuideDialog.tsx +80 -0
  408. package/src/app/InspectionLayer.tsx +77 -0
  409. package/src/app/LogoUploadDialog.tsx +92 -0
  410. package/src/app/Markdown.tsx +34 -0
  411. package/src/app/MaterialsBrowser.tsx +149 -0
  412. package/src/app/PageNumberInput.tsx +56 -0
  413. package/src/app/Pdf.tsx +561 -0
  414. package/src/app/ProjectDialogs.tsx +100 -0
  415. package/src/app/Reader.tsx +769 -0
  416. package/src/app/SearchField.tsx +13 -0
  417. package/src/app/Sidebar.tsx +86 -0
  418. package/src/app/SkillIndex.tsx +30 -0
  419. package/src/app/TemplatesBrowser.tsx +149 -0
  420. package/src/app/ThemesBrowser.tsx +159 -0
  421. package/src/app/api.ts +47 -0
  422. package/src/app/appearance.ts +35 -0
  423. package/src/app/assets.css +139 -0
  424. package/src/app/catalogPreview.ts +20 -0
  425. package/src/app/colors.css +167 -0
  426. package/src/app/comment-dock.css +53 -0
  427. package/src/app/commentDrafts.ts +67 -0
  428. package/src/app/componentCorrection.ts +17 -0
  429. package/src/app/edit-workbench.css +87 -0
  430. package/src/app/editSession.ts +238 -0
  431. package/src/app/editorRecovery.ts +25 -0
  432. package/src/app/export-history.css +31 -0
  433. package/src/app/export.css +17 -0
  434. package/src/app/guideLinks.ts +21 -0
  435. package/src/app/guides.css +40 -0
  436. package/src/app/main.tsx +221 -0
  437. package/src/app/materials.css +53 -0
  438. package/src/app/pdfLoading.ts +12 -0
  439. package/src/app/pdfSelection.ts +112 -0
  440. package/src/app/projects.css +63 -0
  441. package/src/app/reader-toolbar.css +65 -0
  442. package/src/app/selection.css +150 -0
  443. package/src/app/sidebar.css +60 -0
  444. package/src/app/skills.css +7 -0
  445. package/src/app/style.css +1061 -0
  446. package/src/app/templates.css +49 -0
  447. package/src/app/themes.css +80 -0
  448. package/src/app/ui/Icon.tsx +92 -0
  449. package/src/app/ui/README.md +27 -0
  450. package/src/app/ui/fonts.css +36 -0
  451. package/src/app/ui/index.tsx +223 -0
  452. package/src/app/ui/ui.css +388 -0
  453. package/src/app/useReaderPreview.ts +19 -0
  454. package/src/app/useTextEditing.ts +155 -0
  455. package/src/assets/adapter.ts +122 -0
  456. package/src/assets/files.ts +378 -0
  457. package/src/assets/import-worker.ts +294 -0
  458. package/src/assets/imports.ts +124 -0
  459. package/src/assets/index.ts +60 -0
  460. package/src/assets/store.ts +798 -0
  461. package/src/assets/usage.ts +118 -0
  462. package/src/cli/check.ts +25 -0
  463. package/src/cli/init.ts +119 -0
  464. package/src/cli/lock.ts +34 -0
  465. package/src/cli/main.ts +118 -0
  466. package/src/cli/process.ts +19 -0
  467. package/src/cli/start.ts +96 -0
  468. package/src/cli/update.ts +348 -0
  469. package/src/cli/workspace.ts +94 -0
  470. package/src/document/index.tsx +641 -0
  471. package/src/document/page.tsx +53 -0
  472. package/src/document/text-targets.tsx +162 -0
  473. package/src/media/files.ts +124 -0
  474. package/src/media/render.ts +63 -0
  475. package/src/rendering/resolve-sources.ts +84 -0
  476. package/src/runtime/jsx-dev-runtime.ts +2 -0
  477. package/src/runtime/jsx-runtime.ts +2 -0
  478. package/src/runtime/paths.ts +12 -0
  479. package/src/server/assets-cli.ts +162 -0
  480. package/src/server/assets-http.ts +100 -0
  481. package/src/server/client.ts +50 -0
  482. package/src/server/clipboard.ts +22 -0
  483. package/src/server/comments-cli.ts +64 -0
  484. package/src/server/comments.ts +130 -0
  485. package/src/server/create-cli.ts +33 -0
  486. package/src/server/create.ts +228 -0
  487. package/src/server/dependencies.ts +91 -0
  488. package/src/server/documents.ts +143 -0
  489. package/src/server/edits.ts +249 -0
  490. package/src/server/export-batch.ts +105 -0
  491. package/src/server/export-errors.ts +2 -0
  492. package/src/server/export-file.ts +57 -0
  493. package/src/server/export-inputs.ts +66 -0
  494. package/src/server/export-preview.ts +69 -0
  495. package/src/server/export.ts +32 -0
  496. package/src/server/exports.ts +283 -0
  497. package/src/server/files.ts +21 -0
  498. package/src/server/guides.ts +71 -0
  499. package/src/server/index.ts +432 -0
  500. package/src/server/materials.ts +39 -0
  501. package/src/server/media-cli.ts +73 -0
  502. package/src/server/media-mutations.ts +168 -0
  503. package/src/server/pptx.ts +160 -0
  504. package/src/server/preflight.ts +129 -0
  505. package/src/server/projects-cli.ts +29 -0
  506. package/src/server/projects.ts +187 -0
  507. package/src/server/render-error.ts +9 -0
  508. package/src/server/render-source.ts +24 -0
  509. package/src/server/render.ts +48 -0
  510. package/src/server/review-cli.ts +40 -0
  511. package/src/server/review.ts +161 -0
  512. package/src/server/selection.ts +23 -0
  513. package/src/server/source-overrides.ts +97 -0
  514. package/src/server/templates-cli.ts +51 -0
  515. package/src/server/templates.ts +186 -0
  516. package/src/server/text-layout.ts +41 -0
  517. package/src/server/text-source.ts +307 -0
  518. package/src/server/themes-cli.ts +59 -0
  519. package/src/server/themes.ts +215 -0
  520. package/src/server/ttf2eot.d.ts +3 -0
  521. package/src/server/worker.ts +166 -0
  522. package/src/server/workspace.ts +242 -0
  523. package/src/shared/anchors.ts +69 -0
  524. package/src/shared/assets.ts +154 -0
  525. package/src/shared/export.ts +34 -0
  526. package/src/shared/media.ts +33 -0
  527. package/src/shared/projects.ts +19 -0
  528. package/src/shared/selection.ts +94 -0
  529. package/src/shared/skill-index.ts +14 -0
  530. package/src/shared/starters.ts +19 -0
  531. package/src/shared/templates.ts +18 -0
  532. package/src/shared/themes.ts +24 -0
  533. package/src/shared/types.ts +39 -0
  534. package/src/template/index.ts +27 -0
  535. package/src/themes/index.ts +3 -0
  536. package/src/themes/neutral.ts +20 -0
  537. package/src/themes/types.ts +110 -0
  538. package/starter/assets/brand/wordmark.png +0 -0
  539. package/starter/assets/fonts/InterUI-LICENSE.txt +93 -0
  540. package/starter/assets/fonts/InterUI-Medium.ttf +0 -0
  541. package/starter/assets/fonts/InterUI-Regular.ttf +0 -0
  542. package/starter/assets/fonts/InterUI-source.json +19 -0
  543. package/starter/assets/fonts/OpenDocMono-Regular.ttf +0 -0
  544. package/starter/assets/fonts/OpenDocSans-Italic.ttf +0 -0
  545. package/starter/assets/fonts/OpenDocSans-Regular.ttf +0 -0
  546. package/starter/assets/fonts/OpenDocSans-Semibold.ttf +0 -0
  547. package/starter/assets/fonts/OpenDocSans-SemiboldItalic.ttf +0 -0
  548. package/starter/assets/fonts/OpenDocSerif-Italic.ttf +0 -0
  549. package/starter/assets/fonts/OpenDocSerif-Regular.ttf +0 -0
  550. package/starter/assets/fonts/OpenDocSerif-Semibold.ttf +0 -0
  551. package/starter/assets/fonts/OpenDocSerif-SemiboldItalic.ttf +0 -0
  552. package/starter/assets/fonts/SourceCode-LICENSE.md +93 -0
  553. package/starter/assets/fonts/SourceSans-LICENSE.md +93 -0
  554. package/starter/assets/fonts/SourceSerif-LICENSE.md +93 -0
  555. package/starter/assets/fonts/geist/OFL.txt +93 -0
  556. package/starter/assets/fonts/geist/asset.json +7 -0
  557. package/starter/assets/fonts/geist/files/1a9874b3be0fc168692a3d2327bccb4d28835653d3b91537a755296a467a83e3.ttf +0 -0
  558. package/starter/assets/fonts/geist/files/a8eefb873ba9c9020665f8a98302697ce1f3b79ab2deef6ee508c0ca6a82e876.ttf +0 -0
  559. package/starter/assets/fonts/geist/files/ccce59465ae5c61930ada5453834f60500fbd95084d85db63e0e65fad0125455.ttf +0 -0
  560. package/starter/assets/fonts/geist/files/f5e95110d70593672515080bee9148463ada0a7f77b89ed65a3d43cb2b0ff83a.pdf +0 -0
  561. package/starter/assets/fonts/geist/revisions/9a2bc12fb2f23cb27bc227087e63e1407bb804ee0586480bd6b7966ec69fb474.json +60 -0
  562. package/starter/assets/fonts/inter/OFL.txt +93 -0
  563. package/starter/assets/fonts/inter/asset.json +7 -0
  564. package/starter/assets/fonts/inter/files/1b08e7fc267a5c7e1d614100f604b83e7e8a0be241f0f288faa2b3ac93a683ba.ttf +0 -0
  565. package/starter/assets/fonts/inter/files/5b6f0c6f26e5c554a64cdcc3a9b5d802b7f9aec6206f1dbcfcdcad7b5860a2a9.ttf +0 -0
  566. package/starter/assets/fonts/inter/files/957db8560d510a198a7d0333fae7b6b444b00c20801581126273978d778eb3c3.pdf +0 -0
  567. package/starter/assets/fonts/inter/files/b37284b5701b6b168dfc770aa1a4ac492106422fd3ba76bc7641e37434e8019c.ttf +0 -0
  568. package/starter/assets/fonts/inter/files/c1811d32ac0f6eed1bbf57529f2ecdfc6c717d48a969dd864942436315a1b198.ttf +0 -0
  569. package/starter/assets/fonts/inter/files/e7a1aaf7eda9f2fad4131725fa556265ec75ca7b2d756260173a040363e8d4f7.ttf +0 -0
  570. package/starter/assets/fonts/inter/files/ef8f755d933b9310804cc9152f1f18cb2ac460d6b05054ec913d889c9f11f79e.ttf +0 -0
  571. package/starter/assets/fonts/inter/revisions/600391517c413963b71e278a57c26c40366c81fa3939a6b9755f446206766d12.json +99 -0
  572. package/starter/assets/fonts/inter/source.json +57 -0
  573. package/starter/assets/fonts/lato/OFL.txt +93 -0
  574. package/starter/assets/fonts/lato/asset.json +7 -0
  575. package/starter/assets/fonts/lato/files/4a6b566dbb28adb473a8789ce5169306f42f0c8a070ac92bae93636f36348b0d.pdf +0 -0
  576. package/starter/assets/fonts/lato/files/5adeb6b334d8fb99ef053bc052b952773d544315e0e1d668a12c0ce8bd51375c.ttf +0 -0
  577. package/starter/assets/fonts/lato/files/62c1b7f0d2e74b45960154c3520efc337b553db0961bfdc950d5618334596cc8.ttf +0 -0
  578. package/starter/assets/fonts/lato/files/71b8b7decbe75a881ed267be539d402bd1e9420b799658aada4e0d1bd5af803c.ttf +0 -0
  579. package/starter/assets/fonts/lato/files/8a0aace75d33794eece4b28187bfc1df0bbd2888b5d8a56e01788c8d65d16be1.ttf +0 -0
  580. package/starter/assets/fonts/lato/files/d636e4683231f931eda222d588e944d082bfd3bdba02f928bee461c0f185b251.ttf +0 -0
  581. package/starter/assets/fonts/lato/files/e399c44efe1387100531d26c7e4800c5d12251b890d6654a3098c7c679cb1786.ttf +0 -0
  582. package/starter/assets/fonts/lato/revisions/49ccb93400a9d466fab7d9843b1ecf8916ec6d47a475dd79a597a22eb39616bc.json +99 -0
  583. package/starter/assets/fonts/lato/source.json +57 -0
  584. package/starter/assets/fonts/merriweather/OFL.txt +93 -0
  585. package/starter/assets/fonts/merriweather/asset.json +7 -0
  586. package/starter/assets/fonts/merriweather/files/1c54f91b910454251c4c2b7bd4e472e1abf265fba7ca3c0ef2eee2f41324099e.ttf +0 -0
  587. package/starter/assets/fonts/merriweather/files/8bde8da2bb7f0265e27ba0481f70bb48d0f98a976c145f2f239c648ddd6532e0.pdf +0 -0
  588. package/starter/assets/fonts/merriweather/files/90b7db4460fcd1a5ca49575c2668a793f3cd6447664d312a068d690e1c01e6bc.ttf +0 -0
  589. package/starter/assets/fonts/merriweather/files/afff81272b7653417bb6f8bef57add055b1f9fda36f27eba5f32b40752bd08da.ttf +0 -0
  590. package/starter/assets/fonts/merriweather/files/e029d3b71e5bae3877c73f4f2b15af28db16593d49b0aed2a328d37ff7075846.ttf +0 -0
  591. package/starter/assets/fonts/merriweather/files/e9864a6790bf712a04e20f3662b206a1535186ed3e877fd859dd5fb9682335df.ttf +0 -0
  592. package/starter/assets/fonts/merriweather/files/fa71baebdd20a7d0de2e5e445a5922530fe9e1d740efbe791f113b682d3cb093.ttf +0 -0
  593. package/starter/assets/fonts/merriweather/revisions/1888e390b3e4f38a3d7cd2dc1bb805aeb6ce13f986a97656f0265fd436bc91d2.json +99 -0
  594. package/starter/assets/fonts/merriweather/source.json +57 -0
  595. package/starter/assets/fonts/open-sans/OFL.txt +92 -0
  596. package/starter/assets/fonts/open-sans/asset.json +7 -0
  597. package/starter/assets/fonts/open-sans/files/1bc0594a83762b2c25d38915a34464b7fec6088298ca22d151757bf98d6700ec.ttf +0 -0
  598. package/starter/assets/fonts/open-sans/files/47ed1cfaa7ffca04a04ab850b2938fd52c09d1b44cfa3e2980878e166b0cbd87.ttf +0 -0
  599. package/starter/assets/fonts/open-sans/files/574939af301f07df8e21cfff279465c5981dd9d9cf62086f7515897df951c6f5.pdf +0 -0
  600. package/starter/assets/fonts/open-sans/files/6d3884d0d57c1b67e9c50c54eca7b69c535c114e76bd7a9cfda0258588185553.ttf +0 -0
  601. package/starter/assets/fonts/open-sans/files/733eb93b167e6d45de09aa768f6c0355647c2c26f5416dbc7407a08ed41e81c6.ttf +0 -0
  602. package/starter/assets/fonts/open-sans/files/75367e6da7d914eaed87883ba51b2a2b5816b5cdbb39f96ec5c81a5b032bfd5a.ttf +0 -0
  603. package/starter/assets/fonts/open-sans/files/ff4fdc11204e0edd14e9a0bb6c374b847a9093b0ec2c16702e03afca79ac4ef7.ttf +0 -0
  604. package/starter/assets/fonts/open-sans/revisions/bbbe3a4915b9bccbc883c0decb4097511c43b6bd09ae22a1516aff128c219bc5.json +99 -0
  605. package/starter/assets/fonts/open-sans/source.json +57 -0
  606. package/starter/assets/fonts/roboto/OFL.txt +93 -0
  607. package/starter/assets/fonts/roboto/asset.json +7 -0
  608. package/starter/assets/fonts/roboto/files/22d45d989248a624252b8382067ac56550212fa675dcdbaf12f03d297dd87a58.pdf +0 -0
  609. package/starter/assets/fonts/roboto/files/35757eaa996b3359022f47f164a67ee9eac04971af24c5b8fbd4b89e844ff190.ttf +0 -0
  610. package/starter/assets/fonts/roboto/files/4d3035883c531846bd1ce2dc89f36d932e72dc114f56062c7e3a9cdd74f3d3ea.ttf +0 -0
  611. package/starter/assets/fonts/roboto/files/be7639306a4fc4a02ce2ae2ff59eb1335e4db4a7379dd0a384ed7cc053817789.ttf +0 -0
  612. package/starter/assets/fonts/roboto/files/d2920cbb1b60a3fd11fbf22049286e43a6baf522d37fdf1e7c89562319bcfea5.ttf +0 -0
  613. package/starter/assets/fonts/roboto/files/dece7c71bbe61710787f0839c722c65e87355dd2eb4a823e6b5488121ff81e4b.ttf +0 -0
  614. package/starter/assets/fonts/roboto/files/f478ba88b0292e685e487901dfbb1401457d32d6ebee4030cdfd5698235bffa8.ttf +0 -0
  615. package/starter/assets/fonts/roboto/revisions/bda5e2d84c17313373dd2dbf3e64fe0dd450c7e1b59e6929e69557e122fe976e.json +99 -0
  616. package/starter/assets/fonts/roboto/source.json +57 -0
  617. package/starter/assets/logos/opendoc/asset.json +6 -0
  618. package/starter/assets/logos/opendoc/files/831d5ccd9eb6709cc8439ea257c03d81452e81a28a3d1eedbd6a3b7daff687b6.png +0 -0
  619. package/starter/assets/logos/opendoc/revisions/834dde8926ddb81de687254195a168bb13bfb77803307f1257de1f2228be63b2.json +33 -0
  620. package/starter/assets/ui-fonts/geist/OFL.txt +93 -0
  621. package/starter/assets/ui-fonts/geist/geist-latin-ext-wght-italic.woff2 +0 -0
  622. package/starter/assets/ui-fonts/geist/geist-latin-ext-wght-normal.woff2 +0 -0
  623. package/starter/assets/ui-fonts/geist/geist-latin-wght-italic.woff2 +0 -0
  624. package/starter/assets/ui-fonts/geist/geist-latin-wght-normal.woff2 +0 -0
  625. package/starter/assets/ui-fonts/geist/source.json +26 -0
  626. package/starter/documents/welcome/assets.json +7 -0
  627. package/starter/documents/welcome/index.tsx +160 -0
  628. package/starter/documents/welcome/media/.gitkeep +0 -0
  629. package/starter/documents/welcome/media/paper-architecture/image.png +0 -0
  630. package/starter/documents/welcome/media/paper-architecture/meta.json +9 -0
  631. package/starter/documents/welcome/media/paper-architecture/prompt.txt +1 -0
  632. package/starter/documents/welcome/media/studio-rhythm/chart.svg +2343 -0
  633. package/starter/documents/welcome/media/studio-rhythm/data.json +234 -0
  634. package/starter/documents/welcome/media/studio-rhythm/generation.json +9 -0
  635. package/starter/documents/welcome/media/studio-rhythm/image.png +0 -0
  636. package/starter/documents/welcome/media/studio-rhythm/meta.json +11 -0
  637. package/starter/documents/welcome/media/studio-rhythm/recipe.py +79 -0
  638. package/starter/documents/welcome/theme.tsx +5 -0
  639. package/starter/documents/welcome-presentation/assets.json +7 -0
  640. package/starter/documents/welcome-presentation/index.tsx +166 -0
  641. package/starter/documents/welcome-presentation/media/.gitkeep +0 -0
  642. package/starter/documents/welcome-presentation/media/paper-architecture/image.png +0 -0
  643. package/starter/documents/welcome-presentation/media/paper-architecture/meta.json +9 -0
  644. package/starter/documents/welcome-presentation/media/paper-architecture/prompt.txt +1 -0
  645. package/starter/documents/welcome-presentation/media/studio-rhythm/chart.svg +1336 -0
  646. package/starter/documents/welcome-presentation/media/studio-rhythm/data.json +234 -0
  647. package/starter/documents/welcome-presentation/media/studio-rhythm/generation.json +9 -0
  648. package/starter/documents/welcome-presentation/media/studio-rhythm/image.png +0 -0
  649. package/starter/documents/welcome-presentation/media/studio-rhythm/meta.json +13 -0
  650. package/starter/documents/welcome-presentation/media/studio-rhythm/recipe.py +49 -0
  651. package/starter/documents/welcome-presentation/theme.tsx +5 -0
  652. package/starter/projects.json +17 -0
  653. package/starter/templates/AGENTS.md +9 -0
  654. package/starter/templates/_shared/BusinessLogo.tsx +14 -0
  655. package/starter/templates/_shared/Pricing.tsx +40 -0
  656. package/starter/templates/_shared/commerce.ts +93 -0
  657. package/starter/templates/brand-guidelines/AGENTS.md +32 -0
  658. package/starter/templates/brand-guidelines/index.tsx +62 -0
  659. package/starter/templates/brand-guidelines/preview.tsx +181 -0
  660. package/starter/templates/brand-guidelines/starter.tsx +179 -0
  661. package/starter/templates/brand-guidelines/template.json +15 -0
  662. package/starter/templates/business-proposal/AGENTS.md +13 -0
  663. package/starter/templates/business-proposal/README.md +36 -0
  664. package/starter/templates/business-proposal/data.json +37 -0
  665. package/starter/templates/business-proposal/examples/long.json +142 -0
  666. package/starter/templates/business-proposal/examples/sparse.json +17 -0
  667. package/starter/templates/business-proposal/examples/typical.json +37 -0
  668. package/starter/templates/business-proposal/index.tsx +59 -0
  669. package/starter/templates/business-proposal/preview.tsx +47 -0
  670. package/starter/templates/business-proposal/schema.ts +14 -0
  671. package/starter/templates/business-proposal/starter.tsx +18 -0
  672. package/starter/templates/business-proposal/template.json +11 -0
  673. package/starter/templates/company-profile/AGENTS.md +48 -0
  674. package/starter/templates/company-profile/index.tsx +69 -0
  675. package/starter/templates/company-profile/preview.tsx +185 -0
  676. package/starter/templates/company-profile/starter.tsx +186 -0
  677. package/starter/templates/company-profile/template.json +15 -0
  678. package/starter/templates/consulting-report/AGENTS.md +11 -0
  679. package/starter/templates/consulting-report/README.md +13 -0
  680. package/starter/templates/consulting-report/RESEARCH.md +10 -0
  681. package/starter/templates/consulting-report/index.tsx +44 -0
  682. package/starter/templates/consulting-report/preview.tsx +39 -0
  683. package/starter/templates/consulting-report/starter.tsx +15 -0
  684. package/starter/templates/consulting-report/template.json +11 -0
  685. package/starter/templates/editorial-essay/AGENTS.md +11 -0
  686. package/starter/templates/editorial-essay/README.md +11 -0
  687. package/starter/templates/editorial-essay/index.tsx +30 -0
  688. package/starter/templates/editorial-essay/preview.tsx +26 -0
  689. package/starter/templates/editorial-essay/starter.tsx +15 -0
  690. package/starter/templates/editorial-essay/template.json +11 -0
  691. package/starter/templates/executive-brief/AGENTS.md +9 -0
  692. package/starter/templates/executive-brief/README.md +11 -0
  693. package/starter/templates/executive-brief/index.tsx +33 -0
  694. package/starter/templates/executive-brief/preview.tsx +37 -0
  695. package/starter/templates/executive-brief/starter.tsx +11 -0
  696. package/starter/templates/executive-brief/template.json +11 -0
  697. package/starter/templates/image-story/AGENTS.md +37 -0
  698. package/starter/templates/image-story/index.tsx +106 -0
  699. package/starter/templates/image-story/preview.tsx +33 -0
  700. package/starter/templates/image-story/starter.tsx +24 -0
  701. package/starter/templates/image-story/template.json +13 -0
  702. package/starter/templates/invoice/AGENTS.md +13 -0
  703. package/starter/templates/invoice/README.md +40 -0
  704. package/starter/templates/invoice/data.json +61 -0
  705. package/starter/templates/invoice/examples/long.json +241 -0
  706. package/starter/templates/invoice/examples/sparse.json +33 -0
  707. package/starter/templates/invoice/examples/typical.json +61 -0
  708. package/starter/templates/invoice/index.tsx +57 -0
  709. package/starter/templates/invoice/preview.tsx +12 -0
  710. package/starter/templates/invoice/schema.ts +45 -0
  711. package/starter/templates/invoice/starter.tsx +12 -0
  712. package/starter/templates/invoice/template.json +11 -0
  713. package/starter/templates/literary-text/AGENTS.md +9 -0
  714. package/starter/templates/literary-text/README.md +11 -0
  715. package/starter/templates/literary-text/index.tsx +31 -0
  716. package/starter/templates/literary-text/preview.tsx +20 -0
  717. package/starter/templates/literary-text/starter.tsx +11 -0
  718. package/starter/templates/literary-text/template.json +11 -0
  719. package/starter/templates/magazine-feature/AGENTS.md +11 -0
  720. package/starter/templates/magazine-feature/README.md +13 -0
  721. package/starter/templates/magazine-feature/index.tsx +41 -0
  722. package/starter/templates/magazine-feature/preview.tsx +34 -0
  723. package/starter/templates/magazine-feature/starter.tsx +15 -0
  724. package/starter/templates/magazine-feature/template.json +11 -0
  725. package/starter/templates/monthly-report/AGENTS.md +11 -0
  726. package/starter/templates/monthly-report/README.md +24 -0
  727. package/starter/templates/monthly-report/data.json +131 -0
  728. package/starter/templates/monthly-report/examples/long.json +519 -0
  729. package/starter/templates/monthly-report/examples/sparse.json +20 -0
  730. package/starter/templates/monthly-report/examples/typical.json +37 -0
  731. package/starter/templates/monthly-report/index.tsx +92 -0
  732. package/starter/templates/monthly-report/preview.tsx +14 -0
  733. package/starter/templates/monthly-report/schema.ts +127 -0
  734. package/starter/templates/monthly-report/starter.tsx +13 -0
  735. package/starter/templates/monthly-report/template.json +11 -0
  736. package/starter/templates/pitch-deck/AGENTS.md +32 -0
  737. package/starter/templates/pitch-deck/index.tsx +46 -0
  738. package/starter/templates/pitch-deck/preview.tsx +142 -0
  739. package/starter/templates/pitch-deck/starter.tsx +140 -0
  740. package/starter/templates/pitch-deck/template.json +15 -0
  741. package/starter/templates/proposal-deck/AGENTS.md +25 -0
  742. package/starter/templates/proposal-deck/index.tsx +52 -0
  743. package/starter/templates/proposal-deck/preview.tsx +172 -0
  744. package/starter/templates/proposal-deck/starter.tsx +168 -0
  745. package/starter/templates/proposal-deck/template.json +7 -0
  746. package/starter/templates/quotation/AGENTS.md +13 -0
  747. package/starter/templates/quotation/README.md +42 -0
  748. package/starter/templates/quotation/data.json +64 -0
  749. package/starter/templates/quotation/examples/long.json +272 -0
  750. package/starter/templates/quotation/examples/sparse.json +31 -0
  751. package/starter/templates/quotation/examples/typical.json +64 -0
  752. package/starter/templates/quotation/index.tsx +51 -0
  753. package/starter/templates/quotation/preview.tsx +12 -0
  754. package/starter/templates/quotation/schema.ts +27 -0
  755. package/starter/templates/quotation/starter.tsx +12 -0
  756. package/starter/templates/quotation/template.json +11 -0
  757. package/starter/templates/scientific-paper/AGENTS.md +11 -0
  758. package/starter/templates/scientific-paper/README.md +13 -0
  759. package/starter/templates/scientific-paper/index.tsx +47 -0
  760. package/starter/templates/scientific-paper/preview.tsx +43 -0
  761. package/starter/templates/scientific-paper/starter.tsx +15 -0
  762. package/starter/templates/scientific-paper/template.json +11 -0
  763. package/starter/themes/Specimen.tsx +54 -0
  764. package/starter/themes/civic-spectrum/components.tsx +92 -0
  765. package/starter/themes/civic-spectrum/design.md +70 -0
  766. package/starter/themes/civic-spectrum/index.ts +57 -0
  767. package/starter/themes/civic-spectrum/preview.tsx +66 -0
  768. package/starter/themes/field-manual/components.tsx +106 -0
  769. package/starter/themes/field-manual/design.md +72 -0
  770. package/starter/themes/field-manual/index.ts +57 -0
  771. package/starter/themes/field-manual/preview.tsx +82 -0
  772. package/starter/themes/index.ts +3 -0
  773. package/starter/themes/mckinsey-consulting/components.tsx +69 -0
  774. package/starter/themes/mckinsey-consulting/design.md +68 -0
  775. package/starter/themes/mckinsey-consulting/index.ts +60 -0
  776. package/starter/themes/mckinsey-consulting/preview.tsx +53 -0
  777. package/starter/themes/neutral/design.md +35 -0
  778. package/starter/themes/neutral/index.ts +21 -0
  779. package/starter/themes/neutral/preview.tsx +4 -0
  780. package/starter/themes/opendoc-neutral/components.tsx +77 -0
  781. package/starter/themes/opendoc-neutral/design.md +70 -0
  782. package/starter/themes/opendoc-neutral/index.ts +54 -0
  783. package/starter/themes/opendoc-neutral/preview.tsx +43 -0
  784. package/starter/themes/types.ts +3 -0
  785. package/tsconfig.workspace.json +24 -0
  786. package/vendor/formepdf/LICENSE +21 -0
  787. package/vendor/formepdf/README.md +97 -0
  788. package/vendor/formepdf/font-subset.patch +228 -0
  789. package/vendor/formepdf/text-writer.patch +507 -0
@@ -0,0 +1,378 @@
1
+ import { readFileSync, lstatSync, realpathSync, statSync } from 'node:fs';
2
+ import { resolve, relative, sep } from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import type {
5
+ AssetKind,
6
+ AssetFile,
7
+ AssetHead,
8
+ AssetRevision,
9
+ DocumentAssets,
10
+ ThemeAssetDefaults,
11
+ AssetRef,
12
+ LogoBinding,
13
+ } from '../shared/assets';
14
+ import { fontCanBeDefault } from '../shared/assets';
15
+ export class AssetError extends Error {
16
+ constructor(
17
+ message: string,
18
+ public status = 400,
19
+ ) {
20
+ super(message);
21
+ }
22
+ }
23
+ export const validAssetId = (id: unknown): id is string =>
24
+ typeof id === 'string' && id.length <= 80 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(id);
25
+ export const validRevision = (id: unknown): id is string => typeof id === 'string' && /^[a-f0-9]{64}$/.test(id);
26
+ export const assetHash = (bytes: Uint8Array | string) => createHash('sha256').update(bytes).digest('hex');
27
+ export function assertAssetId(id: unknown): asserts id is string {
28
+ if (!validAssetId(id)) throw new AssetError('Use a short lowercase asset ID with single hyphens.');
29
+ }
30
+ export function assertKind(kind: unknown): asserts kind is AssetKind {
31
+ if (kind !== 'logo' && kind !== 'font') throw new AssetError('Choose a logo or font asset.');
32
+ }
33
+ export function assetDirectory(root: string, kind: AssetKind, id: string) {
34
+ assertKind(kind);
35
+ assertAssetId(id);
36
+ return resolve(root, 'assets', kind === 'logo' ? 'logos' : 'fonts', id);
37
+ }
38
+ export function assetRevisionPath(root: string, kind: AssetKind, id: string, revision: string) {
39
+ if (!validRevision(revision)) throw new AssetError('Choose a valid saved asset version.');
40
+ return resolve(assetDirectory(root, kind, id), 'revisions', `${revision}.json`);
41
+ }
42
+ export function safeAssetPath(root: string, file: string, directory = false) {
43
+ const base = realpathSync(root),
44
+ rel = relative(root, file);
45
+ if (!rel || rel === '..' || rel.startsWith(`..${sep}`) || resolve(root, rel) !== file)
46
+ throw new AssetError('Asset files must stay inside this workspace.');
47
+ let cursor = base;
48
+ for (const part of rel.split(sep)) {
49
+ cursor = resolve(cursor, part);
50
+ const info = lstatSync(cursor);
51
+ if (info.isSymbolicLink()) throw new AssetError('Asset files must be ordinary local files, not symbolic links.');
52
+ }
53
+ const info = lstatSync(cursor);
54
+ if (directory ? !info.isDirectory() : !info.isFile()) throw new AssetError('Expected an ordinary local asset file.');
55
+ return cursor;
56
+ }
57
+ function json(root: string, file: string, limit = 256000): any {
58
+ const path = safeAssetPath(root, file);
59
+ if (statSync(path).size > limit) throw new AssetError('Asset metadata is too large.');
60
+ try {
61
+ return JSON.parse(readFileSync(path, 'utf8'));
62
+ } catch {
63
+ throw new AssetError(`Cannot read asset metadata: ${relative(root, file)}.`);
64
+ }
65
+ }
66
+ function text(value: unknown, label: string, maximum = 4000, empty = false): asserts value is string {
67
+ if (typeof value !== 'string' || value.length > maximum || (!empty && !value.trim()))
68
+ throw new AssetError(`${label} must be ${empty ? '' : 'nonempty '}text, up to ${maximum} characters.`);
69
+ }
70
+ export function readAssetHead(root: string, kind: AssetKind, id: string): AssetHead {
71
+ const value = json(root, resolve(assetDirectory(root, kind, id), 'asset.json'));
72
+ if (
73
+ !value ||
74
+ typeof value !== 'object' ||
75
+ Array.isArray(value) ||
76
+ value.version !== 1 ||
77
+ value.id !== id ||
78
+ value.kind !== kind ||
79
+ !validRevision(value.revision) ||
80
+ (value.archived !== undefined && typeof value.archived !== 'boolean') ||
81
+ (value.builtIn !== undefined && typeof value.builtIn !== 'boolean')
82
+ )
83
+ throw new AssetError(`Asset ${id} has invalid library metadata.`);
84
+ if (value.archivedDefaults !== undefined) {
85
+ if (!Array.isArray(value.archivedDefaults) || value.archivedDefaults.length > 512)
86
+ throw new AssetError('The archived theme defaults are invalid.');
87
+ const themes = new Set<string>();
88
+ for (const saved of value.archivedDefaults) {
89
+ if (!saved || !validAssetId(saved.id) || themes.has(saved.id) || !validRevision(saved.cleared))
90
+ throw new AssetError('The archived theme defaults are invalid.');
91
+ themes.add(saved.id);
92
+ parseThemeAssetDefaults(saved.defaults);
93
+ }
94
+ }
95
+ return value;
96
+ }
97
+ function validateFile(file: AssetFile) {
98
+ if (
99
+ !file ||
100
+ !validRevision(file.hash) ||
101
+ !/^files\/[a-f0-9]{64}\.(png|svg|ttf|otf|pdf)$/.test(file.file) ||
102
+ !file.file.startsWith(`files/${file.hash}.`) ||
103
+ !Number.isSafeInteger(file.bytes) ||
104
+ file.bytes < 1 ||
105
+ typeof file.mime !== 'string'
106
+ )
107
+ throw new AssetError('An asset file record is invalid.');
108
+ }
109
+ const inspectedVersions = new Map<
110
+ string,
111
+ {
112
+ stamp: string;
113
+ value: AssetRevision;
114
+ }
115
+ >();
116
+ export function readAssetRevision(root: string, kind: AssetKind, id: string, revision: string): AssetRevision {
117
+ const manifest = assetRevisionPath(root, kind, id, revision);
118
+ let stamp: string;
119
+ try {
120
+ const info = statSync(safeAssetPath(root, manifest), { bigint: true });
121
+ stamp = `${info.ino}:${info.size}:${info.mtimeNs}:${info.ctimeNs}`;
122
+ } catch (error) {
123
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT')
124
+ throw new AssetError(
125
+ `The saved version of ${id} is missing. Restore its version manifest or rebind the document to an available version.`,
126
+ 404,
127
+ );
128
+ throw error;
129
+ }
130
+ const cached = inspectedVersions.get(manifest);
131
+ if (cached?.stamp === stamp) return structuredClone(cached.value);
132
+ let value: AssetRevision;
133
+ try {
134
+ value = json(root, assetRevisionPath(root, kind, id, revision)) as AssetRevision;
135
+ } catch (error) {
136
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT')
137
+ throw new AssetError(
138
+ `The saved version of ${id} is missing. Restore its version manifest or rebind the document to an available version.`,
139
+ 404,
140
+ );
141
+ throw error;
142
+ }
143
+ if (
144
+ !value ||
145
+ value.version !== 1 ||
146
+ value.id !== id ||
147
+ value.kind !== kind ||
148
+ value.revision !== revision ||
149
+ !Number.isFinite(Date.parse(value.createdAt))
150
+ )
151
+ throw new AssetError(`Asset ${id} has invalid saved version metadata.`);
152
+ const { revision: _, ...contents } = value;
153
+ if (assetHash(JSON.stringify(contents)) !== revision)
154
+ throw new AssetError(
155
+ `Saved version of ${id} was changed outside OpenDoc. Restore the original version or import a new copy.`,
156
+ 409,
157
+ );
158
+ text(value.name, 'Asset name', 200);
159
+ text(value.description, 'Asset guidance', 4000, true);
160
+ const seen = new Set<string>();
161
+ if (value.kind === 'logo') {
162
+ if (!Array.isArray(value.variations) || !value.variations.length || value.variations.length > 64)
163
+ throw new AssetError('A logo needs between one and 64 variations.');
164
+ for (const variant of value.variations) {
165
+ assertAssetId(variant.id);
166
+ if (seen.has(variant.id)) throw new AssetError('Variation IDs must be unique.');
167
+ seen.add(variant.id);
168
+ text(variant.name, 'Variation name', 200);
169
+ text(variant.description, 'Variation guidance', 4000, true);
170
+ validateFile(variant.image);
171
+ validateFile(variant.original);
172
+ }
173
+ if (!seen.has(value.defaultVariation)) throw new AssetError('Choose an existing default logo variation.');
174
+ } else {
175
+ if (
176
+ !Array.isArray(value.faces) ||
177
+ !value.faces.length ||
178
+ value.faces.length > 24 ||
179
+ !value.compatibility ||
180
+ !['ready', 'needs-attention'].includes(value.compatibility.status) ||
181
+ typeof value.compatibility.defaultEligible !== 'boolean'
182
+ )
183
+ throw new AssetError('The font family metadata is invalid.');
184
+ for (const face of value.faces) {
185
+ assertAssetId(face.id);
186
+ if (seen.has(face.id)) throw new AssetError('Font face IDs must be unique.');
187
+ seen.add(face.id);
188
+ validateFile(face.file);
189
+ text(face.family, 'Font family', 200);
190
+ if (
191
+ !Number.isInteger(face.weight) ||
192
+ face.weight < 1 ||
193
+ face.weight > 1000 ||
194
+ !['normal', 'italic'].includes(face.style)
195
+ )
196
+ throw new AssetError('The font face needs a valid weight and style.');
197
+ }
198
+ if (value.specimen) validateFile(value.specimen);
199
+ }
200
+ if (inspectedVersions.size >= 256) inspectedVersions.delete(inspectedVersions.keys().next().value!);
201
+ inspectedVersions.set(manifest, { stamp, value: structuredClone(value) });
202
+ return value;
203
+ }
204
+ const verified = new Map<
205
+ string,
206
+ {
207
+ stamp: string;
208
+ hash: string;
209
+ }
210
+ >();
211
+ export function assetFile(root: string, kind: AssetKind, id: string, file: AssetFile) {
212
+ validateFile(file);
213
+ let path: string;
214
+ try {
215
+ path = safeAssetPath(root, resolve(assetDirectory(root, kind, id), file.file));
216
+ } catch (error) {
217
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT')
218
+ throw new AssetError(
219
+ `A saved file for ${id} is missing. Restore that file or rebind the document to an available version.`,
220
+ 404,
221
+ );
222
+ throw error;
223
+ }
224
+ const info = statSync(path, { bigint: true });
225
+ const stamp = `${info.ino}:${info.size}:${info.mtimeNs}:${info.ctimeNs}`;
226
+ let hash = verified.get(path)?.stamp === stamp ? verified.get(path)!.hash : undefined;
227
+ if (!hash) {
228
+ hash = assetHash(readFileSync(path));
229
+ if (verified.size >= 256) verified.delete(verified.keys().next().value!);
230
+ verified.set(path, { stamp, hash });
231
+ }
232
+ if (hash !== file.hash || info.size !== BigInt(file.bytes))
233
+ throw new AssetError(
234
+ `A saved file for ${id} was changed outside OpenDoc. Restore that file or import a new version.`,
235
+ 409,
236
+ );
237
+ return path;
238
+ }
239
+ export function revisionFiles(value: AssetRevision): AssetFile[] {
240
+ return value.kind === 'logo'
241
+ ? value.variations.flatMap((v) => [v.original, v.image])
242
+ : [...value.faces.map((f) => f.file), ...(value.specimen ? [value.specimen] : [])];
243
+ }
244
+ function ref(value: unknown, logo = false): asserts value is AssetRef | LogoBinding {
245
+ const v = value as LogoBinding;
246
+ if (
247
+ !v ||
248
+ typeof v !== 'object' ||
249
+ Array.isArray(v) ||
250
+ !validAssetId(v.id) ||
251
+ !validRevision(v.revision) ||
252
+ Object.keys(v).some((key) => !['id', 'revision', ...(logo ? ['variation'] : [])].includes(key)) ||
253
+ (v.variation !== undefined && !validAssetId(v.variation))
254
+ )
255
+ throw new AssetError('Document asset choices must identify an exact saved version.');
256
+ }
257
+ export function parseDocumentAssets(value: unknown): DocumentAssets {
258
+ const v = value as DocumentAssets;
259
+ if (
260
+ !v ||
261
+ typeof v !== 'object' ||
262
+ Array.isArray(v) ||
263
+ v.version !== 1 ||
264
+ Object.keys(v).some((key) => !['version', 'logo', 'logos', 'bodyFont', 'headingFont'].includes(key))
265
+ )
266
+ throw new AssetError('Document assets must be a version 1 binding record.');
267
+ if (v.logo !== undefined) ref(v.logo, true);
268
+ if (v.bodyFont !== undefined) ref(v.bodyFont);
269
+ if (v.headingFont !== undefined) ref(v.headingFont);
270
+ if (v.logos !== undefined) {
271
+ if (!v.logos || typeof v.logos !== 'object' || Array.isArray(v.logos) || Object.keys(v.logos).length > 64)
272
+ throw new AssetError('Named logos must be a map of saved logo choices.');
273
+ for (const [name, item] of Object.entries(v.logos)) {
274
+ assertAssetId(name);
275
+ ref(item, true);
276
+ }
277
+ }
278
+ return v;
279
+ }
280
+ export function parseThemeAssetDefaults(value: unknown): ThemeAssetDefaults {
281
+ const v = value as ThemeAssetDefaults;
282
+ if (
283
+ !v ||
284
+ typeof v !== 'object' ||
285
+ Array.isArray(v) ||
286
+ v.version !== 1 ||
287
+ Object.keys(v).some((key) => !['version', 'logo', 'bodyFont', 'headingFont'].includes(key))
288
+ )
289
+ throw new AssetError('Theme assets must be a version 1 defaults record.');
290
+ if (v.logo !== undefined) {
291
+ if (
292
+ !v.logo ||
293
+ typeof v.logo !== 'object' ||
294
+ Array.isArray(v.logo) ||
295
+ Object.keys(v.logo).some((key) => !['id', 'variation'].includes(key))
296
+ )
297
+ throw new AssetError('Choose a logo asset.');
298
+ assertAssetId(v.logo.id);
299
+ if (v.logo.variation !== undefined) assertAssetId(v.logo.variation);
300
+ }
301
+ if (v.bodyFont !== undefined) assertAssetId(v.bodyFont);
302
+ if (v.headingFont !== undefined) assertAssetId(v.headingFont);
303
+ return v;
304
+ }
305
+ export function readDocumentAssetsAt(root: string, directory: string): DocumentAssets {
306
+ try {
307
+ return parseDocumentAssets(json(root, resolve(directory, 'assets.json')));
308
+ } catch (error) {
309
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { version: 1 };
310
+ throw error;
311
+ }
312
+ }
313
+ export function readDocumentAssets(root: string, id: string) {
314
+ assertAssetId(id);
315
+ return readDocumentAssetsAt(root, resolve(root, 'documents', id));
316
+ }
317
+ export function readThemeAssetDefaults(root: string, id: string): ThemeAssetDefaults {
318
+ assertAssetId(id);
319
+ try {
320
+ return parseThemeAssetDefaults(json(root, resolve(root, 'themes', id, 'assets.json')));
321
+ } catch (error) {
322
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { version: 1 };
323
+ throw error;
324
+ }
325
+ }
326
+ export function resolveThemeAssetDefaults(root: string, value: ThemeAssetDefaults): DocumentAssets {
327
+ const defaults = parseThemeAssetDefaults(value),
328
+ out: DocumentAssets = { version: 1 };
329
+ function current(kind: AssetKind, id: string) {
330
+ const head = readAssetHead(root, kind, id);
331
+ if (head.archived) throw new AssetError(`Choose an active asset instead of archived ${id}.`);
332
+ const record = readAssetRevision(root, kind, id, head.revision);
333
+ for (const file of revisionFiles(record)) assetFile(root, kind, id, file);
334
+ return record;
335
+ }
336
+ if (defaults.logo) {
337
+ const record = current('logo', defaults.logo.id);
338
+ if (record.kind !== 'logo') throw new AssetError('Choose a logo asset.');
339
+ if (defaults.logo.variation && !record.variations.some((v) => v.id === defaults.logo!.variation))
340
+ throw new AssetError('Choose an available logo variation.');
341
+ out.logo = {
342
+ id: record.id,
343
+ revision: record.revision,
344
+ ...(defaults.logo.variation ? { variation: defaults.logo.variation } : {}),
345
+ };
346
+ }
347
+ for (const role of ['bodyFont', 'headingFont'] as const)
348
+ if (defaults[role]) {
349
+ const record = current('font', defaults[role]!);
350
+ if (record.kind !== 'font' || !fontCanBeDefault(record))
351
+ throw new AssetError(
352
+ `Font ${record.name} is not ready as a theme default. Choose a family with a verified regular and emphasis face.`,
353
+ );
354
+ out[role] = { id: record.id, revision: record.revision };
355
+ }
356
+ return out;
357
+ }
358
+ export function resolveThemeAssets(root: string, id: string): DocumentAssets {
359
+ return resolveThemeAssetDefaults(root, readThemeAssetDefaults(root, id));
360
+ }
361
+ export function bindingDependencies(root: string, bindings: DocumentAssets): string[] {
362
+ const entries: [AssetKind, AssetRef][] = [];
363
+ if (bindings.logo) entries.push(['logo', bindings.logo]);
364
+ for (const logo of Object.values(bindings.logos ?? {})) entries.push(['logo', logo]);
365
+ for (const font of [bindings.bodyFont, bindings.headingFont]) if (font) entries.push(['font', font]);
366
+ const files = new Set<string>();
367
+ for (const [kind, binding] of entries) {
368
+ files.add(relative(root, assetRevisionPath(root, kind, binding.id, binding.revision)));
369
+ try {
370
+ const record = readAssetRevision(root, kind, binding.id, binding.revision);
371
+ for (const file of revisionFiles(record))
372
+ files.add(relative(root, resolve(assetDirectory(root, kind, binding.id), file.file)));
373
+ } catch {
374
+ /* Keep missing manifest in dependencies for repair. */
375
+ }
376
+ }
377
+ return [...files];
378
+ }
@@ -0,0 +1,294 @@
1
+ import { dirname, extname, resolve, sep } from 'node:path';
2
+ import { createInflate } from 'node:zlib';
3
+ import { Resvg } from '@resvg/resvg-js';
4
+ import { XMLParser, XMLValidator } from 'fast-xml-parser';
5
+ import { create as createFont, type Font } from 'fontkit';
6
+ import { createElement as h, type ReactNode } from 'react';
7
+ import * as F from '@formepdf/react';
8
+ import { renderDocument } from '@formepdf/core';
9
+ import { getDocument } from 'pdfjs-dist/legacy/build/pdf.mjs';
10
+ import { preparedFile, type PreparedFonts, type PreparedLogo, type UploadFile } from './imports';
11
+ import { imageInfo } from '../media/files';
12
+ import { runtimeResolve } from '../runtime/paths';
13
+
14
+ const crcTable = Array.from({ length: 256 }, (_, value) => {
15
+ let crc = value;
16
+ for (let bit = 0; bit < 8; bit++) crc = crc & 1 ? (crc >>> 1) ^ 0xedb88320 : crc >>> 1;
17
+ return crc >>> 0;
18
+ });
19
+ function crc32(bytes: Uint8Array) {
20
+ let crc = 0xffffffff;
21
+ for (const byte of bytes) crc = (crc >>> 8) ^ crcTable[(crc ^ byte) & 255];
22
+ return (crc ^ 0xffffffff) >>> 0;
23
+ }
24
+
25
+ async function pngDimensions(contents: Uint8Array) {
26
+ const bytes = Buffer.from(contents);
27
+ if (bytes.length < 45 || !bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) throw new Error('This file is not a valid PNG. Export the logo as PNG again.');
28
+ let width = 0, height = 0, bitDepth = 0, colorType = 0, interlace = 0;
29
+ let offset = 8, ended = false, imageEnded = false, palette = false;
30
+ const data: Buffer[] = [];
31
+ while (offset + 12 <= bytes.length) {
32
+ const length = bytes.readUInt32BE(offset), end = offset + length + 12;
33
+ if (end > bytes.length) throw new Error('The PNG is truncated. Export the logo again.');
34
+ const name = bytes.toString('ascii', offset + 4, offset + 8);
35
+ if (!/^[A-Za-z]{4}$/.test(name) || crc32(bytes.subarray(offset + 4, end - 4)) !== bytes.readUInt32BE(end - 4)) throw new Error('The PNG has a damaged image chunk. Export the logo again.');
36
+ if (offset === 8 && name !== 'IHDR') throw new Error('The PNG has no valid image header.');
37
+ if (name === 'IHDR') {
38
+ if (offset !== 8 || length !== 13) throw new Error('The PNG has an invalid image header.');
39
+ width = bytes.readUInt32BE(offset + 8); height = bytes.readUInt32BE(offset + 12);
40
+ bitDepth = bytes[offset + 16]; colorType = bytes[offset + 17]; interlace = bytes[offset + 20];
41
+ const depths: Record<number, number[]> = { 0: [1, 2, 4, 8, 16], 2: [8, 16], 3: [1, 2, 4, 8], 4: [8, 16], 6: [8, 16] };
42
+ if (!width || !height || width * height > 100_000_000) throw new Error('PNG logos must have positive dimensions and no more than 100 megapixels.');
43
+ if (!depths[colorType]?.includes(bitDepth) || bytes[offset + 18] !== 0 || bytes[offset + 19] !== 0 || interlace > 1) throw new Error('The PNG uses an invalid image format.');
44
+ } else if (name === 'PLTE') {
45
+ if (data.length || palette || !length || length % 3 || length > 768) throw new Error('The PNG color palette is invalid.');
46
+ palette = true;
47
+ } else if (name === 'IDAT') {
48
+ if (imageEnded) throw new Error('The PNG image chunks are out of order.');
49
+ data.push(bytes.subarray(offset + 8, end - 4));
50
+ } else if (name === 'IEND') {
51
+ if (length || !data.length || end !== bytes.length) throw new Error('The PNG has an invalid ending.');
52
+ ended = true; break;
53
+ } else {
54
+ if (data.length) imageEnded = true;
55
+ if (name[0] === name[0].toUpperCase()) throw new Error(`The PNG has an unsupported ${name} image chunk.`);
56
+ }
57
+ offset = end;
58
+ }
59
+ if (!ended || (colorType === 3 && !palette)) throw new Error('The PNG is incomplete or has no required color palette.');
60
+ const channels: Record<number, number> = { 0: 1, 2: 3, 3: 1, 4: 2, 6: 4 };
61
+ const passes = interlace ? [[0, 0, 8, 8], [4, 0, 8, 8], [0, 4, 4, 8], [2, 0, 4, 4], [0, 2, 2, 4], [1, 0, 2, 2], [0, 1, 1, 2]] : [[0, 0, 1, 1]];
62
+ const rows = passes.flatMap(([x, y, dx, dy]) => {
63
+ const columns = Math.max(0, Math.ceil((width - x) / dx));
64
+ const count = Math.max(0, Math.ceil((height - y) / dy));
65
+ return columns && count ? [{ count, bytes: Math.ceil(columns * bitDepth * channels[colorType] / 8) + 1 }] : [];
66
+ });
67
+ // Stream decompression: a large valid image never allocates an equally large decoded buffer.
68
+ await new Promise<void>((accept, reject) => {
69
+ const stream = createInflate();
70
+ let pass = 0, row = 0, position = 0;
71
+ stream.on('data', (chunk: Buffer) => {
72
+ let cursor = 0;
73
+ while (cursor < chunk.length) {
74
+ if (pass >= rows.length) { stream.destroy(new Error('The PNG has excess decompressed image data.')); return; }
75
+ if (position === 0 && chunk[cursor] > 4) { stream.destroy(new Error('The PNG has an invalid pixel filter.')); return; }
76
+ const step = Math.min(chunk.length - cursor, rows[pass].bytes - position);
77
+ cursor += step; position += step;
78
+ if (position === rows[pass].bytes) { position = 0; row++; if (row === rows[pass].count) { row = 0; pass++; } }
79
+ }
80
+ });
81
+ stream.once('error', () => reject(new Error('The PNG pixel data is damaged. Export the logo again.')));
82
+ stream.once('end', () => pass === rows.length && position === 0 ? accept() : reject(new Error('The PNG pixel data is incomplete.')));
83
+ for (const chunk of data) stream.write(chunk);
84
+ stream.end();
85
+ });
86
+ return { width, height };
87
+ }
88
+
89
+ async function validateSvg(source: string) {
90
+ if (/<!DOCTYPE|<!ENTITY/i.test(source)) throw new Error('SVG logos must be self-contained and cannot use document types or XML entities.');
91
+ if (XMLValidator.validate(source) !== true) throw new Error('The SVG is not well-formed XML. Export the logo as SVG again.');
92
+ const parsed = new XMLParser({ ignoreAttributes: false, processEntities: true, parseTagValue: false, parseAttributeValue: false, removeNSPrefix: true }).parse(source) as Record<string, unknown>;
93
+ if (!Object.hasOwn(parsed, 'svg')) throw new Error('The file must contain an SVG root element.');
94
+ const embedded = new Set<string>();
95
+ let nodes = 0;
96
+ function inspect(value: unknown, key = '', depth = 0) {
97
+ if (++nodes > 50_000) throw new Error('This SVG contains too many elements. Simplify it before importing.');
98
+ if (depth > 100) throw new Error('This SVG is too deeply nested. Simplify it before importing.');
99
+ const tag = key.toLowerCase();
100
+ if (['script', 'foreignobject', 'animate', 'animatetransform', 'animatemotion', 'set'].includes(tag)) throw new Error('Logo SVGs must be static artwork. Remove scripts, animation, or foreign content first.');
101
+ if (['text', 'tspan', 'textpath'].includes(tag)) throw new Error('This SVG contains text whose fonts are not embedded as outlines. Convert text to paths before uploading, or use a PNG. OpenDoc does not substitute system fonts.');
102
+ if (typeof value === 'string') {
103
+ if (tag.startsWith('@_on')) throw new Error('Logo SVGs cannot contain scripted event handlers.');
104
+ if (tag === '@_href') {
105
+ const href = value.trim();
106
+ if (href && !href.startsWith('#') && !/^data:image\/(?:png|jpeg);base64,[a-z0-9+/=\s]+$/i.test(href)) throw new Error('The SVG references an external image or file. Embed images as PNG/JPEG data, or upload a self-contained PNG.');
107
+ if (href.startsWith('data:')) embedded.add(href);
108
+ }
109
+ if (tag === '@_base' && value.trim()) throw new Error('SVG logos cannot set an external base path. Embed their images and resources first.');
110
+ if (tag === 'style' || tag === '@_style' || (tag.startsWith('@_') && /url\s*\(|\\/i.test(value))) {
111
+ const css = value.replace(/\/\*[\s\S]*?\*\//g, '');
112
+ if (/\\|@import|@font-face|expression\s*\(/i.test(css)) throw new Error('SVG logos cannot load external styles or fonts. Convert text to paths and embed images first.');
113
+ for (const match of css.matchAll(/url\s*\(([^)]*)\)/gi)) if (!/^['"]?#[^\s'"()]+['"]?$/.test(match[1].trim())) throw new Error('The SVG uses an external style resource. Use only local SVG fragment references.');
114
+ }
115
+ } else if (Array.isArray(value)) { for (const child of value) inspect(child, key, depth + 1); }
116
+ else if (value && typeof value === 'object') { for (const [childKey, child] of Object.entries(value)) inspect(child, childKey, depth + 1); }
117
+ }
118
+ inspect(parsed);
119
+ for (const href of embedded) {
120
+ const bytes = Buffer.from(href.slice(href.indexOf(',') + 1).replace(/\s/g, ''), 'base64');
121
+ if (/^data:image\/png/i.test(href)) await pngDimensions(bytes);
122
+ else {
123
+ if (bytes[0] !== 255 || bytes[1] !== 216 || bytes[bytes.length - 2] !== 255 || bytes[bytes.length - 1] !== 217) throw new Error('An embedded JPEG image is damaged. Export the SVG with its images embedded again.');
124
+ let offset = 2, bounded = false;
125
+ while (offset + 4 < bytes.length) {
126
+ if (bytes[offset++] !== 255) break;
127
+ while (bytes[offset] === 255) offset++;
128
+ const marker = bytes[offset++];
129
+ if (marker === 0xda || marker === 0xd9) break;
130
+ if (marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) continue;
131
+ const length = bytes.readUInt16BE(offset);
132
+ if (length < 2 || offset + length > bytes.length) break;
133
+ if ([0xc0, 0xc1, 0xc2].includes(marker) && length >= 8) {
134
+ const height = bytes.readUInt16BE(offset + 3), width = bytes.readUInt16BE(offset + 5);
135
+ if (!width || !height || width * height > 100_000_000) throw new Error('An embedded SVG image exceeds the 100-megapixel limit. Reduce its dimensions first.');
136
+ bounded = true; break;
137
+ }
138
+ offset += length;
139
+ }
140
+ if (!bounded) throw new Error('An embedded JPEG has no supported image dimensions. Re-export it as PNG before embedding.');
141
+ }
142
+ // usvg otherwise silently drops embedded images that its decoder cannot read.
143
+ const probe = new Resvg(`<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"><image href="${href.replace(/\s/g, '')}" width="1" height="1"/></svg>`, { font: { loadSystemFonts: false }, logLevel: 'off' });
144
+ if (!probe.toString().includes('<image')) throw new Error('An embedded SVG image could not be decoded. Export the SVG with valid embedded PNG/JPEG images again.');
145
+ }
146
+ }
147
+
148
+ async function logo(file: UploadFile): Promise<PreparedLogo> {
149
+ if (extname(file.filename).toLowerCase() === '.png') {
150
+ const dimensions = await pngDimensions(file.bytes);
151
+ const original = preparedFile(file.bytes, 'png', 'image/png', dimensions);
152
+ return { original, image: original };
153
+ }
154
+ const source = new TextDecoder('utf-8', { fatal: true }).decode(file.bytes);
155
+ await validateSvg(source);
156
+ try {
157
+ const options = { font: { loadSystemFonts: false }, logLevel: 'off' as const };
158
+ const inspected = new Resvg(source, options);
159
+ if (inspected.imagesToResolve().length) throw new Error('The SVG contains unresolved external images. Embed them before importing.');
160
+ if (!Number.isFinite(inspected.width) || !Number.isFinite(inspected.height) || inspected.width <= 0 || inspected.height <= 0) throw new Error('The SVG needs a positive width and height or viewBox.');
161
+ const fitTo = inspected.width >= inspected.height ? { mode: 'width' as const, value: 4096 } : { mode: 'height' as const, value: 4096 };
162
+ const rendered = new Resvg(source, { ...options, fitTo }).render();
163
+ if (!rendered.width || !rendered.height || rendered.width > 4096 || rendered.height > 4096) throw new Error('The SVG proportions could not be prepared within the 4096-pixel limit.');
164
+ return {
165
+ original: preparedFile(file.bytes, 'svg', 'image/svg+xml', { width: inspected.width, height: inspected.height }),
166
+ image: preparedFile(rendered.asPng(), 'png', 'image/png', { width: rendered.width, height: rendered.height }),
167
+ };
168
+ } catch (error) { throw new Error(`The SVG could not be prepared: ${error instanceof Error ? error.message : String(error)}`); }
169
+ }
170
+
171
+ async function media(file: UploadFile) {
172
+ const bytes = Buffer.from(file.bytes);
173
+ const info = imageInfo(bytes);
174
+ if ((extname(file.filename).toLowerCase() === '.png') !== (info.mime === 'image/png')) throw new Error('The image extension does not match its contents. Export it as PNG or JPEG again.');
175
+ if (info.mime === 'image/png') await pngDimensions(bytes);
176
+ else {
177
+ if (bytes[bytes.length - 2] !== 255 || bytes[bytes.length - 1] !== 217) throw new Error('The JPEG is incomplete. Export it again from its original.');
178
+ const probe = new Resvg(`<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"><image href="data:image/jpeg;base64,${bytes.toString('base64')}" width="1" height="1"/></svg>`, { font: { loadSystemFonts: false }, logLevel: 'off' });
179
+ if (!probe.toString().includes('<image')) throw new Error('The JPEG pixel data could not be decoded. Export it again from its original.');
180
+ }
181
+ return { image: preparedFile(file.bytes, info.mime === 'image/png' ? 'png' : 'jpg', info.mime, { width: info.width, height: info.height }) };
182
+ }
183
+
184
+ const plainSample = 'office efficiency finished';
185
+ const styleSample = 'Before bold words after italic words finish.';
186
+ const kerningSample = 'AVATAR To Wa office after space';
187
+ const alphabetSample = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789';
188
+
189
+ async function fonts(files: UploadFile[]): Promise<PreparedFonts> {
190
+ const parsed: Font[] = [];
191
+ const collisions = new Set<string>();
192
+ let name = '';
193
+ const faces: PreparedFonts['faces'] = files.map(file => {
194
+ const bytes = Buffer.from(file.bytes);
195
+ const signature = bytes.subarray(0, 4).toString('ascii');
196
+ if (signature !== 'OTTO' && !bytes.subarray(0, 4).equals(Buffer.from([0, 1, 0, 0]))) throw new Error(`${file.filename}: choose a static TTF or OTF file. Web fonts and font collections are not supported.`);
197
+ let font: Font;
198
+ try {
199
+ const opened = createFont(bytes);
200
+ if ('fonts' in opened) throw new Error('Font collections are not supported.');
201
+ font = opened;
202
+ if (Object.keys(font.variationAxes ?? {}).length) throw new Error('Variable fonts are not supported. Export a static TTF or OTF face.');
203
+ if (!font.numGlyphs || !font.familyName) throw new Error('The font has no readable family or glyphs.');
204
+ } catch (error) { throw new Error(`${file.filename}: ${error instanceof Error ? error.message : 'The font metadata could not be read.'}`); }
205
+ const family = (font.getName('preferredFamily', 'en') || font.familyName).trim();
206
+ if (name && name !== family) throw new Error(`Import one family at a time. ${file.filename} belongs to ${family}, while the other files belong to ${name}.`);
207
+ name = family;
208
+ const weight = font['OS/2']?.usWeightClass;
209
+ if (!Number.isInteger(weight) || weight < 1 || weight > 1000) throw new Error(`${file.filename}: the font has no valid weight metadata.`);
210
+ const style = font['OS/2']?.fsSelection?.italic || font['OS/2']?.fsSelection?.oblique || font.italicAngle !== 0 ? 'italic' : 'normal';
211
+ const id = `${weight}-${style}`;
212
+ if (collisions.has(id)) throw new Error(`${family} includes more than one ${weight} ${style} face. Choose one file for each weight and style.`);
213
+ collisions.add(id); parsed.push(font);
214
+ const extension = signature === 'OTTO' ? 'otf' : 'ttf';
215
+ return { id, family, postscriptName: font.postscriptName || undefined, weight, style, file: preparedFile(file.bytes, extension, extension === 'otf' ? 'font/otf' : 'font/ttf') };
216
+ });
217
+ const problems: string[] = [];
218
+ for (let index = 0; index < parsed.length; index++) {
219
+ const missing = Array.from({ length: 95 }, (_, character) => character + 32).filter(character => !parsed[index].hasGlyphForCodePoint(character));
220
+ if (missing.length) problems.push(`${faces[index].weight} ${faces[index].style} is missing English glyphs (${missing.slice(0, 6).map(code => String.fromCodePoint(code)).join(' ')}).`);
221
+ }
222
+ const regular = faces.find(face => face.weight === 400 && face.style === 'normal');
223
+ const strong = faces.find(face => face.weight === 600 && face.style === 'normal') ?? faces.find(face => face.weight === 700 && face.style === 'normal');
224
+ const italic = faces.find(face => face.weight === 400 && face.style === 'italic');
225
+ const descriptionFonts = regular ? [parsed[faces.indexOf(regular)], ...parsed] : parsed;
226
+ const description = descriptionFonts.map(font => font.getName('description', 'en')?.replace(/\s+/g, ' ').trim()).find(Boolean)?.slice(0, 4000) ?? '';
227
+ const expected: string[] = [];
228
+ const lines: ReactNode[] = [];
229
+ const sample = (text: string, face: (typeof faces)[number], size = 13) => {
230
+ expected.push(text);
231
+ return h(F.Text, { style: { fontFamily: name, fontWeight: face.weight, fontStyle: face.style, fontSize: size, lineHeight: 1.4, marginBottom: 8 } }, text);
232
+ };
233
+ lines.push(h(F.Text, { style: { fontFamily: 'Helvetica', fontSize: 21, marginBottom: 8 } }, name));
234
+ lines.push(h(F.Text, { style: { fontFamily: 'Helvetica', fontSize: 10, marginBottom: 22, color: '#596273' } }, 'Original font files · OpenDoc PDF compatibility specimen'));
235
+ for (const face of faces) {
236
+ lines.push(h(F.Text, { style: { fontFamily: 'Helvetica', fontSize: 9, marginTop: 12, marginBottom: 7, color: '#596273' } }, `${face.weight} ${face.style}`));
237
+ lines.push(sample(alphabetSample, face, 11), sample(plainSample, face));
238
+ }
239
+ if (regular && strong) {
240
+ const mix = (before: string, bold: string, after: string, emphasized: string, final: string, expectedText: string) => {
241
+ expected.push(expectedText);
242
+ return h(F.Text, { style: { fontFamily: name, fontWeight: 400, fontSize: 14, marginTop: 10, lineHeight: 1.4 } },
243
+ before, h(F.Text, { style: { fontWeight: strong.weight } }, bold), after,
244
+ h(F.Text, { style: { fontStyle: italic ? 'italic' : 'normal' } }, emphasized), final);
245
+ };
246
+ lines.push(mix('Before ', 'bold words', ' after ', 'italic words', ' finish.', styleSample));
247
+ lines.push(mix('AVATAR ', 'To Wa', ' office ', 'after', ' space', kerningSample));
248
+ }
249
+ let specimen: PreparedFonts['specimen'];
250
+ try {
251
+ const bytes = await renderDocument(h(F.Document, { title: `${name} — font specimen`, fonts: faces.map(face => ({ family: name, src: face.file.contents, fontWeight: face.weight, fontStyle: face.style })) }, h(F.Page, { size: 'A4', margin: 45 }, ...lines)));
252
+ specimen = preparedFile(bytes, 'pdf', 'application/pdf');
253
+ const pdfTask = getDocument({ data: new Uint8Array(bytes), standardFontDataUrl: resolve(dirname(runtimeResolve('pdfjs-dist/package.json')), 'standard_fonts') + sep, verbosity: 0, useSystemFonts: false, disableFontFace: true });
254
+ try {
255
+ const pdf = await pdfTask.promise;
256
+ const actual: string[] = [];
257
+ for (let pageIndex = 1; pageIndex <= pdf.numPages; pageIndex++) {
258
+ const content = await (await pdf.getPage(pageIndex)).getTextContent();
259
+ let line = '';
260
+ for (const item of content.items) {
261
+ if (!('str' in item)) continue;
262
+ if (!Number.isFinite(item.width) || item.width < 0 || item.transform.some(value => !Number.isFinite(value))) problems.push('The PDF contains invalid text geometry.');
263
+ line += item.str;
264
+ if (item.hasEOL) { actual.push(line.normalize('NFKC')); line = ''; }
265
+ }
266
+ if (line) actual.push(line.normalize('NFKC'));
267
+ }
268
+ for (const text of expected) {
269
+ const found = actual.indexOf(text);
270
+ if (found >= 0) actual.splice(found, 1);
271
+ else problems.push(`The PDF does not preserve the text or spacing in “${text}”.`);
272
+ }
273
+ } finally { await pdfTask.destroy(); }
274
+ } catch (error) { problems.push(`PDF validation failed: ${error instanceof Error ? error.message : String(error)}`); }
275
+ const missingStyles = !regular || !strong ? 'Theme defaults require regular (400) plus semibold (600) or bold (700).' : undefined;
276
+ return {
277
+ name, description, faces, specimen,
278
+ compatibility: {
279
+ status: problems.length ? 'needs-attention' : 'ready',
280
+ defaultEligible: !problems.length && Boolean(regular && strong),
281
+ ...((problems.length || missingStyles) ? { message: [...new Set(problems), ...(missingStyles ? [missingStyles] : [])].join(' ') } : {}),
282
+ },
283
+ };
284
+ }
285
+
286
+ process.once('message', async (message: { kind: 'logo' | 'fonts' | 'media'; files: UploadFile[] }) => {
287
+ try {
288
+ const result = message.kind === 'logo' ? await logo(message.files[0]) : message.kind === 'media' ? await media(message.files[0]) : await fonts(message.files);
289
+ process.send?.({ ok: true, result }, () => process.disconnect());
290
+ } catch (error) {
291
+ process.send?.({ ok: false, error: error instanceof Error ? error.message : String(error) }, () => process.disconnect());
292
+ process.exitCode = 1;
293
+ }
294
+ });