@maniclang/workbench 0.1.11
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/CONTRIBUTING.md +40 -0
- package/README.md +155 -0
- package/dist/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/client/assets/abap-CRCWOmpq.js +1 -0
- package/dist/client/assets/apex-DnsZk_dE.js +1 -0
- package/dist/client/assets/azcli-1IWB1ccx.js +1 -0
- package/dist/client/assets/bat-DPkNLes8.js +1 -0
- package/dist/client/assets/bicep-Corcdgou.js +2 -0
- package/dist/client/assets/cameligo-CGrWLZr3.js +1 -0
- package/dist/client/assets/clojure-D9WOWImG.js +1 -0
- package/dist/client/assets/codicon-CgENjH2v.ttf +0 -0
- package/dist/client/assets/coffee-B7EJu28W.js +1 -0
- package/dist/client/assets/cpp-SEyurbux.js +1 -0
- package/dist/client/assets/csharp-BoL64M5l.js +1 -0
- package/dist/client/assets/csp-C46ZqvIl.js +1 -0
- package/dist/client/assets/css-DQU6DXDx.js +3 -0
- package/dist/client/assets/cssMode-CtRONlr8.js +4 -0
- package/dist/client/assets/cypher-D84EuPTj.js +1 -0
- package/dist/client/assets/dart-D8lhlL1r.js +1 -0
- package/dist/client/assets/dockerfile-DLk6rpji.js +1 -0
- package/dist/client/assets/ecl-BO6FnfXk.js +1 -0
- package/dist/client/assets/editor.worker-CZyr7Ur9.js +26 -0
- package/dist/client/assets/elixir-BRjLKONM.js +1 -0
- package/dist/client/assets/flow9-Cac8vKd7.js +1 -0
- package/dist/client/assets/freemarker2-BTSNJUl8.js +3 -0
- package/dist/client/assets/fsharp-fd1GTHhf.js +1 -0
- package/dist/client/assets/go-O9LJTZXk.js +1 -0
- package/dist/client/assets/graphql-LQdxqEYJ.js +1 -0
- package/dist/client/assets/handlebars-qkUBjVg6.js +1 -0
- package/dist/client/assets/hcl-DxDQ3s82.js +1 -0
- package/dist/client/assets/html-pguqE00h.js +1 -0
- package/dist/client/assets/htmlMode-BCCLuk2F.js +4 -0
- package/dist/client/assets/index-BFrMLHHu.css +1 -0
- package/dist/client/assets/index-CdBC-xgi.js +1250 -0
- package/dist/client/assets/ini-BvajGCUy.js +1 -0
- package/dist/client/assets/java-SYsfObOQ.js +1 -0
- package/dist/client/assets/javascript-ciDUXdez.js +1 -0
- package/dist/client/assets/jsonMode-BmkXC0tI.js +10 -0
- package/dist/client/assets/julia-DQXNmw_w.js +1 -0
- package/dist/client/assets/kotlin-qQ0MG-9I.js +1 -0
- package/dist/client/assets/less-GGFNNJHn.js +2 -0
- package/dist/client/assets/lexon-Canl7DCW.js +1 -0
- package/dist/client/assets/liquid-CwE4UIwf.js +1 -0
- package/dist/client/assets/lua-D28Ae8-K.js +1 -0
- package/dist/client/assets/m3-DPitgjJI.js +1 -0
- package/dist/client/assets/markdown-B811l8j2.js +1 -0
- package/dist/client/assets/mdx-K_9Emnjy.js +1 -0
- package/dist/client/assets/mips-CdjsipkG.js +1 -0
- package/dist/client/assets/msdax-CYqgjx_P.js +1 -0
- package/dist/client/assets/mysql-BHd6q0vd.js +1 -0
- package/dist/client/assets/objective-c-B1aVtJYH.js +1 -0
- package/dist/client/assets/pascal-BhNW15KB.js +1 -0
- package/dist/client/assets/pascaligo-5jv8CcQD.js +1 -0
- package/dist/client/assets/perl-DlYyT36c.js +1 -0
- package/dist/client/assets/pgsql-Dy0bjov7.js +1 -0
- package/dist/client/assets/php-120yhfDK.js +1 -0
- package/dist/client/assets/pla-CjnFlu4u.js +1 -0
- package/dist/client/assets/postiats-CQpG440k.js +1 -0
- package/dist/client/assets/powerquery-DdJtto1Z.js +1 -0
- package/dist/client/assets/powershell-Bu_VLpJB.js +1 -0
- package/dist/client/assets/protobuf-IBS6jZEB.js +2 -0
- package/dist/client/assets/pug-kFxLfcjb.js +1 -0
- package/dist/client/assets/python-BzIc0EVe.js +1 -0
- package/dist/client/assets/qsharp-q7JyzKFN.js +1 -0
- package/dist/client/assets/r-BIFz-_sK.js +1 -0
- package/dist/client/assets/razor-lXZl6dtu.js +1 -0
- package/dist/client/assets/redis-CHOsPHWR.js +1 -0
- package/dist/client/assets/redshift-CBifECDb.js +1 -0
- package/dist/client/assets/restructuredtext-CghPJEOS.js +1 -0
- package/dist/client/assets/ruby-CYWGW-b1.js +1 -0
- package/dist/client/assets/rust-DMDD0SHb.js +1 -0
- package/dist/client/assets/sb-BYAiYHFx.js +1 -0
- package/dist/client/assets/scala-Bqvq8jcR.js +1 -0
- package/dist/client/assets/scheme-Dhb-2j9p.js +1 -0
- package/dist/client/assets/scss-CTwUZ5N7.js +3 -0
- package/dist/client/assets/shell-CsDZo4DB.js +1 -0
- package/dist/client/assets/solidity-CME5AdoB.js +1 -0
- package/dist/client/assets/sophia-RYC1BQQz.js +1 -0
- package/dist/client/assets/sparql-KEyrF7De.js +1 -0
- package/dist/client/assets/sql-BdTr02Mf.js +1 -0
- package/dist/client/assets/st-C7iG7M4S.js +1 -0
- package/dist/client/assets/swift-D7IUmUK8.js +1 -0
- package/dist/client/assets/systemverilog-DgMryOEJ.js +1 -0
- package/dist/client/assets/tcl-PloMZuKG.js +1 -0
- package/dist/client/assets/tsMode-BAXmgo_t.js +11 -0
- package/dist/client/assets/twig-BfRIq3la.js +1 -0
- package/dist/client/assets/typescript-Cdf8nS1n.js +1 -0
- package/dist/client/assets/typespec-CzxlYoT_.js +1 -0
- package/dist/client/assets/vb-BwAE3J76.js +1 -0
- package/dist/client/assets/wgsl-B_1kOXbF.js +298 -0
- package/dist/client/assets/xml-DGyPgYnj.js +1 -0
- package/dist/client/assets/yaml-Dqv3HtbL.js +1 -0
- package/dist/client/index.html +14 -0
- package/dist/client/manic-logo.png +0 -0
- package/dist/client/wasm/manic_lang.d.ts +74 -0
- package/dist/client/wasm/manic_lang.js +302 -0
- package/dist/client/wasm/manic_lang_bg.wasm +0 -0
- package/dist/client/wasm/manic_lang_bg.wasm.d.ts +13 -0
- package/dist/server/agentProtocol.d.ts +131 -0
- package/dist/server/agentProtocol.js +21 -0
- package/dist/server/agentProtocol.js.map +1 -0
- package/dist/server/agentRuns.d.ts +46 -0
- package/dist/server/agentRuns.js +138 -0
- package/dist/server/agentRuns.js.map +1 -0
- package/dist/server/agentThreads.d.ts +20 -0
- package/dist/server/agentThreads.js +205 -0
- package/dist/server/agentThreads.js.map +1 -0
- package/dist/server/aiSecrets.d.ts +21 -0
- package/dist/server/aiSecrets.js +68 -0
- package/dist/server/aiSecrets.js.map +1 -0
- package/dist/server/app.d.ts +34 -0
- package/dist/server/app.js +804 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/assets.d.ts +34 -0
- package/dist/server/assets.js +659 -0
- package/dist/server/assets.js.map +1 -0
- package/dist/server/candidateFix.d.ts +28 -0
- package/dist/server/candidateFix.js +111 -0
- package/dist/server/candidateFix.js.map +1 -0
- package/dist/server/cli.d.ts +2 -0
- package/dist/server/cli.js +118 -0
- package/dist/server/cli.js.map +1 -0
- package/dist/server/diagnostics.d.ts +13 -0
- package/dist/server/diagnostics.js +73 -0
- package/dist/server/diagnostics.js.map +1 -0
- package/dist/server/engineCheck.d.ts +7 -0
- package/dist/server/engineCheck.js +60 -0
- package/dist/server/engineCheck.js.map +1 -0
- package/dist/server/engineInstall.d.ts +34 -0
- package/dist/server/engineInstall.js +228 -0
- package/dist/server/engineInstall.js.map +1 -0
- package/dist/server/enginePaths.d.ts +3 -0
- package/dist/server/enginePaths.js +76 -0
- package/dist/server/enginePaths.js.map +1 -0
- package/dist/server/folderPicker.d.ts +1 -0
- package/dist/server/folderPicker.js +54 -0
- package/dist/server/folderPicker.js.map +1 -0
- package/dist/server/manicAgent.d.ts +75 -0
- package/dist/server/manicAgent.js +476 -0
- package/dist/server/manicAgent.js.map +1 -0
- package/dist/server/manicEnv.d.ts +18 -0
- package/dist/server/manicEnv.js +64 -0
- package/dist/server/manicEnv.js.map +1 -0
- package/dist/server/promptStore.d.ts +11 -0
- package/dist/server/promptStore.js +85 -0
- package/dist/server/promptStore.js.map +1 -0
- package/dist/server/renderJobs.d.ts +54 -0
- package/dist/server/renderJobs.js +290 -0
- package/dist/server/renderJobs.js.map +1 -0
- package/dist/server/settings.d.ts +40 -0
- package/dist/server/settings.js +262 -0
- package/dist/server/settings.js.map +1 -0
- package/dist/server/smartDraw.d.ts +7 -0
- package/dist/server/smartDraw.js +88 -0
- package/dist/server/smartDraw.js.map +1 -0
- package/dist/server/workspace.d.ts +27 -0
- package/dist/server/workspace.js +172 -0
- package/dist/server/workspace.js.map +1 -0
- package/examples/.manic-output/40b6f3b9-7638-4c0e-bb4f-570d45d1b225/job.json +26 -0
- package/examples/.manic-output/993f3788-f75e-445c-ba45-c401907b3c02/job.json +26 -0
- package/examples/.manic-output/993f3788-f75e-445c-ba45-c401907b3c02/markers.json +13 -0
- package/examples/.manic-output/993f3788-f75e-445c-ba45-c401907b3c02/out.mp4 +0 -0
- package/examples/.manic-workbench-threads/thread_3ce7448a13f64f9e887d1bc8106a97a8.json +45 -0
- package/examples/.manic-workbench-threads/thread_d494cda29249477591056234719e4a3a.json +21 -0
- package/examples/.manic-workbench-threads/thread_e98ebdc225184ea5b8ddda8b44541f63.json +29 -0
- package/examples/README.md +35 -0
- package/examples/a-story-1.manic +222 -0
- package/examples/a-story.manic +100 -0
- package/examples/achromat-cinematic.manic +105 -0
- package/examples/achromat.manic +32 -0
- package/examples/aes-decrypt.manic +359 -0
- package/examples/aes-encrypt.manic +359 -0
- package/examples/aes-round.manic +70 -0
- package/examples/aes-story.manic +622 -0
- package/examples/ai-story.manic +118 -0
- package/examples/analysis.manic +53 -0
- package/examples/archimedes_pi.manic +89 -0
- package/examples/area_under_curve.manic +131 -0
- package/examples/art-rakkan.manic +69 -0
- package/examples/aspheric-lens.manic +32 -0
- package/examples/astronomical-watch.manic +96 -0
- package/examples/asymptote-randomwalk3-reference.manic +58 -0
- package/examples/asymptote-tiling-reference.manic +65 -0
- package/examples/aws-clustered-web-services.manic +186 -0
- package/examples/aws-event-processing-clusters-poc.manic +97 -0
- package/examples/aws-three-tier-web-application.manic +134 -0
- package/examples/band.manic +43 -0
- package/examples/banner.manic +37 -0
- package/examples/bayes.manic +27 -0
- package/examples/bellcurve.manic +41 -0
- package/examples/bfs_dfs.manic +35 -0
- package/examples/block-tackle.manic +26 -0
- package/examples/bloom-scope.manic +172 -0
- package/examples/boolean.manic +46 -0
- package/examples/boxplot-wave.manic +93 -0
- package/examples/boxplot.manic +43 -0
- package/examples/brace.manic +46 -0
- package/examples/brachistochrone-annotated.manic +51 -0
- package/examples/brachistochrone.manic +27 -0
- package/examples/bubble_sort.manic +41 -0
- package/examples/bullet-block-annotated.manic +48 -0
- package/examples/bullet-block.manic +11 -0
- package/examples/bullet-impact.manic +65 -0
- package/examples/bungee.manic +9 -0
- package/examples/c4-internet-banking-components.manic +33 -0
- package/examples/c4-internet-banking-containers.manic +29 -0
- package/examples/c4-internet-banking.manic +26 -0
- package/examples/c4-story.manic +171 -0
- package/examples/c4-test.manic +52 -0
- package/examples/c4-zoom.manic +69 -0
- package/examples/calculus-demo.manic +129 -0
- package/examples/calculus-one.manic +288 -0
- package/examples/captions.manic +31 -0
- package/examples/car-suspension-annotated.manic +57 -0
- package/examples/car-suspension.manic +8 -0
- package/examples/cart-pendulum.manic +11 -0
- package/examples/charts-bar-line.manic +26 -0
- package/examples/charts-column-race.manic +19 -0
- package/examples/charts-gdp-race.manic +43 -0
- package/examples/charts-german-elections.manic +28 -0
- package/examples/charts-line-race.manic +21 -0
- package/examples/circle-in-three.manic +156 -0
- package/examples/circle-thirds-no-triangle.manic +161 -0
- package/examples/clip-window.manic +34 -0
- package/examples/cloud-feathers.manic +50 -0
- package/examples/cloud-jellyfish-v2.manic +87 -0
- package/examples/cloud-jellyfish.manic +48 -0
- package/examples/cloud-kaleidoscope.manic +48 -0
- package/examples/cloud-koi.manic +51 -0
- package/examples/cloud-lissajous.manic +23 -0
- package/examples/cloud-medusae.manic +46 -0
- package/examples/cloud-phoenix.manic +49 -0
- package/examples/cloud-plumes.manic +47 -0
- package/examples/cloud-pottery.manic +104 -0
- package/examples/cloud-shells.manic +50 -0
- package/examples/cloud-starfield.manic +23 -0
- package/examples/cloud-wave-lattice.manic +23 -0
- package/examples/cloud-word.manic +31 -0
- package/examples/cloud3-ripple.manic +53 -0
- package/examples/cloud3-sphere.manic +26 -0
- package/examples/clt.manic +35 -0
- package/examples/collide-blocks-annotated.manic +45 -0
- package/examples/collide-blocks.manic +11 -0
- package/examples/compare-pendulum.manic +11 -0
- package/examples/complex-flowchart.manic +196 -0
- package/examples/compound-pulley.manic +25 -0
- package/examples/conics.manic +46 -0
- package/examples/coordinates.manic +52 -0
- package/examples/correlation.manic +35 -0
- package/examples/covariance.manic +30 -0
- package/examples/creator-affine-fern-growth.manic +72 -0
- package/examples/creator-bowl-to-saddle.manic +86 -0
- package/examples/creator-branch-counting-tree3.manic +77 -0
- package/examples/creator-chaos-game-fern.manic +72 -0
- package/examples/creator-circle-inversion-chain.manic +61 -0
- package/examples/creator-convex-hull-depth.manic +59 -0
- package/examples/creator-coordinate-worlds.manic +182 -0
- package/examples/creator-ellipse-reflection-property.manic +59 -0
- package/examples/creator-free-kicks.manic +261 -0
- package/examples/creator-geometry-language-showcase.manic +259 -0
- package/examples/creator-geometry-morph-promo.manic +151 -0
- package/examples/creator-heightmap-world.manic +130 -0
- package/examples/creator-hilbert3-spatial-index.manic +203 -0
- package/examples/creator-how-rocket-launch-works.manic +192 -0
- package/examples/creator-implicit-surface-parameterized.manic +51 -0
- package/examples/creator-incenter-dissection.manic +56 -0
- package/examples/creator-lattice-paths.manic +118 -0
- package/examples/creator-line-inversion.manic +49 -0
- package/examples/creator-lsystem-fractal-curve.manic +121 -0
- package/examples/creator-mandelbrot-escape-test.manic +58 -0
- package/examples/creator-monty-hall.manic +104 -0
- package/examples/creator-noise-story.manic +123 -0
- package/examples/creator-one-tile-pattern-story.manic +169 -0
- package/examples/creator-pathfinding.manic +82 -0
- package/examples/creator-point-to-plane-distance.manic +167 -0
- package/examples/creator-race-quiz.manic +76 -0
- package/examples/creator-randomwalk3-diffusion.manic +72 -0
- package/examples/creator-reflected-ellipse.manic +48 -0
- package/examples/creator-rule90-sierpinski.manic +64 -0
- package/examples/creator-three-shadows-of-a-curve.manic +48 -0
- package/examples/creator-trigonometry-one-angle.manic +307 -0
- package/examples/creator-v2-latex-algebra.manic +29 -0
- package/examples/creator-v2-latex-calculus.manic +37 -0
- package/examples/creator-v2-latex-physics.manic +29 -0
- package/examples/creator-v2-olympiad-geometry.manic +92 -0
- package/examples/creator-v2-options-socials.manic +21 -0
- package/examples/creator-v2-timers.manic +25 -0
- package/examples/creator-v2-timing-square.manic +25 -0
- package/examples/creator-v2-timing.manic +34 -0
- package/examples/creator-v2.manic +36 -0
- package/examples/creator-why-rockets-use-stages.manic +198 -0
- package/examples/creator-wrap-real-line.manic +51 -0
- package/examples/cubic-graphs.manic +432 -0
- package/examples/curve-features.manic +41 -0
- package/examples/definedmotion-fourier-gallery.manic +171 -0
- package/examples/derivative-of-ln-x.manic +194 -0
- package/examples/diagonalise.manic +56 -0
- package/examples/dijkstra.manic +29 -0
- package/examples/dimensions-unfold.manic +211 -0
- package/examples/disc-integration.manic +172 -0
- package/examples/double-incline.manic +9 -0
- package/examples/double-integral3.manic +43 -0
- package/examples/double-pendulum.manic +35 -0
- package/examples/double-spring.manic +9 -0
- package/examples/drop-mass.manic +25 -0
- package/examples/eigen3.manic +34 -0
- package/examples/equal_cuts.manic +44 -0
- package/examples/equation.manic +16 -0
- package/examples/equilateral.manic +57 -0
- package/examples/euler_line.manic +51 -0
- package/examples/exponential-shells.manic +188 -0
- package/examples/extrude3.manic +37 -0
- package/examples/factorial-flowchart.manic +69 -0
- package/examples/fibonacci-sphere.manic +57 -0
- package/examples/flow-lorenz.manic +47 -0
- package/examples/fourier-series-live-wave.manic +114 -0
- package/examples/fourier-square-wave-live.manic +114 -0
- package/examples/fractal_tree.manic +39 -0
- package/examples/frame3-grid-policies.manic +48 -0
- package/examples/ftc.manic +54 -0
- package/examples/function_graph.manic +54 -0
- package/examples/galton-board-process.manic +150 -0
- package/examples/gcp-clustered-web-services.manic +186 -0
- package/examples/gcp-message-collecting.manic +139 -0
- package/examples/geo-pythagoras-short.manic +119 -0
- package/examples/glsl-boxgrid.manic +105 -0
- package/examples/glsl-parameter.manic +30 -0
- package/examples/glsl-raymarch.manic +59 -0
- package/examples/glsl-shapes.manic +122 -0
- package/examples/gradient-descent-field.manic +116 -0
- package/examples/gradient-fastest-descent-shorts.manic +153 -0
- package/examples/gradient-fastest-descent.manic +125 -0
- package/examples/gradient-pendulum-shorts.manic +117 -0
- package/examples/gradient.manic +74 -0
- package/examples/graph.manic +45 -0
- package/examples/graph_moving.manic +67 -0
- package/examples/grid-astar.manic +15 -0
- package/examples/grid-life-soup.manic +31 -0
- package/examples/grid-life-zoo.manic +46 -0
- package/examples/grid-life.manic +19 -0
- package/examples/grid-wfc.manic +13 -0
- package/examples/growing-fractal-tree3.manic +58 -0
- package/examples/gun-shot.manic +82 -0
- package/examples/hashmap.manic +38 -0
- package/examples/heightmap3-world.manic +64 -0
- package/examples/heightmap3.manic +23 -0
- package/examples/hilbert-curve3-space-filling.manic +117 -0
- package/examples/hill_run.manic +71 -0
- package/examples/histogram.manic +43 -0
- package/examples/hotdog-taco.manic +147 -0
- package/examples/hue_wave.manic +35 -0
- package/examples/hypothesis.manic +32 -0
- package/examples/image.manic +29 -0
- package/examples/incircle_tangents.manic +64 -0
- package/examples/incline-bumper.manic +11 -0
- package/examples/incline-pulley.manic +11 -0
- package/examples/incline-showcase.manic +55 -0
- package/examples/inline-math.manic +16 -0
- package/examples/inscribed-angle-short.manic +56 -0
- package/examples/integral-sqrt-tanx.manic +255 -0
- package/examples/integrals.manic +274 -0
- package/examples/inverse-derivatives.manic +94 -0
- package/examples/k8s-cluster-components.manic +82 -0
- package/examples/k8s-stateful-architecture.manic +134 -0
- package/examples/k8s-three-tier.manic +146 -0
- package/examples/kapitza.manic +11 -0
- package/examples/latex-disintegration.manic +123 -0
- package/examples/lens-paper.manic +36 -0
- package/examples/lens-prescription.manic +33 -0
- package/examples/lens-system.manic +34 -0
- package/examples/lens.manic +31 -0
- package/examples/limit-infinity.manic +30 -0
- package/examples/limit.manic +33 -0
- package/examples/linear-algebra-3d.manic +50 -0
- package/examples/linear-algebra.manic +115 -0
- package/examples/linear-map.manic +39 -0
- package/examples/linear-map3.manic +33 -0
- package/examples/linear-system.manic +99 -0
- package/examples/linear_transform.manic +43 -0
- package/examples/linked_list.manic +38 -0
- package/examples/lln.manic +31 -0
- package/examples/loop-cinematic.manic +41 -0
- package/examples/loop-track.manic +11 -0
- package/examples/lorenz-attractor.manic +55 -0
- package/examples/lorenz-shells.manic +43 -0
- package/examples/lost-in-patterns.manic +149 -0
- package/examples/lsystem-asymptote-curves.manic +81 -0
- package/examples/manic-ml-activation-focus.manic +133 -0
- package/examples/manic-ml-cnn-edge-story.manic +102 -0
- package/examples/manic-ml-forward-pass.manic +93 -0
- package/examples/manic-ml-learning-step.manic +116 -0
- package/examples/manic-ml-logits-sampling.manic +112 -0
- package/examples/manic-ml-scalar-to-tensor.manic +143 -0
- package/examples/manic-ml-token-embedding.manic +110 -0
- package/examples/manic-ml-transformer-attention.manic +102 -0
- package/examples/manic-ml-transformer-block.manic +116 -0
- package/examples/manic-promo.manic +64 -0
- package/examples/map-attractor.manic +45 -0
- package/examples/mask-lens.manic +33 -0
- package/examples/matrix.manic +37 -0
- package/examples/matrix3.manic +101 -0
- package/examples/matrix_addition.manic +66 -0
- package/examples/matrix_addition_plane.manic +91 -0
- package/examples/maxwell-boltzmann-effusion-v2.manic +142 -0
- package/examples/maxwell-boltzmann-process.manic +86 -0
- package/examples/microservices-platform.manic +140 -0
- package/examples/molecule.manic +8 -0
- package/examples/morph-icons.manic +29 -0
- package/examples/morph.manic +29 -0
- package/examples/morph3.manic +49 -0
- package/examples/motion-flow-foundation.manic +148 -0
- package/examples/motion-graphics-v2-story.manic +189 -0
- package/examples/motion-graphics-v2.manic +81 -0
- package/examples/motion-graphics.manic +81 -0
- package/examples/multivariable3.manic +26 -0
- package/examples/mystory.manic +9 -0
- package/examples/newton.manic +39 -0
- package/examples/newtons-cradle.manic +10 -0
- package/examples/nine_point.manic +59 -0
- package/examples/noise-terrain.manic +16 -0
- package/examples/off-axis.manic +32 -0
- package/examples/onprem-advanced-web-service-v2.manic +196 -0
- package/examples/onprem-advanced-web-service.manic +175 -0
- package/examples/orthocenter.manic +63 -0
- package/examples/param3.manic +43 -0
- package/examples/parameter-journeys.manic +154 -0
- package/examples/parameterized-field-advection.manic +57 -0
- package/examples/parameterized-generated-families3.manic +83 -0
- package/examples/particles-flow.manic +61 -0
- package/examples/pascal-triangle.manic +92 -0
- package/examples/pendulum-annotated.manic +72 -0
- package/examples/pendulum-damped.manic +35 -0
- package/examples/pendulum.manic +38 -0
- package/examples/perfect-reel.manic +43 -0
- package/examples/pie.manic +41 -0
- package/examples/pieday.manic +113 -0
- package/examples/piston.manic +7 -0
- package/examples/popkorn-field.manic +38 -0
- package/examples/prism-cinematic.manic +36 -0
- package/examples/prism.manic +32 -0
- package/examples/probability.manic +57 -0
- package/examples/process-branching-dispatch.manic +71 -0
- package/examples/process-stream-observe.manic +54 -0
- package/examples/projection.manic +57 -0
- package/examples/prompt-test-10.manic +257 -0
- package/examples/prompt-test-11.manic +168 -0
- package/examples/prompt-test-12.manic +177 -0
- package/examples/prompt-test-13.manic +228 -0
- package/examples/prompt-test-14.manic +319 -0
- package/examples/prompt-test-15.manic +325 -0
- package/examples/prompt-test-16.manic +252 -0
- package/examples/prompt-test-2.manic +239 -0
- package/examples/prompt-test-3.manic +336 -0
- package/examples/prompt-test-4.manic +195 -0
- package/examples/prompt-test-5.manic +223 -0
- package/examples/prompt-test-6.manic +222 -0
- package/examples/prompt-test-7.manic +156 -0
- package/examples/prompt-test-8.manic +266 -0
- package/examples/prompt-test-9.manic +171 -0
- package/examples/prompt-test.manic +158 -0
- package/examples/pulley-annotated.manic +54 -0
- package/examples/pulley-paper.manic +52 -0
- package/examples/pulley-scale.manic +23 -0
- package/examples/pulley.manic +24 -0
- package/examples/quadratic-formula-continuity.manic +110 -0
- package/examples/quiz-euler.manic +52 -0
- package/examples/quiz-geometry-2.manic +107 -0
- package/examples/quiz-geometry.manic +108 -0
- package/examples/quiz-skins.manic +22 -0
- package/examples/raft-cm.manic +24 -0
- package/examples/ramp.manic +25 -0
- package/examples/ray-fan.manic +27 -0
- package/examples/raymarch-alpha.manic +39 -0
- package/examples/raymarch-boxgrid.manic +47 -0
- package/examples/raymarch-docker-latency.manic +74 -0
- package/examples/raymarch-metaballs.manic +37 -0
- package/examples/raymarch-sculpture.manic +39 -0
- package/examples/raymarch-shapes3.manic +31 -0
- package/examples/reactive-integral.manic +172 -0
- package/examples/reactive-math-journey.manic +185 -0
- package/examples/reactive-math-notation.manic +150 -0
- package/examples/reactive-multiformat.manic +130 -0
- package/examples/reactive-world.manic +111 -0
- package/examples/refraction-paper.manic +40 -0
- package/examples/refraction.manic +32 -0
- package/examples/resonance.manic +10 -0
- package/examples/rewrite-exponential-cubic.manic +141 -0
- package/examples/rewrite-integration.manic +199 -0
- package/examples/riemann_rainbow.manic +61 -0
- package/examples/riemann_readout.manic +61 -0
- package/examples/robot-arm.manic +25 -0
- package/examples/rref.manic +48 -0
- package/examples/second-law-thermodynamics.manic +385 -0
- package/examples/series-parallel-springs.manic +8 -0
- package/examples/serverless-processing.manic +145 -0
- package/examples/shader-cellular.manic +35 -0
- package/examples/shader-fractal.manic +45 -0
- package/examples/shader-fx.manic +34 -0
- package/examples/shader-glitch-grid.manic +55 -0
- package/examples/shader-parameter.manic +25 -0
- package/examples/shader-patterns.manic +37 -0
- package/examples/shader-plasma.manic +43 -0
- package/examples/shader-shapes-dsl.manic +46 -0
- package/examples/shader-shapes.manic +37 -0
- package/examples/shader-warp.manic +22 -0
- package/examples/shapes-howto.manic +411 -0
- package/examples/sine_wave.manic +42 -0
- package/examples/skew.manic +40 -0
- package/examples/smoke.rs +57 -0
- package/examples/solids3.manic +22 -0
- package/examples/some-story.manic +299 -0
- package/examples/spinning-cylinder-flow.manic +87 -0
- package/examples/spline.manic +21 -0
- package/examples/spot-diagram.manic +32 -0
- package/examples/spring-annotated.manic +60 -0
- package/examples/spring-chain.manic +11 -0
- package/examples/spring-damped.manic +33 -0
- package/examples/spring-incline.manic +10 -0
- package/examples/spring-paper.manic +46 -0
- package/examples/spring-pendulum.manic +14 -0
- package/examples/spring.manic +33 -0
- package/examples/sqrt-tanx.manic +217 -0
- package/examples/ssl-handshake-sdf.manic +116 -0
- package/examples/stack_queue.manic +53 -0
- package/examples/statistics.manic +60 -0
- package/examples/story-addressable-asset-cues.manic +71 -0
- package/examples/story-dependent-chain-history.manic +56 -0
- package/examples/story-living-dependency-cloud.manic +50 -0
- package/examples/story-time-varying-field3.manic +57 -0
- package/examples/story.manic +4 -0
- package/examples/string-art-breath.manic +70 -0
- package/examples/string-wave.manic +10 -0
- package/examples/summary.manic +48 -0
- package/examples/svg-howto.manic +172 -0
- package/examples/svg-import.manic +18 -0
- package/examples/systems-architecture-poc.manic +92 -0
- package/examples/systems-arrow-patterns.manic +151 -0
- package/examples/systems-foundation.manic +71 -0
- package/examples/systems-rabbitmq-consumers.manic +118 -0
- package/examples/table.manic +39 -0
- package/examples/table_braces.manic +54 -0
- package/examples/tangent-length-short.manic +57 -0
- package/examples/tangent.manic +29 -0
- package/examples/tangents.manic +54 -0
- package/examples/taylor.manic +44 -0
- package/examples/terminal_boot.manic +40 -0
- package/examples/test.manic +61 -0
- package/examples/text-guide.manic +304 -0
- package/examples/textbook-coordinate-worlds.manic +129 -0
- package/examples/textbook-doubly-list.manic +33 -0
- package/examples/textbook-function-to-solid.manic +126 -0
- package/examples/textbook-geometry-dimension-reduction.manic +129 -0
- package/examples/textbook-incline-fbd.manic +43 -0
- package/examples/textbook-length-area-volume.manic +137 -0
- package/examples/textbook-matrix-inverses.manic +172 -0
- package/examples/textbook-pulley.manic +35 -0
- package/examples/textbook-statistical-dimensions.manic +151 -0
- package/examples/textbook-tension.manic +39 -0
- package/examples/textbook-watermelon-sections.manic +216 -0
- package/examples/thales-semicircle-short.manic +53 -0
- package/examples/three-d-v2-lab.manic +83 -0
- package/examples/three-d-v2-story.manic +106 -0
- package/examples/three-d-v2.manic +69 -0
- package/examples/three_d.manic +39 -0
- package/examples/timing-v2-scene.manic +47 -0
- package/examples/trajectory.manic +28 -0
- package/examples/transform_copy.manic +35 -0
- package/examples/transforms.manic +54 -0
- package/examples/trapped-light-dimensions.manic +226 -0
- package/examples/tree-of-leaves.manic +215 -0
- package/examples/triangle.manic +68 -0
- package/examples/two_person_walk.manic +296 -0
- package/examples/two_pointer.manic +32 -0
- package/examples/type-to-sdf.manic +139 -0
- package/examples/typewriter.manic +28 -0
- package/examples/vector_field.manic +32 -0
- package/examples/vertical-spring.manic +10 -0
- package/examples/volume3.manic +21 -0
- package/examples/volumes-solid-of-revolution.manic +111 -0
- package/examples/walk.manic +154 -0
- package/examples/wheel-duo.manic +91 -0
- package/examples/wheel-radial.manic +78 -0
- package/examples/wheel-square.manic +83 -0
- package/examples/wireframe-spheres.manic +37 -0
- package/examples/zeroth-law-thermodynamics.manic +269 -0
- package/package.json +59 -0
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { lstat, mkdir, readFile, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { suggestAssetsDirFromEnginePath } from "./manicEnv.js";
|
|
5
|
+
const MAX_ASSET_BYTES = 16 * 1024 * 1024;
|
|
6
|
+
const PROJECT_MANIFEST = ".manic/assets.json";
|
|
7
|
+
const PROJECT_ASSET_ROOT = ".manic/assets";
|
|
8
|
+
const projectMutationTails = new Map();
|
|
9
|
+
const libraryCache = new Map();
|
|
10
|
+
export async function searchAssets(workspace, settings, input, engineOverride = "") {
|
|
11
|
+
const source = input.scope === "project"
|
|
12
|
+
? (await readProjectManifest(workspace)).assets
|
|
13
|
+
: (await readLibraryManifest(settings, engineOverride)).assets.filter((asset) => asset.uiVisible).map((asset) => ({ ...asset, scope: "library" }));
|
|
14
|
+
const needle = input.query.trim().toLowerCase();
|
|
15
|
+
const filtered = source.filter((asset) => (input.kind === "all" || asset.kind === input.kind) && (!needle || searchable(asset).includes(needle)));
|
|
16
|
+
const offset = parseCursor(input.cursor);
|
|
17
|
+
const limit = Math.max(1, Math.min(100, Math.round(input.limit) || 48));
|
|
18
|
+
const assets = filtered.slice(offset, offset + limit).map(publicAsset);
|
|
19
|
+
const next = offset + assets.length;
|
|
20
|
+
return { assets, total: filtered.length, nextCursor: next < filtered.length ? String(next) : null };
|
|
21
|
+
}
|
|
22
|
+
export async function resolveAsset(workspace, settings, uri, engineOverride = "") {
|
|
23
|
+
validateAssetUri(uri);
|
|
24
|
+
if (uri.startsWith("asset:project/")) {
|
|
25
|
+
const manifest = await readProjectManifest(workspace);
|
|
26
|
+
const asset = manifest.assets.find((candidate) => candidate.uri === uri);
|
|
27
|
+
if (!asset)
|
|
28
|
+
throw new Error(`Project asset is not registered: ${uri}`);
|
|
29
|
+
const root = join(await realpath(workspace), PROJECT_ASSET_ROOT);
|
|
30
|
+
return { asset: publicAsset(asset), path: await safeExistingAsset(root, uri.slice("asset:".length)) };
|
|
31
|
+
}
|
|
32
|
+
const root = await libraryRoot(settings, engineOverride);
|
|
33
|
+
const manifest = await readLibraryManifest(settings, engineOverride);
|
|
34
|
+
const entry = manifest.assets.find((candidate) => candidate.uri === uri);
|
|
35
|
+
if (!entry)
|
|
36
|
+
throw new Error(`Bundled asset is not in the catalogue: ${uri}`);
|
|
37
|
+
return { asset: publicAsset({ ...entry, scope: "library" }), path: await safeExistingAsset(root, uri.slice("asset:".length)) };
|
|
38
|
+
}
|
|
39
|
+
export async function importProjectAsset(workspace, file) {
|
|
40
|
+
if (!file.name || file.name.includes("\0"))
|
|
41
|
+
throw new Error("The uploaded asset needs a filename.");
|
|
42
|
+
if (file.size < 1)
|
|
43
|
+
throw new Error("The uploaded asset is empty.");
|
|
44
|
+
if (file.size > MAX_ASSET_BYTES)
|
|
45
|
+
throw new Error("Project assets cannot exceed 16 MB.");
|
|
46
|
+
const bytes = Buffer.from(await file.arrayBuffer());
|
|
47
|
+
const inspected = inspectAsset(file.name, bytes);
|
|
48
|
+
const manifest = await readProjectManifest(workspace);
|
|
49
|
+
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
50
|
+
const duplicate = manifest.assets.find((asset) => asset.sha256 === sha256 && asset.mediaType === inspected.mediaType);
|
|
51
|
+
if (duplicate)
|
|
52
|
+
return publicAsset(duplicate);
|
|
53
|
+
const id = randomUUID();
|
|
54
|
+
const filename = safeFilename(file.name, inspected.extension);
|
|
55
|
+
const relativePath = `project/${id}/${filename}`;
|
|
56
|
+
const root = await ensureProjectAssetRoot(workspace);
|
|
57
|
+
const directory = join(root, "project", id);
|
|
58
|
+
await mkdir(directory, { mode: 0o700 });
|
|
59
|
+
const target = join(directory, filename);
|
|
60
|
+
await writeFile(target, bytes, { flag: "wx", mode: 0o600 });
|
|
61
|
+
const asset = {
|
|
62
|
+
uri: `asset:${relativePath}`,
|
|
63
|
+
kind: inspected.kind,
|
|
64
|
+
scope: "project",
|
|
65
|
+
mediaType: inspected.mediaType,
|
|
66
|
+
title: titleFromName(filename),
|
|
67
|
+
category: ["project"],
|
|
68
|
+
keywords: tokens(filename),
|
|
69
|
+
byteSize: bytes.length,
|
|
70
|
+
sha256,
|
|
71
|
+
...(inspected.width && inspected.height ? { width: inspected.width, height: inspected.height, aspectRatio: Number((inspected.width / inspected.height).toFixed(6)) } : {}),
|
|
72
|
+
...(inspected.parts.length ? { parts: inspected.parts } : {}),
|
|
73
|
+
themeable: inspected.themeable,
|
|
74
|
+
license: null,
|
|
75
|
+
warnings: inspected.warnings,
|
|
76
|
+
createdAt: Date.now(),
|
|
77
|
+
};
|
|
78
|
+
manifest.assets.push(asset);
|
|
79
|
+
await writeProjectManifest(workspace, manifest);
|
|
80
|
+
return publicAsset(asset);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Install a relocatable Smart Draw package and let the engine create its
|
|
84
|
+
* adjacent manifest before the package becomes visible in the project
|
|
85
|
+
* catalogue. Any engine or catalogue failure rolls back the new directory.
|
|
86
|
+
*/
|
|
87
|
+
export async function importProjectSmartDraw(workspace, sourceFile, guideFile, prepare, metadata = {}) {
|
|
88
|
+
return withProjectAssetMutation(workspace, () => importProjectSmartDrawUnlocked(workspace, sourceFile, guideFile, prepare, metadata));
|
|
89
|
+
}
|
|
90
|
+
async function importProjectSmartDrawUnlocked(workspace, sourceFile, guideFile, prepare, metadata) {
|
|
91
|
+
const source = await inspectUploadedFile(sourceFile);
|
|
92
|
+
if (source.inspected.mediaType !== "image/svg+xml" && !(guideFile && source.inspected.mediaType === "image/png")) {
|
|
93
|
+
throw new Error("Stroke Smart Draw needs an SVG. Filled SVG or PNG artwork also needs an SVG reveal guide.");
|
|
94
|
+
}
|
|
95
|
+
const guide = guideFile ? await inspectUploadedFile(guideFile) : null;
|
|
96
|
+
if (guide && guide.inspected.mediaType !== "image/svg+xml")
|
|
97
|
+
throw new Error("The Smart Draw reveal guide must be an SVG file.");
|
|
98
|
+
const manifest = await readProjectManifest(workspace);
|
|
99
|
+
const packageSha256 = smartDrawPackageSha256(source.bytes, guide?.bytes ?? null);
|
|
100
|
+
const duplicate = manifest.assets.find((asset) => asset.kind === "smartdraw" && asset.packageSha256 === packageSha256);
|
|
101
|
+
if (duplicate)
|
|
102
|
+
return publicAsset(duplicate);
|
|
103
|
+
const title = validateAssetTitle(metadata.title?.trim() || titleFromName(sourceFile.name));
|
|
104
|
+
const collision = manifest.assets.find((asset) => asset.kind === "smartdraw" && asset.title.toLowerCase() === title.toLowerCase());
|
|
105
|
+
if (collision)
|
|
106
|
+
throw new Error(`A different Smart Draw package is already named “${title}”. Choose another title.`);
|
|
107
|
+
const license = validateLicense(metadata.license);
|
|
108
|
+
const provenance = validateProvenance(metadata, sourceFile.name);
|
|
109
|
+
const id = randomUUID();
|
|
110
|
+
const sourceName = safeFilename(sourceFile.name, source.inspected.extension);
|
|
111
|
+
const guideName = guide ? uniqueGuideFilename(guideFile.name, sourceName) : null;
|
|
112
|
+
const relativePath = `project/${id}/${sourceName}`;
|
|
113
|
+
const root = await ensureProjectAssetRoot(workspace);
|
|
114
|
+
const directory = join(root, "project", id);
|
|
115
|
+
await mkdir(directory, { mode: 0o700 });
|
|
116
|
+
try {
|
|
117
|
+
const sourcePath = join(directory, sourceName);
|
|
118
|
+
const guidePath = guideName ? join(directory, guideName) : null;
|
|
119
|
+
await writeFile(sourcePath, source.bytes, { flag: "wx", mode: 0o600 });
|
|
120
|
+
if (guide && guidePath)
|
|
121
|
+
await writeFile(guidePath, guide.bytes, { flag: "wx", mode: 0o600 });
|
|
122
|
+
await prepare(sourcePath, guidePath);
|
|
123
|
+
const manifestPath = sourcePath.slice(0, -extname(sourcePath).length) + ".draw";
|
|
124
|
+
const manifestInformation = await lstat(manifestPath).catch(() => null);
|
|
125
|
+
if (!manifestInformation?.isFile() || manifestInformation.isSymbolicLink()) {
|
|
126
|
+
throw new Error("The Manic Engine did not create a safe adjacent .draw manifest.");
|
|
127
|
+
}
|
|
128
|
+
const manifestBytes = await readFile(manifestPath);
|
|
129
|
+
const asset = {
|
|
130
|
+
uri: `asset:${relativePath}`,
|
|
131
|
+
kind: "smartdraw",
|
|
132
|
+
scope: "project",
|
|
133
|
+
mediaType: source.inspected.mediaType,
|
|
134
|
+
title,
|
|
135
|
+
category: ["project", "smartdraw"],
|
|
136
|
+
keywords: [...new Set([...tokens(sourceName), "smart", "draw"])],
|
|
137
|
+
byteSize: source.bytes.length + (guide?.bytes.length ?? 0) + manifestBytes.length,
|
|
138
|
+
sha256: source.sha256,
|
|
139
|
+
...(source.inspected.width && source.inspected.height ? {
|
|
140
|
+
width: source.inspected.width,
|
|
141
|
+
height: source.inspected.height,
|
|
142
|
+
aspectRatio: Number((source.inspected.width / source.inspected.height).toFixed(6)),
|
|
143
|
+
} : {}),
|
|
144
|
+
themeable: source.inspected.themeable,
|
|
145
|
+
license,
|
|
146
|
+
...(Object.keys(provenance).length ? { provenance } : {}),
|
|
147
|
+
warnings: source.inspected.warnings,
|
|
148
|
+
createdAt: Date.now(),
|
|
149
|
+
packageSha256,
|
|
150
|
+
};
|
|
151
|
+
manifest.assets.push(asset);
|
|
152
|
+
await writeProjectManifest(workspace, manifest);
|
|
153
|
+
return publicAsset(asset);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
await rm(directory, { recursive: true, force: true });
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Rename catalogue metadata without changing the immutable portable URI. */
|
|
161
|
+
export async function renameProjectSmartDraw(workspace, uri, titleValue) {
|
|
162
|
+
return withProjectAssetMutation(workspace, () => renameProjectSmartDrawUnlocked(workspace, uri, titleValue));
|
|
163
|
+
}
|
|
164
|
+
async function renameProjectSmartDrawUnlocked(workspace, uri, titleValue) {
|
|
165
|
+
const title = validateAssetTitle(titleValue);
|
|
166
|
+
const manifest = await readProjectManifest(workspace);
|
|
167
|
+
const asset = requireProjectSmartDrawRecord(manifest, uri);
|
|
168
|
+
const collision = manifest.assets.find((candidate) => candidate.uri !== uri && candidate.kind === "smartdraw"
|
|
169
|
+
&& candidate.title.toLowerCase() === title.toLowerCase());
|
|
170
|
+
if (collision)
|
|
171
|
+
throw new Error(`A different Smart Draw package is already named “${title}”. Choose another title.`);
|
|
172
|
+
asset.title = title;
|
|
173
|
+
asset.keywords = [...new Set([...tokens(title), "smart", "draw"])];
|
|
174
|
+
await writeProjectManifest(workspace, manifest);
|
|
175
|
+
return publicAsset(asset);
|
|
176
|
+
}
|
|
177
|
+
/** Move the complete package to recoverable project trash, then unpublish it. */
|
|
178
|
+
export async function trashProjectSmartDraw(workspace, uri) {
|
|
179
|
+
return withProjectAssetMutation(workspace, () => trashProjectSmartDrawUnlocked(workspace, uri));
|
|
180
|
+
}
|
|
181
|
+
async function trashProjectSmartDrawUnlocked(workspace, uri) {
|
|
182
|
+
const manifest = await readProjectManifest(workspace);
|
|
183
|
+
const asset = requireProjectSmartDrawRecord(manifest, uri);
|
|
184
|
+
const root = await ensureProjectAssetRoot(workspace);
|
|
185
|
+
const sourcePath = await safeExistingAsset(root, uri.slice("asset:".length));
|
|
186
|
+
const directory = dirname(sourcePath);
|
|
187
|
+
const packageId = basename(directory);
|
|
188
|
+
const trashRoot = join(dirname(root), "trash", "assets");
|
|
189
|
+
await mkdir(trashRoot, { recursive: true, mode: 0o700 });
|
|
190
|
+
const trashDirectory = join(trashRoot, `${Date.now()}-${packageId}`);
|
|
191
|
+
await rename(directory, trashDirectory);
|
|
192
|
+
try {
|
|
193
|
+
manifest.assets = manifest.assets.filter((candidate) => candidate.uri !== uri);
|
|
194
|
+
await writeProjectManifest(workspace, manifest);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
await rename(trashDirectory, directory);
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
return publicAsset(asset);
|
|
201
|
+
}
|
|
202
|
+
/** Export only the registered source, adjacent manifest, and referenced guide. */
|
|
203
|
+
export async function exportProjectSmartDraw(workspace, uri) {
|
|
204
|
+
const manifest = await readProjectManifest(workspace);
|
|
205
|
+
const asset = requireProjectSmartDrawRecord(manifest, uri);
|
|
206
|
+
const root = await ensureProjectAssetRoot(workspace);
|
|
207
|
+
const sourcePath = await safeExistingAsset(root, uri.slice("asset:".length));
|
|
208
|
+
const directory = dirname(sourcePath);
|
|
209
|
+
const drawName = `${basename(sourcePath, extname(sourcePath))}.draw`;
|
|
210
|
+
const drawPath = join(directory, drawName);
|
|
211
|
+
const draw = await safePackageFile(directory, drawPath);
|
|
212
|
+
const guideRef = /^\s*guide\s+(.+?)\s*$/mu.exec(draw.toString("utf8"))?.[1]?.trim() ?? null;
|
|
213
|
+
const files = [
|
|
214
|
+
{ name: basename(sourcePath), data: await readFile(sourcePath) },
|
|
215
|
+
{ name: drawName, data: draw },
|
|
216
|
+
];
|
|
217
|
+
if (guideRef) {
|
|
218
|
+
if (guideRef.includes("\0") || guideRef.startsWith("/") || guideRef.split(/[\\/]/u).some((part) => !part || part === "." || part === "..")) {
|
|
219
|
+
throw new Error("The Smart Draw manifest references an unsafe reveal guide.");
|
|
220
|
+
}
|
|
221
|
+
const guidePath = join(directory, ...guideRef.split("/"));
|
|
222
|
+
files.push({ name: guideRef, data: await safePackageFile(directory, guidePath) });
|
|
223
|
+
}
|
|
224
|
+
const metadata = Buffer.from(`${JSON.stringify({
|
|
225
|
+
schemaVersion: 1,
|
|
226
|
+
asset: publicAsset(asset),
|
|
227
|
+
packageSha256: asset.packageSha256 ?? null,
|
|
228
|
+
files: files.map((file) => file.name),
|
|
229
|
+
}, null, 2)}\n`, "utf8");
|
|
230
|
+
files.push({ name: "manic-smartdraw-package.json", data: metadata });
|
|
231
|
+
return {
|
|
232
|
+
filename: `${safeFilename(asset.title, "").replace(/-$/u, "") || "smartdraw"}.manic-smartdraw.zip`,
|
|
233
|
+
mediaType: "application/zip",
|
|
234
|
+
bytes: zipStored(files),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
export function projectAssetsDirectory(workspace) {
|
|
238
|
+
return join(workspace, PROJECT_ASSET_ROOT);
|
|
239
|
+
}
|
|
240
|
+
async function libraryRoot(settings, engineOverride) {
|
|
241
|
+
const configured = settings.engineEnv.MANIC_ASSETS_DIR?.trim() || process.env.MANIC_ASSETS_DIR?.trim();
|
|
242
|
+
const inferred = suggestAssetsDirFromEnginePath(engineOverride || settings.enginePath || process.env.MANIC_BIN || "");
|
|
243
|
+
const candidate = configured || inferred;
|
|
244
|
+
if (!candidate)
|
|
245
|
+
throw new Error("Configure MANIC_ASSETS_DIR to browse bundled assets.");
|
|
246
|
+
const root = resolve(candidate);
|
|
247
|
+
const information = await lstat(root).catch(() => null);
|
|
248
|
+
if (!information?.isDirectory() || information.isSymbolicLink())
|
|
249
|
+
throw new Error(`MANIC_ASSETS_DIR is not a safe directory: ${root}`);
|
|
250
|
+
return realpath(root);
|
|
251
|
+
}
|
|
252
|
+
async function readLibraryManifest(settings, engineOverride) {
|
|
253
|
+
const root = await libraryRoot(settings, engineOverride);
|
|
254
|
+
const path = join(root, "catalogue-manifest.json");
|
|
255
|
+
const information = await stat(path).catch(() => null);
|
|
256
|
+
if (!information?.isFile())
|
|
257
|
+
throw new Error(`Asset catalogue is missing. Run scripts/gen-asset-catalog.py for ${root}.`);
|
|
258
|
+
const signature = `${information.mtimeMs}:${information.size}`;
|
|
259
|
+
const cached = libraryCache.get(path);
|
|
260
|
+
if (cached?.signature === signature)
|
|
261
|
+
return cached.manifest;
|
|
262
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
263
|
+
if (parsed.schemaVersion !== 1 || !Array.isArray(parsed.assets))
|
|
264
|
+
throw new Error("The bundled asset catalogue schema is not supported.");
|
|
265
|
+
libraryCache.set(path, { signature, manifest: parsed });
|
|
266
|
+
return parsed;
|
|
267
|
+
}
|
|
268
|
+
async function readProjectManifest(workspace) {
|
|
269
|
+
const root = await realpath(workspace);
|
|
270
|
+
const manic = join(root, ".manic");
|
|
271
|
+
const directory = await lstat(manic).catch(() => null);
|
|
272
|
+
if (!directory)
|
|
273
|
+
return { schemaVersion: 1, assets: [] };
|
|
274
|
+
if (!directory.isDirectory() || directory.isSymbolicLink() || await realpath(manic) !== manic)
|
|
275
|
+
throw new Error("The project .manic directory is not safe to use.");
|
|
276
|
+
const path = join(root, PROJECT_MANIFEST);
|
|
277
|
+
const information = await lstat(path).catch(() => null);
|
|
278
|
+
if (!information)
|
|
279
|
+
return { schemaVersion: 1, assets: [] };
|
|
280
|
+
if (!information.isFile() || information.isSymbolicLink())
|
|
281
|
+
throw new Error("The project asset catalogue is not a safe file.");
|
|
282
|
+
const raw = await readFile(path, "utf8").catch((error) => {
|
|
283
|
+
if (error.code === "ENOENT")
|
|
284
|
+
return "";
|
|
285
|
+
throw error;
|
|
286
|
+
});
|
|
287
|
+
if (!raw)
|
|
288
|
+
return { schemaVersion: 1, assets: [] };
|
|
289
|
+
const parsed = JSON.parse(raw);
|
|
290
|
+
if (parsed.schemaVersion !== 1 || !Array.isArray(parsed.assets))
|
|
291
|
+
throw new Error("The project asset catalogue is invalid.");
|
|
292
|
+
return parsed;
|
|
293
|
+
}
|
|
294
|
+
async function writeProjectManifest(workspace, manifest) {
|
|
295
|
+
const root = await ensureProjectAssetRoot(workspace);
|
|
296
|
+
const target = join(dirname(root), "assets.json");
|
|
297
|
+
const temporary = join(dirname(root), `.assets-${randomUUID()}.tmp`);
|
|
298
|
+
await writeFile(temporary, `${JSON.stringify({ ...manifest, assets: [...manifest.assets].sort((a, b) => a.uri.localeCompare(b.uri)) }, null, 2)}\n`, { flag: "wx", mode: 0o600 });
|
|
299
|
+
try {
|
|
300
|
+
await rename(temporary, target);
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
await rm(temporary, { force: true });
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async function withProjectAssetMutation(workspace, operation) {
|
|
308
|
+
const key = await realpath(workspace);
|
|
309
|
+
const previous = projectMutationTails.get(key) ?? Promise.resolve();
|
|
310
|
+
let release = () => { };
|
|
311
|
+
const gate = new Promise((resolveGate) => { release = resolveGate; });
|
|
312
|
+
const tail = previous.then(() => gate);
|
|
313
|
+
projectMutationTails.set(key, tail);
|
|
314
|
+
await previous;
|
|
315
|
+
try {
|
|
316
|
+
return await operation();
|
|
317
|
+
}
|
|
318
|
+
finally {
|
|
319
|
+
release();
|
|
320
|
+
await tail;
|
|
321
|
+
if (projectMutationTails.get(key) === tail)
|
|
322
|
+
projectMutationTails.delete(key);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async function ensureProjectAssetRoot(workspace) {
|
|
326
|
+
const canonicalWorkspace = await realpath(workspace);
|
|
327
|
+
const manic = join(canonicalWorkspace, ".manic");
|
|
328
|
+
const root = join(manic, "assets");
|
|
329
|
+
if (!await lstat(manic).catch(() => null))
|
|
330
|
+
await mkdir(manic, { mode: 0o700 });
|
|
331
|
+
assertSafeDirectory(manic, await lstat(manic), await realpath(manic));
|
|
332
|
+
if (!await lstat(root).catch(() => null))
|
|
333
|
+
await mkdir(root, { mode: 0o700 });
|
|
334
|
+
for (const directory of [manic, root]) {
|
|
335
|
+
const information = await lstat(directory);
|
|
336
|
+
assertSafeDirectory(directory, information, await realpath(directory));
|
|
337
|
+
}
|
|
338
|
+
const project = join(root, "project");
|
|
339
|
+
if (!await lstat(project).catch(() => null))
|
|
340
|
+
await mkdir(project, { mode: 0o700 });
|
|
341
|
+
assertSafeDirectory(project, await lstat(project), await realpath(project));
|
|
342
|
+
return root;
|
|
343
|
+
}
|
|
344
|
+
function assertSafeDirectory(expected, information, canonical) {
|
|
345
|
+
if (!information.isDirectory() || information.isSymbolicLink() || canonical !== expected)
|
|
346
|
+
throw new Error("The project asset directory is not safe to use.");
|
|
347
|
+
}
|
|
348
|
+
async function safeExistingAsset(root, localPath) {
|
|
349
|
+
if (!localPath || localPath.includes("\0") || localPath.startsWith("/") || localPath.split("/").some((part) => !part || part === "." || part === ".."))
|
|
350
|
+
throw new Error("Asset paths must stay inside their configured root.");
|
|
351
|
+
const canonicalRoot = await realpath(root);
|
|
352
|
+
const candidate = join(canonicalRoot, ...localPath.split("/"));
|
|
353
|
+
const information = await lstat(candidate).catch(() => null);
|
|
354
|
+
if (!information?.isFile() || information.isSymbolicLink())
|
|
355
|
+
throw new Error(`Asset file is missing: asset:${localPath}`);
|
|
356
|
+
const absolute = await realpath(candidate);
|
|
357
|
+
const local = relative(canonicalRoot, absolute);
|
|
358
|
+
if (!local || local === ".." || local.startsWith(`..${sep}`))
|
|
359
|
+
throw new Error("Asset access escaped its configured root.");
|
|
360
|
+
return absolute;
|
|
361
|
+
}
|
|
362
|
+
function publicAsset(asset) {
|
|
363
|
+
const { createdAt: _createdAt, packageSha256: _packageSha256, ...result } = asset;
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
function requireProjectSmartDrawRecord(manifest, uri) {
|
|
367
|
+
validateAssetUri(uri);
|
|
368
|
+
if (!uri.startsWith("asset:project/"))
|
|
369
|
+
throw new Error("Only project Smart Draw packages can be changed.");
|
|
370
|
+
const asset = manifest.assets.find((candidate) => candidate.uri === uri);
|
|
371
|
+
if (!asset || asset.kind !== "smartdraw")
|
|
372
|
+
throw new Error(`Project Smart Draw package is not registered: ${uri}`);
|
|
373
|
+
return asset;
|
|
374
|
+
}
|
|
375
|
+
function validateAssetTitle(value) {
|
|
376
|
+
const title = value.normalize("NFC").replaceAll(/\s+/gu, " ").trim();
|
|
377
|
+
if (!title)
|
|
378
|
+
throw new Error("A Smart Draw package title is required.");
|
|
379
|
+
if (title.length > 120)
|
|
380
|
+
throw new Error("Smart Draw package titles cannot exceed 120 characters.");
|
|
381
|
+
if (/\p{Cc}/u.test(title))
|
|
382
|
+
throw new Error("The Smart Draw package title contains unsupported control characters.");
|
|
383
|
+
return title;
|
|
384
|
+
}
|
|
385
|
+
function validateProvenance(metadata, importedFilename) {
|
|
386
|
+
const author = optionalText(metadata.author, 120, "Author");
|
|
387
|
+
const sourceUrl = optionalWebUrl(metadata.sourceUrl, "Source URL");
|
|
388
|
+
return {
|
|
389
|
+
...(author ? { author } : {}),
|
|
390
|
+
...(sourceUrl ? { sourceUrl } : {}),
|
|
391
|
+
importedFilename: basename(importedFilename),
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
function validateLicense(value) {
|
|
395
|
+
if (!value)
|
|
396
|
+
return null;
|
|
397
|
+
const id = optionalText(value.id, 80, "License ID");
|
|
398
|
+
const name = optionalText(value.name, 120, "License name");
|
|
399
|
+
const attribution = optionalText(value.attribution, 500, "Attribution");
|
|
400
|
+
const url = optionalWebUrl(value.url, "License URL");
|
|
401
|
+
if (!id && !name && !attribution && !url)
|
|
402
|
+
return null;
|
|
403
|
+
if (!id || !name)
|
|
404
|
+
throw new Error("License ID and license name are both required when license metadata is supplied.");
|
|
405
|
+
return {
|
|
406
|
+
id,
|
|
407
|
+
name,
|
|
408
|
+
attributionRequired: value.attributionRequired === true,
|
|
409
|
+
...(attribution ? { attribution } : {}),
|
|
410
|
+
...(url ? { url } : {}),
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function optionalText(value, limit, label) {
|
|
414
|
+
if (value === undefined || value === null || value === "")
|
|
415
|
+
return null;
|
|
416
|
+
if (typeof value !== "string")
|
|
417
|
+
throw new Error(`${label} must be text.`);
|
|
418
|
+
const normalized = value.normalize("NFC").replaceAll(/\s+/gu, " ").trim();
|
|
419
|
+
if (!normalized)
|
|
420
|
+
return null;
|
|
421
|
+
if (normalized.length > limit)
|
|
422
|
+
throw new Error(`${label} cannot exceed ${limit} characters.`);
|
|
423
|
+
if (/\p{Cc}/u.test(normalized))
|
|
424
|
+
throw new Error(`${label} contains unsupported control characters.`);
|
|
425
|
+
return normalized;
|
|
426
|
+
}
|
|
427
|
+
function optionalWebUrl(value, label) {
|
|
428
|
+
const text = optionalText(value, 500, label);
|
|
429
|
+
if (!text)
|
|
430
|
+
return null;
|
|
431
|
+
let parsed;
|
|
432
|
+
try {
|
|
433
|
+
parsed = new URL(text);
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
throw new Error(`${label} must be an absolute HTTP or HTTPS URL.`);
|
|
437
|
+
}
|
|
438
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
|
|
439
|
+
throw new Error(`${label} must use HTTP or HTTPS.`);
|
|
440
|
+
return parsed.toString();
|
|
441
|
+
}
|
|
442
|
+
function smartDrawPackageSha256(source, guide) {
|
|
443
|
+
const hash = createHash("sha256");
|
|
444
|
+
hash.update("manic-smartdraw-package-v1\0source\0", "utf8");
|
|
445
|
+
hash.update(source);
|
|
446
|
+
hash.update("\0guide\0", "utf8");
|
|
447
|
+
if (guide)
|
|
448
|
+
hash.update(guide);
|
|
449
|
+
return hash.digest("hex");
|
|
450
|
+
}
|
|
451
|
+
async function safePackageFile(directory, candidate) {
|
|
452
|
+
const canonicalDirectory = await realpath(directory);
|
|
453
|
+
const information = await lstat(candidate).catch(() => null);
|
|
454
|
+
if (!information?.isFile() || information.isSymbolicLink())
|
|
455
|
+
throw new Error(`Smart Draw package file is missing: ${basename(candidate)}`);
|
|
456
|
+
const absolute = await realpath(candidate);
|
|
457
|
+
const local = relative(canonicalDirectory, absolute);
|
|
458
|
+
if (!local || local === ".." || local.startsWith(`..${sep}`))
|
|
459
|
+
throw new Error("Smart Draw package content escaped its package directory.");
|
|
460
|
+
return readFile(absolute);
|
|
461
|
+
}
|
|
462
|
+
function searchable(asset) {
|
|
463
|
+
return [asset.title, asset.uri, ...asset.category, ...asset.keywords].join(" ").toLowerCase();
|
|
464
|
+
}
|
|
465
|
+
function parseCursor(cursor) {
|
|
466
|
+
if (!cursor)
|
|
467
|
+
return 0;
|
|
468
|
+
const value = Number(cursor);
|
|
469
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : 0;
|
|
470
|
+
}
|
|
471
|
+
function validateAssetUri(uri) {
|
|
472
|
+
if (!uri.startsWith("asset:") || uri.includes("\0") || uri.slice(6).startsWith("/") || uri.slice(6).split("/").some((part) => !part || part === "." || part === ".."))
|
|
473
|
+
throw new Error("A safe asset: URI is required.");
|
|
474
|
+
}
|
|
475
|
+
function inspectAsset(name, data) {
|
|
476
|
+
const suffix = extname(name).toLowerCase();
|
|
477
|
+
if (data.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
|
|
478
|
+
if (data.length < 24 || data.toString("ascii", 12, 16) !== "IHDR")
|
|
479
|
+
throw new Error("The PNG header is invalid.");
|
|
480
|
+
return { kind: "image", mediaType: "image/png", extension: ".png", width: data.readUInt32BE(16), height: data.readUInt32BE(20), themeable: false, warnings: suffix === ".png" ? [] : ["filename-extension-normalized"], parts: [] };
|
|
481
|
+
}
|
|
482
|
+
if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) {
|
|
483
|
+
const dimensions = jpegDimensions(data);
|
|
484
|
+
return { kind: "image", mediaType: "image/jpeg", extension: suffix === ".jpeg" ? ".jpeg" : ".jpg", width: dimensions?.width ?? null, height: dimensions?.height ?? null, themeable: false, warnings: dimensions ? [] : ["missing-raster-dimensions"], parts: [] };
|
|
485
|
+
}
|
|
486
|
+
const source = data.toString("utf8");
|
|
487
|
+
if (/<svg\b/iu.test(source.slice(0, 4096))) {
|
|
488
|
+
validateSvg(source);
|
|
489
|
+
const dimensions = svgDimensions(source);
|
|
490
|
+
const markup = source.replaceAll(/<!--[^]*?-->/gu, "");
|
|
491
|
+
const warnings = [
|
|
492
|
+
[/<(?:clipPath)\b/iu, "native-svg-skips-clip-path"], [/<mask\b/iu, "native-svg-skips-mask"],
|
|
493
|
+
[/<filter\b/iu, "native-svg-skips-filter"], [/<(?:linearGradient|radialGradient)\b/iu, "native-svg-skips-gradient-paint"],
|
|
494
|
+
[/<pattern\b/iu, "native-svg-skips-pattern-paint"], [/<text\b/iu, "native-svg-skips-text"], [/<image\b/iu, "native-svg-skips-embedded-image"],
|
|
495
|
+
].flatMap(([pattern, warning]) => pattern.test(markup) ? [warning] : []);
|
|
496
|
+
if (!dimensions)
|
|
497
|
+
warnings.push("missing-svg-intrinsic-dimensions");
|
|
498
|
+
return { kind: "svg", mediaType: "image/svg+xml", extension: ".svg", width: dimensions?.width ?? null, height: dimensions?.height ?? null, themeable: /currentColor/iu.test(markup), warnings: [...new Set(warnings)].sort(), parts: [] };
|
|
499
|
+
}
|
|
500
|
+
if (suffix === ".obj") {
|
|
501
|
+
const parts = [], warnings = [];
|
|
502
|
+
let vertices = 0, drawable = 0;
|
|
503
|
+
for (const line of source.split(/\r?\n/u)) {
|
|
504
|
+
const fields = line.trim().split(/\s+/u);
|
|
505
|
+
if (!fields[0] || fields[0].startsWith("#"))
|
|
506
|
+
continue;
|
|
507
|
+
if (fields[0] === "v") {
|
|
508
|
+
if (fields.length < 4 || fields.slice(1, 4).some((value) => !Number.isFinite(Number(value))))
|
|
509
|
+
throw new Error("The OBJ contains an invalid vertex.");
|
|
510
|
+
vertices += 1;
|
|
511
|
+
}
|
|
512
|
+
else if (fields[0] === "f" || fields[0] === "l") {
|
|
513
|
+
if (fields.length < (fields[0] === "f" ? 4 : 3))
|
|
514
|
+
throw new Error("The OBJ contains invalid drawable geometry.");
|
|
515
|
+
drawable += 1;
|
|
516
|
+
}
|
|
517
|
+
else if ((fields[0] === "o" || fields[0] === "g") && fields.length > 1) {
|
|
518
|
+
const part = fields.slice(1).join("_").replaceAll(/[^A-Za-z0-9_-]+/gu, "_").replaceAll(/_+/gu, "_").replaceAll(/^_+|_+$/gu, "").slice(0, 80);
|
|
519
|
+
if (part && !parts.includes(part))
|
|
520
|
+
parts.push(part);
|
|
521
|
+
}
|
|
522
|
+
else if (fields[0] === "mtllib" || fields[0] === "usemtl")
|
|
523
|
+
warnings.push("obj-materials-ignored");
|
|
524
|
+
}
|
|
525
|
+
if (!vertices || !drawable)
|
|
526
|
+
throw new Error("The OBJ needs vertices and face or line geometry.");
|
|
527
|
+
return { kind: "model", mediaType: "model/obj", extension: ".obj", width: null, height: null, themeable: false, warnings: [...new Set(warnings)].sort(), parts };
|
|
528
|
+
}
|
|
529
|
+
throw new Error("Workbench accepts PNG, JPEG, SVG, and geometry-only OBJ project assets.");
|
|
530
|
+
}
|
|
531
|
+
async function inspectUploadedFile(file) {
|
|
532
|
+
if (!file.name || file.name.includes("\0"))
|
|
533
|
+
throw new Error("The uploaded asset needs a filename.");
|
|
534
|
+
if (file.size < 1)
|
|
535
|
+
throw new Error("The uploaded asset is empty.");
|
|
536
|
+
if (file.size > MAX_ASSET_BYTES)
|
|
537
|
+
throw new Error("Project assets cannot exceed 16 MB.");
|
|
538
|
+
const bytes = Buffer.from(await file.arrayBuffer());
|
|
539
|
+
return {
|
|
540
|
+
bytes,
|
|
541
|
+
inspected: inspectAsset(file.name, bytes),
|
|
542
|
+
sha256: createHash("sha256").update(bytes).digest("hex"),
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function uniqueGuideFilename(original, sourceName) {
|
|
546
|
+
const candidate = safeFilename(original, ".svg");
|
|
547
|
+
return candidate === sourceName ? "reveal-guide.svg" : candidate;
|
|
548
|
+
}
|
|
549
|
+
function validateSvg(source) {
|
|
550
|
+
const withoutComments = source.replaceAll(/<!--[^]*?-->/gu, "");
|
|
551
|
+
if (/<!DOCTYPE|<!ENTITY|<script\b|<foreignObject\b/iu.test(withoutComments))
|
|
552
|
+
throw new Error("SVG scripts, document types, entities, and foreignObject are not allowed.");
|
|
553
|
+
if (/\son[a-z]+\s*=/iu.test(withoutComments))
|
|
554
|
+
throw new Error("SVG event handlers are not allowed.");
|
|
555
|
+
if (/(?:href|xlink:href)\s*=\s*["']\s*(?:https?:|\/\/|data:)/iu.test(withoutComments) || /url\(\s*["']?\s*(?:https?:|\/\/|data:)/iu.test(withoutComments))
|
|
556
|
+
throw new Error("SVG assets cannot load external or embedded resources.");
|
|
557
|
+
}
|
|
558
|
+
function svgDimensions(source) {
|
|
559
|
+
const tag = /<svg\b([^>]*)>/iu.exec(source)?.[1] ?? "";
|
|
560
|
+
const width = absoluteSvgNumber(attribute(tag, "width")), height = absoluteSvgNumber(attribute(tag, "height"));
|
|
561
|
+
if (width && height)
|
|
562
|
+
return { width, height };
|
|
563
|
+
const viewBox = attribute(tag, "viewBox")?.trim().split(/[\s,]+/u).map(Number);
|
|
564
|
+
return viewBox?.length === 4 && viewBox[2] > 0 && viewBox[3] > 0 ? { width: viewBox[2], height: viewBox[3] } : null;
|
|
565
|
+
}
|
|
566
|
+
function attribute(tag, name) {
|
|
567
|
+
return new RegExp(`\\b${name}\\s*=\\s*["']([^"']+)["']`, "iu").exec(tag)?.[1] ?? null;
|
|
568
|
+
}
|
|
569
|
+
function absoluteSvgNumber(value) {
|
|
570
|
+
if (!value || value.trim().endsWith("%"))
|
|
571
|
+
return null;
|
|
572
|
+
const match = /^\s*(\d+(?:\.\d+)?)\s*(?:px)?\s*$/iu.exec(value);
|
|
573
|
+
return match && Number(match[1]) > 0 ? Number(match[1]) : null;
|
|
574
|
+
}
|
|
575
|
+
function jpegDimensions(data) {
|
|
576
|
+
let offset = 2;
|
|
577
|
+
while (offset + 9 < data.length) {
|
|
578
|
+
if (data[offset] !== 0xff) {
|
|
579
|
+
offset += 1;
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
const marker = data[offset + 1];
|
|
583
|
+
if (marker === 0xd8 || marker === 0xd9) {
|
|
584
|
+
offset += 2;
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
const length = data.readUInt16BE(offset + 2);
|
|
588
|
+
if (length < 2 || offset + 2 + length > data.length)
|
|
589
|
+
return null;
|
|
590
|
+
if ([0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf].includes(marker))
|
|
591
|
+
return { height: data.readUInt16BE(offset + 5), width: data.readUInt16BE(offset + 7) };
|
|
592
|
+
offset += 2 + length;
|
|
593
|
+
}
|
|
594
|
+
return null;
|
|
595
|
+
}
|
|
596
|
+
function safeFilename(original, extension) {
|
|
597
|
+
const stem = basename(original, extname(original)).normalize("NFKD").replaceAll(/[^A-Za-z0-9]+/gu, "-").replaceAll(/^-+|-+$/gu, "").toLowerCase().slice(0, 64) || "asset";
|
|
598
|
+
return `${stem}${extension}`;
|
|
599
|
+
}
|
|
600
|
+
function titleFromName(name) {
|
|
601
|
+
const stem = basename(name, extname(name));
|
|
602
|
+
return stem.split(/[-_]+/u).filter(Boolean).map((word) => word[0]?.toUpperCase() + word.slice(1)).join(" ") || "Asset";
|
|
603
|
+
}
|
|
604
|
+
function tokens(name) {
|
|
605
|
+
return [...new Set(basename(name, extname(name)).toLowerCase().split(/[^a-z0-9]+/u).filter(Boolean))];
|
|
606
|
+
}
|
|
607
|
+
/** Minimal deterministic ZIP writer using stored entries; avoids a runtime archive dependency. */
|
|
608
|
+
function zipStored(files) {
|
|
609
|
+
const localParts = [], centralParts = [];
|
|
610
|
+
let offset = 0;
|
|
611
|
+
for (const file of files) {
|
|
612
|
+
const name = Buffer.from(file.name.replaceAll("\\", "/"), "utf8");
|
|
613
|
+
if (!name.length || file.name.startsWith("/") || file.name.split(/[\\/]/u).some((part) => !part || part === "." || part === "..")) {
|
|
614
|
+
throw new Error("A Smart Draw export entry has an unsafe name.");
|
|
615
|
+
}
|
|
616
|
+
const crc = crc32(file.data);
|
|
617
|
+
const local = Buffer.alloc(30);
|
|
618
|
+
local.writeUInt32LE(0x04034b50, 0);
|
|
619
|
+
local.writeUInt16LE(20, 4);
|
|
620
|
+
local.writeUInt16LE(0x0800, 6);
|
|
621
|
+
local.writeUInt16LE(0x0021, 12); // 1980-01-01, the ZIP epoch.
|
|
622
|
+
local.writeUInt32LE(crc, 14);
|
|
623
|
+
local.writeUInt32LE(file.data.length, 18);
|
|
624
|
+
local.writeUInt32LE(file.data.length, 22);
|
|
625
|
+
local.writeUInt16LE(name.length, 26);
|
|
626
|
+
localParts.push(local, name, file.data);
|
|
627
|
+
const central = Buffer.alloc(46);
|
|
628
|
+
central.writeUInt32LE(0x02014b50, 0);
|
|
629
|
+
central.writeUInt16LE(20, 4);
|
|
630
|
+
central.writeUInt16LE(20, 6);
|
|
631
|
+
central.writeUInt16LE(0x0800, 8);
|
|
632
|
+
central.writeUInt16LE(0x0021, 14);
|
|
633
|
+
central.writeUInt32LE(crc, 16);
|
|
634
|
+
central.writeUInt32LE(file.data.length, 20);
|
|
635
|
+
central.writeUInt32LE(file.data.length, 24);
|
|
636
|
+
central.writeUInt16LE(name.length, 28);
|
|
637
|
+
central.writeUInt32LE(offset, 42);
|
|
638
|
+
centralParts.push(central, name);
|
|
639
|
+
offset += local.length + name.length + file.data.length;
|
|
640
|
+
}
|
|
641
|
+
const centralDirectory = Buffer.concat(centralParts);
|
|
642
|
+
const end = Buffer.alloc(22);
|
|
643
|
+
end.writeUInt32LE(0x06054b50, 0);
|
|
644
|
+
end.writeUInt16LE(files.length, 8);
|
|
645
|
+
end.writeUInt16LE(files.length, 10);
|
|
646
|
+
end.writeUInt32LE(centralDirectory.length, 12);
|
|
647
|
+
end.writeUInt32LE(offset, 16);
|
|
648
|
+
return Buffer.concat([...localParts, centralDirectory, end]);
|
|
649
|
+
}
|
|
650
|
+
function crc32(data) {
|
|
651
|
+
let crc = 0xffffffff;
|
|
652
|
+
for (const byte of data) {
|
|
653
|
+
crc ^= byte;
|
|
654
|
+
for (let bit = 0; bit < 8; bit += 1)
|
|
655
|
+
crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1));
|
|
656
|
+
}
|
|
657
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
658
|
+
}
|
|
659
|
+
//# sourceMappingURL=assets.js.map
|