@ryanyahya/opendoc-headless 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 (716) 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/docs/APPEARANCE.md +21 -0
  24. package/docs/ASSETS.md +176 -0
  25. package/docs/AUTHORING.md +178 -0
  26. package/docs/HEADLESS.md +120 -0
  27. package/docs/MEDIA.md +112 -0
  28. package/docs/PROJECTS.md +55 -0
  29. package/docs/PROSE.md +15 -0
  30. package/docs/SELECTION.md +59 -0
  31. package/docs/TEMPLATES.md +55 -0
  32. package/docs/THEMES.md +106 -0
  33. package/node_modules/@formepdf/core/LICENSE +21 -0
  34. package/node_modules/@formepdf/core/README.md +53 -0
  35. package/node_modules/@formepdf/core/dist/attachments.d.ts +55 -0
  36. package/node_modules/@formepdf/core/dist/attachments.js +59 -0
  37. package/node_modules/@formepdf/core/dist/extract.d.ts +8 -0
  38. package/node_modules/@formepdf/core/dist/extract.js +56 -0
  39. package/node_modules/@formepdf/core/dist/index.d.ts +311 -0
  40. package/node_modules/@formepdf/core/dist/index.js +167 -0
  41. package/node_modules/@formepdf/core/dist/layout.d.ts +132 -0
  42. package/node_modules/@formepdf/core/dist/layout.js +240 -0
  43. package/node_modules/@formepdf/core/dist/shared/browserHelpers.d.ts +19 -0
  44. package/node_modules/@formepdf/core/dist/shared/browserHelpers.js +128 -0
  45. package/node_modules/@formepdf/core/package.json +35 -0
  46. package/node_modules/@formepdf/core/pkg-node/LICENSE +21 -0
  47. package/node_modules/@formepdf/core/pkg-node/README.md +84 -0
  48. package/node_modules/@formepdf/core/pkg-node/forme.d.ts +39 -0
  49. package/node_modules/@formepdf/core/pkg-node/forme.js +394 -0
  50. package/node_modules/@formepdf/core/pkg-node/forme_bg.wasm +0 -0
  51. package/node_modules/@formepdf/core/pkg-node/forme_bg.wasm.d.ts +21 -0
  52. package/node_modules/@formepdf/core/pkg-node/package.json +25 -0
  53. package/node_modules/@formepdf/react/README.md +70 -0
  54. package/node_modules/@formepdf/react/dist/charts.d.ts +72 -0
  55. package/node_modules/@formepdf/react/dist/charts.js +338 -0
  56. package/node_modules/@formepdf/react/dist/components.d.ts +533 -0
  57. package/node_modules/@formepdf/react/dist/components.js +608 -0
  58. package/node_modules/@formepdf/react/dist/expr.d.ts +20 -0
  59. package/node_modules/@formepdf/react/dist/expr.js +39 -0
  60. package/node_modules/@formepdf/react/dist/font.d.ts +2 -0
  61. package/node_modules/@formepdf/react/dist/font.js +1 -0
  62. package/node_modules/@formepdf/react/dist/index.d.ts +11 -0
  63. package/node_modules/@formepdf/react/dist/index.js +15 -0
  64. package/node_modules/@formepdf/react/dist/render.d.ts +12 -0
  65. package/node_modules/@formepdf/react/dist/render.js +15 -0
  66. package/node_modules/@formepdf/react/dist/serialize.d.ts +12 -0
  67. package/node_modules/@formepdf/react/dist/serialize.js +1470 -0
  68. package/node_modules/@formepdf/react/dist/stylesheet.d.ts +4 -0
  69. package/node_modules/@formepdf/react/dist/stylesheet.js +5 -0
  70. package/node_modules/@formepdf/react/dist/template-proxy.d.ts +38 -0
  71. package/node_modules/@formepdf/react/dist/template-proxy.js +100 -0
  72. package/node_modules/@formepdf/react/dist/types.d.ts +287 -0
  73. package/node_modules/@formepdf/react/dist/types.js +1 -0
  74. package/node_modules/@formepdf/react/package.json +41 -0
  75. package/node_modules/@formepdf/shared/README.md +7 -0
  76. package/node_modules/@formepdf/shared/dist/canvas.d.ts +6 -0
  77. package/node_modules/@formepdf/shared/dist/canvas.js +43 -0
  78. package/node_modules/@formepdf/shared/dist/charts.d.ts +100 -0
  79. package/node_modules/@formepdf/shared/dist/charts.js +98 -0
  80. package/node_modules/@formepdf/shared/dist/encode.d.ts +27 -0
  81. package/node_modules/@formepdf/shared/dist/encode.js +93 -0
  82. package/node_modules/@formepdf/shared/dist/font.d.ts +13 -0
  83. package/node_modules/@formepdf/shared/dist/font.js +52 -0
  84. package/node_modules/@formepdf/shared/dist/index.d.ts +10 -0
  85. package/node_modules/@formepdf/shared/dist/index.js +15 -0
  86. package/node_modules/@formepdf/shared/dist/parser.d.ts +30 -0
  87. package/node_modules/@formepdf/shared/dist/parser.js +756 -0
  88. package/node_modules/@formepdf/shared/dist/semantics.d.ts +15 -0
  89. package/node_modules/@formepdf/shared/dist/semantics.js +44 -0
  90. package/node_modules/@formepdf/shared/dist/style.d.ts +7 -0
  91. package/node_modules/@formepdf/shared/dist/style.js +1024 -0
  92. package/node_modules/@formepdf/shared/dist/types.d.ts +743 -0
  93. package/node_modules/@formepdf/shared/dist/types.js +2 -0
  94. package/node_modules/@formepdf/shared/package.json +35 -0
  95. package/node_modules/@types/node/LICENSE +21 -0
  96. package/node_modules/@types/node/README.md +15 -0
  97. package/node_modules/@types/node/assert/strict.d.ts +111 -0
  98. package/node_modules/@types/node/assert.d.ts +1078 -0
  99. package/node_modules/@types/node/async_hooks.d.ts +603 -0
  100. package/node_modules/@types/node/buffer.buffer.d.ts +472 -0
  101. package/node_modules/@types/node/buffer.d.ts +1934 -0
  102. package/node_modules/@types/node/child_process.d.ts +1476 -0
  103. package/node_modules/@types/node/cluster.d.ts +578 -0
  104. package/node_modules/@types/node/compatibility/disposable.d.ts +14 -0
  105. package/node_modules/@types/node/compatibility/index.d.ts +9 -0
  106. package/node_modules/@types/node/compatibility/indexable.d.ts +20 -0
  107. package/node_modules/@types/node/compatibility/iterators.d.ts +20 -0
  108. package/node_modules/@types/node/console.d.ts +452 -0
  109. package/node_modules/@types/node/constants.d.ts +21 -0
  110. package/node_modules/@types/node/crypto.d.ts +4545 -0
  111. package/node_modules/@types/node/dgram.d.ts +600 -0
  112. package/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
  113. package/node_modules/@types/node/dns/promises.d.ts +503 -0
  114. package/node_modules/@types/node/dns.d.ts +923 -0
  115. package/node_modules/@types/node/domain.d.ts +170 -0
  116. package/node_modules/@types/node/events.d.ts +976 -0
  117. package/node_modules/@types/node/fs/promises.d.ts +1306 -0
  118. package/node_modules/@types/node/fs.d.ts +4463 -0
  119. package/node_modules/@types/node/globals.d.ts +172 -0
  120. package/node_modules/@types/node/globals.typedarray.d.ts +38 -0
  121. package/node_modules/@types/node/http.d.ts +2097 -0
  122. package/node_modules/@types/node/http2.d.ts +2843 -0
  123. package/node_modules/@types/node/https.d.ts +579 -0
  124. package/node_modules/@types/node/index.d.ts +98 -0
  125. package/node_modules/@types/node/inspector.d.ts +253 -0
  126. package/node_modules/@types/node/inspector.generated.d.ts +4052 -0
  127. package/node_modules/@types/node/module.d.ts +891 -0
  128. package/node_modules/@types/node/net.d.ts +1076 -0
  129. package/node_modules/@types/node/os.d.ts +506 -0
  130. package/node_modules/@types/node/package.json +145 -0
  131. package/node_modules/@types/node/path.d.ts +200 -0
  132. package/node_modules/@types/node/perf_hooks.d.ts +968 -0
  133. package/node_modules/@types/node/process.d.ts +2084 -0
  134. package/node_modules/@types/node/punycode.d.ts +117 -0
  135. package/node_modules/@types/node/querystring.d.ts +152 -0
  136. package/node_modules/@types/node/readline/promises.d.ts +161 -0
  137. package/node_modules/@types/node/readline.d.ts +594 -0
  138. package/node_modules/@types/node/repl.d.ts +428 -0
  139. package/node_modules/@types/node/sea.d.ts +162 -0
  140. package/node_modules/@types/node/sqlite.d.ts +722 -0
  141. package/node_modules/@types/node/stream/consumers.d.ts +38 -0
  142. package/node_modules/@types/node/stream/promises.d.ts +90 -0
  143. package/node_modules/@types/node/stream/web.d.ts +573 -0
  144. package/node_modules/@types/node/stream.d.ts +1694 -0
  145. package/node_modules/@types/node/string_decoder.d.ts +67 -0
  146. package/node_modules/@types/node/test.d.ts +2265 -0
  147. package/node_modules/@types/node/timers/promises.d.ts +108 -0
  148. package/node_modules/@types/node/timers.d.ts +287 -0
  149. package/node_modules/@types/node/tls.d.ts +1319 -0
  150. package/node_modules/@types/node/trace_events.d.ts +197 -0
  151. package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +468 -0
  152. package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +34 -0
  153. package/node_modules/@types/node/ts5.6/index.d.ts +98 -0
  154. package/node_modules/@types/node/tty.d.ts +208 -0
  155. package/node_modules/@types/node/url.d.ts +984 -0
  156. package/node_modules/@types/node/util.d.ts +2606 -0
  157. package/node_modules/@types/node/v8.d.ts +920 -0
  158. package/node_modules/@types/node/vm.d.ts +1053 -0
  159. package/node_modules/@types/node/wasi.d.ts +181 -0
  160. package/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
  161. package/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  162. package/node_modules/@types/node/web-globals/events.d.ts +97 -0
  163. package/node_modules/@types/node/web-globals/fetch.d.ts +55 -0
  164. package/node_modules/@types/node/web-globals/navigator.d.ts +22 -0
  165. package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
  166. package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
  167. package/node_modules/@types/node/worker_threads.d.ts +819 -0
  168. package/node_modules/@types/node/zlib.d.ts +747 -0
  169. package/node_modules/@types/react/LICENSE +21 -0
  170. package/node_modules/@types/react/README.md +15 -0
  171. package/node_modules/@types/react/canary.d.ts +129 -0
  172. package/node_modules/@types/react/compiler-runtime.d.ts +4 -0
  173. package/node_modules/@types/react/experimental.d.ts +184 -0
  174. package/node_modules/@types/react/global.d.ts +166 -0
  175. package/node_modules/@types/react/index.d.ts +4378 -0
  176. package/node_modules/@types/react/jsx-dev-runtime.d.ts +33 -0
  177. package/node_modules/@types/react/jsx-runtime.d.ts +24 -0
  178. package/node_modules/@types/react/package.json +210 -0
  179. package/node_modules/@types/react/ts5.0/canary.d.ts +129 -0
  180. package/node_modules/@types/react/ts5.0/experimental.d.ts +184 -0
  181. package/node_modules/@types/react/ts5.0/global.d.ts +166 -0
  182. package/node_modules/@types/react/ts5.0/index.d.ts +4365 -0
  183. package/node_modules/@types/react/ts5.0/jsx-dev-runtime.d.ts +33 -0
  184. package/node_modules/@types/react/ts5.0/jsx-runtime.d.ts +24 -0
  185. package/node_modules/csstype/LICENSE +19 -0
  186. package/node_modules/csstype/README.md +291 -0
  187. package/node_modules/csstype/index.d.ts +22569 -0
  188. package/node_modules/csstype/index.js.flow +6863 -0
  189. package/node_modules/csstype/package.json +70 -0
  190. package/node_modules/entities/LICENSE +11 -0
  191. package/node_modules/entities/decode.d.ts +1 -0
  192. package/node_modules/entities/decode.js +3 -0
  193. package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts +19 -0
  194. package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts.map +1 -0
  195. package/node_modules/entities/dist/commonjs/decode-codepoint.js +77 -0
  196. package/node_modules/entities/dist/commonjs/decode-codepoint.js.map +1 -0
  197. package/node_modules/entities/dist/commonjs/decode.d.ts +209 -0
  198. package/node_modules/entities/dist/commonjs/decode.d.ts.map +1 -0
  199. package/node_modules/entities/dist/commonjs/decode.js +511 -0
  200. package/node_modules/entities/dist/commonjs/decode.js.map +1 -0
  201. package/node_modules/entities/dist/commonjs/encode.d.ts +22 -0
  202. package/node_modules/entities/dist/commonjs/encode.d.ts.map +1 -0
  203. package/node_modules/entities/dist/commonjs/encode.js +73 -0
  204. package/node_modules/entities/dist/commonjs/encode.js.map +1 -0
  205. package/node_modules/entities/dist/commonjs/escape.d.ts +43 -0
  206. package/node_modules/entities/dist/commonjs/escape.d.ts.map +1 -0
  207. package/node_modules/entities/dist/commonjs/escape.js +121 -0
  208. package/node_modules/entities/dist/commonjs/escape.js.map +1 -0
  209. package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts +2 -0
  210. package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts.map +1 -0
  211. package/node_modules/entities/dist/commonjs/generated/decode-data-html.js +10 -0
  212. package/node_modules/entities/dist/commonjs/generated/decode-data-html.js.map +1 -0
  213. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts +2 -0
  214. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts.map +1 -0
  215. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js +10 -0
  216. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js.map +1 -0
  217. package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts +8 -0
  218. package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts.map +1 -0
  219. package/node_modules/entities/dist/commonjs/generated/encode-html.js +13 -0
  220. package/node_modules/entities/dist/commonjs/generated/encode-html.js.map +1 -0
  221. package/node_modules/entities/dist/commonjs/index.d.ts +96 -0
  222. package/node_modules/entities/dist/commonjs/index.d.ts.map +1 -0
  223. package/node_modules/entities/dist/commonjs/index.js +131 -0
  224. package/node_modules/entities/dist/commonjs/index.js.map +1 -0
  225. package/node_modules/entities/dist/commonjs/package.json +3 -0
  226. package/node_modules/entities/dist/esm/decode-codepoint.d.ts +19 -0
  227. package/node_modules/entities/dist/esm/decode-codepoint.d.ts.map +1 -0
  228. package/node_modules/entities/dist/esm/decode-codepoint.js +72 -0
  229. package/node_modules/entities/dist/esm/decode-codepoint.js.map +1 -0
  230. package/node_modules/entities/dist/esm/decode.d.ts +209 -0
  231. package/node_modules/entities/dist/esm/decode.d.ts.map +1 -0
  232. package/node_modules/entities/dist/esm/decode.js +497 -0
  233. package/node_modules/entities/dist/esm/decode.js.map +1 -0
  234. package/node_modules/entities/dist/esm/encode.d.ts +22 -0
  235. package/node_modules/entities/dist/esm/encode.d.ts.map +1 -0
  236. package/node_modules/entities/dist/esm/encode.js +69 -0
  237. package/node_modules/entities/dist/esm/encode.js.map +1 -0
  238. package/node_modules/entities/dist/esm/escape.d.ts +43 -0
  239. package/node_modules/entities/dist/esm/escape.d.ts.map +1 -0
  240. package/node_modules/entities/dist/esm/escape.js +117 -0
  241. package/node_modules/entities/dist/esm/escape.js.map +1 -0
  242. package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts +2 -0
  243. package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts.map +1 -0
  244. package/node_modules/entities/dist/esm/generated/decode-data-html.js +7 -0
  245. package/node_modules/entities/dist/esm/generated/decode-data-html.js.map +1 -0
  246. package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts +2 -0
  247. package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts.map +1 -0
  248. package/node_modules/entities/dist/esm/generated/decode-data-xml.js +7 -0
  249. package/node_modules/entities/dist/esm/generated/decode-data-xml.js.map +1 -0
  250. package/node_modules/entities/dist/esm/generated/encode-html.d.ts +8 -0
  251. package/node_modules/entities/dist/esm/generated/encode-html.d.ts.map +1 -0
  252. package/node_modules/entities/dist/esm/generated/encode-html.js +10 -0
  253. package/node_modules/entities/dist/esm/generated/encode-html.js.map +1 -0
  254. package/node_modules/entities/dist/esm/index.d.ts +96 -0
  255. package/node_modules/entities/dist/esm/index.d.ts.map +1 -0
  256. package/node_modules/entities/dist/esm/index.js +107 -0
  257. package/node_modules/entities/dist/esm/index.js.map +1 -0
  258. package/node_modules/entities/dist/esm/package.json +3 -0
  259. package/node_modules/entities/escape.d.ts +1 -0
  260. package/node_modules/entities/escape.js +3 -0
  261. package/node_modules/entities/package.json +118 -0
  262. package/node_modules/entities/readme.md +122 -0
  263. package/node_modules/entities/src/decode-codepoint.ts +81 -0
  264. package/node_modules/entities/src/decode.spec.ts +320 -0
  265. package/node_modules/entities/src/decode.ts +620 -0
  266. package/node_modules/entities/src/encode.spec.ts +78 -0
  267. package/node_modules/entities/src/encode.ts +77 -0
  268. package/node_modules/entities/src/escape.spec.ts +14 -0
  269. package/node_modules/entities/src/escape.ts +148 -0
  270. package/node_modules/entities/src/generated/.eslintrc.json +10 -0
  271. package/node_modules/entities/src/generated/decode-data-html.ts +8 -0
  272. package/node_modules/entities/src/generated/decode-data-xml.ts +8 -0
  273. package/node_modules/entities/src/generated/encode-html.ts +17 -0
  274. package/node_modules/entities/src/index.spec.ts +125 -0
  275. package/node_modules/entities/src/index.ts +188 -0
  276. package/node_modules/parse5/LICENSE +19 -0
  277. package/node_modules/parse5/README.md +38 -0
  278. package/node_modules/parse5/dist/cjs/common/doctype.d.ts +4 -0
  279. package/node_modules/parse5/dist/cjs/common/doctype.js +118 -0
  280. package/node_modules/parse5/dist/cjs/common/error-codes.d.ts +67 -0
  281. package/node_modules/parse5/dist/cjs/common/error-codes.js +66 -0
  282. package/node_modules/parse5/dist/cjs/common/foreign-content.d.ts +9 -0
  283. package/node_modules/parse5/dist/cjs/common/foreign-content.js +237 -0
  284. package/node_modules/parse5/dist/cjs/common/html.d.ts +289 -0
  285. package/node_modules/parse5/dist/cjs/common/html.js +528 -0
  286. package/node_modules/parse5/dist/cjs/common/token.d.ts +84 -0
  287. package/node_modules/parse5/dist/cjs/common/token.js +24 -0
  288. package/node_modules/parse5/dist/cjs/common/unicode.d.ts +42 -0
  289. package/node_modules/parse5/dist/cjs/common/unicode.js +70 -0
  290. package/node_modules/parse5/dist/cjs/index.d.ts +71 -0
  291. package/node_modules/parse5/dist/cjs/index.js +54 -0
  292. package/node_modules/parse5/dist/cjs/package.json +1 -0
  293. package/node_modules/parse5/dist/cjs/parser/formatting-element-list.d.ts +36 -0
  294. package/node_modules/parse5/dist/cjs/parser/formatting-element-list.js +114 -0
  295. package/node_modules/parse5/dist/cjs/parser/index.d.ts +221 -0
  296. package/node_modules/parse5/dist/cjs/parser/index.js +3240 -0
  297. package/node_modules/parse5/dist/cjs/parser/open-element-stack.d.ts +53 -0
  298. package/node_modules/parse5/dist/cjs/parser/open-element-stack.js +328 -0
  299. package/node_modules/parse5/dist/cjs/serializer/index.d.ts +60 -0
  300. package/node_modules/parse5/dist/cjs/serializer/index.js +172 -0
  301. package/node_modules/parse5/dist/cjs/tokenizer/index.d.ts +247 -0
  302. package/node_modules/parse5/dist/cjs/tokenizer/index.js +2714 -0
  303. package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.d.ts +36 -0
  304. package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.js +200 -0
  305. package/node_modules/parse5/dist/cjs/tree-adapters/default.d.ts +84 -0
  306. package/node_modules/parse5/dist/cjs/tree-adapters/default.js +176 -0
  307. package/node_modules/parse5/dist/cjs/tree-adapters/interface.d.ts +255 -0
  308. package/node_modules/parse5/dist/cjs/tree-adapters/interface.js +2 -0
  309. package/node_modules/parse5/dist/common/doctype.d.ts +4 -0
  310. package/node_modules/parse5/dist/common/doctype.js +114 -0
  311. package/node_modules/parse5/dist/common/error-codes.d.ts +67 -0
  312. package/node_modules/parse5/dist/common/error-codes.js +63 -0
  313. package/node_modules/parse5/dist/common/foreign-content.d.ts +9 -0
  314. package/node_modules/parse5/dist/common/foreign-content.js +228 -0
  315. package/node_modules/parse5/dist/common/html.d.ts +289 -0
  316. package/node_modules/parse5/dist/common/html.js +523 -0
  317. package/node_modules/parse5/dist/common/token.d.ts +84 -0
  318. package/node_modules/parse5/dist/common/token.js +20 -0
  319. package/node_modules/parse5/dist/common/unicode.d.ts +42 -0
  320. package/node_modules/parse5/dist/common/unicode.js +62 -0
  321. package/node_modules/parse5/dist/index.d.ts +71 -0
  322. package/node_modules/parse5/dist/index.js +42 -0
  323. package/node_modules/parse5/dist/parser/formatting-element-list.d.ts +36 -0
  324. package/node_modules/parse5/dist/parser/formatting-element-list.js +110 -0
  325. package/node_modules/parse5/dist/parser/index.d.ts +221 -0
  326. package/node_modules/parse5/dist/parser/index.js +3245 -0
  327. package/node_modules/parse5/dist/parser/open-element-stack.d.ts +53 -0
  328. package/node_modules/parse5/dist/parser/open-element-stack.js +324 -0
  329. package/node_modules/parse5/dist/serializer/index.d.ts +60 -0
  330. package/node_modules/parse5/dist/serializer/index.js +168 -0
  331. package/node_modules/parse5/dist/tokenizer/index.d.ts +247 -0
  332. package/node_modules/parse5/dist/tokenizer/index.js +2710 -0
  333. package/node_modules/parse5/dist/tokenizer/preprocessor.d.ts +36 -0
  334. package/node_modules/parse5/dist/tokenizer/preprocessor.js +196 -0
  335. package/node_modules/parse5/dist/tree-adapters/default.d.ts +84 -0
  336. package/node_modules/parse5/dist/tree-adapters/default.js +173 -0
  337. package/node_modules/parse5/dist/tree-adapters/interface.d.ts +255 -0
  338. package/node_modules/parse5/dist/tree-adapters/interface.js +1 -0
  339. package/node_modules/parse5/package.json +50 -0
  340. package/node_modules/undici-types/LICENSE +21 -0
  341. package/node_modules/undici-types/README.md +6 -0
  342. package/node_modules/undici-types/agent.d.ts +31 -0
  343. package/node_modules/undici-types/api.d.ts +43 -0
  344. package/node_modules/undici-types/balanced-pool.d.ts +29 -0
  345. package/node_modules/undici-types/cache.d.ts +36 -0
  346. package/node_modules/undici-types/client.d.ts +108 -0
  347. package/node_modules/undici-types/connector.d.ts +34 -0
  348. package/node_modules/undici-types/content-type.d.ts +21 -0
  349. package/node_modules/undici-types/cookies.d.ts +28 -0
  350. package/node_modules/undici-types/diagnostics-channel.d.ts +66 -0
  351. package/node_modules/undici-types/dispatcher.d.ts +256 -0
  352. package/node_modules/undici-types/env-http-proxy-agent.d.ts +21 -0
  353. package/node_modules/undici-types/errors.d.ts +149 -0
  354. package/node_modules/undici-types/eventsource.d.ts +61 -0
  355. package/node_modules/undici-types/fetch.d.ts +209 -0
  356. package/node_modules/undici-types/file.d.ts +39 -0
  357. package/node_modules/undici-types/filereader.d.ts +54 -0
  358. package/node_modules/undici-types/formdata.d.ts +108 -0
  359. package/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  360. package/node_modules/undici-types/global-origin.d.ts +7 -0
  361. package/node_modules/undici-types/handlers.d.ts +15 -0
  362. package/node_modules/undici-types/header.d.ts +4 -0
  363. package/node_modules/undici-types/index.d.ts +71 -0
  364. package/node_modules/undici-types/interceptors.d.ts +17 -0
  365. package/node_modules/undici-types/mock-agent.d.ts +50 -0
  366. package/node_modules/undici-types/mock-client.d.ts +25 -0
  367. package/node_modules/undici-types/mock-errors.d.ts +12 -0
  368. package/node_modules/undici-types/mock-interceptor.d.ts +93 -0
  369. package/node_modules/undici-types/mock-pool.d.ts +25 -0
  370. package/node_modules/undici-types/package.json +55 -0
  371. package/node_modules/undici-types/patch.d.ts +33 -0
  372. package/node_modules/undici-types/pool-stats.d.ts +19 -0
  373. package/node_modules/undici-types/pool.d.ts +39 -0
  374. package/node_modules/undici-types/proxy-agent.d.ts +28 -0
  375. package/node_modules/undici-types/readable.d.ts +65 -0
  376. package/node_modules/undici-types/retry-agent.d.ts +8 -0
  377. package/node_modules/undici-types/retry-handler.d.ts +116 -0
  378. package/node_modules/undici-types/util.d.ts +18 -0
  379. package/node_modules/undici-types/webidl.d.ts +228 -0
  380. package/node_modules/undici-types/websocket.d.ts +150 -0
  381. package/package.json +72 -0
  382. package/scripts/rebuild-forme.mjs +61 -0
  383. package/src/assets/adapter.ts +122 -0
  384. package/src/assets/files.ts +378 -0
  385. package/src/assets/import-worker.ts +294 -0
  386. package/src/assets/imports.ts +124 -0
  387. package/src/assets/index.ts +60 -0
  388. package/src/assets/store.ts +798 -0
  389. package/src/assets/usage.ts +118 -0
  390. package/src/cli/check.ts +25 -0
  391. package/src/cli/init.ts +119 -0
  392. package/src/cli/lock.ts +34 -0
  393. package/src/cli/main.ts +118 -0
  394. package/src/cli/process.ts +19 -0
  395. package/src/cli/start.ts +96 -0
  396. package/src/cli/update.ts +348 -0
  397. package/src/cli/workspace.ts +94 -0
  398. package/src/document/index.tsx +641 -0
  399. package/src/document/page.tsx +53 -0
  400. package/src/document/text-targets.tsx +162 -0
  401. package/src/media/files.ts +124 -0
  402. package/src/media/render.ts +63 -0
  403. package/src/rendering/resolve-sources.ts +84 -0
  404. package/src/runtime/jsx-dev-runtime.ts +2 -0
  405. package/src/runtime/jsx-runtime.ts +2 -0
  406. package/src/runtime/paths.ts +12 -0
  407. package/src/server/assets-cli.ts +162 -0
  408. package/src/server/assets-http.ts +100 -0
  409. package/src/server/client.ts +50 -0
  410. package/src/server/clipboard.ts +22 -0
  411. package/src/server/comments-cli.ts +64 -0
  412. package/src/server/comments.ts +130 -0
  413. package/src/server/create-cli.ts +33 -0
  414. package/src/server/create.ts +228 -0
  415. package/src/server/dependencies.ts +91 -0
  416. package/src/server/documents.ts +143 -0
  417. package/src/server/edits.ts +249 -0
  418. package/src/server/export-batch.ts +105 -0
  419. package/src/server/export-errors.ts +2 -0
  420. package/src/server/export-file.ts +57 -0
  421. package/src/server/export-inputs.ts +66 -0
  422. package/src/server/export-preview.ts +69 -0
  423. package/src/server/export.ts +32 -0
  424. package/src/server/exports.ts +283 -0
  425. package/src/server/files.ts +21 -0
  426. package/src/server/guides.ts +71 -0
  427. package/src/server/materials.ts +39 -0
  428. package/src/server/media-cli.ts +73 -0
  429. package/src/server/media-mutations.ts +168 -0
  430. package/src/server/pptx.ts +160 -0
  431. package/src/server/preflight.ts +129 -0
  432. package/src/server/projects-cli.ts +29 -0
  433. package/src/server/projects.ts +187 -0
  434. package/src/server/render-error.ts +9 -0
  435. package/src/server/render-source.ts +24 -0
  436. package/src/server/render.ts +48 -0
  437. package/src/server/review-cli.ts +40 -0
  438. package/src/server/review.ts +161 -0
  439. package/src/server/selection.ts +23 -0
  440. package/src/server/source-overrides.ts +97 -0
  441. package/src/server/templates-cli.ts +51 -0
  442. package/src/server/templates.ts +186 -0
  443. package/src/server/text-layout.ts +41 -0
  444. package/src/server/text-source.ts +307 -0
  445. package/src/server/themes-cli.ts +59 -0
  446. package/src/server/themes.ts +215 -0
  447. package/src/server/ttf2eot.d.ts +3 -0
  448. package/src/server/worker.ts +166 -0
  449. package/src/server/workspace.ts +242 -0
  450. package/src/shared/anchors.ts +69 -0
  451. package/src/shared/assets.ts +154 -0
  452. package/src/shared/export.ts +34 -0
  453. package/src/shared/media.ts +33 -0
  454. package/src/shared/projects.ts +19 -0
  455. package/src/shared/selection.ts +94 -0
  456. package/src/shared/skill-index.ts +14 -0
  457. package/src/shared/starters.ts +19 -0
  458. package/src/shared/templates.ts +18 -0
  459. package/src/shared/themes.ts +24 -0
  460. package/src/shared/types.ts +39 -0
  461. package/src/template/index.ts +27 -0
  462. package/src/themes/index.ts +3 -0
  463. package/src/themes/neutral.ts +20 -0
  464. package/src/themes/types.ts +110 -0
  465. package/starter/assets/brand/wordmark.png +0 -0
  466. package/starter/assets/fonts/InterUI-LICENSE.txt +93 -0
  467. package/starter/assets/fonts/InterUI-Medium.ttf +0 -0
  468. package/starter/assets/fonts/InterUI-Regular.ttf +0 -0
  469. package/starter/assets/fonts/InterUI-source.json +19 -0
  470. package/starter/assets/fonts/OpenDocMono-Regular.ttf +0 -0
  471. package/starter/assets/fonts/OpenDocSans-Italic.ttf +0 -0
  472. package/starter/assets/fonts/OpenDocSans-Regular.ttf +0 -0
  473. package/starter/assets/fonts/OpenDocSans-Semibold.ttf +0 -0
  474. package/starter/assets/fonts/OpenDocSans-SemiboldItalic.ttf +0 -0
  475. package/starter/assets/fonts/OpenDocSerif-Italic.ttf +0 -0
  476. package/starter/assets/fonts/OpenDocSerif-Regular.ttf +0 -0
  477. package/starter/assets/fonts/OpenDocSerif-Semibold.ttf +0 -0
  478. package/starter/assets/fonts/OpenDocSerif-SemiboldItalic.ttf +0 -0
  479. package/starter/assets/fonts/SourceCode-LICENSE.md +93 -0
  480. package/starter/assets/fonts/SourceSans-LICENSE.md +93 -0
  481. package/starter/assets/fonts/SourceSerif-LICENSE.md +93 -0
  482. package/starter/assets/fonts/geist/OFL.txt +93 -0
  483. package/starter/assets/fonts/geist/asset.json +7 -0
  484. package/starter/assets/fonts/geist/files/1a9874b3be0fc168692a3d2327bccb4d28835653d3b91537a755296a467a83e3.ttf +0 -0
  485. package/starter/assets/fonts/geist/files/a8eefb873ba9c9020665f8a98302697ce1f3b79ab2deef6ee508c0ca6a82e876.ttf +0 -0
  486. package/starter/assets/fonts/geist/files/ccce59465ae5c61930ada5453834f60500fbd95084d85db63e0e65fad0125455.ttf +0 -0
  487. package/starter/assets/fonts/geist/files/f5e95110d70593672515080bee9148463ada0a7f77b89ed65a3d43cb2b0ff83a.pdf +0 -0
  488. package/starter/assets/fonts/geist/revisions/9a2bc12fb2f23cb27bc227087e63e1407bb804ee0586480bd6b7966ec69fb474.json +60 -0
  489. package/starter/assets/fonts/inter/OFL.txt +93 -0
  490. package/starter/assets/fonts/inter/asset.json +7 -0
  491. package/starter/assets/fonts/inter/files/1b08e7fc267a5c7e1d614100f604b83e7e8a0be241f0f288faa2b3ac93a683ba.ttf +0 -0
  492. package/starter/assets/fonts/inter/files/5b6f0c6f26e5c554a64cdcc3a9b5d802b7f9aec6206f1dbcfcdcad7b5860a2a9.ttf +0 -0
  493. package/starter/assets/fonts/inter/files/957db8560d510a198a7d0333fae7b6b444b00c20801581126273978d778eb3c3.pdf +0 -0
  494. package/starter/assets/fonts/inter/files/b37284b5701b6b168dfc770aa1a4ac492106422fd3ba76bc7641e37434e8019c.ttf +0 -0
  495. package/starter/assets/fonts/inter/files/c1811d32ac0f6eed1bbf57529f2ecdfc6c717d48a969dd864942436315a1b198.ttf +0 -0
  496. package/starter/assets/fonts/inter/files/e7a1aaf7eda9f2fad4131725fa556265ec75ca7b2d756260173a040363e8d4f7.ttf +0 -0
  497. package/starter/assets/fonts/inter/files/ef8f755d933b9310804cc9152f1f18cb2ac460d6b05054ec913d889c9f11f79e.ttf +0 -0
  498. package/starter/assets/fonts/inter/revisions/600391517c413963b71e278a57c26c40366c81fa3939a6b9755f446206766d12.json +99 -0
  499. package/starter/assets/fonts/inter/source.json +57 -0
  500. package/starter/assets/fonts/lato/OFL.txt +93 -0
  501. package/starter/assets/fonts/lato/asset.json +7 -0
  502. package/starter/assets/fonts/lato/files/4a6b566dbb28adb473a8789ce5169306f42f0c8a070ac92bae93636f36348b0d.pdf +0 -0
  503. package/starter/assets/fonts/lato/files/5adeb6b334d8fb99ef053bc052b952773d544315e0e1d668a12c0ce8bd51375c.ttf +0 -0
  504. package/starter/assets/fonts/lato/files/62c1b7f0d2e74b45960154c3520efc337b553db0961bfdc950d5618334596cc8.ttf +0 -0
  505. package/starter/assets/fonts/lato/files/71b8b7decbe75a881ed267be539d402bd1e9420b799658aada4e0d1bd5af803c.ttf +0 -0
  506. package/starter/assets/fonts/lato/files/8a0aace75d33794eece4b28187bfc1df0bbd2888b5d8a56e01788c8d65d16be1.ttf +0 -0
  507. package/starter/assets/fonts/lato/files/d636e4683231f931eda222d588e944d082bfd3bdba02f928bee461c0f185b251.ttf +0 -0
  508. package/starter/assets/fonts/lato/files/e399c44efe1387100531d26c7e4800c5d12251b890d6654a3098c7c679cb1786.ttf +0 -0
  509. package/starter/assets/fonts/lato/revisions/49ccb93400a9d466fab7d9843b1ecf8916ec6d47a475dd79a597a22eb39616bc.json +99 -0
  510. package/starter/assets/fonts/lato/source.json +57 -0
  511. package/starter/assets/fonts/merriweather/OFL.txt +93 -0
  512. package/starter/assets/fonts/merriweather/asset.json +7 -0
  513. package/starter/assets/fonts/merriweather/files/1c54f91b910454251c4c2b7bd4e472e1abf265fba7ca3c0ef2eee2f41324099e.ttf +0 -0
  514. package/starter/assets/fonts/merriweather/files/8bde8da2bb7f0265e27ba0481f70bb48d0f98a976c145f2f239c648ddd6532e0.pdf +0 -0
  515. package/starter/assets/fonts/merriweather/files/90b7db4460fcd1a5ca49575c2668a793f3cd6447664d312a068d690e1c01e6bc.ttf +0 -0
  516. package/starter/assets/fonts/merriweather/files/afff81272b7653417bb6f8bef57add055b1f9fda36f27eba5f32b40752bd08da.ttf +0 -0
  517. package/starter/assets/fonts/merriweather/files/e029d3b71e5bae3877c73f4f2b15af28db16593d49b0aed2a328d37ff7075846.ttf +0 -0
  518. package/starter/assets/fonts/merriweather/files/e9864a6790bf712a04e20f3662b206a1535186ed3e877fd859dd5fb9682335df.ttf +0 -0
  519. package/starter/assets/fonts/merriweather/files/fa71baebdd20a7d0de2e5e445a5922530fe9e1d740efbe791f113b682d3cb093.ttf +0 -0
  520. package/starter/assets/fonts/merriweather/revisions/1888e390b3e4f38a3d7cd2dc1bb805aeb6ce13f986a97656f0265fd436bc91d2.json +99 -0
  521. package/starter/assets/fonts/merriweather/source.json +57 -0
  522. package/starter/assets/fonts/open-sans/OFL.txt +92 -0
  523. package/starter/assets/fonts/open-sans/asset.json +7 -0
  524. package/starter/assets/fonts/open-sans/files/1bc0594a83762b2c25d38915a34464b7fec6088298ca22d151757bf98d6700ec.ttf +0 -0
  525. package/starter/assets/fonts/open-sans/files/47ed1cfaa7ffca04a04ab850b2938fd52c09d1b44cfa3e2980878e166b0cbd87.ttf +0 -0
  526. package/starter/assets/fonts/open-sans/files/574939af301f07df8e21cfff279465c5981dd9d9cf62086f7515897df951c6f5.pdf +0 -0
  527. package/starter/assets/fonts/open-sans/files/6d3884d0d57c1b67e9c50c54eca7b69c535c114e76bd7a9cfda0258588185553.ttf +0 -0
  528. package/starter/assets/fonts/open-sans/files/733eb93b167e6d45de09aa768f6c0355647c2c26f5416dbc7407a08ed41e81c6.ttf +0 -0
  529. package/starter/assets/fonts/open-sans/files/75367e6da7d914eaed87883ba51b2a2b5816b5cdbb39f96ec5c81a5b032bfd5a.ttf +0 -0
  530. package/starter/assets/fonts/open-sans/files/ff4fdc11204e0edd14e9a0bb6c374b847a9093b0ec2c16702e03afca79ac4ef7.ttf +0 -0
  531. package/starter/assets/fonts/open-sans/revisions/bbbe3a4915b9bccbc883c0decb4097511c43b6bd09ae22a1516aff128c219bc5.json +99 -0
  532. package/starter/assets/fonts/open-sans/source.json +57 -0
  533. package/starter/assets/fonts/roboto/OFL.txt +93 -0
  534. package/starter/assets/fonts/roboto/asset.json +7 -0
  535. package/starter/assets/fonts/roboto/files/22d45d989248a624252b8382067ac56550212fa675dcdbaf12f03d297dd87a58.pdf +0 -0
  536. package/starter/assets/fonts/roboto/files/35757eaa996b3359022f47f164a67ee9eac04971af24c5b8fbd4b89e844ff190.ttf +0 -0
  537. package/starter/assets/fonts/roboto/files/4d3035883c531846bd1ce2dc89f36d932e72dc114f56062c7e3a9cdd74f3d3ea.ttf +0 -0
  538. package/starter/assets/fonts/roboto/files/be7639306a4fc4a02ce2ae2ff59eb1335e4db4a7379dd0a384ed7cc053817789.ttf +0 -0
  539. package/starter/assets/fonts/roboto/files/d2920cbb1b60a3fd11fbf22049286e43a6baf522d37fdf1e7c89562319bcfea5.ttf +0 -0
  540. package/starter/assets/fonts/roboto/files/dece7c71bbe61710787f0839c722c65e87355dd2eb4a823e6b5488121ff81e4b.ttf +0 -0
  541. package/starter/assets/fonts/roboto/files/f478ba88b0292e685e487901dfbb1401457d32d6ebee4030cdfd5698235bffa8.ttf +0 -0
  542. package/starter/assets/fonts/roboto/revisions/bda5e2d84c17313373dd2dbf3e64fe0dd450c7e1b59e6929e69557e122fe976e.json +99 -0
  543. package/starter/assets/fonts/roboto/source.json +57 -0
  544. package/starter/assets/logos/opendoc/asset.json +6 -0
  545. package/starter/assets/logos/opendoc/files/831d5ccd9eb6709cc8439ea257c03d81452e81a28a3d1eedbd6a3b7daff687b6.png +0 -0
  546. package/starter/assets/logos/opendoc/revisions/834dde8926ddb81de687254195a168bb13bfb77803307f1257de1f2228be63b2.json +33 -0
  547. package/starter/assets/ui-fonts/geist/OFL.txt +93 -0
  548. package/starter/assets/ui-fonts/geist/geist-latin-ext-wght-italic.woff2 +0 -0
  549. package/starter/assets/ui-fonts/geist/geist-latin-ext-wght-normal.woff2 +0 -0
  550. package/starter/assets/ui-fonts/geist/geist-latin-wght-italic.woff2 +0 -0
  551. package/starter/assets/ui-fonts/geist/geist-latin-wght-normal.woff2 +0 -0
  552. package/starter/assets/ui-fonts/geist/source.json +26 -0
  553. package/starter/documents/welcome/assets.json +7 -0
  554. package/starter/documents/welcome/index.tsx +160 -0
  555. package/starter/documents/welcome/media/.gitkeep +0 -0
  556. package/starter/documents/welcome/media/paper-architecture/image.png +0 -0
  557. package/starter/documents/welcome/media/paper-architecture/meta.json +9 -0
  558. package/starter/documents/welcome/media/paper-architecture/prompt.txt +1 -0
  559. package/starter/documents/welcome/media/studio-rhythm/chart.svg +2343 -0
  560. package/starter/documents/welcome/media/studio-rhythm/data.json +234 -0
  561. package/starter/documents/welcome/media/studio-rhythm/generation.json +9 -0
  562. package/starter/documents/welcome/media/studio-rhythm/image.png +0 -0
  563. package/starter/documents/welcome/media/studio-rhythm/meta.json +11 -0
  564. package/starter/documents/welcome/media/studio-rhythm/recipe.py +79 -0
  565. package/starter/documents/welcome/theme.tsx +5 -0
  566. package/starter/documents/welcome-presentation/assets.json +7 -0
  567. package/starter/documents/welcome-presentation/index.tsx +166 -0
  568. package/starter/documents/welcome-presentation/media/.gitkeep +0 -0
  569. package/starter/documents/welcome-presentation/media/paper-architecture/image.png +0 -0
  570. package/starter/documents/welcome-presentation/media/paper-architecture/meta.json +9 -0
  571. package/starter/documents/welcome-presentation/media/paper-architecture/prompt.txt +1 -0
  572. package/starter/documents/welcome-presentation/media/studio-rhythm/chart.svg +1336 -0
  573. package/starter/documents/welcome-presentation/media/studio-rhythm/data.json +234 -0
  574. package/starter/documents/welcome-presentation/media/studio-rhythm/generation.json +9 -0
  575. package/starter/documents/welcome-presentation/media/studio-rhythm/image.png +0 -0
  576. package/starter/documents/welcome-presentation/media/studio-rhythm/meta.json +13 -0
  577. package/starter/documents/welcome-presentation/media/studio-rhythm/recipe.py +49 -0
  578. package/starter/documents/welcome-presentation/theme.tsx +5 -0
  579. package/starter/projects.json +17 -0
  580. package/starter/templates/AGENTS.md +9 -0
  581. package/starter/templates/_shared/BusinessLogo.tsx +14 -0
  582. package/starter/templates/_shared/Pricing.tsx +40 -0
  583. package/starter/templates/_shared/commerce.ts +93 -0
  584. package/starter/templates/brand-guidelines/AGENTS.md +32 -0
  585. package/starter/templates/brand-guidelines/index.tsx +62 -0
  586. package/starter/templates/brand-guidelines/preview.tsx +181 -0
  587. package/starter/templates/brand-guidelines/starter.tsx +179 -0
  588. package/starter/templates/brand-guidelines/template.json +15 -0
  589. package/starter/templates/business-proposal/AGENTS.md +13 -0
  590. package/starter/templates/business-proposal/README.md +36 -0
  591. package/starter/templates/business-proposal/data.json +37 -0
  592. package/starter/templates/business-proposal/examples/long.json +142 -0
  593. package/starter/templates/business-proposal/examples/sparse.json +17 -0
  594. package/starter/templates/business-proposal/examples/typical.json +37 -0
  595. package/starter/templates/business-proposal/index.tsx +59 -0
  596. package/starter/templates/business-proposal/preview.tsx +47 -0
  597. package/starter/templates/business-proposal/schema.ts +14 -0
  598. package/starter/templates/business-proposal/starter.tsx +18 -0
  599. package/starter/templates/business-proposal/template.json +11 -0
  600. package/starter/templates/company-profile/AGENTS.md +48 -0
  601. package/starter/templates/company-profile/index.tsx +69 -0
  602. package/starter/templates/company-profile/preview.tsx +185 -0
  603. package/starter/templates/company-profile/starter.tsx +186 -0
  604. package/starter/templates/company-profile/template.json +15 -0
  605. package/starter/templates/consulting-report/AGENTS.md +11 -0
  606. package/starter/templates/consulting-report/README.md +13 -0
  607. package/starter/templates/consulting-report/RESEARCH.md +10 -0
  608. package/starter/templates/consulting-report/index.tsx +44 -0
  609. package/starter/templates/consulting-report/preview.tsx +39 -0
  610. package/starter/templates/consulting-report/starter.tsx +15 -0
  611. package/starter/templates/consulting-report/template.json +11 -0
  612. package/starter/templates/editorial-essay/AGENTS.md +11 -0
  613. package/starter/templates/editorial-essay/README.md +11 -0
  614. package/starter/templates/editorial-essay/index.tsx +30 -0
  615. package/starter/templates/editorial-essay/preview.tsx +26 -0
  616. package/starter/templates/editorial-essay/starter.tsx +15 -0
  617. package/starter/templates/editorial-essay/template.json +11 -0
  618. package/starter/templates/executive-brief/AGENTS.md +9 -0
  619. package/starter/templates/executive-brief/README.md +11 -0
  620. package/starter/templates/executive-brief/index.tsx +33 -0
  621. package/starter/templates/executive-brief/preview.tsx +37 -0
  622. package/starter/templates/executive-brief/starter.tsx +11 -0
  623. package/starter/templates/executive-brief/template.json +11 -0
  624. package/starter/templates/image-story/AGENTS.md +37 -0
  625. package/starter/templates/image-story/index.tsx +106 -0
  626. package/starter/templates/image-story/preview.tsx +33 -0
  627. package/starter/templates/image-story/starter.tsx +24 -0
  628. package/starter/templates/image-story/template.json +13 -0
  629. package/starter/templates/invoice/AGENTS.md +13 -0
  630. package/starter/templates/invoice/README.md +40 -0
  631. package/starter/templates/invoice/data.json +61 -0
  632. package/starter/templates/invoice/examples/long.json +241 -0
  633. package/starter/templates/invoice/examples/sparse.json +33 -0
  634. package/starter/templates/invoice/examples/typical.json +61 -0
  635. package/starter/templates/invoice/index.tsx +57 -0
  636. package/starter/templates/invoice/preview.tsx +12 -0
  637. package/starter/templates/invoice/schema.ts +45 -0
  638. package/starter/templates/invoice/starter.tsx +12 -0
  639. package/starter/templates/invoice/template.json +11 -0
  640. package/starter/templates/literary-text/AGENTS.md +9 -0
  641. package/starter/templates/literary-text/README.md +11 -0
  642. package/starter/templates/literary-text/index.tsx +31 -0
  643. package/starter/templates/literary-text/preview.tsx +20 -0
  644. package/starter/templates/literary-text/starter.tsx +11 -0
  645. package/starter/templates/literary-text/template.json +11 -0
  646. package/starter/templates/magazine-feature/AGENTS.md +11 -0
  647. package/starter/templates/magazine-feature/README.md +13 -0
  648. package/starter/templates/magazine-feature/index.tsx +41 -0
  649. package/starter/templates/magazine-feature/preview.tsx +34 -0
  650. package/starter/templates/magazine-feature/starter.tsx +15 -0
  651. package/starter/templates/magazine-feature/template.json +11 -0
  652. package/starter/templates/monthly-report/AGENTS.md +11 -0
  653. package/starter/templates/monthly-report/README.md +24 -0
  654. package/starter/templates/monthly-report/data.json +131 -0
  655. package/starter/templates/monthly-report/examples/long.json +519 -0
  656. package/starter/templates/monthly-report/examples/sparse.json +20 -0
  657. package/starter/templates/monthly-report/examples/typical.json +37 -0
  658. package/starter/templates/monthly-report/index.tsx +92 -0
  659. package/starter/templates/monthly-report/preview.tsx +14 -0
  660. package/starter/templates/monthly-report/schema.ts +127 -0
  661. package/starter/templates/monthly-report/starter.tsx +13 -0
  662. package/starter/templates/monthly-report/template.json +11 -0
  663. package/starter/templates/pitch-deck/AGENTS.md +32 -0
  664. package/starter/templates/pitch-deck/index.tsx +46 -0
  665. package/starter/templates/pitch-deck/preview.tsx +142 -0
  666. package/starter/templates/pitch-deck/starter.tsx +140 -0
  667. package/starter/templates/pitch-deck/template.json +15 -0
  668. package/starter/templates/proposal-deck/AGENTS.md +25 -0
  669. package/starter/templates/proposal-deck/index.tsx +52 -0
  670. package/starter/templates/proposal-deck/preview.tsx +172 -0
  671. package/starter/templates/proposal-deck/starter.tsx +168 -0
  672. package/starter/templates/proposal-deck/template.json +7 -0
  673. package/starter/templates/quotation/AGENTS.md +13 -0
  674. package/starter/templates/quotation/README.md +42 -0
  675. package/starter/templates/quotation/data.json +64 -0
  676. package/starter/templates/quotation/examples/long.json +272 -0
  677. package/starter/templates/quotation/examples/sparse.json +31 -0
  678. package/starter/templates/quotation/examples/typical.json +64 -0
  679. package/starter/templates/quotation/index.tsx +51 -0
  680. package/starter/templates/quotation/preview.tsx +12 -0
  681. package/starter/templates/quotation/schema.ts +27 -0
  682. package/starter/templates/quotation/starter.tsx +12 -0
  683. package/starter/templates/quotation/template.json +11 -0
  684. package/starter/templates/scientific-paper/AGENTS.md +11 -0
  685. package/starter/templates/scientific-paper/README.md +13 -0
  686. package/starter/templates/scientific-paper/index.tsx +47 -0
  687. package/starter/templates/scientific-paper/preview.tsx +43 -0
  688. package/starter/templates/scientific-paper/starter.tsx +15 -0
  689. package/starter/templates/scientific-paper/template.json +11 -0
  690. package/starter/themes/Specimen.tsx +54 -0
  691. package/starter/themes/civic-spectrum/components.tsx +92 -0
  692. package/starter/themes/civic-spectrum/design.md +70 -0
  693. package/starter/themes/civic-spectrum/index.ts +57 -0
  694. package/starter/themes/civic-spectrum/preview.tsx +66 -0
  695. package/starter/themes/field-manual/components.tsx +106 -0
  696. package/starter/themes/field-manual/design.md +72 -0
  697. package/starter/themes/field-manual/index.ts +57 -0
  698. package/starter/themes/field-manual/preview.tsx +82 -0
  699. package/starter/themes/index.ts +3 -0
  700. package/starter/themes/mckinsey-consulting/components.tsx +69 -0
  701. package/starter/themes/mckinsey-consulting/design.md +68 -0
  702. package/starter/themes/mckinsey-consulting/index.ts +60 -0
  703. package/starter/themes/mckinsey-consulting/preview.tsx +53 -0
  704. package/starter/themes/neutral/design.md +35 -0
  705. package/starter/themes/neutral/index.ts +21 -0
  706. package/starter/themes/neutral/preview.tsx +4 -0
  707. package/starter/themes/opendoc-neutral/components.tsx +77 -0
  708. package/starter/themes/opendoc-neutral/design.md +70 -0
  709. package/starter/themes/opendoc-neutral/index.ts +54 -0
  710. package/starter/themes/opendoc-neutral/preview.tsx +43 -0
  711. package/starter/themes/types.ts +3 -0
  712. package/tsconfig.workspace.json +24 -0
  713. package/vendor/formepdf/LICENSE +21 -0
  714. package/vendor/formepdf/README.md +97 -0
  715. package/vendor/formepdf/font-subset.patch +228 -0
  716. package/vendor/formepdf/text-writer.patch +507 -0
@@ -0,0 +1,162 @@
1
+ import { readFile, stat } from 'node:fs/promises';
2
+ import { basename, resolve } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { parseArgs } from 'node:util';
5
+ import { AssetStore } from '../assets/store';
6
+ import type { UploadFile } from '../assets/imports';
7
+ import type { AssetKind, ThemeAssetDefaults } from '../shared/assets';
8
+
9
+ const usage = `Usage: npx opendoc assets list [logo|font] [--archived]
10
+ npx opendoc assets inspect <logo|font> <id> [--revision <revision>]
11
+ npx opendoc assets import logo --file <svg-or-png> --name "Name" [--id <id>] [--description "Guidance"] [--variation-name "Name"] [--variation-description "When to use"]
12
+ npx opendoc assets import font --file <ttf-or-otf> [--file <another-face> ...] [--id <id>] [--name "Name"] [--description "Guidance"]
13
+ npx opendoc assets revise <logo|font> <id> --metadata <json-file>
14
+ npx opendoc assets add-variation <logo-id> --file <svg-or-png> --name "Name" --expected-revision <revision> [--id <variation-id>] [--description "When to use"] [--replace <variation-id>]
15
+ npx opendoc assets add-faces <font-id> --file <ttf-or-otf> [--file <another-face> ...] --expected-revision <revision>
16
+ npx opendoc assets archive <logo|font> <id> --expected-revision <revision> [--clear-defaults]
17
+ npx opendoc assets restore <logo|font> <id> --expected-revision <revision>
18
+ npx opendoc assets defaults <theme-id> [--metadata <json-file> --expected-revision <revision>]
19
+ npx opendoc assets bind <document-id> <logo|body-font|heading-font> <asset-id> [--revision <revision>] [--variation <variation-id>] [--name <logo-binding>]
20
+ npx opendoc assets unbind <document-id> <logo|body-font|heading-font> [--name <logo-binding>]
21
+
22
+ Successful commands print JSON. Inspect before editing: revisions prevent overwriting another writer.
23
+ revise metadata requires expectedRevision plus the fields to change. defaults metadata is the complete ThemeAssetDefaults object.
24
+ Binding saves an exact version now; changing a theme default affects only new documents.
25
+ See docs/ASSETS.md for file contracts and authoring examples.`;
26
+
27
+ function kind(value: string | undefined): AssetKind {
28
+ if (value !== 'logo' && value !== 'font') throw new Error('Choose asset kind logo or font.\n' + usage);
29
+ return value;
30
+ }
31
+
32
+ function role(value: string | undefined): 'logo' | 'body-font' | 'heading-font' {
33
+ if (value !== 'logo' && value !== 'body-font' && value !== 'heading-font') throw new Error('Choose document role logo, body-font, or heading-font.\n' + usage);
34
+ return value;
35
+ }
36
+
37
+ async function localFile(file: string): Promise<UploadFile> {
38
+ const path = resolve(file);
39
+ const info = await stat(path);
40
+ if (!info.isFile()) throw new Error(`Choose a regular local file: ${file}`);
41
+ if (!info.size || info.size > 100 * 1024 * 1024) throw new Error('Choose a nonempty asset file no larger than 100 MB.');
42
+ const bytes = await readFile(path);
43
+ if (!bytes.length || bytes.length > 100 * 1024 * 1024) throw new Error('Choose a nonempty asset file no larger than 100 MB.');
44
+ return { filename: basename(path), bytes };
45
+ }
46
+
47
+ async function metadata(file: string) {
48
+ const path = resolve(file);
49
+ const info = await stat(path);
50
+ if (!info.isFile() || info.size > 256_000) throw new Error('Choose a regular JSON metadata file no larger than 256 KB.');
51
+ const bytes = await readFile(path);
52
+ if (bytes.length > 256_000) throw new Error('Asset metadata must be no larger than 256 KB.');
53
+ const data: unknown = JSON.parse(bytes.toString('utf8'));
54
+ if (!data || typeof data !== 'object' || Array.isArray(data)) throw new Error('Asset metadata must be a JSON object.');
55
+ return data as Record<string, unknown>;
56
+ }
57
+
58
+ /** The CLI and HTTP routes deliberately delegate all asset rules to the same store. */
59
+ export async function runAssetsCli(args: string[], root = process.cwd()) {
60
+ const { values, positionals } = parseArgs({
61
+ args: args[0] === '--' ? args.slice(1) : args, allowPositionals: true,
62
+ options: {
63
+ help: { type: 'boolean', short: 'h' }, json: { type: 'boolean' }, archived: { type: 'boolean' },
64
+ file: { type: 'string', multiple: true }, name: { type: 'string' }, id: { type: 'string' },
65
+ description: { type: 'string' }, 'variation-name': { type: 'string' }, 'variation-description': { type: 'string' },
66
+ revision: { type: 'string' }, 'expected-revision': { type: 'string' }, metadata: { type: 'string' },
67
+ variation: { type: 'string' }, replace: { type: 'string' }, 'clear-defaults': { type: 'boolean' },
68
+ },
69
+ });
70
+ if (values.help) { console.log(values.json ? JSON.stringify({ usage }, null, 2) : usage); return; }
71
+ const [command = 'list', first, second, third] = positionals;
72
+ const store = new AssetStore(root);
73
+ const shape = (count: number | number[], flags: string[]) => {
74
+ if (!(Array.isArray(count) ? count : [count]).includes(positionals.length)) throw new Error(usage);
75
+ const unexpected = Object.keys(values).filter(key => !['json', ...flags].includes(key));
76
+ if (unexpected.length) throw new Error(`Option --${unexpected[0]} is not used by ${command}.\n${usage}`);
77
+ };
78
+ const required = (value: string | undefined, name: string) => {
79
+ if (!value?.trim()) throw new Error(`Provide --${name}.\n${usage}`);
80
+ return value;
81
+ };
82
+ const expected = () => required(values['expected-revision'], 'expected-revision');
83
+ const files = async (single = false) => {
84
+ if (!values.file?.length || (single && values.file.length !== 1)) throw new Error(`Provide ${single ? 'exactly one --file' : 'at least one --file'}.\n${usage}`);
85
+ if (values.file.length > 24) throw new Error('Import at most 24 font faces together.');
86
+ const uploads: UploadFile[] = [];
87
+ let total = 0;
88
+ for (const path of values.file) {
89
+ const upload = await localFile(path);
90
+ total += upload.bytes.byteLength;
91
+ if (total > 100 * 1024 * 1024) throw new Error('A font import must be 100 MB or smaller.');
92
+ uploads.push(upload);
93
+ }
94
+ return uploads;
95
+ };
96
+ let result: unknown;
97
+ switch (command) {
98
+ case 'list':
99
+ shape([0, 1, 2], ['archived']);
100
+ result = await store.list(first === undefined ? undefined : kind(first), values.archived ?? false);
101
+ break;
102
+ case 'inspect':
103
+ shape(3, ['revision']);
104
+ result = await store.inspect(kind(first), second, values.revision);
105
+ break;
106
+ case 'import': {
107
+ const assetKind = kind(first);
108
+ shape(2, ['file', 'id', 'name', 'description', ...(assetKind === 'logo' ? ['variation-name', 'variation-description'] : [])]);
109
+ result = assetKind === 'logo'
110
+ ? await store.createLogo({ id: values.id, name: required(values.name, 'name'), description: values.description, variationName: values['variation-name'], variationDescription: values['variation-description'] }, (await files(true))[0])
111
+ : await store.createFont({ id: values.id, name: values.name, description: values.description }, await files());
112
+ break;
113
+ }
114
+ case 'revise': {
115
+ shape(3, ['metadata']);
116
+ const input = await metadata(required(values.metadata, 'metadata'));
117
+ if (typeof input.expectedRevision !== 'string' || !input.expectedRevision) throw new Error('Revision metadata needs expectedRevision from the latest inspection.');
118
+ result = await store.revise(kind(first), second, input as Parameters<AssetStore['revise']>[2]);
119
+ break;
120
+ }
121
+ case 'add-variation':
122
+ shape(2, ['file', 'name', 'id', 'description', 'expected-revision', 'replace']);
123
+ result = await store.addVariation(first, { expectedRevision: expected(), id: values.id, name: required(values.name, 'name'), description: values.description, replaceId: values.replace }, (await files(true))[0]);
124
+ break;
125
+ case 'add-faces':
126
+ shape(2, ['file', 'expected-revision']);
127
+ result = await store.addFaces(first, { expectedRevision: expected() }, await files());
128
+ break;
129
+ case 'archive':
130
+ shape(3, ['expected-revision', 'clear-defaults']);
131
+ result = await store.archive(kind(first), second, expected(), values['clear-defaults'] ?? false);
132
+ break;
133
+ case 'restore':
134
+ shape(3, ['expected-revision']);
135
+ result = await store.restore(kind(first), second, expected());
136
+ break;
137
+ case 'defaults':
138
+ shape(2, values.metadata ? ['metadata', 'expected-revision'] : []);
139
+ result = values.metadata
140
+ ? await store.setDefaults(first, await metadata(values.metadata) as unknown as ThemeAssetDefaults, expected())
141
+ : await store.defaults(first);
142
+ break;
143
+ case 'bind': {
144
+ const documentRole = role(second);
145
+ shape(4, ['revision', ...(documentRole === 'logo' ? ['variation', 'name'] : [])]);
146
+ result = await store.bind(first, documentRole, third, { revision: values.revision, variation: values.variation, name: values.name });
147
+ break;
148
+ }
149
+ case 'unbind': {
150
+ const documentRole = role(second);
151
+ shape(3, documentRole === 'logo' ? ['name'] : []);
152
+ result = await store.unbind(first, documentRole, values.name);
153
+ break;
154
+ }
155
+ default: throw new Error(usage);
156
+ }
157
+ console.log(JSON.stringify(result, null, 2));
158
+ }
159
+
160
+ if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
161
+ runAssetsCli(process.argv.slice(2)).catch(error => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; });
162
+ }
@@ -0,0 +1,100 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { AssetStore } from '../assets/store';
4
+ import { AssetError, assertKind, assetFile, readAssetRevision, revisionFiles } from '../assets/files';
5
+ import type { UploadFile } from '../assets/imports';
6
+ import { importMedia, editMedia } from './media-mutations';
7
+ import { themeFile } from './themes';
8
+
9
+ type Send = (res: ServerResponse, value: unknown, status?: number) => void;
10
+ type Body = (req: IncomingMessage, limit?: number) => Promise<any>;
11
+ function object(value: unknown, fields: string[]): asserts value is Record<string, any> {
12
+ if (!value || typeof value !== 'object' || Array.isArray(value) || Object.keys(value).some(key => !fields.includes(key))) throw new AssetError('Invalid asset request. Reload the form and try again.');
13
+ }
14
+ /** Use the platform multipart parser, with a byte bound before parsing or publication. */
15
+ export async function assetUpload(req: IncomingMessage, multiple = false): Promise<{ metadata: Record<string, any>; files: UploadFile[] }> {
16
+ const type = req.headers['content-type'];
17
+ if (!type?.startsWith('multipart/form-data;')) throw new AssetError('Choose files using a multipart upload.');
18
+ const chunks: Buffer[] = []; let size = 0;
19
+ for await (const chunk of req) {
20
+ size += chunk.length;
21
+ if (size > 100 * 1024 * 1024) throw new AssetError('Keep the complete upload below 100 MB.', 413);
22
+ chunks.push(Buffer.from(chunk));
23
+ }
24
+ let form: FormData;
25
+ try { form = await new Response(new Uint8Array(Buffer.concat(chunks)), { headers: { 'Content-Type': type } }).formData(); }
26
+ catch { throw new AssetError('The upload was interrupted or malformed. Choose the files and try again.'); }
27
+ if ([...form.keys()].some(key => !['metadata', multiple ? 'files' : 'file'].includes(key)) || form.getAll('metadata').length !== 1) throw new AssetError('Include one metadata record and the chosen files.');
28
+ let metadata: unknown;
29
+ const raw = form.get('metadata');
30
+ if (typeof raw !== 'string' || raw.length > 32_000) throw new AssetError('The upload metadata is too large or missing.');
31
+ try { metadata = JSON.parse(raw); } catch { throw new AssetError('The upload metadata must be valid JSON.'); }
32
+ if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) throw new AssetError('Include an upload metadata object.');
33
+ const entries = form.getAll(multiple ? 'files' : 'file');
34
+ if (!entries.length || entries.length > (multiple ? 24 : 1) || entries.some(entry => typeof entry === 'string')) throw new AssetError(multiple ? 'Choose between one and 24 static font files.' : 'Choose one image file.');
35
+ const files = await Promise.all((entries as File[]).map(async file => ({ filename: file.name, bytes: new Uint8Array(await file.arrayBuffer()) })));
36
+ return { metadata: metadata as Record<string, any>, files };
37
+ }
38
+
39
+ /** Called after the server's local-session write guard. App and CLI share AssetStore. */
40
+ export async function handleAssetRequest(root: string, store: AssetStore, req: IncomingMessage, res: ServerResponse, url: URL, json: Send, body: Body, changed: () => void): Promise<boolean> {
41
+ if (url.pathname === '/api/assets' && req.method === 'GET') {
42
+ const kind = url.searchParams.get('kind') ?? undefined; if (kind) assertKind(kind);
43
+ json(res, await store.list(kind as 'logo' | 'font' | undefined, url.searchParams.get('archived') === 'true')); return true;
44
+ }
45
+ const defaults = url.pathname.match(/^\/api\/themes\/([a-z0-9-]+)\/assets$/);
46
+ if (defaults) {
47
+ await themeFile(root, defaults[1], 'index.ts');
48
+ if (req.method === 'GET') { json(res, await store.defaults(defaults[1])); return true; }
49
+ if (req.method === 'PUT') { const input = await body(req); object(input, ['defaults', 'expectedRevision']); json(res, await store.setDefaults(defaults[1], input.defaults, input.expectedRevision)); changed(); return true; }
50
+ }
51
+ const media = url.pathname.match(/^\/api\/materials\/([a-z0-9-]+)\/(import|meta)$/);
52
+ if (media?.[2] === 'import' && req.method === 'POST') {
53
+ const upload = await assetUpload(req); object(upload.metadata, ['id', 'title', 'description', 'kind', 'alt', 'attribution', 'sources']);
54
+ json(res, await importMedia(root, media[1], upload.metadata as Parameters<typeof importMedia>[2], upload.files[0]), 201); changed(); return true;
55
+ }
56
+ if (media?.[2] === 'meta' && req.method === 'PATCH') {
57
+ const input = await body(req); object(input, ['expectedRevision', 'meta']);
58
+ json(res, await editMedia(root, media[1], url.searchParams.get('item') ?? '', input as Parameters<typeof editMedia>[3])); changed(); return true;
59
+ }
60
+ const route = url.pathname.match(/^\/api\/assets\/(logo|font)(?:\/([a-z0-9-]+)(?:\/(file|variations|faces|archive|restore))?)?$/);
61
+ if (!route) return false;
62
+ const [, kindValue, id, action] = route; assertKind(kindValue); const kind = kindValue;
63
+ if (!id && req.method === 'POST') {
64
+ const { metadata, files } = await assetUpload(req, kind === 'font');
65
+ object(metadata, kind === 'logo' ? ['id', 'name', 'description', 'variationName', 'variationDescription'] : ['id', 'name', 'description']);
66
+ const result = kind === 'logo' ? await store.createLogo(metadata as Parameters<AssetStore['createLogo']>[0], files[0]) : await store.createFont(metadata, files);
67
+ json(res, result, 201); changed(); return true;
68
+ }
69
+ if (!id) throw new AssetError('Asset not found.', 404);
70
+ if (req.method === 'GET' && !action) { json(res, await store.inspect(kind, id, url.searchParams.get('revision') ?? undefined)); return true; }
71
+ if (req.method === 'GET' && action === 'file') {
72
+ const revision = url.searchParams.get('revision'); if (!revision) throw new AssetError('Choose the saved version for this asset file.');
73
+ const asset = readAssetRevision(root, kind, id, revision);
74
+ const file = revisionFiles(asset).find(file => file.file === url.searchParams.get('file'));
75
+ if (!file) throw new AssetError('This file is not part of the chosen asset version.', 404);
76
+ const bytes = await readFile(assetFile(root, kind, id, file));
77
+ const extension = file.file.split('.').at(-1)!;
78
+ const mime = ({ png: 'image/png', svg: 'image/svg+xml', ttf: 'font/ttf', otf: 'font/otf', pdf: 'application/pdf' } as Record<string, string>)[extension];
79
+ res.writeHead(200, { 'Content-Type': mime, 'Content-Length': bytes.length, 'Content-Disposition': `${extension === 'svg' ? 'attachment' : 'inline'}; filename="${id}.${extension}"`, 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff', ...(extension === 'svg' ? { 'Content-Security-Policy': "default-src 'none'; sandbox" } : {}) });
80
+ res.end(bytes); return true;
81
+ }
82
+ if (req.method === 'PATCH' && !action) {
83
+ const input = await body(req); object(input, ['expectedRevision', 'name', 'description', 'defaultVariation', 'variation', 'removeVariation', 'removeFace']);
84
+ json(res, await store.revise(kind, id, input as Parameters<AssetStore['revise']>[2])); changed(); return true;
85
+ }
86
+ if (req.method === 'POST' && (action === 'archive' || action === 'restore')) {
87
+ const input = await body(req); object(input, action === 'archive' ? ['expectedRevision', 'clearDefaults'] : ['expectedRevision']);
88
+ if (input.clearDefaults !== undefined && typeof input.clearDefaults !== 'boolean') throw new AssetError('Confirm whether theme defaults should be cleared.');
89
+ json(res, action === 'archive' ? await store.archive(kind, id, input.expectedRevision, input.clearDefaults) : await store.restore(kind, id, input.expectedRevision)); changed(); return true;
90
+ }
91
+ if (req.method === 'POST' && kind === 'logo' && action === 'variations') {
92
+ const { metadata, files } = await assetUpload(req); object(metadata, ['expectedRevision', 'id', 'name', 'description', 'replaceId']);
93
+ json(res, await store.addVariation(id, metadata as Parameters<AssetStore['addVariation']>[1], files[0])); changed(); return true;
94
+ }
95
+ if (req.method === 'POST' && kind === 'font' && action === 'faces') {
96
+ const { metadata, files } = await assetUpload(req, true); object(metadata, ['expectedRevision']);
97
+ json(res, await store.addFaces(id, metadata as Parameters<AssetStore['addFaces']>[1], files)); changed(); return true;
98
+ }
99
+ throw new AssetError('Asset action not found.', 404);
100
+ }
@@ -0,0 +1,50 @@
1
+ import { createReadStream, existsSync } from 'node:fs';
2
+ import { readFile, stat } from 'node:fs/promises';
3
+ import type { IncomingMessage, ServerResponse } from 'node:http';
4
+ import { extname, relative, resolve, sep } from 'node:path';
5
+ import { containedFile } from './files';
6
+
7
+ const contentTypes: Record<string, string> = {
8
+ '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.mjs': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8',
9
+ '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.webp': 'image/webp',
10
+ '.ico': 'image/x-icon', '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/ttf', '.otf': 'font/otf', '.wasm': 'application/wasm', '.json': 'application/json',
11
+ };
12
+
13
+ /** Production serves only the built browser app; authoring and PDF APIs stay live. */
14
+ export async function builtClient(root: string) {
15
+ const directory = resolve(root, 'dist');
16
+ const repair = existsSync(resolve(root, 'vite.config.ts')) ? 'Run pnpm build, then pnpm start.' : 'Run npm ci in your workspace, then npx opendoc start.';
17
+ try { await readFile(await containedFile(directory, resolve(directory, 'index.html'))); }
18
+ catch { throw new Error(`The built OpenDoc app is missing. ${repair}`); }
19
+ return async (req: IncomingMessage, res: ServerResponse) => {
20
+ const fail = (status: number, message: string) => {
21
+ res.writeHead(status, { 'Content-Type': 'text/plain; charset=utf-8', 'Cache-Control': 'no-store' });
22
+ res.end(req.method === 'HEAD' ? undefined : message);
23
+ };
24
+ if (req.method !== 'GET' && req.method !== 'HEAD') { fail(405, 'Method not allowed.'); return; }
25
+ let path: string;
26
+ try { path = decodeURIComponent(new URL(req.url ?? '/', 'http://localhost').pathname); }
27
+ catch { fail(400, 'Invalid local path.'); return; }
28
+ if (path.includes('\\') || path.includes('\0') || path.split('/').some(part => part.startsWith('.'))) { fail(404, 'Not found.'); return; }
29
+ const file = resolve(directory, `.${path === '/' ? '/index.html' : path}`);
30
+ const local = relative(directory, file);
31
+ if (local === '..' || local.startsWith(`..${sep}`)) { fail(404, 'Not found.'); return; }
32
+ try {
33
+ const actual = await containedFile(directory, file);
34
+ const info = await stat(actual);
35
+ if (!info.isFile()) { fail(404, 'Not found.'); return; }
36
+ res.writeHead(200, {
37
+ 'Content-Type': contentTypes[extname(actual)] ?? 'application/octet-stream', 'Content-Length': info.size,
38
+ 'Cache-Control': path.startsWith('/assets/') ? 'public, max-age=31536000, immutable' : 'no-cache',
39
+ 'X-Content-Type-Options': 'nosniff',
40
+ });
41
+ if (req.method === 'HEAD') { res.end(); return; }
42
+ const stream = createReadStream(actual);
43
+ stream.on('error', () => res.destroy());
44
+ stream.pipe(res);
45
+ } catch (error) {
46
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT' || (error instanceof Error && error.message === 'Path is outside the workspace.')) fail(404, 'Not found.');
47
+ else fail(500, `This app file could not be read. ${repair}`);
48
+ }
49
+ };
50
+ }
@@ -0,0 +1,22 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+
4
+ export const canCopyFile = process.platform === 'darwin';
5
+
6
+ // Pass paths as arguments, never as executable script text. A named pasteboard
7
+ // lets native integration checks exercise this without changing the user's clipboard.
8
+ export async function copyFileToClipboard(path: string, pasteboardName?: string) {
9
+ if (!canCopyFile) throw new Error('Copying files to the clipboard is currently available on macOS. Use Download a copy instead.');
10
+ const script = `ObjC.import('AppKit');
11
+ function run(argv) {
12
+ var url = $.NSURL.fileURLWithPath($(argv[0]));
13
+ var board = argv.length > 1 ? $.NSPasteboard.pasteboardWithName($(argv[1])) : $.NSPasteboard.generalPasteboard;
14
+ board.clearContents;
15
+ if (!board.writeObjects($.NSArray.arrayWithObject(url)) || ObjC.unwrap(board.stringForType('public.file-url')) !== ObjC.unwrap(url.absoluteString)) throw new Error('The clipboard could not accept this file.');
16
+ }`;
17
+ try {
18
+ await promisify(execFile)('/usr/bin/osascript', ['-l', 'JavaScript', '-e', script, path, ...(pasteboardName ? [pasteboardName] : [])], { timeout: 10_000 });
19
+ } catch {
20
+ throw new Error('The file could not be copied to the clipboard. Try again or use Download a copy.');
21
+ }
22
+ }
@@ -0,0 +1,64 @@
1
+ import { readComments, changeComment, addComment } from './comments';
2
+ import { readJSON } from './files';
3
+ import { resolve } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { parseArgs } from 'node:util';
6
+ import { rm } from 'node:fs/promises';
7
+ import { renderOnce, validId } from './render';
8
+ import { captureExportInputs } from './export-inputs';
9
+ import { getBlock, type DocumentState } from '../shared/types';
10
+
11
+ const usage = 'Usage: npx opendoc comments list <doc> [--json]\n npx opendoc comments resolve <doc> <comment-id> [--json]\n npx opendoc comments reopen <doc> <comment-id> [--json]\n npx opendoc comments add <doc> <block-id> "text" [--json]';
12
+
13
+ async function request<T>(origin: string, path: string, init?: RequestInit): Promise<T> {
14
+ let response: Response;
15
+ try { response = await fetch(`${origin}${path}`, { ...init, signal: AbortSignal.timeout(5_000) }); }
16
+ catch { throw new Error('OpenDoc is unavailable. Start or restart it before adding a comment.'); }
17
+ const result = await response.json();
18
+ if (!response.ok) throw new Error(result.error ?? 'OpenDoc could not save this comment.');
19
+ return result as T;
20
+ }
21
+
22
+ export async function runCommentsCli(args: string[], root = process.cwd(), options: { mode?: 'auto' | 'direct' } = {}): Promise<void> {
23
+ const { values, positionals } = parseArgs({ args: args[0] === '--' ? args.slice(1) : args, allowPositionals: true, options: {
24
+ json: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
25
+ } });
26
+ if (values.help) { console.log(values.json ? JSON.stringify({ usage }, null, 2) : usage); return; }
27
+ const [action, doc, target, ...words] = positionals;
28
+ if (!doc || !validId(doc)) throw new Error(usage);
29
+ else if (action === 'list' && positionals.length === 2) console.log(JSON.stringify(await readComments(root, doc), null, 2));
30
+ else if ((action === 'resolve' || action === 'reopen') && target && positionals.length === 3) {
31
+ const comment = (await readComments(root, doc)).find(c => c.id === target);
32
+ if (!comment) throw new Error('Comment not found.');
33
+ const comments = await changeComment(root, doc, target, action === 'resolve' ? 'resolved' : 'open', comment.version);
34
+ console.log(values.json ? JSON.stringify(comments.find(c => c.id === target), null, 2) : `${action === 'resolve' ? 'Resolved' : 'Reopened'} ${target}`);
35
+ } else if (action === 'add' && target && words.length) {
36
+ if (options.mode === 'direct') {
37
+ const unchanged = await captureExportInputs(root, doc);
38
+ const rendered = await renderOnce(root, doc);
39
+ try {
40
+ const block = getBlock(rendered.artifact, target);
41
+ if (!block) throw new Error('The target block does not exist in the current document. Inspect its review output to find the block ID.');
42
+ const comments = await addComment(root, doc, { blockId: target, text: words.join(' '), quote: block.text }, unchanged);
43
+ console.log(values.json ? JSON.stringify(comments, null, 2) : `Added comment on ${target}`);
44
+ } finally { await rm(rendered.directory, { recursive: true, force: true }); }
45
+ return;
46
+ }
47
+ const server = await readJSON<{ origin: string; token: string } | null>(resolve(root, '.opendoc/server.json'), null);
48
+ if (!server) throw new Error('Start OpenDoc before adding a comment, so the target can be verified.');
49
+ if (typeof server.origin !== 'string' || !/^http:\/\/127\.0\.0\.1:\d+$/.test(server.origin) || typeof server.token !== 'string' || !server.token) throw new Error('The local OpenDoc session file is invalid. Restart OpenDoc before adding a comment.');
50
+ const docs = await request<DocumentState[]>(server.origin, '/api/documents');
51
+ const state = docs.find(d => d.id === doc);
52
+ const block = getBlock(state?.artifact, target);
53
+ if (state?.status !== 'ready' || !block) throw new Error('Target is unavailable or still rendering.');
54
+ const comments = await request(server.origin, `/api/documents/${doc}/comments`, {
55
+ method: 'POST', headers: { 'Content-Type': 'application/json', Origin: server.origin, 'X-OpenDoc-Token': server.token },
56
+ body: JSON.stringify({ blockId: target, text: words.join(' '), hash: state.artifact!.hash }),
57
+ });
58
+ console.log(values.json ? JSON.stringify(comments, null, 2) : `Added comment on ${target}`);
59
+ } else throw new Error(`Unknown comments command or missing arguments.\n${usage}`);
60
+ }
61
+
62
+ if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
63
+ runCommentsCli(process.argv.slice(2)).catch(error => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; });
64
+ }
@@ -0,0 +1,130 @@
1
+ import { mkdir, rm } from 'node:fs/promises';
2
+ import { lstatSync, readFileSync, rmSync } from 'node:fs';
3
+ import { resolve, dirname } from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { atomicWrite, readJSON, containedFile } from './files';
6
+ import { documentEntry } from './render';
7
+ import type { Comment } from '../shared/types';
8
+ import type { TextAnchor } from '../shared/selection';
9
+
10
+ export class Conflict extends Error {}
11
+ const validDate = (value: unknown): value is string => typeof value === 'string' && Number.isFinite(Date.parse(value));
12
+ const nonempty = (value: unknown): value is string => typeof value === 'string' && value.length > 0;
13
+
14
+ function validAnchor(anchor: unknown): anchor is TextAnchor {
15
+ if (!anchor || typeof anchor !== 'object') return false;
16
+ const value = anchor as TextAnchor;
17
+ return typeof value.targetId === 'string' && value.targetId.length > 0 && value.targetId.length <= 1000
18
+ && Number.isInteger(value.start) && Number.isInteger(value.end) && value.start >= 0 && value.end > value.start
19
+ && typeof value.quote === 'string' && value.quote.length > 0 && value.quote.length <= 8000
20
+ && value.end - value.start === value.quote.length
21
+ && typeof value.prefix === 'string' && value.prefix.length <= 40
22
+ && typeof value.suffix === 'string' && value.suffix.length <= 40;
23
+ }
24
+ export async function readComments(root: string, id: string): Promise<Comment[]> {
25
+ const entry = await documentEntry(root, id);
26
+ const file = resolve(dirname(entry), 'comments.json');
27
+ try { await containedFile(dirname(entry), file); } catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }
28
+ const rows = await readJSON<unknown>(file, []);
29
+ if (!Array.isArray(rows) || new Set(rows.map(row => row?.id)).size !== rows.length || rows.some(row => !row
30
+ || !nonempty(row.id) || !nonempty(row.blockId) || !nonempty(row.text) || typeof row.quote !== 'string'
31
+ || !['open', 'resolved', 'deleted'].includes(row.status) || !Number.isInteger(row.version) || row.version < 1
32
+ || !validDate(row.createdAt) || !validDate(row.updatedAt) || !Array.isArray(row.history) || !row.history.length
33
+ || row.history.some((event: Comment['history'][number]) => !event || !validDate(event.at)
34
+ || !['created', 'resolved', 'reopened', 'edited', 'deleted'].includes(event.action)
35
+ || (event.previousText !== undefined && typeof event.previousText !== 'string'))
36
+ || (row.anchor !== undefined && !validAnchor(row.anchor)))) throw new Error(`Invalid comments file for ${id}. Restore valid JSON; existing feedback has not been overwritten.`);
37
+ return rows as Comment[];
38
+ }
39
+
40
+ /** A crash before owner publication must not permanently strand a document. */
41
+ function removeAbandonedLock(lock: string) {
42
+ try {
43
+ const before = lstatSync(lock);
44
+ let pid: number | undefined;
45
+ try { pid = JSON.parse(readFileSync(resolve(lock, 'owner.json'), 'utf8')).pid; } catch { /* An interrupted acquisition may have no owner yet. */ }
46
+ if (Number.isSafeInteger(pid) && pid! > 0) {
47
+ try { process.kill(pid!, 0); return; } catch (error) {
48
+ if ((error as NodeJS.ErrnoException).code !== 'ESRCH') return;
49
+ }
50
+ } else if (Date.now() - before.mtimeMs < 30_000) return;
51
+ const current = lstatSync(lock);
52
+ if (current.dev === before.dev && current.ino === before.ino && current.mtimeMs === before.mtimeMs) rmSync(lock, { recursive: true, force: true });
53
+ } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
54
+ }
55
+
56
+ export async function withCommentLock<T>(root: string, id: string, operation: () => Promise<T>) {
57
+ const lock = resolve(root, '.opendoc/locks', `${id}.lock`);
58
+ await mkdir(dirname(lock), { recursive: true });
59
+ let acquired = false;
60
+ for (let attempt = 0; attempt < 80; attempt++) {
61
+ try {
62
+ await mkdir(lock); acquired = true;
63
+ await atomicWrite(resolve(lock, 'owner.json'), JSON.stringify({ pid: process.pid }));
64
+ break;
65
+ } catch (e) {
66
+ if (acquired) { await rm(lock, { recursive: true, force: true }); throw e; }
67
+ if ((e as NodeJS.ErrnoException).code !== 'EEXIST') throw e;
68
+ removeAbandonedLock(lock);
69
+ await new Promise(r => setTimeout(r, 25));
70
+ }
71
+ }
72
+ if (!acquired) throw new Conflict('Feedback is being updated. Retry in a moment.');
73
+ try {
74
+ return await operation();
75
+ } finally { await rm(lock, { recursive: true, force: true }); }
76
+ }
77
+
78
+ async function mutate(root: string, id: string, fn: (rows: Comment[]) => Comment[], unchanged?: () => boolean) {
79
+ await documentEntry(root, id);
80
+ return withCommentLock(root, id, async () => {
81
+ const entry = await documentEntry(root, id);
82
+ const updated = fn(await readComments(root, id));
83
+ if (unchanged && !unchanged()) throw new Conflict('The document changed while verifying the comment target. Retry against the current source.');
84
+ await atomicWrite(resolve(dirname(entry), 'comments.json'), JSON.stringify(updated, null, 2) + '\n');
85
+ return updated;
86
+ });
87
+ }
88
+
89
+ export async function addComment(root: string, id: string, input: { blockId: string; text: string; quote: string; anchor?: TextAnchor; exactQuote?: boolean }, unchanged?: () => boolean) {
90
+ if (typeof input.text !== 'string' || !input.text.trim() || input.text.length > 8000) throw new Error('Write a comment between 1 and 8,000 characters.');
91
+ if (typeof input.blockId !== 'string' || !input.blockId) throw new Error('Select a document element first.');
92
+ if (typeof input.quote !== 'string') throw new Error('Select the document element again before commenting.');
93
+ if (input.anchor !== undefined && !validAnchor(input.anchor)) throw new Error('Select the phrase again before commenting.');
94
+ const at = new Date().toISOString();
95
+ return mutate(root, id, rows => [...rows, { id: randomUUID(), blockId: input.blockId, text: input.text.trim(), quote: input.anchor?.quote ?? input.quote.slice(0, input.exactQuote ? 8000 : 500), ...(input.anchor ? { anchor: input.anchor } : {}), status: 'open', createdAt: at, updatedAt: at, version: 1, history: [{ at, action: 'created' }] }], unchanged);
96
+ }
97
+
98
+ /** Every mutation checks the same current record before appending its history. */
99
+ async function updateComment(root: string, documentId: string, commentId: string, version: number, update: (comment: Comment, at: string) => Partial<Comment> | undefined) {
100
+ return mutate(root, documentId, rows => {
101
+ const comment = rows.find(row => row.id === commentId);
102
+ if (!comment) throw new Error('Comment not found.');
103
+ if (comment.status === 'deleted' || comment.version !== version) throw new Conflict('This comment changed elsewhere. Refresh and try again.');
104
+ const at = new Date().toISOString();
105
+ const changes = update(comment, at);
106
+ if (!changes) return rows;
107
+ return rows.map(row => row === comment ? { ...row, ...changes, version: row.version + 1, updatedAt: at } : row);
108
+ });
109
+ }
110
+
111
+ export async function changeComment(root: string, documentId: string, commentId: string, status: 'open' | 'resolved', version: number) {
112
+ if (!['open', 'resolved'].includes(status)) throw new Error('Invalid comment status.');
113
+ return updateComment(root, documentId, commentId, version, (comment, at) => {
114
+ if (comment.status === status) return undefined;
115
+ return { status, history: [...comment.history, { at, action: status === 'resolved' ? 'resolved' : 'reopened' }] };
116
+ });
117
+ }
118
+
119
+ export async function editComment(root: string, documentId: string, commentId: string, text: string, version: number) {
120
+ if (typeof text !== 'string' || !text.trim() || text.length > 8000) throw new Error('Write a comment between 1 and 8,000 characters.');
121
+ return updateComment(root, documentId, commentId, version, (comment, at) => {
122
+ if (comment.text === text.trim()) return undefined;
123
+ return { text: text.trim(), history: [...comment.history, { at, action: 'edited', previousText: comment.text }] };
124
+ });
125
+ }
126
+
127
+ /** Keep the local audit history while removing deleted feedback from the app. */
128
+ export async function deleteComment(root: string, documentId: string, commentId: string, version: number) {
129
+ return updateComment(root, documentId, commentId, version, (comment, at) => ({ status: 'deleted', history: [...comment.history, { at, action: 'deleted' }] }));
130
+ }
@@ -0,0 +1,33 @@
1
+ import { resolve } from 'node:path';
2
+ import { pathToFileURL } from 'node:url';
3
+ import { parseArgs } from 'node:util';
4
+ import { createDocument, CreateDocumentError, listStarters } from './create';
5
+ import { createFromTemplate } from './templates';
6
+
7
+ const invalid = (message: string) => new CreateDocumentError(message, 'INVALID_INPUT', 400);
8
+ const usage = 'Usage: npx opendoc create [<id>] --project <project-id> --title "Document title" [--theme <theme-id>] [--format document|presentation]\n Add --template <template-id> for a reusable template or --starter <starter> for an example draft.\n npx opendoc create --list [--json]';
9
+
10
+ export async function runCreateCli(args: string[], root = process.cwd()): Promise<void> {
11
+ const { values, positionals } = parseArgs({ args: args[0] === '--' ? args.slice(1) : args, allowPositionals: true, options: {
12
+ format: { type: 'string' }, starter: { type: 'string' }, template: { type: 'string' }, title: { type: 'string' }, project: { type: 'string' }, theme: { type: 'string' }, list: { type: 'boolean' }, json: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
13
+ } });
14
+ if (values.help) { console.log(values.json ? JSON.stringify({ usage }, null, 2) : usage); return; }
15
+ if (values.list) {
16
+ if (positionals.length || values.title || values.starter || values.template || values.project || values.theme || values.format) throw invalid('--list cannot be combined with document creation.');
17
+ console.log(values.json ? JSON.stringify({ starters: listStarters() }, null, 2) : listStarters().map(item => `${item.id.padEnd(16)}${item.name} — ${item.description}`).join('\n'));
18
+ return;
19
+ }
20
+ if (positionals.length > 1) throw invalid('Provide one document ID. Use --title for the document title.');
21
+ if (values.starter && values.template) throw invalid('Choose --starter or --template, not both.');
22
+ if (values.format && !['document', 'presentation'].includes(values.format)) throw invalid('Choose document or presentation format.');
23
+ const input = { id: positionals[0], title: values.title, projectId: values.project, theme: values.theme, format: values.format };
24
+ const result = values.template
25
+ ? await createFromTemplate(root, values.template, input)
26
+ : await createDocument(root, { ...input, starter: values.starter, format: values.format });
27
+ console.log(values.json ? JSON.stringify(result, null, 2) : `Created ${result.entry}\nOpen it in OpenDoc, then ask Codex to develop it using your brief and sources.`);
28
+ }
29
+
30
+ if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
31
+ try { await runCreateCli(process.argv.slice(2)); }
32
+ catch (error) { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; }
33
+ }