@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.
- package/.agents/skills/opendoc-apply-comments/SKILL.md +30 -0
- package/.agents/skills/opendoc-apply-comments/agents/openai.yaml +4 -0
- package/.agents/skills/opendoc-create/SKILL.md +63 -0
- package/.agents/skills/opendoc-create/agents/openai.yaml +6 -0
- package/.agents/skills/opendoc-create-template/SKILL.md +50 -0
- package/.agents/skills/opendoc-create-template/agents/openai.yaml +4 -0
- package/.agents/skills/opendoc-create-template/references/structured-reports.md +11 -0
- package/.agents/skills/opendoc-create-theme/SKILL.md +40 -0
- package/.agents/skills/opendoc-create-theme/agents/openai.yaml +4 -0
- package/.agents/skills/opendoc-current-document/SKILL.md +32 -0
- package/.agents/skills/opendoc-current-document/agents/openai.yaml +4 -0
- package/.agents/skills/opendoc-current-document/references/context-fields.md +20 -0
- package/.agents/skills/opendoc-review-document/SKILL.md +60 -0
- package/.agents/skills/opendoc-review-document/agents/openai.yaml +4 -0
- package/AGENTS.md +69 -0
- package/CONTRIBUTING.md +38 -0
- package/LICENSE +21 -0
- package/README.md +179 -0
- package/SECURITY.md +9 -0
- package/THIRD_PARTY.md +49 -0
- package/VALIDATION.md +99 -0
- package/bin/opendoc.mjs +6 -0
- package/dist/assets/Markdown-sNZyjJi7.js +29 -0
- package/dist/assets/OpenDocSerif-Regular-D3OXs9A9.ttf +0 -0
- package/dist/assets/OpenDocSerif-Semibold-CjL9oDRo.ttf +0 -0
- package/dist/assets/geist-latin-ext-wght-italic-XgKbg5n7.woff2 +0 -0
- package/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/assets/geist-latin-wght-italic-dTnRTFFJ.woff2 +0 -0
- package/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/assets/index-DdrZ6ozO.css +1 -0
- package/dist/assets/index-DgNBz7mL.js +39 -0
- package/dist/assets/pdf-B7Emtyld.js +54 -0
- package/dist/assets/pdf.worker.min-Dswkl-cV.mjs +29 -0
- package/dist/assets/wordmark-DsqLlZpb.png +0 -0
- package/dist/index.html +17 -0
- package/docs/APPEARANCE.md +21 -0
- package/docs/ASSETS.md +176 -0
- package/docs/AUTHORING.md +178 -0
- package/docs/HEADLESS.md +120 -0
- package/docs/MEDIA.md +112 -0
- package/docs/PROJECTS.md +55 -0
- package/docs/PROSE.md +15 -0
- package/docs/SELECTION.md +59 -0
- package/docs/TEMPLATES.md +55 -0
- package/docs/THEMES.md +106 -0
- package/node_modules/@formepdf/core/LICENSE +21 -0
- package/node_modules/@formepdf/core/README.md +53 -0
- package/node_modules/@formepdf/core/dist/attachments.d.ts +55 -0
- package/node_modules/@formepdf/core/dist/attachments.js +59 -0
- package/node_modules/@formepdf/core/dist/extract.d.ts +8 -0
- package/node_modules/@formepdf/core/dist/extract.js +56 -0
- package/node_modules/@formepdf/core/dist/index.d.ts +311 -0
- package/node_modules/@formepdf/core/dist/index.js +167 -0
- package/node_modules/@formepdf/core/dist/layout.d.ts +132 -0
- package/node_modules/@formepdf/core/dist/layout.js +240 -0
- package/node_modules/@formepdf/core/dist/shared/browserHelpers.d.ts +19 -0
- package/node_modules/@formepdf/core/dist/shared/browserHelpers.js +128 -0
- package/node_modules/@formepdf/core/package.json +35 -0
- package/node_modules/@formepdf/core/pkg-node/LICENSE +21 -0
- package/node_modules/@formepdf/core/pkg-node/README.md +84 -0
- package/node_modules/@formepdf/core/pkg-node/forme.d.ts +39 -0
- package/node_modules/@formepdf/core/pkg-node/forme.js +394 -0
- package/node_modules/@formepdf/core/pkg-node/forme_bg.wasm +0 -0
- package/node_modules/@formepdf/core/pkg-node/forme_bg.wasm.d.ts +21 -0
- package/node_modules/@formepdf/core/pkg-node/package.json +25 -0
- package/node_modules/@formepdf/react/README.md +70 -0
- package/node_modules/@formepdf/react/dist/charts.d.ts +72 -0
- package/node_modules/@formepdf/react/dist/charts.js +338 -0
- package/node_modules/@formepdf/react/dist/components.d.ts +533 -0
- package/node_modules/@formepdf/react/dist/components.js +608 -0
- package/node_modules/@formepdf/react/dist/expr.d.ts +20 -0
- package/node_modules/@formepdf/react/dist/expr.js +39 -0
- package/node_modules/@formepdf/react/dist/font.d.ts +2 -0
- package/node_modules/@formepdf/react/dist/font.js +1 -0
- package/node_modules/@formepdf/react/dist/index.d.ts +11 -0
- package/node_modules/@formepdf/react/dist/index.js +15 -0
- package/node_modules/@formepdf/react/dist/render.d.ts +12 -0
- package/node_modules/@formepdf/react/dist/render.js +15 -0
- package/node_modules/@formepdf/react/dist/serialize.d.ts +12 -0
- package/node_modules/@formepdf/react/dist/serialize.js +1470 -0
- package/node_modules/@formepdf/react/dist/stylesheet.d.ts +4 -0
- package/node_modules/@formepdf/react/dist/stylesheet.js +5 -0
- package/node_modules/@formepdf/react/dist/template-proxy.d.ts +38 -0
- package/node_modules/@formepdf/react/dist/template-proxy.js +100 -0
- package/node_modules/@formepdf/react/dist/types.d.ts +287 -0
- package/node_modules/@formepdf/react/dist/types.js +1 -0
- package/node_modules/@formepdf/react/package.json +41 -0
- package/node_modules/@formepdf/shared/README.md +7 -0
- package/node_modules/@formepdf/shared/dist/canvas.d.ts +6 -0
- package/node_modules/@formepdf/shared/dist/canvas.js +43 -0
- package/node_modules/@formepdf/shared/dist/charts.d.ts +100 -0
- package/node_modules/@formepdf/shared/dist/charts.js +98 -0
- package/node_modules/@formepdf/shared/dist/encode.d.ts +27 -0
- package/node_modules/@formepdf/shared/dist/encode.js +93 -0
- package/node_modules/@formepdf/shared/dist/font.d.ts +13 -0
- package/node_modules/@formepdf/shared/dist/font.js +52 -0
- package/node_modules/@formepdf/shared/dist/index.d.ts +10 -0
- package/node_modules/@formepdf/shared/dist/index.js +15 -0
- package/node_modules/@formepdf/shared/dist/parser.d.ts +30 -0
- package/node_modules/@formepdf/shared/dist/parser.js +756 -0
- package/node_modules/@formepdf/shared/dist/semantics.d.ts +15 -0
- package/node_modules/@formepdf/shared/dist/semantics.js +44 -0
- package/node_modules/@formepdf/shared/dist/style.d.ts +7 -0
- package/node_modules/@formepdf/shared/dist/style.js +1024 -0
- package/node_modules/@formepdf/shared/dist/types.d.ts +743 -0
- package/node_modules/@formepdf/shared/dist/types.js +2 -0
- package/node_modules/@formepdf/shared/package.json +35 -0
- package/node_modules/@types/node/LICENSE +21 -0
- package/node_modules/@types/node/README.md +15 -0
- package/node_modules/@types/node/assert/strict.d.ts +111 -0
- package/node_modules/@types/node/assert.d.ts +1078 -0
- package/node_modules/@types/node/async_hooks.d.ts +603 -0
- package/node_modules/@types/node/buffer.buffer.d.ts +472 -0
- package/node_modules/@types/node/buffer.d.ts +1934 -0
- package/node_modules/@types/node/child_process.d.ts +1476 -0
- package/node_modules/@types/node/cluster.d.ts +578 -0
- package/node_modules/@types/node/compatibility/disposable.d.ts +14 -0
- package/node_modules/@types/node/compatibility/index.d.ts +9 -0
- package/node_modules/@types/node/compatibility/indexable.d.ts +20 -0
- package/node_modules/@types/node/compatibility/iterators.d.ts +20 -0
- package/node_modules/@types/node/console.d.ts +452 -0
- package/node_modules/@types/node/constants.d.ts +21 -0
- package/node_modules/@types/node/crypto.d.ts +4545 -0
- package/node_modules/@types/node/dgram.d.ts +600 -0
- package/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
- package/node_modules/@types/node/dns/promises.d.ts +503 -0
- package/node_modules/@types/node/dns.d.ts +923 -0
- package/node_modules/@types/node/domain.d.ts +170 -0
- package/node_modules/@types/node/events.d.ts +976 -0
- package/node_modules/@types/node/fs/promises.d.ts +1306 -0
- package/node_modules/@types/node/fs.d.ts +4463 -0
- package/node_modules/@types/node/globals.d.ts +172 -0
- package/node_modules/@types/node/globals.typedarray.d.ts +38 -0
- package/node_modules/@types/node/http.d.ts +2097 -0
- package/node_modules/@types/node/http2.d.ts +2843 -0
- package/node_modules/@types/node/https.d.ts +579 -0
- package/node_modules/@types/node/index.d.ts +98 -0
- package/node_modules/@types/node/inspector.d.ts +253 -0
- package/node_modules/@types/node/inspector.generated.d.ts +4052 -0
- package/node_modules/@types/node/module.d.ts +891 -0
- package/node_modules/@types/node/net.d.ts +1076 -0
- package/node_modules/@types/node/os.d.ts +506 -0
- package/node_modules/@types/node/package.json +145 -0
- package/node_modules/@types/node/path.d.ts +200 -0
- package/node_modules/@types/node/perf_hooks.d.ts +968 -0
- package/node_modules/@types/node/process.d.ts +2084 -0
- package/node_modules/@types/node/punycode.d.ts +117 -0
- package/node_modules/@types/node/querystring.d.ts +152 -0
- package/node_modules/@types/node/readline/promises.d.ts +161 -0
- package/node_modules/@types/node/readline.d.ts +594 -0
- package/node_modules/@types/node/repl.d.ts +428 -0
- package/node_modules/@types/node/sea.d.ts +162 -0
- package/node_modules/@types/node/sqlite.d.ts +722 -0
- package/node_modules/@types/node/stream/consumers.d.ts +38 -0
- package/node_modules/@types/node/stream/promises.d.ts +90 -0
- package/node_modules/@types/node/stream/web.d.ts +573 -0
- package/node_modules/@types/node/stream.d.ts +1694 -0
- package/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/node_modules/@types/node/test.d.ts +2265 -0
- package/node_modules/@types/node/timers/promises.d.ts +108 -0
- package/node_modules/@types/node/timers.d.ts +287 -0
- package/node_modules/@types/node/tls.d.ts +1319 -0
- package/node_modules/@types/node/trace_events.d.ts +197 -0
- package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +468 -0
- package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +34 -0
- package/node_modules/@types/node/ts5.6/index.d.ts +98 -0
- package/node_modules/@types/node/tty.d.ts +208 -0
- package/node_modules/@types/node/url.d.ts +984 -0
- package/node_modules/@types/node/util.d.ts +2606 -0
- package/node_modules/@types/node/v8.d.ts +920 -0
- package/node_modules/@types/node/vm.d.ts +1053 -0
- package/node_modules/@types/node/wasi.d.ts +181 -0
- package/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
- package/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
- package/node_modules/@types/node/web-globals/events.d.ts +97 -0
- package/node_modules/@types/node/web-globals/fetch.d.ts +55 -0
- package/node_modules/@types/node/web-globals/navigator.d.ts +22 -0
- package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
- package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
- package/node_modules/@types/node/worker_threads.d.ts +819 -0
- package/node_modules/@types/node/zlib.d.ts +747 -0
- package/node_modules/@types/react/LICENSE +21 -0
- package/node_modules/@types/react/README.md +15 -0
- package/node_modules/@types/react/canary.d.ts +129 -0
- package/node_modules/@types/react/compiler-runtime.d.ts +4 -0
- package/node_modules/@types/react/experimental.d.ts +184 -0
- package/node_modules/@types/react/global.d.ts +166 -0
- package/node_modules/@types/react/index.d.ts +4378 -0
- package/node_modules/@types/react/jsx-dev-runtime.d.ts +33 -0
- package/node_modules/@types/react/jsx-runtime.d.ts +24 -0
- package/node_modules/@types/react/package.json +210 -0
- package/node_modules/@types/react/ts5.0/canary.d.ts +129 -0
- package/node_modules/@types/react/ts5.0/experimental.d.ts +184 -0
- package/node_modules/@types/react/ts5.0/global.d.ts +166 -0
- package/node_modules/@types/react/ts5.0/index.d.ts +4365 -0
- package/node_modules/@types/react/ts5.0/jsx-dev-runtime.d.ts +33 -0
- package/node_modules/@types/react/ts5.0/jsx-runtime.d.ts +24 -0
- package/node_modules/csstype/LICENSE +19 -0
- package/node_modules/csstype/README.md +291 -0
- package/node_modules/csstype/index.d.ts +22569 -0
- package/node_modules/csstype/index.js.flow +6863 -0
- package/node_modules/csstype/package.json +70 -0
- package/node_modules/entities/LICENSE +11 -0
- package/node_modules/entities/decode.d.ts +1 -0
- package/node_modules/entities/decode.js +3 -0
- package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts +19 -0
- package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/decode-codepoint.js +77 -0
- package/node_modules/entities/dist/commonjs/decode-codepoint.js.map +1 -0
- package/node_modules/entities/dist/commonjs/decode.d.ts +209 -0
- package/node_modules/entities/dist/commonjs/decode.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/decode.js +511 -0
- package/node_modules/entities/dist/commonjs/decode.js.map +1 -0
- package/node_modules/entities/dist/commonjs/encode.d.ts +22 -0
- package/node_modules/entities/dist/commonjs/encode.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/encode.js +73 -0
- package/node_modules/entities/dist/commonjs/encode.js.map +1 -0
- package/node_modules/entities/dist/commonjs/escape.d.ts +43 -0
- package/node_modules/entities/dist/commonjs/escape.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/escape.js +121 -0
- package/node_modules/entities/dist/commonjs/escape.js.map +1 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts +2 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-html.js +10 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-html.js.map +1 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts +2 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js +10 -0
- package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js.map +1 -0
- package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts +8 -0
- package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/generated/encode-html.js +13 -0
- package/node_modules/entities/dist/commonjs/generated/encode-html.js.map +1 -0
- package/node_modules/entities/dist/commonjs/index.d.ts +96 -0
- package/node_modules/entities/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/entities/dist/commonjs/index.js +131 -0
- package/node_modules/entities/dist/commonjs/index.js.map +1 -0
- package/node_modules/entities/dist/commonjs/package.json +3 -0
- package/node_modules/entities/dist/esm/decode-codepoint.d.ts +19 -0
- package/node_modules/entities/dist/esm/decode-codepoint.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/decode-codepoint.js +72 -0
- package/node_modules/entities/dist/esm/decode-codepoint.js.map +1 -0
- package/node_modules/entities/dist/esm/decode.d.ts +209 -0
- package/node_modules/entities/dist/esm/decode.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/decode.js +497 -0
- package/node_modules/entities/dist/esm/decode.js.map +1 -0
- package/node_modules/entities/dist/esm/encode.d.ts +22 -0
- package/node_modules/entities/dist/esm/encode.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/encode.js +69 -0
- package/node_modules/entities/dist/esm/encode.js.map +1 -0
- package/node_modules/entities/dist/esm/escape.d.ts +43 -0
- package/node_modules/entities/dist/esm/escape.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/escape.js +117 -0
- package/node_modules/entities/dist/esm/escape.js.map +1 -0
- package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts +2 -0
- package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/generated/decode-data-html.js +7 -0
- package/node_modules/entities/dist/esm/generated/decode-data-html.js.map +1 -0
- package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts +2 -0
- package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/generated/decode-data-xml.js +7 -0
- package/node_modules/entities/dist/esm/generated/decode-data-xml.js.map +1 -0
- package/node_modules/entities/dist/esm/generated/encode-html.d.ts +8 -0
- package/node_modules/entities/dist/esm/generated/encode-html.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/generated/encode-html.js +10 -0
- package/node_modules/entities/dist/esm/generated/encode-html.js.map +1 -0
- package/node_modules/entities/dist/esm/index.d.ts +96 -0
- package/node_modules/entities/dist/esm/index.d.ts.map +1 -0
- package/node_modules/entities/dist/esm/index.js +107 -0
- package/node_modules/entities/dist/esm/index.js.map +1 -0
- package/node_modules/entities/dist/esm/package.json +3 -0
- package/node_modules/entities/escape.d.ts +1 -0
- package/node_modules/entities/escape.js +3 -0
- package/node_modules/entities/package.json +118 -0
- package/node_modules/entities/readme.md +122 -0
- package/node_modules/entities/src/decode-codepoint.ts +81 -0
- package/node_modules/entities/src/decode.spec.ts +320 -0
- package/node_modules/entities/src/decode.ts +620 -0
- package/node_modules/entities/src/encode.spec.ts +78 -0
- package/node_modules/entities/src/encode.ts +77 -0
- package/node_modules/entities/src/escape.spec.ts +14 -0
- package/node_modules/entities/src/escape.ts +148 -0
- package/node_modules/entities/src/generated/.eslintrc.json +10 -0
- package/node_modules/entities/src/generated/decode-data-html.ts +8 -0
- package/node_modules/entities/src/generated/decode-data-xml.ts +8 -0
- package/node_modules/entities/src/generated/encode-html.ts +17 -0
- package/node_modules/entities/src/index.spec.ts +125 -0
- package/node_modules/entities/src/index.ts +188 -0
- package/node_modules/parse5/LICENSE +19 -0
- package/node_modules/parse5/README.md +38 -0
- package/node_modules/parse5/dist/cjs/common/doctype.d.ts +4 -0
- package/node_modules/parse5/dist/cjs/common/doctype.js +118 -0
- package/node_modules/parse5/dist/cjs/common/error-codes.d.ts +67 -0
- package/node_modules/parse5/dist/cjs/common/error-codes.js +66 -0
- package/node_modules/parse5/dist/cjs/common/foreign-content.d.ts +9 -0
- package/node_modules/parse5/dist/cjs/common/foreign-content.js +237 -0
- package/node_modules/parse5/dist/cjs/common/html.d.ts +289 -0
- package/node_modules/parse5/dist/cjs/common/html.js +528 -0
- package/node_modules/parse5/dist/cjs/common/token.d.ts +84 -0
- package/node_modules/parse5/dist/cjs/common/token.js +24 -0
- package/node_modules/parse5/dist/cjs/common/unicode.d.ts +42 -0
- package/node_modules/parse5/dist/cjs/common/unicode.js +70 -0
- package/node_modules/parse5/dist/cjs/index.d.ts +71 -0
- package/node_modules/parse5/dist/cjs/index.js +54 -0
- package/node_modules/parse5/dist/cjs/package.json +1 -0
- package/node_modules/parse5/dist/cjs/parser/formatting-element-list.d.ts +36 -0
- package/node_modules/parse5/dist/cjs/parser/formatting-element-list.js +114 -0
- package/node_modules/parse5/dist/cjs/parser/index.d.ts +221 -0
- package/node_modules/parse5/dist/cjs/parser/index.js +3240 -0
- package/node_modules/parse5/dist/cjs/parser/open-element-stack.d.ts +53 -0
- package/node_modules/parse5/dist/cjs/parser/open-element-stack.js +328 -0
- package/node_modules/parse5/dist/cjs/serializer/index.d.ts +60 -0
- package/node_modules/parse5/dist/cjs/serializer/index.js +172 -0
- package/node_modules/parse5/dist/cjs/tokenizer/index.d.ts +247 -0
- package/node_modules/parse5/dist/cjs/tokenizer/index.js +2714 -0
- package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.d.ts +36 -0
- package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.js +200 -0
- package/node_modules/parse5/dist/cjs/tree-adapters/default.d.ts +84 -0
- package/node_modules/parse5/dist/cjs/tree-adapters/default.js +176 -0
- package/node_modules/parse5/dist/cjs/tree-adapters/interface.d.ts +255 -0
- package/node_modules/parse5/dist/cjs/tree-adapters/interface.js +2 -0
- package/node_modules/parse5/dist/common/doctype.d.ts +4 -0
- package/node_modules/parse5/dist/common/doctype.js +114 -0
- package/node_modules/parse5/dist/common/error-codes.d.ts +67 -0
- package/node_modules/parse5/dist/common/error-codes.js +63 -0
- package/node_modules/parse5/dist/common/foreign-content.d.ts +9 -0
- package/node_modules/parse5/dist/common/foreign-content.js +228 -0
- package/node_modules/parse5/dist/common/html.d.ts +289 -0
- package/node_modules/parse5/dist/common/html.js +523 -0
- package/node_modules/parse5/dist/common/token.d.ts +84 -0
- package/node_modules/parse5/dist/common/token.js +20 -0
- package/node_modules/parse5/dist/common/unicode.d.ts +42 -0
- package/node_modules/parse5/dist/common/unicode.js +62 -0
- package/node_modules/parse5/dist/index.d.ts +71 -0
- package/node_modules/parse5/dist/index.js +42 -0
- package/node_modules/parse5/dist/parser/formatting-element-list.d.ts +36 -0
- package/node_modules/parse5/dist/parser/formatting-element-list.js +110 -0
- package/node_modules/parse5/dist/parser/index.d.ts +221 -0
- package/node_modules/parse5/dist/parser/index.js +3245 -0
- package/node_modules/parse5/dist/parser/open-element-stack.d.ts +53 -0
- package/node_modules/parse5/dist/parser/open-element-stack.js +324 -0
- package/node_modules/parse5/dist/serializer/index.d.ts +60 -0
- package/node_modules/parse5/dist/serializer/index.js +168 -0
- package/node_modules/parse5/dist/tokenizer/index.d.ts +247 -0
- package/node_modules/parse5/dist/tokenizer/index.js +2710 -0
- package/node_modules/parse5/dist/tokenizer/preprocessor.d.ts +36 -0
- package/node_modules/parse5/dist/tokenizer/preprocessor.js +196 -0
- package/node_modules/parse5/dist/tree-adapters/default.d.ts +84 -0
- package/node_modules/parse5/dist/tree-adapters/default.js +173 -0
- package/node_modules/parse5/dist/tree-adapters/interface.d.ts +255 -0
- package/node_modules/parse5/dist/tree-adapters/interface.js +1 -0
- package/node_modules/parse5/package.json +50 -0
- package/node_modules/undici-types/LICENSE +21 -0
- package/node_modules/undici-types/README.md +6 -0
- package/node_modules/undici-types/agent.d.ts +31 -0
- package/node_modules/undici-types/api.d.ts +43 -0
- package/node_modules/undici-types/balanced-pool.d.ts +29 -0
- package/node_modules/undici-types/cache.d.ts +36 -0
- package/node_modules/undici-types/client.d.ts +108 -0
- package/node_modules/undici-types/connector.d.ts +34 -0
- package/node_modules/undici-types/content-type.d.ts +21 -0
- package/node_modules/undici-types/cookies.d.ts +28 -0
- package/node_modules/undici-types/diagnostics-channel.d.ts +66 -0
- package/node_modules/undici-types/dispatcher.d.ts +256 -0
- package/node_modules/undici-types/env-http-proxy-agent.d.ts +21 -0
- package/node_modules/undici-types/errors.d.ts +149 -0
- package/node_modules/undici-types/eventsource.d.ts +61 -0
- package/node_modules/undici-types/fetch.d.ts +209 -0
- package/node_modules/undici-types/file.d.ts +39 -0
- package/node_modules/undici-types/filereader.d.ts +54 -0
- package/node_modules/undici-types/formdata.d.ts +108 -0
- package/node_modules/undici-types/global-dispatcher.d.ts +9 -0
- package/node_modules/undici-types/global-origin.d.ts +7 -0
- package/node_modules/undici-types/handlers.d.ts +15 -0
- package/node_modules/undici-types/header.d.ts +4 -0
- package/node_modules/undici-types/index.d.ts +71 -0
- package/node_modules/undici-types/interceptors.d.ts +17 -0
- package/node_modules/undici-types/mock-agent.d.ts +50 -0
- package/node_modules/undici-types/mock-client.d.ts +25 -0
- package/node_modules/undici-types/mock-errors.d.ts +12 -0
- package/node_modules/undici-types/mock-interceptor.d.ts +93 -0
- package/node_modules/undici-types/mock-pool.d.ts +25 -0
- package/node_modules/undici-types/package.json +55 -0
- package/node_modules/undici-types/patch.d.ts +33 -0
- package/node_modules/undici-types/pool-stats.d.ts +19 -0
- package/node_modules/undici-types/pool.d.ts +39 -0
- package/node_modules/undici-types/proxy-agent.d.ts +28 -0
- package/node_modules/undici-types/readable.d.ts +65 -0
- package/node_modules/undici-types/retry-agent.d.ts +8 -0
- package/node_modules/undici-types/retry-handler.d.ts +116 -0
- package/node_modules/undici-types/util.d.ts +18 -0
- package/node_modules/undici-types/webidl.d.ts +228 -0
- package/node_modules/undici-types/websocket.d.ts +150 -0
- package/package.json +80 -0
- package/scripts/rebuild-forme.mjs +61 -0
- package/src/app/AppearanceControl.tsx +44 -0
- package/src/app/AssetThemeDefaults.tsx +87 -0
- package/src/app/AssetsBrowser.tsx +273 -0
- package/src/app/CommentDock.tsx +108 -0
- package/src/app/CreateDocumentDialog.tsx +51 -0
- package/src/app/DocumentActions.tsx +69 -0
- package/src/app/DocumentCard.tsx +50 -0
- package/src/app/DocumentViewControl.tsx +31 -0
- package/src/app/DocumentsBrowser.tsx +70 -0
- package/src/app/ExportHistoryDialog.tsx +86 -0
- package/src/app/ExportMenu.tsx +127 -0
- package/src/app/GuideDialog.tsx +80 -0
- package/src/app/InspectionLayer.tsx +77 -0
- package/src/app/LogoUploadDialog.tsx +92 -0
- package/src/app/Markdown.tsx +34 -0
- package/src/app/MaterialsBrowser.tsx +149 -0
- package/src/app/PageNumberInput.tsx +56 -0
- package/src/app/Pdf.tsx +561 -0
- package/src/app/ProjectDialogs.tsx +100 -0
- package/src/app/Reader.tsx +769 -0
- package/src/app/SearchField.tsx +13 -0
- package/src/app/Sidebar.tsx +86 -0
- package/src/app/SkillIndex.tsx +30 -0
- package/src/app/TemplatesBrowser.tsx +149 -0
- package/src/app/ThemesBrowser.tsx +159 -0
- package/src/app/api.ts +47 -0
- package/src/app/appearance.ts +35 -0
- package/src/app/assets.css +139 -0
- package/src/app/catalogPreview.ts +20 -0
- package/src/app/colors.css +167 -0
- package/src/app/comment-dock.css +53 -0
- package/src/app/commentDrafts.ts +67 -0
- package/src/app/componentCorrection.ts +17 -0
- package/src/app/edit-workbench.css +87 -0
- package/src/app/editSession.ts +238 -0
- package/src/app/editorRecovery.ts +25 -0
- package/src/app/export-history.css +31 -0
- package/src/app/export.css +17 -0
- package/src/app/guideLinks.ts +21 -0
- package/src/app/guides.css +40 -0
- package/src/app/main.tsx +221 -0
- package/src/app/materials.css +53 -0
- package/src/app/pdfLoading.ts +12 -0
- package/src/app/pdfSelection.ts +112 -0
- package/src/app/projects.css +63 -0
- package/src/app/reader-toolbar.css +65 -0
- package/src/app/selection.css +150 -0
- package/src/app/sidebar.css +60 -0
- package/src/app/skills.css +7 -0
- package/src/app/style.css +1061 -0
- package/src/app/templates.css +49 -0
- package/src/app/themes.css +80 -0
- package/src/app/ui/Icon.tsx +92 -0
- package/src/app/ui/README.md +27 -0
- package/src/app/ui/fonts.css +36 -0
- package/src/app/ui/index.tsx +223 -0
- package/src/app/ui/ui.css +388 -0
- package/src/app/useReaderPreview.ts +19 -0
- package/src/app/useTextEditing.ts +155 -0
- package/src/assets/adapter.ts +122 -0
- package/src/assets/files.ts +378 -0
- package/src/assets/import-worker.ts +294 -0
- package/src/assets/imports.ts +124 -0
- package/src/assets/index.ts +60 -0
- package/src/assets/store.ts +798 -0
- package/src/assets/usage.ts +118 -0
- package/src/cli/check.ts +25 -0
- package/src/cli/init.ts +119 -0
- package/src/cli/lock.ts +34 -0
- package/src/cli/main.ts +118 -0
- package/src/cli/process.ts +19 -0
- package/src/cli/start.ts +96 -0
- package/src/cli/update.ts +348 -0
- package/src/cli/workspace.ts +94 -0
- package/src/document/index.tsx +641 -0
- package/src/document/page.tsx +53 -0
- package/src/document/text-targets.tsx +162 -0
- package/src/media/files.ts +124 -0
- package/src/media/render.ts +63 -0
- package/src/rendering/resolve-sources.ts +84 -0
- package/src/runtime/jsx-dev-runtime.ts +2 -0
- package/src/runtime/jsx-runtime.ts +2 -0
- package/src/runtime/paths.ts +12 -0
- package/src/server/assets-cli.ts +162 -0
- package/src/server/assets-http.ts +100 -0
- package/src/server/client.ts +50 -0
- package/src/server/clipboard.ts +22 -0
- package/src/server/comments-cli.ts +64 -0
- package/src/server/comments.ts +130 -0
- package/src/server/create-cli.ts +33 -0
- package/src/server/create.ts +228 -0
- package/src/server/dependencies.ts +91 -0
- package/src/server/documents.ts +143 -0
- package/src/server/edits.ts +249 -0
- package/src/server/export-batch.ts +105 -0
- package/src/server/export-errors.ts +2 -0
- package/src/server/export-file.ts +57 -0
- package/src/server/export-inputs.ts +66 -0
- package/src/server/export-preview.ts +69 -0
- package/src/server/export.ts +32 -0
- package/src/server/exports.ts +283 -0
- package/src/server/files.ts +21 -0
- package/src/server/guides.ts +71 -0
- package/src/server/index.ts +432 -0
- package/src/server/materials.ts +39 -0
- package/src/server/media-cli.ts +73 -0
- package/src/server/media-mutations.ts +168 -0
- package/src/server/pptx.ts +160 -0
- package/src/server/preflight.ts +129 -0
- package/src/server/projects-cli.ts +29 -0
- package/src/server/projects.ts +187 -0
- package/src/server/render-error.ts +9 -0
- package/src/server/render-source.ts +24 -0
- package/src/server/render.ts +48 -0
- package/src/server/review-cli.ts +40 -0
- package/src/server/review.ts +161 -0
- package/src/server/selection.ts +23 -0
- package/src/server/source-overrides.ts +97 -0
- package/src/server/templates-cli.ts +51 -0
- package/src/server/templates.ts +186 -0
- package/src/server/text-layout.ts +41 -0
- package/src/server/text-source.ts +307 -0
- package/src/server/themes-cli.ts +59 -0
- package/src/server/themes.ts +215 -0
- package/src/server/ttf2eot.d.ts +3 -0
- package/src/server/worker.ts +166 -0
- package/src/server/workspace.ts +242 -0
- package/src/shared/anchors.ts +69 -0
- package/src/shared/assets.ts +154 -0
- package/src/shared/export.ts +34 -0
- package/src/shared/media.ts +33 -0
- package/src/shared/projects.ts +19 -0
- package/src/shared/selection.ts +94 -0
- package/src/shared/skill-index.ts +14 -0
- package/src/shared/starters.ts +19 -0
- package/src/shared/templates.ts +18 -0
- package/src/shared/themes.ts +24 -0
- package/src/shared/types.ts +39 -0
- package/src/template/index.ts +27 -0
- package/src/themes/index.ts +3 -0
- package/src/themes/neutral.ts +20 -0
- package/src/themes/types.ts +110 -0
- package/starter/assets/brand/wordmark.png +0 -0
- package/starter/assets/fonts/InterUI-LICENSE.txt +93 -0
- package/starter/assets/fonts/InterUI-Medium.ttf +0 -0
- package/starter/assets/fonts/InterUI-Regular.ttf +0 -0
- package/starter/assets/fonts/InterUI-source.json +19 -0
- package/starter/assets/fonts/OpenDocMono-Regular.ttf +0 -0
- package/starter/assets/fonts/OpenDocSans-Italic.ttf +0 -0
- package/starter/assets/fonts/OpenDocSans-Regular.ttf +0 -0
- package/starter/assets/fonts/OpenDocSans-Semibold.ttf +0 -0
- package/starter/assets/fonts/OpenDocSans-SemiboldItalic.ttf +0 -0
- package/starter/assets/fonts/OpenDocSerif-Italic.ttf +0 -0
- package/starter/assets/fonts/OpenDocSerif-Regular.ttf +0 -0
- package/starter/assets/fonts/OpenDocSerif-Semibold.ttf +0 -0
- package/starter/assets/fonts/OpenDocSerif-SemiboldItalic.ttf +0 -0
- package/starter/assets/fonts/SourceCode-LICENSE.md +93 -0
- package/starter/assets/fonts/SourceSans-LICENSE.md +93 -0
- package/starter/assets/fonts/SourceSerif-LICENSE.md +93 -0
- package/starter/assets/fonts/geist/OFL.txt +93 -0
- package/starter/assets/fonts/geist/asset.json +7 -0
- package/starter/assets/fonts/geist/files/1a9874b3be0fc168692a3d2327bccb4d28835653d3b91537a755296a467a83e3.ttf +0 -0
- package/starter/assets/fonts/geist/files/a8eefb873ba9c9020665f8a98302697ce1f3b79ab2deef6ee508c0ca6a82e876.ttf +0 -0
- package/starter/assets/fonts/geist/files/ccce59465ae5c61930ada5453834f60500fbd95084d85db63e0e65fad0125455.ttf +0 -0
- package/starter/assets/fonts/geist/files/f5e95110d70593672515080bee9148463ada0a7f77b89ed65a3d43cb2b0ff83a.pdf +0 -0
- package/starter/assets/fonts/geist/revisions/9a2bc12fb2f23cb27bc227087e63e1407bb804ee0586480bd6b7966ec69fb474.json +60 -0
- package/starter/assets/fonts/inter/OFL.txt +93 -0
- package/starter/assets/fonts/inter/asset.json +7 -0
- package/starter/assets/fonts/inter/files/1b08e7fc267a5c7e1d614100f604b83e7e8a0be241f0f288faa2b3ac93a683ba.ttf +0 -0
- package/starter/assets/fonts/inter/files/5b6f0c6f26e5c554a64cdcc3a9b5d802b7f9aec6206f1dbcfcdcad7b5860a2a9.ttf +0 -0
- package/starter/assets/fonts/inter/files/957db8560d510a198a7d0333fae7b6b444b00c20801581126273978d778eb3c3.pdf +0 -0
- package/starter/assets/fonts/inter/files/b37284b5701b6b168dfc770aa1a4ac492106422fd3ba76bc7641e37434e8019c.ttf +0 -0
- package/starter/assets/fonts/inter/files/c1811d32ac0f6eed1bbf57529f2ecdfc6c717d48a969dd864942436315a1b198.ttf +0 -0
- package/starter/assets/fonts/inter/files/e7a1aaf7eda9f2fad4131725fa556265ec75ca7b2d756260173a040363e8d4f7.ttf +0 -0
- package/starter/assets/fonts/inter/files/ef8f755d933b9310804cc9152f1f18cb2ac460d6b05054ec913d889c9f11f79e.ttf +0 -0
- package/starter/assets/fonts/inter/revisions/600391517c413963b71e278a57c26c40366c81fa3939a6b9755f446206766d12.json +99 -0
- package/starter/assets/fonts/inter/source.json +57 -0
- package/starter/assets/fonts/lato/OFL.txt +93 -0
- package/starter/assets/fonts/lato/asset.json +7 -0
- package/starter/assets/fonts/lato/files/4a6b566dbb28adb473a8789ce5169306f42f0c8a070ac92bae93636f36348b0d.pdf +0 -0
- package/starter/assets/fonts/lato/files/5adeb6b334d8fb99ef053bc052b952773d544315e0e1d668a12c0ce8bd51375c.ttf +0 -0
- package/starter/assets/fonts/lato/files/62c1b7f0d2e74b45960154c3520efc337b553db0961bfdc950d5618334596cc8.ttf +0 -0
- package/starter/assets/fonts/lato/files/71b8b7decbe75a881ed267be539d402bd1e9420b799658aada4e0d1bd5af803c.ttf +0 -0
- package/starter/assets/fonts/lato/files/8a0aace75d33794eece4b28187bfc1df0bbd2888b5d8a56e01788c8d65d16be1.ttf +0 -0
- package/starter/assets/fonts/lato/files/d636e4683231f931eda222d588e944d082bfd3bdba02f928bee461c0f185b251.ttf +0 -0
- package/starter/assets/fonts/lato/files/e399c44efe1387100531d26c7e4800c5d12251b890d6654a3098c7c679cb1786.ttf +0 -0
- package/starter/assets/fonts/lato/revisions/49ccb93400a9d466fab7d9843b1ecf8916ec6d47a475dd79a597a22eb39616bc.json +99 -0
- package/starter/assets/fonts/lato/source.json +57 -0
- package/starter/assets/fonts/merriweather/OFL.txt +93 -0
- package/starter/assets/fonts/merriweather/asset.json +7 -0
- package/starter/assets/fonts/merriweather/files/1c54f91b910454251c4c2b7bd4e472e1abf265fba7ca3c0ef2eee2f41324099e.ttf +0 -0
- package/starter/assets/fonts/merriweather/files/8bde8da2bb7f0265e27ba0481f70bb48d0f98a976c145f2f239c648ddd6532e0.pdf +0 -0
- package/starter/assets/fonts/merriweather/files/90b7db4460fcd1a5ca49575c2668a793f3cd6447664d312a068d690e1c01e6bc.ttf +0 -0
- package/starter/assets/fonts/merriweather/files/afff81272b7653417bb6f8bef57add055b1f9fda36f27eba5f32b40752bd08da.ttf +0 -0
- package/starter/assets/fonts/merriweather/files/e029d3b71e5bae3877c73f4f2b15af28db16593d49b0aed2a328d37ff7075846.ttf +0 -0
- package/starter/assets/fonts/merriweather/files/e9864a6790bf712a04e20f3662b206a1535186ed3e877fd859dd5fb9682335df.ttf +0 -0
- package/starter/assets/fonts/merriweather/files/fa71baebdd20a7d0de2e5e445a5922530fe9e1d740efbe791f113b682d3cb093.ttf +0 -0
- package/starter/assets/fonts/merriweather/revisions/1888e390b3e4f38a3d7cd2dc1bb805aeb6ce13f986a97656f0265fd436bc91d2.json +99 -0
- package/starter/assets/fonts/merriweather/source.json +57 -0
- package/starter/assets/fonts/open-sans/OFL.txt +92 -0
- package/starter/assets/fonts/open-sans/asset.json +7 -0
- package/starter/assets/fonts/open-sans/files/1bc0594a83762b2c25d38915a34464b7fec6088298ca22d151757bf98d6700ec.ttf +0 -0
- package/starter/assets/fonts/open-sans/files/47ed1cfaa7ffca04a04ab850b2938fd52c09d1b44cfa3e2980878e166b0cbd87.ttf +0 -0
- package/starter/assets/fonts/open-sans/files/574939af301f07df8e21cfff279465c5981dd9d9cf62086f7515897df951c6f5.pdf +0 -0
- package/starter/assets/fonts/open-sans/files/6d3884d0d57c1b67e9c50c54eca7b69c535c114e76bd7a9cfda0258588185553.ttf +0 -0
- package/starter/assets/fonts/open-sans/files/733eb93b167e6d45de09aa768f6c0355647c2c26f5416dbc7407a08ed41e81c6.ttf +0 -0
- package/starter/assets/fonts/open-sans/files/75367e6da7d914eaed87883ba51b2a2b5816b5cdbb39f96ec5c81a5b032bfd5a.ttf +0 -0
- package/starter/assets/fonts/open-sans/files/ff4fdc11204e0edd14e9a0bb6c374b847a9093b0ec2c16702e03afca79ac4ef7.ttf +0 -0
- package/starter/assets/fonts/open-sans/revisions/bbbe3a4915b9bccbc883c0decb4097511c43b6bd09ae22a1516aff128c219bc5.json +99 -0
- package/starter/assets/fonts/open-sans/source.json +57 -0
- package/starter/assets/fonts/roboto/OFL.txt +93 -0
- package/starter/assets/fonts/roboto/asset.json +7 -0
- package/starter/assets/fonts/roboto/files/22d45d989248a624252b8382067ac56550212fa675dcdbaf12f03d297dd87a58.pdf +0 -0
- package/starter/assets/fonts/roboto/files/35757eaa996b3359022f47f164a67ee9eac04971af24c5b8fbd4b89e844ff190.ttf +0 -0
- package/starter/assets/fonts/roboto/files/4d3035883c531846bd1ce2dc89f36d932e72dc114f56062c7e3a9cdd74f3d3ea.ttf +0 -0
- package/starter/assets/fonts/roboto/files/be7639306a4fc4a02ce2ae2ff59eb1335e4db4a7379dd0a384ed7cc053817789.ttf +0 -0
- package/starter/assets/fonts/roboto/files/d2920cbb1b60a3fd11fbf22049286e43a6baf522d37fdf1e7c89562319bcfea5.ttf +0 -0
- package/starter/assets/fonts/roboto/files/dece7c71bbe61710787f0839c722c65e87355dd2eb4a823e6b5488121ff81e4b.ttf +0 -0
- package/starter/assets/fonts/roboto/files/f478ba88b0292e685e487901dfbb1401457d32d6ebee4030cdfd5698235bffa8.ttf +0 -0
- package/starter/assets/fonts/roboto/revisions/bda5e2d84c17313373dd2dbf3e64fe0dd450c7e1b59e6929e69557e122fe976e.json +99 -0
- package/starter/assets/fonts/roboto/source.json +57 -0
- package/starter/assets/logos/opendoc/asset.json +6 -0
- package/starter/assets/logos/opendoc/files/831d5ccd9eb6709cc8439ea257c03d81452e81a28a3d1eedbd6a3b7daff687b6.png +0 -0
- package/starter/assets/logos/opendoc/revisions/834dde8926ddb81de687254195a168bb13bfb77803307f1257de1f2228be63b2.json +33 -0
- package/starter/assets/ui-fonts/geist/OFL.txt +93 -0
- package/starter/assets/ui-fonts/geist/geist-latin-ext-wght-italic.woff2 +0 -0
- package/starter/assets/ui-fonts/geist/geist-latin-ext-wght-normal.woff2 +0 -0
- package/starter/assets/ui-fonts/geist/geist-latin-wght-italic.woff2 +0 -0
- package/starter/assets/ui-fonts/geist/geist-latin-wght-normal.woff2 +0 -0
- package/starter/assets/ui-fonts/geist/source.json +26 -0
- package/starter/documents/welcome/assets.json +7 -0
- package/starter/documents/welcome/index.tsx +160 -0
- package/starter/documents/welcome/media/.gitkeep +0 -0
- package/starter/documents/welcome/media/paper-architecture/image.png +0 -0
- package/starter/documents/welcome/media/paper-architecture/meta.json +9 -0
- package/starter/documents/welcome/media/paper-architecture/prompt.txt +1 -0
- package/starter/documents/welcome/media/studio-rhythm/chart.svg +2343 -0
- package/starter/documents/welcome/media/studio-rhythm/data.json +234 -0
- package/starter/documents/welcome/media/studio-rhythm/generation.json +9 -0
- package/starter/documents/welcome/media/studio-rhythm/image.png +0 -0
- package/starter/documents/welcome/media/studio-rhythm/meta.json +11 -0
- package/starter/documents/welcome/media/studio-rhythm/recipe.py +79 -0
- package/starter/documents/welcome/theme.tsx +5 -0
- package/starter/documents/welcome-presentation/assets.json +7 -0
- package/starter/documents/welcome-presentation/index.tsx +166 -0
- package/starter/documents/welcome-presentation/media/.gitkeep +0 -0
- package/starter/documents/welcome-presentation/media/paper-architecture/image.png +0 -0
- package/starter/documents/welcome-presentation/media/paper-architecture/meta.json +9 -0
- package/starter/documents/welcome-presentation/media/paper-architecture/prompt.txt +1 -0
- package/starter/documents/welcome-presentation/media/studio-rhythm/chart.svg +1336 -0
- package/starter/documents/welcome-presentation/media/studio-rhythm/data.json +234 -0
- package/starter/documents/welcome-presentation/media/studio-rhythm/generation.json +9 -0
- package/starter/documents/welcome-presentation/media/studio-rhythm/image.png +0 -0
- package/starter/documents/welcome-presentation/media/studio-rhythm/meta.json +13 -0
- package/starter/documents/welcome-presentation/media/studio-rhythm/recipe.py +49 -0
- package/starter/documents/welcome-presentation/theme.tsx +5 -0
- package/starter/projects.json +17 -0
- package/starter/templates/AGENTS.md +9 -0
- package/starter/templates/_shared/BusinessLogo.tsx +14 -0
- package/starter/templates/_shared/Pricing.tsx +40 -0
- package/starter/templates/_shared/commerce.ts +93 -0
- package/starter/templates/brand-guidelines/AGENTS.md +32 -0
- package/starter/templates/brand-guidelines/index.tsx +62 -0
- package/starter/templates/brand-guidelines/preview.tsx +181 -0
- package/starter/templates/brand-guidelines/starter.tsx +179 -0
- package/starter/templates/brand-guidelines/template.json +15 -0
- package/starter/templates/business-proposal/AGENTS.md +13 -0
- package/starter/templates/business-proposal/README.md +36 -0
- package/starter/templates/business-proposal/data.json +37 -0
- package/starter/templates/business-proposal/examples/long.json +142 -0
- package/starter/templates/business-proposal/examples/sparse.json +17 -0
- package/starter/templates/business-proposal/examples/typical.json +37 -0
- package/starter/templates/business-proposal/index.tsx +59 -0
- package/starter/templates/business-proposal/preview.tsx +47 -0
- package/starter/templates/business-proposal/schema.ts +14 -0
- package/starter/templates/business-proposal/starter.tsx +18 -0
- package/starter/templates/business-proposal/template.json +11 -0
- package/starter/templates/company-profile/AGENTS.md +48 -0
- package/starter/templates/company-profile/index.tsx +69 -0
- package/starter/templates/company-profile/preview.tsx +185 -0
- package/starter/templates/company-profile/starter.tsx +186 -0
- package/starter/templates/company-profile/template.json +15 -0
- package/starter/templates/consulting-report/AGENTS.md +11 -0
- package/starter/templates/consulting-report/README.md +13 -0
- package/starter/templates/consulting-report/RESEARCH.md +10 -0
- package/starter/templates/consulting-report/index.tsx +44 -0
- package/starter/templates/consulting-report/preview.tsx +39 -0
- package/starter/templates/consulting-report/starter.tsx +15 -0
- package/starter/templates/consulting-report/template.json +11 -0
- package/starter/templates/editorial-essay/AGENTS.md +11 -0
- package/starter/templates/editorial-essay/README.md +11 -0
- package/starter/templates/editorial-essay/index.tsx +30 -0
- package/starter/templates/editorial-essay/preview.tsx +26 -0
- package/starter/templates/editorial-essay/starter.tsx +15 -0
- package/starter/templates/editorial-essay/template.json +11 -0
- package/starter/templates/executive-brief/AGENTS.md +9 -0
- package/starter/templates/executive-brief/README.md +11 -0
- package/starter/templates/executive-brief/index.tsx +33 -0
- package/starter/templates/executive-brief/preview.tsx +37 -0
- package/starter/templates/executive-brief/starter.tsx +11 -0
- package/starter/templates/executive-brief/template.json +11 -0
- package/starter/templates/image-story/AGENTS.md +37 -0
- package/starter/templates/image-story/index.tsx +106 -0
- package/starter/templates/image-story/preview.tsx +33 -0
- package/starter/templates/image-story/starter.tsx +24 -0
- package/starter/templates/image-story/template.json +13 -0
- package/starter/templates/invoice/AGENTS.md +13 -0
- package/starter/templates/invoice/README.md +40 -0
- package/starter/templates/invoice/data.json +61 -0
- package/starter/templates/invoice/examples/long.json +241 -0
- package/starter/templates/invoice/examples/sparse.json +33 -0
- package/starter/templates/invoice/examples/typical.json +61 -0
- package/starter/templates/invoice/index.tsx +57 -0
- package/starter/templates/invoice/preview.tsx +12 -0
- package/starter/templates/invoice/schema.ts +45 -0
- package/starter/templates/invoice/starter.tsx +12 -0
- package/starter/templates/invoice/template.json +11 -0
- package/starter/templates/literary-text/AGENTS.md +9 -0
- package/starter/templates/literary-text/README.md +11 -0
- package/starter/templates/literary-text/index.tsx +31 -0
- package/starter/templates/literary-text/preview.tsx +20 -0
- package/starter/templates/literary-text/starter.tsx +11 -0
- package/starter/templates/literary-text/template.json +11 -0
- package/starter/templates/magazine-feature/AGENTS.md +11 -0
- package/starter/templates/magazine-feature/README.md +13 -0
- package/starter/templates/magazine-feature/index.tsx +41 -0
- package/starter/templates/magazine-feature/preview.tsx +34 -0
- package/starter/templates/magazine-feature/starter.tsx +15 -0
- package/starter/templates/magazine-feature/template.json +11 -0
- package/starter/templates/monthly-report/AGENTS.md +11 -0
- package/starter/templates/monthly-report/README.md +24 -0
- package/starter/templates/monthly-report/data.json +131 -0
- package/starter/templates/monthly-report/examples/long.json +519 -0
- package/starter/templates/monthly-report/examples/sparse.json +20 -0
- package/starter/templates/monthly-report/examples/typical.json +37 -0
- package/starter/templates/monthly-report/index.tsx +92 -0
- package/starter/templates/monthly-report/preview.tsx +14 -0
- package/starter/templates/monthly-report/schema.ts +127 -0
- package/starter/templates/monthly-report/starter.tsx +13 -0
- package/starter/templates/monthly-report/template.json +11 -0
- package/starter/templates/pitch-deck/AGENTS.md +32 -0
- package/starter/templates/pitch-deck/index.tsx +46 -0
- package/starter/templates/pitch-deck/preview.tsx +142 -0
- package/starter/templates/pitch-deck/starter.tsx +140 -0
- package/starter/templates/pitch-deck/template.json +15 -0
- package/starter/templates/proposal-deck/AGENTS.md +25 -0
- package/starter/templates/proposal-deck/index.tsx +52 -0
- package/starter/templates/proposal-deck/preview.tsx +172 -0
- package/starter/templates/proposal-deck/starter.tsx +168 -0
- package/starter/templates/proposal-deck/template.json +7 -0
- package/starter/templates/quotation/AGENTS.md +13 -0
- package/starter/templates/quotation/README.md +42 -0
- package/starter/templates/quotation/data.json +64 -0
- package/starter/templates/quotation/examples/long.json +272 -0
- package/starter/templates/quotation/examples/sparse.json +31 -0
- package/starter/templates/quotation/examples/typical.json +64 -0
- package/starter/templates/quotation/index.tsx +51 -0
- package/starter/templates/quotation/preview.tsx +12 -0
- package/starter/templates/quotation/schema.ts +27 -0
- package/starter/templates/quotation/starter.tsx +12 -0
- package/starter/templates/quotation/template.json +11 -0
- package/starter/templates/scientific-paper/AGENTS.md +11 -0
- package/starter/templates/scientific-paper/README.md +13 -0
- package/starter/templates/scientific-paper/index.tsx +47 -0
- package/starter/templates/scientific-paper/preview.tsx +43 -0
- package/starter/templates/scientific-paper/starter.tsx +15 -0
- package/starter/templates/scientific-paper/template.json +11 -0
- package/starter/themes/Specimen.tsx +54 -0
- package/starter/themes/civic-spectrum/components.tsx +92 -0
- package/starter/themes/civic-spectrum/design.md +70 -0
- package/starter/themes/civic-spectrum/index.ts +57 -0
- package/starter/themes/civic-spectrum/preview.tsx +66 -0
- package/starter/themes/field-manual/components.tsx +106 -0
- package/starter/themes/field-manual/design.md +72 -0
- package/starter/themes/field-manual/index.ts +57 -0
- package/starter/themes/field-manual/preview.tsx +82 -0
- package/starter/themes/index.ts +3 -0
- package/starter/themes/mckinsey-consulting/components.tsx +69 -0
- package/starter/themes/mckinsey-consulting/design.md +68 -0
- package/starter/themes/mckinsey-consulting/index.ts +60 -0
- package/starter/themes/mckinsey-consulting/preview.tsx +53 -0
- package/starter/themes/neutral/design.md +35 -0
- package/starter/themes/neutral/index.ts +21 -0
- package/starter/themes/neutral/preview.tsx +4 -0
- package/starter/themes/opendoc-neutral/components.tsx +77 -0
- package/starter/themes/opendoc-neutral/design.md +70 -0
- package/starter/themes/opendoc-neutral/index.ts +54 -0
- package/starter/themes/opendoc-neutral/preview.tsx +43 -0
- package/starter/themes/types.ts +3 -0
- package/tsconfig.workspace.json +24 -0
- package/vendor/formepdf/LICENSE +21 -0
- package/vendor/formepdf/README.md +97 -0
- package/vendor/formepdf/font-subset.patch +228 -0
- package/vendor/formepdf/text-writer.patch +507 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { lstat, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { linkSync, lstatSync, readFileSync, unlinkSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { execFile } from 'node:child_process';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
import { atomicWrite, containedFile } from './files';
|
|
8
|
+
import { ExportChangedError } from './export-file';
|
|
9
|
+
import { validId } from './render';
|
|
10
|
+
import { exportInfo, type ExportFormat, type SavedExport, type ExportHistoryEntry } from '../shared/export';
|
|
11
|
+
import { readZip } from '@shbernal/ts-pptx/zip';
|
|
12
|
+
import { copyFileToClipboard } from './clipboard';
|
|
13
|
+
import type { AssetUse, DocumentAssets } from '../shared/assets';
|
|
14
|
+
import { parseDocumentAssets, validAssetId, validRevision } from '../assets/files';
|
|
15
|
+
|
|
16
|
+
type Receipt = SavedExport & { digest: string; requestedName: string; deletedAt?: string; deletedFile?: boolean };
|
|
17
|
+
type ExportPreparation = { bytes: Uint8Array; isCurrent: () => boolean; assetBindings?: DocumentAssets; assets?: AssetUse[] };
|
|
18
|
+
export class ExportError extends Error {
|
|
19
|
+
constructor(message: string, public status = 400) { super(message); }
|
|
20
|
+
}
|
|
21
|
+
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
22
|
+
const maxReceiptBytes = 2_000_000;
|
|
23
|
+
const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex');
|
|
24
|
+
function assetProvenance(value: Pick<ExportPreparation, 'assetBindings' | 'assets'>): Pick<SavedExport, 'assetBindings' | 'assets'> {
|
|
25
|
+
const result: Pick<SavedExport, 'assetBindings' | 'assets'> = {};
|
|
26
|
+
if (value.assetBindings !== undefined) result.assetBindings = structuredClone(parseDocumentAssets(value.assetBindings));
|
|
27
|
+
if (value.assets !== undefined) {
|
|
28
|
+
if (!Array.isArray(value.assets) || value.assets.length > 100_000) throw new ExportError('The export asset provenance is invalid.');
|
|
29
|
+
const uses = new Map<string, AssetUse>();
|
|
30
|
+
for (const use of value.assets) {
|
|
31
|
+
if (!use || !['logo', 'font'].includes(use.kind) || !validAssetId(use.id) || !validRevision(use.revision)
|
|
32
|
+
|| (use.variation !== undefined && !validAssetId(use.variation)) || (use.face !== undefined && !validAssetId(use.face))) throw new ExportError('The export asset provenance is invalid.');
|
|
33
|
+
// Block-level evidence remains in the render artifact; receipts retain compact actual identities.
|
|
34
|
+
const ref: AssetUse = { kind: use.kind, id: use.id, revision: use.revision,
|
|
35
|
+
...(use.variation !== undefined ? { variation: use.variation } : {}), ...(use.face !== undefined ? { face: use.face } : {}) };
|
|
36
|
+
uses.set(JSON.stringify(ref), ref);
|
|
37
|
+
}
|
|
38
|
+
result.assets = [...uses.values()];
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
export function exportFormat(value: unknown = 'pdf'): ExportFormat {
|
|
43
|
+
if (value !== 'pdf' && value !== 'pptx') throw new ExportError('Choose PDF or PowerPoint as the export format.');
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
export function exportFilename(value: unknown, maximum = 120, format: ExportFormat = 'pdf') {
|
|
47
|
+
if (typeof value !== 'string') throw new ExportError('Enter a filename.');
|
|
48
|
+
const trimmed = value.trim();
|
|
49
|
+
if (!trimmed || /[<>:"/\\|?*\u0000-\u001f\u007f]/.test(trimmed) || /^[.]/.test(trimmed) || /[. ]$/.test(trimmed)
|
|
50
|
+
|| /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(trimmed)) throw new ExportError('Use a filename without slashes or special characters.');
|
|
51
|
+
const extension = exportInfo(format).extension;
|
|
52
|
+
const name = trimmed.toLowerCase().endsWith(extension) ? trimmed : `${trimmed.replace(/\.(pdf|pptx)$/i, '')}${extension}`;
|
|
53
|
+
if (name.length > maximum || Buffer.byteLength(name) > maximum + 100) throw new ExportError('This filename is too long. Choose a shorter name.');
|
|
54
|
+
return name;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Receipts survive a server restart; a hard link publishes a complete file without overwriting. */
|
|
58
|
+
export class ExportStore {
|
|
59
|
+
private changes = new Map<string, Promise<unknown>>();
|
|
60
|
+
constructor(private root: string) {}
|
|
61
|
+
private async change<T>(id: string, run: () => Promise<T>): Promise<T> {
|
|
62
|
+
const previous = this.changes.get(id);
|
|
63
|
+
const next = (previous ?? Promise.resolve()).catch(() => {}).then(run);
|
|
64
|
+
this.changes.set(id, next);
|
|
65
|
+
try { return await next; } finally { if (this.changes.get(id) === next) this.changes.delete(id); }
|
|
66
|
+
}
|
|
67
|
+
private result(value: Receipt): SavedExport {
|
|
68
|
+
const { digest: _, requestedName: __, deletedAt: ___, deletedFile: ____, ...result } = value;
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
private async records() {
|
|
72
|
+
const folder = await this.folder('.opendoc/exports');
|
|
73
|
+
const records = await Promise.all((await readdir(folder)).filter(name => uuid.test(name.slice(0, -5)) && name.endsWith('.json')).map(async name => {
|
|
74
|
+
try { return await this.receipt(name.slice(0, -5)); } catch { return undefined; }
|
|
75
|
+
}));
|
|
76
|
+
return records.filter((value): value is Receipt => !!value);
|
|
77
|
+
}
|
|
78
|
+
// CLI exports use a fixed filename. Adopt only that documented path,
|
|
79
|
+
// never guess document membership from arbitrary PDF filenames.
|
|
80
|
+
private async adoptCliExport(documentId: string, format: ExportFormat = 'pdf') {
|
|
81
|
+
const extension = exportInfo(format).extension;
|
|
82
|
+
const output = await this.folder('output');
|
|
83
|
+
const path = resolve(output, `${documentId}${extension}`);
|
|
84
|
+
try {
|
|
85
|
+
const info = await lstat(path);
|
|
86
|
+
if (!info.isFile() || info.isSymbolicLink()) return;
|
|
87
|
+
const records = await this.records();
|
|
88
|
+
for (const record of records) {
|
|
89
|
+
try {
|
|
90
|
+
const snapshot = await lstat(resolve(this.root, '.opendoc/exports', `${record.id}${exportInfo(record.format).extension}`));
|
|
91
|
+
if (snapshot.ino === info.ino && snapshot.dev === info.dev) return;
|
|
92
|
+
} catch { /* Missing snapshots do not claim the file. */ }
|
|
93
|
+
}
|
|
94
|
+
const bytes = await readFile(path);
|
|
95
|
+
if (format === 'pdf') { if (bytes.subarray(0, 5).toString() !== '%PDF-') return; }
|
|
96
|
+
else { try { if (!(await readZip(bytes)).has('ppt/presentation.xml')) return; } catch { return; } }
|
|
97
|
+
const key = digest(Buffer.from(`${documentId}:${info.dev}:${info.ino}:${info.mtimeMs}:${info.size}`));
|
|
98
|
+
const id = `${key.slice(0, 8)}-${key.slice(8, 12)}-4${key.slice(13, 16)}-8${key.slice(17, 20)}-${key.slice(20, 32)}`;
|
|
99
|
+
if (await this.receipt(id)) return;
|
|
100
|
+
const folder = await this.folder('.opendoc/exports');
|
|
101
|
+
const current = lstatSync(path);
|
|
102
|
+
if (current.ino !== info.ino || current.dev !== info.dev || current.mtimeMs !== info.mtimeMs || current.size !== info.size || current.isSymbolicLink()) return;
|
|
103
|
+
linkSync(path, resolve(folder, `${id}${extension}`));
|
|
104
|
+
const receipt: Receipt = { id, documentId, format, hash: '', filename: `${documentId}${extension}`, path, bytes: bytes.length, createdAt: info.mtime.toISOString(), digest: digest(bytes), requestedName: `${documentId}${extension}` };
|
|
105
|
+
await atomicWrite(resolve(folder, `${id}.json`), JSON.stringify(receipt));
|
|
106
|
+
} catch (error) { if (!['ENOENT', 'EEXIST'].includes((error as NodeJS.ErrnoException).code ?? '')) throw error; }
|
|
107
|
+
}
|
|
108
|
+
async list(documentId: string): Promise<ExportHistoryEntry[]> {
|
|
109
|
+
if (!validId(documentId)) throw new ExportError('Invalid document.');
|
|
110
|
+
await this.change(`cli:${documentId}`, async () => { await this.adoptCliExport(documentId); await this.adoptCliExport(documentId, 'pptx'); });
|
|
111
|
+
const records = (await this.records()).filter(value => value.documentId === documentId && !value.deletedAt);
|
|
112
|
+
return Promise.all(records.sort((a, b) => b.createdAt.localeCompare(a.createdAt) || b.id.localeCompare(a.id)).map(async value => {
|
|
113
|
+
let available = false;
|
|
114
|
+
try { available = !!await this.get(value.id); } catch { /* Retain history for changed files. */ }
|
|
115
|
+
return { ...this.result(value), available };
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
async remove(id: string) {
|
|
119
|
+
return this.change(id, async () => {
|
|
120
|
+
const value = await this.receipt(id);
|
|
121
|
+
if (!value) throw new ExportError('Export not found.', 404);
|
|
122
|
+
if (value.deletedAt) return;
|
|
123
|
+
let owned = false;
|
|
124
|
+
try { owned = !!await this.get(id); } catch { /* Never remove an externally changed file. */ }
|
|
125
|
+
const removed = { ...value, deletedAt: new Date().toISOString(), deletedFile: owned };
|
|
126
|
+
const receiptPath = resolve(this.root, '.opendoc/exports', `${id}.json`);
|
|
127
|
+
await atomicWrite(receiptPath, JSON.stringify(removed));
|
|
128
|
+
if (owned) {
|
|
129
|
+
try {
|
|
130
|
+
const file = lstatSync(value.path), snapshot = lstatSync(resolve(this.root, '.opendoc/exports', `${id}${exportInfo(value.format).extension}`));
|
|
131
|
+
if (!file.isSymbolicLink() && file.ino === snapshot.ino && file.dev === snapshot.dev && digest(readFileSync(value.path)) === value.digest) unlinkSync(value.path);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { await atomicWrite(receiptPath, JSON.stringify(value)); throw error; }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
async restore(id: string) {
|
|
139
|
+
return this.change(id, async () => {
|
|
140
|
+
const value = await this.receipt(id);
|
|
141
|
+
if (!value) throw new ExportError('Export not found.', 404);
|
|
142
|
+
if (!value.deletedAt) return this.result(value);
|
|
143
|
+
if (value.deletedFile) {
|
|
144
|
+
const snapshot = resolve(this.root, '.opendoc/exports', `${id}${exportInfo(value.format).extension}`);
|
|
145
|
+
const info = await lstat(snapshot);
|
|
146
|
+
if (!info.isFile() || info.isSymbolicLink() || digest(await readFile(snapshot)) !== value.digest) throw new ExportError('The saved copy has changed and cannot be restored.', 409);
|
|
147
|
+
const output = await this.folder('output');
|
|
148
|
+
let restored = false;
|
|
149
|
+
const original = value.filename;
|
|
150
|
+
for (let suffix = 1; suffix <= 10_000; suffix++) {
|
|
151
|
+
const filename = suffix === 1 ? original : `${original.slice(0, -exportInfo(value.format).extension.length)} (${suffix})${exportInfo(value.format).extension}`;
|
|
152
|
+
const path = resolve(output, filename);
|
|
153
|
+
try { linkSync(snapshot, path); }
|
|
154
|
+
catch (error) {
|
|
155
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
|
|
156
|
+
const existing = lstatSync(path);
|
|
157
|
+
if (existing.isSymbolicLink() || existing.ino !== info.ino || existing.dev !== info.dev) continue;
|
|
158
|
+
}
|
|
159
|
+
value.filename = filename; value.path = path; restored = true; break;
|
|
160
|
+
}
|
|
161
|
+
if (!restored) throw new ExportError('Too many files have this name.');
|
|
162
|
+
}
|
|
163
|
+
delete value.deletedAt; delete value.deletedFile;
|
|
164
|
+
await atomicWrite(resolve(this.root, '.opendoc/exports', `${id}.json`), JSON.stringify(value));
|
|
165
|
+
return this.result(value);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
private async folder(relative: string) {
|
|
169
|
+
let path = this.root;
|
|
170
|
+
for (const part of relative.split('/')) {
|
|
171
|
+
path = resolve(path, part);
|
|
172
|
+
await mkdir(path, { recursive: true });
|
|
173
|
+
const info = await lstat(path);
|
|
174
|
+
if (!info.isDirectory() || info.isSymbolicLink()) throw new ExportError('The local export folder must be a regular folder.');
|
|
175
|
+
await containedFile(this.root, path);
|
|
176
|
+
}
|
|
177
|
+
return path;
|
|
178
|
+
}
|
|
179
|
+
private async receipt(id: string): Promise<Receipt | undefined> {
|
|
180
|
+
if (!uuid.test(id)) throw new ExportError('Invalid export request.');
|
|
181
|
+
const folder = await this.folder('.opendoc/exports');
|
|
182
|
+
const path = resolve(folder, `${id}.json`);
|
|
183
|
+
try {
|
|
184
|
+
const info = await lstat(path);
|
|
185
|
+
if (!info.isFile() || info.isSymbolicLink() || info.size > maxReceiptBytes) throw new ExportError('The export receipt cannot be read.');
|
|
186
|
+
const value = JSON.parse(await readFile(path, 'utf8')) as Receipt;
|
|
187
|
+
if (value.id !== id || !validId(value.documentId) || value.filename !== exportFilename(value.filename, 140, exportFormat(value.format))
|
|
188
|
+
|| value.path !== resolve(this.root, 'output', value.filename) || !/^[a-f0-9]{64}$/.test(value.digest) || !Number.isFinite(Date.parse(value.createdAt)) || !Number.isSafeInteger(value.bytes) || value.bytes < 1) throw new ExportError('The export receipt is invalid.');
|
|
189
|
+
assetProvenance(value);
|
|
190
|
+
return value;
|
|
191
|
+
} catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return; throw error; }
|
|
192
|
+
}
|
|
193
|
+
async get(id: string): Promise<SavedExport | undefined> {
|
|
194
|
+
const value = await this.receipt(id);
|
|
195
|
+
if (!value || value.deletedAt) return;
|
|
196
|
+
await this.folder('output');
|
|
197
|
+
try {
|
|
198
|
+
const [output, snapshot] = await Promise.all([lstat(value.path), lstat(resolve(this.root, '.opendoc/exports', `${id}${exportInfo(value.format).extension}`))]);
|
|
199
|
+
if (!output.isFile() || output.isSymbolicLink() || !snapshot.isFile() || snapshot.isSymbolicLink()
|
|
200
|
+
|| output.ino !== snapshot.ino || output.dev !== snapshot.dev) return;
|
|
201
|
+
if (digest(await readFile(value.path)) !== value.digest) throw new ExportError('This exported file was changed outside OpenDoc. Export a new copy.', 409);
|
|
202
|
+
return this.result(value);
|
|
203
|
+
} catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return; throw error; }
|
|
204
|
+
}
|
|
205
|
+
async bytes(id: string) {
|
|
206
|
+
const result = await this.get(id);
|
|
207
|
+
if (!result) throw new ExportError('This export could not be found. Export a new copy.', 404);
|
|
208
|
+
const bytes = await readFile(result.path);
|
|
209
|
+
const receipt = (await this.receipt(id))!;
|
|
210
|
+
if (digest(bytes) !== receipt.digest) throw new ExportError('The exported file changed. Export a new copy.', 409);
|
|
211
|
+
return { result, bytes };
|
|
212
|
+
}
|
|
213
|
+
async save(input: { id: string; documentId: string; hash: string; filename: string; format?: ExportFormat }, prepare: () => Promise<ExportPreparation>) {
|
|
214
|
+
return this.change(input.id, () => this.saveInternal(input, prepare));
|
|
215
|
+
}
|
|
216
|
+
private async saveInternal(input: { id: string; documentId: string; hash: string; filename: string; format?: ExportFormat }, prepare: () => Promise<ExportPreparation>) {
|
|
217
|
+
if (!uuid.test(input.id) || !validId(input.documentId) || typeof input.hash !== 'string' || !input.hash) throw new ExportError('Invalid export request.');
|
|
218
|
+
const format = exportFormat(input.format);
|
|
219
|
+
const filename = exportFilename(input.filename, 120, format);
|
|
220
|
+
try { return await this.publish({ ...input, filename, format }, prepare); }
|
|
221
|
+
catch (error) {
|
|
222
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
223
|
+
if (code === 'ENOSPC') throw new ExportError('There is not enough disk space to save the file. Free some space and try again.');
|
|
224
|
+
if (code && ['EACCES', 'EPERM', 'EROFS'].includes(code)) throw new ExportError('OpenDoc cannot write to the export folder. Check its permissions and try again.');
|
|
225
|
+
if (code === 'EXDEV') throw new ExportError('The output folder and workspace must be on the same disk for a safe export.');
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
private async publish(input: { id: string; documentId: string; hash: string; filename: string; format?: ExportFormat }, prepare: () => Promise<ExportPreparation>) {
|
|
230
|
+
const previous = await this.receipt(input.id);
|
|
231
|
+
if (previous && (previous.documentId !== input.documentId || previous.hash !== input.hash || previous.requestedName !== input.filename || (previous.format ?? 'pdf') !== (input.format ?? 'pdf'))) throw new ExportError('This export request belongs to another file.', 409);
|
|
232
|
+
if (previous?.deletedAt) throw new ExportError('This export was deleted. Start a new export.', 409);
|
|
233
|
+
const saved = await this.get(input.id);
|
|
234
|
+
if (saved) return saved;
|
|
235
|
+
const prepared = await prepare();
|
|
236
|
+
const { bytes, isCurrent } = prepared;
|
|
237
|
+
const provenance = assetProvenance(prepared);
|
|
238
|
+
if (input.format === 'pptx') {
|
|
239
|
+
try {
|
|
240
|
+
const parts = await readZip(bytes);
|
|
241
|
+
if (!parts.has('ppt/presentation.xml') || !parts.has('[Content_Types].xml') || !parts.has('ppt/slides/slide1.xml')) throw new Error('Missing presentation parts');
|
|
242
|
+
} catch { throw new ExportError('The PowerPoint file is incomplete. Try exporting again.'); }
|
|
243
|
+
} else if (!bytes.length || Buffer.from(bytes.subarray(0, 5)).toString() !== '%PDF-') throw new ExportError('The PDF is incomplete. Wait for a valid preview and try again.');
|
|
244
|
+
const folder = await this.folder('.opendoc/exports');
|
|
245
|
+
const output = await this.folder('output');
|
|
246
|
+
const snapshot = resolve(folder, `${input.id}${exportInfo(input.format).extension}`);
|
|
247
|
+
// A receipt without a published link is an interrupted preparation, safe to retry.
|
|
248
|
+
await rm(snapshot, { force: true });
|
|
249
|
+
let published = false;
|
|
250
|
+
try {
|
|
251
|
+
await writeFile(snapshot, bytes, { flag: 'wx' });
|
|
252
|
+
const contentDigest = digest(bytes);
|
|
253
|
+
for (let suffix = 1; suffix <= 10_000; suffix++) {
|
|
254
|
+
const filename = suffix === 1 ? input.filename : `${input.filename.slice(0, -exportInfo(input.format).extension.length)} (${suffix})${exportInfo(input.format).extension}`;
|
|
255
|
+
const receipt: Receipt = { format: input.format, id: input.id, documentId: input.documentId, hash: input.hash, filename, path: resolve(output, filename), bytes: bytes.length, createdAt: new Date().toISOString(), digest: contentDigest, requestedName: input.filename, ...provenance };
|
|
256
|
+
const serialized = JSON.stringify(receipt);
|
|
257
|
+
if (Buffer.byteLength(serialized) > maxReceiptBytes) throw new ExportError('This document has too much asset provenance for one saved export.');
|
|
258
|
+
await atomicWrite(resolve(folder, `${input.id}.json`), serialized);
|
|
259
|
+
if (!isCurrent()) throw new ExportChangedError();
|
|
260
|
+
try { linkSync(snapshot, receipt.path); } catch (error) { if ((error as NodeJS.ErrnoException).code === 'EEXIST') continue; throw error; }
|
|
261
|
+
published = true;
|
|
262
|
+
const { digest: _, requestedName: __, ...result } = receipt;
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
throw new ExportError('Too many files have this name. Choose another filename.');
|
|
266
|
+
} finally {
|
|
267
|
+
if (!published) { await rm(snapshot, { force: true }); await rm(resolve(folder, `${input.id}.json`), { force: true }); }
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async reveal(id: string) {
|
|
271
|
+
const value = await this.get(id);
|
|
272
|
+
if (!value) throw new ExportError('This exported file is no longer available.', 404);
|
|
273
|
+
const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'explorer.exe' : 'xdg-open';
|
|
274
|
+
const args = process.platform === 'darwin' ? ['-R', value.path] : process.platform === 'win32' ? [`/select,${value.path}`] : [resolve(this.root, 'output')];
|
|
275
|
+
try { await promisify(execFile)(command, args, { timeout: 10_000 }); }
|
|
276
|
+
catch { throw new ExportError(`Could not open the file manager. Your file is saved at ${value.path}.`); }
|
|
277
|
+
}
|
|
278
|
+
async copy(id: string) {
|
|
279
|
+
const value = await this.get(id);
|
|
280
|
+
if (!value) throw new ExportError('This exported file is no longer available. Export a new copy.', 404);
|
|
281
|
+
await copyFileToClipboard(value.path);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, rm, writeFile, realpath } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve, relative, sep } from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
|
|
5
|
+
export async function atomicWrite(file: string, contents: string | Uint8Array) {
|
|
6
|
+
await mkdir(dirname(file), { recursive: true });
|
|
7
|
+
const temp = `${file}.${randomUUID()}.tmp`;
|
|
8
|
+
try { await writeFile(temp, contents); await rename(temp, file); }
|
|
9
|
+
finally { await rm(temp, { force: true }); }
|
|
10
|
+
}
|
|
11
|
+
export async function readJSON<T>(file: string, fallback: T): Promise<T> {
|
|
12
|
+
try { return JSON.parse(await readFile(file, 'utf8')); }
|
|
13
|
+
catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return fallback; throw error; }
|
|
14
|
+
}
|
|
15
|
+
export async function containedFile(root: string, file: string) {
|
|
16
|
+
const actualRoot = await realpath(root);
|
|
17
|
+
const actualFile = await realpath(file);
|
|
18
|
+
const rel = relative(actualRoot, actualFile);
|
|
19
|
+
if (rel === '..' || rel.startsWith(`..${sep}`) || resolve(actualRoot, rel) !== actualFile) throw new Error('Path is outside the workspace.');
|
|
20
|
+
return actualFile;
|
|
21
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { readFile, realpath, stat } from 'node:fs/promises';
|
|
2
|
+
import { relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { applicationRoot } from '../runtime/paths';
|
|
4
|
+
import { containedFile } from './files';
|
|
5
|
+
|
|
6
|
+
export class GuideError extends Error {
|
|
7
|
+
constructor(message: string, public status: 400 | 404 = 400) { super(message); }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const namedGuides = new Set(['README.md', 'AGENTS.md', 'VALIDATION.md', 'CONTRIBUTING.md', 'SECURITY.md', 'THIRD_PARTY.md', 'templates/AGENTS.md', 'vendor/formepdf/README.md']);
|
|
11
|
+
const maxGuideBytes = 128_000;
|
|
12
|
+
|
|
13
|
+
function isApplicationGuide(file: string): boolean {
|
|
14
|
+
return namedGuides.has(file) || file.startsWith('docs/') || file.startsWith('.agents/skills/');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isMissing(error: unknown): boolean {
|
|
18
|
+
return ['ENOENT', 'ENOTDIR'].includes((error as NodeJS.ErrnoException).code ?? '');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function guidePath(value: unknown): asserts value is string {
|
|
22
|
+
if (typeof value !== 'string' || !value || value.length > 512 || !value.endsWith('.md') || /[\\\u0000-\u001f\u007f?#:]/.test(value)
|
|
23
|
+
|| value.split('/').some((part, index) => !part || (part.startsWith('.') && !(index === 0 && part === '.agents')))) {
|
|
24
|
+
throw new GuideError('Choose a workspace-relative Markdown guide.');
|
|
25
|
+
}
|
|
26
|
+
if (!namedGuides.has(value) && !/^docs\/.+\.md$/.test(value)
|
|
27
|
+
&& !/^(?:templates|themes)\/[a-z0-9]+(?:-[a-z0-9]+)*\/.+\.md$/.test(value)
|
|
28
|
+
&& !/^\.agents\/skills\/.+\.md$/.test(value)) {
|
|
29
|
+
throw new GuideError('That file is outside the OpenDoc guide locations.');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function readGuideAt(root: string, file: string, application = false): Promise<{ file: string; markdown: string }> {
|
|
34
|
+
const base = await realpath(root);
|
|
35
|
+
const path = await containedFile(base, resolve(base, file));
|
|
36
|
+
const canonical = relative(base, path).split(sep).join('/');
|
|
37
|
+
guidePath(canonical);
|
|
38
|
+
if (application && !isApplicationGuide(canonical)) throw new GuideError('That file is outside the installed OpenDoc guide locations.');
|
|
39
|
+
const info = await stat(path);
|
|
40
|
+
if (!info.isFile()) throw new GuideError('This guide must be a regular Markdown file.');
|
|
41
|
+
if (info.size > maxGuideBytes) throw new GuideError('This guide is too large to display. Keep it below 128 KB.');
|
|
42
|
+
const markdown = await readFile(path, 'utf8');
|
|
43
|
+
if (Buffer.byteLength(markdown) > maxGuideBytes) throw new GuideError('This guide is too large to display. Keep it below 128 KB.');
|
|
44
|
+
return { file: canonical, markdown };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Prefer workspace guidance; only canonical application guides can fall back to the installation. */
|
|
48
|
+
export async function readGuide(root: string, file: unknown): Promise<{ file: string; markdown: string }> {
|
|
49
|
+
try {
|
|
50
|
+
// Generated workspace pointers name this one installed package explicitly.
|
|
51
|
+
// Resolve through our application root, never through arbitrary node_modules paths.
|
|
52
|
+
const prefix = 'node_modules/opendoc/';
|
|
53
|
+
if (typeof file === 'string' && file.startsWith(prefix)) {
|
|
54
|
+
const installed = file.slice(prefix.length);
|
|
55
|
+
guidePath(installed);
|
|
56
|
+
if (/^(?:templates|themes)\//.test(installed)) return await readGuideAt(root, installed);
|
|
57
|
+
if (!isApplicationGuide(installed)) throw new GuideError('That file is outside the installed OpenDoc guide locations.');
|
|
58
|
+
const guide = await readGuideAt(applicationRoot, installed, true);
|
|
59
|
+
return { ...guide, file: `${prefix}${guide.file}` };
|
|
60
|
+
}
|
|
61
|
+
guidePath(file);
|
|
62
|
+
try { return await readGuideAt(root, file); }
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (!isMissing(error) || !isApplicationGuide(file)) throw error;
|
|
65
|
+
}
|
|
66
|
+
return await readGuideAt(applicationRoot, file, true);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (isMissing(error)) throw new GuideError(`This guide is missing: ${file}. Ask your agent to restore it or update the link.`, 404);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|