@1agh/maude 0.28.0 → 0.29.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/README.md +2 -2
- package/{plugins/design/dev-server → apps/studio}/ai-banner.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/annotations-context-toolbar.tsx +286 -6
- package/{plugins/design/dev-server → apps/studio}/annotations-layer.tsx +1209 -122
- package/{plugins/design/dev-server → apps/studio}/api.ts +486 -32
- package/{plugins/design/dev-server → apps/studio}/artboard-activity-overlay.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/artboard-marquee.tsx +1 -1
- package/apps/studio/bin/_motion-sample-playwright.mjs +129 -0
- package/{plugins/design/dev-server → apps/studio}/bin/canvas-edit.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/draw-proof.sh +37 -2
- package/{plugins/design/dev-server → apps/studio}/bin/preflight.sh +1 -1
- package/apps/studio/bin/read-annotations.mjs +438 -0
- package/apps/studio/bin/read-annotations.sh +11 -0
- package/{plugins/design/dev-server → apps/studio}/bin/runtime-health.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/scenario-report.mjs +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/screenshot.sh +62 -2
- package/apps/studio/bin/server-up.sh +234 -0
- package/apps/studio/bin/to-lottie-verify.html +68 -0
- package/apps/studio/bin/to-lottie.sh +128 -0
- package/{plugins/design/dev-server → apps/studio}/bin/visual-sanity.sh +19 -3
- package/{plugins/design/dev-server → apps/studio}/build.ts +5 -3
- package/{plugins/design/dev-server → apps/studio}/canvas-arrowheads.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-comment-mount.tsx +2 -2
- package/apps/studio/canvas-create.ts +104 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-cursors.ts +47 -13
- package/{plugins/design/dev-server → apps/studio}/canvas-icons.tsx +60 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-inline.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-resolver.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib.tsx +41 -33
- package/{plugins/design/dev-server → apps/studio}/canvas-shell.tsx +57 -42
- package/{plugins/design/dev-server → apps/studio}/client/app.jsx +1713 -530
- package/apps/studio/client/canvas-url.js +81 -0
- package/{plugins/design/dev-server → apps/studio}/client/comments-overlay.css +41 -27
- package/{plugins/design/dev-server → apps/studio}/client/index.html +2 -1
- package/apps/studio/client/styles/1-tokens-maude.css +296 -0
- package/apps/studio/client/styles/3-shell-maude.css +459 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/3-shell.css +129 -0
- package/apps/studio/client/styles/4-components-maude.css +74 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/4-components.css +357 -34
- package/apps/studio/client/styles/5-maude-overrides.css +123 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/_index.css +9 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles.css +1 -1
- package/apps/studio/client/tour/overlay.jsx +191 -0
- package/apps/studio/client/tour/usage-tour.js +35 -0
- package/apps/studio/client/whats-new-seen.js +52 -0
- package/apps/studio/client/whats-new.jsx +250 -0
- package/{plugins/design/dev-server → apps/studio}/collab/index.ts +4 -4
- package/{plugins/design/dev-server → apps/studio}/collab/persistence.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/annotation-strokes-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/equal-spacing-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/move-artboards-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/comments-overlay.tsx +25 -6
- package/{plugins/design/dev-server → apps/studio}/context-menu.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/contextual-toolbar.tsx +4 -7
- package/{plugins/design/dev-server → apps/studio}/cursors-overlay.tsx +1 -1
- package/apps/studio/dist/client.bundle.js +22825 -0
- package/apps/studio/dist/comment-mount.js +1960 -0
- package/apps/studio/dist/runtime/lib0_decoding.js +1 -0
- package/apps/studio/dist/runtime/lib0_encoding.js +1 -0
- package/apps/studio/dist/runtime/motion.js +4 -0
- package/apps/studio/dist/runtime/motion_react.js +12 -0
- package/apps/studio/dist/runtime/pixi-js.js +3397 -0
- package/apps/studio/dist/runtime/react-dom.js +1 -0
- package/apps/studio/dist/runtime/react-dom_client.js +9 -0
- package/apps/studio/dist/runtime/react.js +1 -0
- package/apps/studio/dist/runtime/react_jsx-dev-runtime.js +1 -0
- package/apps/studio/dist/runtime/react_jsx-runtime.js +1 -0
- package/apps/studio/dist/runtime/y-protocols_awareness.js +1 -0
- package/apps/studio/dist/runtime/y-protocols_sync.js +1 -0
- package/apps/studio/dist/runtime/yjs.js +5 -0
- package/apps/studio/dist/styles.css +5695 -0
- package/{plugins/design/dev-server → apps/studio}/dom-selection.ts +75 -4
- package/apps/studio/draw/animate.ts +333 -0
- package/{plugins/design/dev-server → apps/studio}/draw/brush.ts +4 -4
- package/{plugins/design/dev-server → apps/studio}/draw/composition.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/geometry.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/index.ts +9 -6
- package/{plugins/design/dev-server → apps/studio}/draw/layout.ts +2 -2
- package/apps/studio/draw/morph.ts +204 -0
- package/{plugins/design/dev-server → apps/studio}/draw/optimize.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/palette.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/primitives.ts +1 -1
- package/apps/studio/draw/serialize-animate.ts +324 -0
- package/{plugins/design/dev-server → apps/studio}/draw/serialize.ts +9 -3
- package/apps/studio/draw/test/animate.test.ts +172 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/layout.test.ts +1 -1
- package/apps/studio/draw/test/morph.test.ts +107 -0
- package/apps/studio/draw/test/serialize-animate.test.ts +142 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/serialize.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-detector.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-handles.tsx +7 -29
- package/{plugins/design/dev-server → apps/studio}/examples/perf-100-artboards.tsx +1 -2
- package/{plugins/design/dev-server → apps/studio}/export-dialog.tsx +14 -2
- package/{plugins/design/dev-server → apps/studio}/exporters/index.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/http.ts +103 -2
- package/{plugins/design/dev-server → apps/studio}/input-router.tsx +8 -1
- package/{plugins/design/dev-server → apps/studio}/inspect.ts +20 -3
- package/{plugins/design/dev-server → apps/studio}/marquee-overlay.tsx +6 -3
- package/{plugins/design/dev-server → apps/studio}/participants-chrome.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/paths.ts +15 -11
- package/{plugins/design/dev-server → apps/studio}/server.ts +19 -1
- package/{plugins/design/dev-server → apps/studio}/sync/index.ts +6 -6
- package/{plugins/design/dev-server → apps/studio}/sync/materialize.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/ai-activity.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/annotations-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/annotations-layer.test.ts +69 -6
- package/{plugins/design/dev-server → apps/studio}/test/annotations-roundtrip.test.ts +98 -1
- package/apps/studio/test/annotations-text-format.test.ts +396 -0
- package/apps/studio/test/asset-api.test.ts +149 -0
- package/{plugins/design/dev-server → apps/studio}/test/boot-self-heal.test.ts +1 -1
- package/apps/studio/test/canvas-create-api.test.ts +361 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-cursors.test.ts +3 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-edit.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-hmr-runtime.test.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-inline.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-resolver.test.ts +2 -3
- package/apps/studio/test/canvas-media-drop.test.ts +158 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-meta-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/canvas-origin-gate.test.ts +18 -3
- package/apps/studio/test/canvas-url.test.ts +99 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-annotations-bridge.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-bridge.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-room.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-stress.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/comments-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/compile-entry.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/canva.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/history.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pw-launch.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/exporters/scope.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/zip.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/git-lifecycle.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/handoff-static-frames.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/hmr-broadcast.test.ts +1 -1
- package/apps/studio/test/index-data-canvas-ds.test.ts +97 -0
- package/apps/studio/test/motion-sample.test.ts +35 -0
- package/{plugins/design/dev-server → apps/studio}/test/perf-harness.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/phase-3.6-smoke.test.ts +3 -1
- package/apps/studio/test/read-annotations.test.ts +409 -0
- package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sanitize-annotation-svg.test.ts +108 -2
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-convergence.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-migrate.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-projection.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/snap-distance-pill.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-agent.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/sync-atomic-write.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/sync-connection-state.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-echo-guard.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-fs-mirror.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/sync-hardening.test.ts +4 -5
- package/{plugins/design/dev-server → apps/studio}/test/sync-hubs-config.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/sync-runtime.test.ts +3 -8
- package/{plugins/design/dev-server → apps/studio}/test/sync-status.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-untrusted.test.ts +1 -2
- package/apps/studio/test/tour-overlay.test.tsx +56 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-agent-presence.test.tsx +4 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-annotation-resize.test.ts +43 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-snap-guides.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-tool-mode.test.tsx +4 -1
- package/apps/studio/test/whats-new.test.ts +101 -0
- package/apps/studio/text-imports.d.ts +9 -0
- package/{plugins/design/dev-server → apps/studio}/tool-palette.tsx +4 -69
- package/{plugins/design/dev-server → apps/studio}/undo-hud.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/undo-stack.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-agent-presence.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-annotation-resize.tsx +41 -12
- package/{plugins/design/dev-server → apps/studio}/use-annotation-selection.tsx +3 -7
- package/{plugins/design/dev-server → apps/studio}/use-annotations-visibility.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-artboard-drag.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-canvas-activity.tsx +2 -2
- package/apps/studio/use-canvas-media-drop.tsx +343 -0
- package/{plugins/design/dev-server → apps/studio}/use-collab.tsx +4 -5
- package/{plugins/design/dev-server → apps/studio}/use-cursor-modifiers.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-keyboard-discipline.tsx +5 -2
- package/{plugins/design/dev-server → apps/studio}/use-selection-set.tsx +10 -2
- package/{plugins/design/dev-server → apps/studio}/use-snap-guides.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-tool-mode.tsx +4 -2
- package/{plugins/design/dev-server → apps/studio}/use-undo-stack.tsx +5 -6
- package/apps/studio/whats-new.json +139 -0
- package/apps/studio/whats-new.schema.json +70 -0
- package/apps/studio/whats-new.ts +87 -0
- package/cli/bin/maude.mjs +10 -0
- package/cli/commands/design.mjs +84 -10
- package/cli/commands/design.test.mjs +133 -1
- package/cli/commands/help.mjs +8 -2
- package/cli/commands/hub.mjs +3 -3
- package/cli/commands/hub.test.mjs +1 -1
- package/cli/commands/scenario-report.mjs +2 -9
- package/cli/lib/cache.mjs +1 -1
- package/cli/lib/config-lint.mjs +1 -1
- package/cli/lib/copy-tree.mjs +1 -1
- package/cli/lib/design-link.mjs +1 -1
- package/cli/lib/flow-design-integration.test.mjs +2 -2
- package/cli/lib/gitignore-block.mjs +1 -0
- package/cli/lib/gitignore-block.test.mjs +2 -2
- package/cli/lib/plugin-cli-reachability.test.mjs +8 -7
- package/cli/lib/preflight.mjs +1 -1
- package/cli/lib/stack-detect.mjs +1 -1
- package/package.json +16 -16
- package/plugins/design/templates/_shell.html +3 -3
- package/plugins/design/templates/brief-board.tsx.template +61 -0
- package/plugins/design/templates/canvas.tsx.template +1 -1
- package/plugins/design/templates/design-system-inspiration/SUB-AGENT-PROMPTS.md +18 -3
- package/plugins/design/templates/design-system-inspiration/core/config.json.tpl +1 -1
- package/plugins/design/templates/design-system-inspiration/core/preview/_motion-readme.md.tpl +1 -1
- package/plugins/flow/.claude-plugin/config.schema.json +16 -0
- package/plugins/design/dev-server/bin/server-up.sh +0 -135
- package/plugins/design/dev-server/dist/client.bundle.js +0 -20692
- package/plugins/design/dev-server/dist/comment-mount.js +0 -1924
- package/plugins/design/dev-server/dist/runtime/lib0_decoding.js +0 -620
- package/plugins/design/dev-server/dist/runtime/lib0_encoding.js +0 -604
- package/plugins/design/dev-server/dist/runtime/motion.js +0 -4944
- package/plugins/design/dev-server/dist/runtime/motion_react.js +0 -10056
- package/plugins/design/dev-server/dist/runtime/pixi-js.js +0 -53104
- package/plugins/design/dev-server/dist/runtime/react-dom.js +0 -231
- package/plugins/design/dev-server/dist/runtime/react-dom_client.js +0 -10357
- package/plugins/design/dev-server/dist/runtime/react.js +0 -535
- package/plugins/design/dev-server/dist/runtime/react_jsx-dev-runtime.js +0 -60
- package/plugins/design/dev-server/dist/runtime/react_jsx-runtime.js +0 -85
- package/plugins/design/dev-server/dist/runtime/y-protocols_awareness.js +0 -376
- package/plugins/design/dev-server/dist/runtime/y-protocols_sync.js +0 -100
- package/plugins/design/dev-server/dist/runtime/yjs.js +0 -6687
- package/plugins/design/dev-server/dist/styles.css +0 -2710
- package/{plugins/design/dev-server → apps/studio}/activity.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_enumerate-artboards-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_html-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_pdf-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_png-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_pptx-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_pw-launch.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_screenshot-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_svg-optimize.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_svg-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/asset-sweep.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/bootstrap-check.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/check-runtime-bundles.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/draw-build.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/handoff.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/prep.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/slug.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/smoke.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/svg-optimize.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/boot-self-heal.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-build.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-edit.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-header.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-meta.schema.json +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-pipeline.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/hmr.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/iframe-lazy.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/0-reset.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/1-tokens.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/2-layout.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/5-utilities.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/ai-activity.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/awareness-bridge.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/collab/git-lifecycle.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/protocol.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/registry.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/room.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/config.schema.json +0 -0
- package/{plugins/design/dev-server → apps/studio}/context.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/dist/runtime/.min-sizes.json +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/brush.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/composition.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/geometry.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/test/gradient.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/optimize.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/palette.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/primitives.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/examples/README.md +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/_browser-bundles.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/canva-handoff-prompt.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/canva.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/html.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/pdf.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/png.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/pptx.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/scope.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/svg.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/zip.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/fs-watch.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/handoff.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/history.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/hmr-broadcast.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/locator.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/mem.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/runtime-bundle.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/server.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/agent.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/sync/atomic-write.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/codec.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/connection-state.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/echo-guard.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/fs-mirror.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/hubs-config.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/migrate-seed.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/sync/origins.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/projection.ts +3 -3
- package/{plugins/design/dev-server → apps/studio}/sync/status.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/untrusted.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/_helpers.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/active-state.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/activity.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotation-strokes-command.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotations-draw-modifiers.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/artboard-activity-overlay.test.tsx +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/binary-smoke.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/bundle-smoke.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-build.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-header.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-motion.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-pipeline.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-route.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-awareness-bridge.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-loopback.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-protocol.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/collab-reseed-guard.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/comment-mount.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/context-resolve-tokens.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/csp-canvas-shell.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/equal-spacing-detector.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/endpoint.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/html.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pdf.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/png.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx-deck.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/svg.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-20-annotations.svg +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-21-annotations.svg +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/fs-watch.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/handoff.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/history-rollback.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/hmr-classify.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/input-router.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/locator.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/marquee-overlay.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/move-artboards-command.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/participants-chrome.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/paths.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle-error-mapping.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/server-lifecycle.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-foundation.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-codec.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-meta-codec.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/system-endpoint.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/tool-palette.test.tsx +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/undo-stack.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/use-annotation-selection.test.tsx +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-artboard-drag.test.ts +3 -3
- package/{plugins/design/dev-server → apps/studio}/test/use-canvas-activity.test.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/use-collab.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-cursor-modifiers.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-keyboard-discipline.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-selection-set.test.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-undo-stack.test.tsx +2 -2
- /package/{plugins/design/dev-server → apps/studio}/test/ws-handshake.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/tsconfig.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/ws.ts +0 -0
|
@@ -19,7 +19,8 @@ import type { ActiveJsonShape } from './exporters/scope.ts';
|
|
|
19
19
|
import type { Inspect } from './inspect.ts';
|
|
20
20
|
import { canvasSlug, writeLocator } from './locator.ts';
|
|
21
21
|
import { DEV_SERVER_ROOT } from './paths.ts';
|
|
22
|
-
import {
|
|
22
|
+
import { getRuntimeBundle, packageForSlug, RUNTIME_PACKAGES, slugFor } from './runtime-bundle.ts';
|
|
23
|
+
import { loadWhatsNew } from './whats-new.ts';
|
|
23
24
|
|
|
24
25
|
// Real disk install root — never the virtual `/$bunfs/root` of compiled bins.
|
|
25
26
|
// See paths.ts for the resolution logic + Phase 19.1 / v0.18.1 rationale.
|
|
@@ -131,7 +132,10 @@ function safePathUnderRoot(reqUrl: string, repoRoot: string): string | null {
|
|
|
131
132
|
// and inside the standalone binary's embedded FS in --compile mode.
|
|
132
133
|
const DIST_DIR = join(HERE, 'dist');
|
|
133
134
|
const CLIENT_DIR = join(HERE, 'client');
|
|
134
|
-
|
|
135
|
+
// Templates stayed under the design *plugin* (plugins/design/templates) when the
|
|
136
|
+
// dev-server moved to apps/studio (DDR-095) — both ship in the npm tarball, so
|
|
137
|
+
// from DEV_SERVER_ROOT (apps/studio) reach across with ../../plugins/design.
|
|
138
|
+
const TEMPLATES_DIR = join(HERE, '..', '..', 'plugins', 'design', 'templates');
|
|
135
139
|
|
|
136
140
|
// In-memory transpile cache. Key = absolute canvas path. Repeat GETs against an
|
|
137
141
|
// unchanged source skip the parse + ID-injection + Bun.Transpiler + Bun.build
|
|
@@ -424,6 +428,12 @@ export function createHttp(ctx: Context, api: Api, inspect: Inspect, ai: AiActiv
|
|
|
424
428
|
|
|
425
429
|
'/_config': () => Response.json({ ...ctx.cfg, canvasOrigin: ctx.canvasOrigin }),
|
|
426
430
|
|
|
431
|
+
// What's New feed (DDR-A) — read-only product-update list surfaced in the
|
|
432
|
+
// Maude UI chrome. Main-origin only by omission from the canvas-origin
|
|
433
|
+
// allowlist below (the untrusted canvas iframe never needs it).
|
|
434
|
+
'/_api/whats-new': () =>
|
|
435
|
+
Response.json(loadWhatsNew(), { headers: { 'Cache-Control': 'no-store' } }),
|
|
436
|
+
|
|
427
437
|
'/_index-data': async () =>
|
|
428
438
|
Response.json(await api.buildIndexData(), { headers: { 'Cache-Control': 'no-store' } }),
|
|
429
439
|
|
|
@@ -582,6 +592,91 @@ export function createHttp(ctx: Context, api: Api, inspect: Inspect, ai: AiActiv
|
|
|
582
592
|
return new Response('Method not allowed', { status: 405 });
|
|
583
593
|
},
|
|
584
594
|
|
|
595
|
+
'/_api/canvas': async (req: Request) => {
|
|
596
|
+
// Phase 22 — create + soft-delete a canvas from the browser file tree.
|
|
597
|
+
// POST body { name, kind?: "brief-board", group? } → 201 { file, rel, slug }
|
|
598
|
+
// DELETE ?file=<rel> → 200 { rel, slug, trashed[] }
|
|
599
|
+
// MAIN ORIGIN ONLY: this route is intentionally absent from
|
|
600
|
+
// startCanvasServer's allowlist (DDR-054) — the untrusted canvas iframe
|
|
601
|
+
// origin must never reach a file-write/-delete endpoint. Validation lives in
|
|
602
|
+
// api.createCanvas / api.deleteCanvas (containment + group allowlist).
|
|
603
|
+
if (req.method === 'DELETE') {
|
|
604
|
+
const file = new URL(req.url).searchParams.get('file');
|
|
605
|
+
const result = await api.deleteCanvas({ file });
|
|
606
|
+
if (!result.ok) {
|
|
607
|
+
return Response.json(
|
|
608
|
+
{ ok: false, error: result.error },
|
|
609
|
+
{ status: result.status, headers: { 'Cache-Control': 'no-store' } }
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
return Response.json(
|
|
613
|
+
{
|
|
614
|
+
ok: true,
|
|
615
|
+
rel: result.rel,
|
|
616
|
+
slug: result.slug,
|
|
617
|
+
trashed: result.trashed,
|
|
618
|
+
trashDir: result.trashDir,
|
|
619
|
+
},
|
|
620
|
+
{ status: 200, headers: { 'Cache-Control': 'no-store' } }
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
if (req.method !== 'POST') return new Response('Method not allowed', { status: 405 });
|
|
624
|
+
const body = await readJson<{ name?: unknown; kind?: unknown; group?: unknown }>(
|
|
625
|
+
req,
|
|
626
|
+
8 * 1024
|
|
627
|
+
);
|
|
628
|
+
if (!body) return new Response('body required', { status: 400 });
|
|
629
|
+
const result = await api.createCanvas(body);
|
|
630
|
+
if (!result.ok) {
|
|
631
|
+
return Response.json(
|
|
632
|
+
{ ok: false, error: result.error },
|
|
633
|
+
{ status: result.status, headers: { 'Cache-Control': 'no-store' } }
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
return Response.json(
|
|
637
|
+
{ ok: true, file: result.file, rel: result.rel, slug: result.slug },
|
|
638
|
+
{ status: 201, headers: { 'Cache-Control': 'no-store' } }
|
|
639
|
+
);
|
|
640
|
+
},
|
|
641
|
+
|
|
642
|
+
'/_api/asset': async (req: Request) => {
|
|
643
|
+
// Phase 23 — binary image upload from the canvas (drag-drop / paste / the
|
|
644
|
+
// a11y file picker). POST raw image bytes → content-addressed write under
|
|
645
|
+
// <designRoot>/assets/<sha8>.<ext>, returns 201 { path }. This route is on
|
|
646
|
+
// the canvas-origin allowlist (CANVAS_SAFE_API below) — a bigger grant than
|
|
647
|
+
// the inert annotation-SVG write (binary, disk) — so the caps in
|
|
648
|
+
// api.saveAsset (magic-byte sniff, 10 MB ceiling, content-addressed name,
|
|
649
|
+
// traversal guard, no-SVG, dedupe) are the load-bearing trust mitigation,
|
|
650
|
+
// NOT optional. See DDR (Task 9).
|
|
651
|
+
if (req.method !== 'POST') return new Response('Method not allowed', { status: 405 });
|
|
652
|
+
// Early reject on a declared oversize body (the post-read length check in
|
|
653
|
+
// saveAsset is the authoritative gate — Content-Length can be omitted/lied).
|
|
654
|
+
const declared = Number(req.headers.get('content-length') || '0');
|
|
655
|
+
if (Number.isFinite(declared) && declared > 10 * 1024 * 1024) {
|
|
656
|
+
return Response.json(
|
|
657
|
+
{ ok: false, error: 'asset exceeds the 10 MB cap' },
|
|
658
|
+
{ status: 413, headers: { 'Cache-Control': 'no-store' } }
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
let bytes: Uint8Array;
|
|
662
|
+
try {
|
|
663
|
+
bytes = new Uint8Array(await req.arrayBuffer());
|
|
664
|
+
} catch {
|
|
665
|
+
return new Response('could not read request body', { status: 400 });
|
|
666
|
+
}
|
|
667
|
+
const result = await api.saveAsset(bytes);
|
|
668
|
+
if (!result.ok) {
|
|
669
|
+
return Response.json(
|
|
670
|
+
{ ok: false, error: result.error },
|
|
671
|
+
{ status: result.status ?? 400, headers: { 'Cache-Control': 'no-store' } }
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
return Response.json(
|
|
675
|
+
{ path: result.path },
|
|
676
|
+
{ status: 201, headers: { 'Cache-Control': 'no-store' } }
|
|
677
|
+
);
|
|
678
|
+
},
|
|
679
|
+
|
|
585
680
|
'/_api/export-history': async (req: Request) => {
|
|
586
681
|
// Phase 6.5 T10 — read-only recent-exports feed for the dialog's
|
|
587
682
|
// Recent tab. Writes happen as a side-effect of `/_api/export`.
|
|
@@ -791,6 +886,11 @@ export function createHttp(ctx: Context, api: Api, inspect: Inspect, ai: AiActiv
|
|
|
791
886
|
headers: {
|
|
792
887
|
'Content-Type': MIME[e] || 'application/octet-stream',
|
|
793
888
|
'Cache-Control': 'no-store',
|
|
889
|
+
// DDR-088 follow-up — never let a browser MIME-sniff a served file
|
|
890
|
+
// (e.g. an uploaded GIF/WEBP polyglot) into a richer type. Assets are
|
|
891
|
+
// only referenced via <image href> + the canvas CSP blocks script, so
|
|
892
|
+
// this is defense-in-depth on the static lane.
|
|
893
|
+
'X-Content-Type-Options': 'nosniff',
|
|
794
894
|
},
|
|
795
895
|
});
|
|
796
896
|
} catch (err) {
|
|
@@ -837,6 +937,7 @@ export function createHttp(ctx: Context, api: Api, inspect: Inspect, ai: AiActiv
|
|
|
837
937
|
'/_api/git-user', // presence display name
|
|
838
938
|
'/_api/canvas-meta', // layout/viewport sidecar (GET + PATCH)
|
|
839
939
|
'/_api/annotations', // annotation SVG (GET + PUT) — drives the collab bridge
|
|
940
|
+
'/_api/asset', // Phase 23 — capped binary image upload (sniff+10MB+sha8 name+no-SVG)
|
|
840
941
|
'/_api/git-committers', // @mention autocomplete
|
|
841
942
|
'/_api/ai', // AI-activity banner
|
|
842
943
|
'/_comments', // per-file comment list (renders pins)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file input-router.tsx — canvas pointer/keyboard classifier + hook
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/input-router.tsx
|
|
4
4
|
* @purpose Owned by canvas-lib's DesignCanvas. Classifies the NON-WHEEL
|
|
5
5
|
* subset of pointer + key events into discrete router actions.
|
|
6
6
|
* `useViewportController` keeps owning wheel + middle-mouse +
|
|
@@ -68,6 +68,10 @@ export type Tool =
|
|
|
68
68
|
| 'hand'
|
|
69
69
|
| 'comment'
|
|
70
70
|
| 'pen'
|
|
71
|
+
// Annotation polish (item 8) — FigJam-style highlighter. A `pen`-shaped tool
|
|
72
|
+
// that produces a translucent wide multiply stroke (a PenStroke with
|
|
73
|
+
// `highlighter:true`), not a new stroke type.
|
|
74
|
+
| 'highlighter'
|
|
71
75
|
// Phase 24 — `shape` is the single active draw tool that produces rect /
|
|
72
76
|
// ellipse / polygon strokes (the kind is chosen via the palette popover).
|
|
73
77
|
// `rect` / `ellipse` stay in the union as the stroke discriminants they
|
|
@@ -82,6 +86,7 @@ export type Tool =
|
|
|
82
86
|
|
|
83
87
|
const ANNOTATION_TOOLS = new Set<Tool>([
|
|
84
88
|
'pen',
|
|
89
|
+
'highlighter',
|
|
85
90
|
'shape',
|
|
86
91
|
'rect',
|
|
87
92
|
'ellipse',
|
|
@@ -167,6 +172,8 @@ export function classify(input: ClassifyInput): RouterAction {
|
|
|
167
172
|
if (k === 'h') return { kind: 'tool', tool: 'hand' };
|
|
168
173
|
if (k === 'c') return { kind: 'tool', tool: 'comment' };
|
|
169
174
|
if (k === 'b') return { kind: 'tool', tool: 'pen' };
|
|
175
|
+
// I = hIghlighter (a free bare letter; 'H' is taken by Hand).
|
|
176
|
+
if (k === 'i') return { kind: 'tool', tool: 'highlighter' };
|
|
170
177
|
// Phase 24 — R (and legacy O) both arm the single Shape tool; the specific
|
|
171
178
|
// primitive is picked from the palette's shape-kind popover.
|
|
172
179
|
if (k === 'r' || k === 'o') return { kind: 'tool', tool: 'shape' };
|
|
@@ -8,6 +8,9 @@ export interface SelectedElement {
|
|
|
8
8
|
file: string;
|
|
9
9
|
/** CSS-selector path (v1 anchor). Always present for backwards-compat + legacy HTML canvases. */
|
|
10
10
|
selector: string;
|
|
11
|
+
/** Occurrence index among `querySelectorAll(selector)` — disambiguates a
|
|
12
|
+
* component repeated within one artboard. Absent → first match. */
|
|
13
|
+
index?: number;
|
|
11
14
|
tag: string;
|
|
12
15
|
classes: string;
|
|
13
16
|
text: string;
|
|
@@ -140,6 +143,7 @@ export function createInspect(
|
|
|
140
143
|
return {
|
|
141
144
|
file,
|
|
142
145
|
selector: String(sel.selector || ''),
|
|
146
|
+
index: typeof sel.index === 'number' ? sel.index : undefined,
|
|
143
147
|
tag: String(sel.tag || ''),
|
|
144
148
|
classes: String(sel.classes || ''),
|
|
145
149
|
text: String(sel.text || '').slice(0, 240),
|
|
@@ -281,7 +285,7 @@ const INSPECTOR_SCRIPT = `
|
|
|
281
285
|
var withSelector = commentsCache.filter(function(c) { return c && c.selector; });
|
|
282
286
|
withSelector.forEach(function(c, i) {
|
|
283
287
|
var target = null;
|
|
284
|
-
try {
|
|
288
|
+
try { var _all = document.querySelectorAll(c.selector); var _i = (typeof c.index === 'number' && c.index > 0 && c.index < _all.length) ? c.index : 0; target = _all[_i] || _all[0] || null; } catch (e) {}
|
|
285
289
|
var pin = document.createElement('button');
|
|
286
290
|
pin.className = 'dgn-pin' + (c.status === 'resolved' ? ' resolved' : '') + (c.id === focusedPinId ? ' focused' : '');
|
|
287
291
|
pin.textContent = String(i + 1);
|
|
@@ -309,7 +313,7 @@ const INSPECTOR_SCRIPT = `
|
|
|
309
313
|
var node = pinNodes[i];
|
|
310
314
|
var x, y, hidden = false;
|
|
311
315
|
if (!node.target || !node.target.isConnected) {
|
|
312
|
-
try { node.
|
|
316
|
+
try { var _nc = node.comment; var _na = document.querySelectorAll(_nc.selector); var _ni = (typeof _nc.index === 'number' && _nc.index > 0 && _nc.index < _na.length) ? _nc.index : 0; node.target = _na[_ni] || _na[0] || null; } catch (e) {}
|
|
313
317
|
}
|
|
314
318
|
if (node.target) {
|
|
315
319
|
var r = node.target.getBoundingClientRect();
|
|
@@ -352,6 +356,19 @@ const INSPECTOR_SCRIPT = `
|
|
|
352
356
|
new MutationObserver(function(){ startTick(); }).observe(document.documentElement, { subtree: true, attributes: true, attributeFilter: ['style', 'class'], childList: true });
|
|
353
357
|
}
|
|
354
358
|
|
|
359
|
+
// ⌘K / Ctrl+K command palette — keydown fired inside the canvas iframe never
|
|
360
|
+
// reaches the shell's window-scoped listener (iframe keyboard isolation), so
|
|
361
|
+
// the palette wouldn't open while focus is in the canvas. Forward the chord to
|
|
362
|
+
// the parent; the shell toggles the palette (mirrors its own handler, which
|
|
363
|
+
// fires "even in inputs"). Capture phase so canvas-lib's pan/zoom keydown
|
|
364
|
+
// handler can't swallow it first.
|
|
365
|
+
document.addEventListener('keydown', function(e) {
|
|
366
|
+
if ((e.metaKey || e.ctrlKey) && (e.key === 'k' || e.key === 'K')) {
|
|
367
|
+
e.preventDefault();
|
|
368
|
+
try { window.parent.postMessage({ dgn: 'toggle-palette' }, '*'); } catch (err) {}
|
|
369
|
+
}
|
|
370
|
+
}, true);
|
|
371
|
+
|
|
355
372
|
window.addEventListener('message', function(e) {
|
|
356
373
|
var m = e.data;
|
|
357
374
|
if (!m || typeof m !== 'object' || !m.dgn) return;
|
|
@@ -368,7 +385,7 @@ const INSPECTOR_SCRIPT = `
|
|
|
368
385
|
var c = commentsCache.find(function(x){ return x && x.id === m.id; });
|
|
369
386
|
if (c && c.selector) {
|
|
370
387
|
try {
|
|
371
|
-
var
|
|
388
|
+
var _ta = document.querySelectorAll(c.selector); var _ti = (typeof c.index === 'number' && c.index > 0 && c.index < _ta.length) ? c.index : 0; var t = _ta[_ti] || _ta[0] || null;
|
|
372
389
|
if (t) t.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
373
390
|
} catch (e) {}
|
|
374
391
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file marquee-overlay.tsx — T26 (Wave 3)
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/marquee-overlay.tsx
|
|
4
4
|
* @purpose Element-level marquee selection. Drag from empty padding inside
|
|
5
5
|
* an artboard body (NOT on top of a `[data-cd-id]` element) to
|
|
6
6
|
* lasso multiple stamped elements. Aseprite modifier vocabulary:
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { useEffect, useRef } from 'react';
|
|
24
24
|
|
|
25
|
+
import { scopedCdSelector, selectorIndex } from './dom-selection.ts';
|
|
25
26
|
import { DRAG_THRESHOLD_PX } from './input-router.tsx';
|
|
26
27
|
import { type Selection, useSelectionSet } from './use-selection-set.tsx';
|
|
27
28
|
import { useToolMode } from './use-tool-mode.tsx';
|
|
@@ -103,10 +104,12 @@ function elementToSelection(el: Element, bodyAncestor: Element): Selection | nul
|
|
|
103
104
|
const artboardEl = bodyAncestor.closest('[data-dc-screen]');
|
|
104
105
|
const artboardId = artboardEl?.getAttribute('data-dc-screen') ?? null;
|
|
105
106
|
const rect = (el as HTMLElement).getBoundingClientRect();
|
|
107
|
+
const marqueeSelector = scopedCdSelector(cdId, artboardId);
|
|
106
108
|
return {
|
|
107
109
|
id: cdId,
|
|
108
|
-
selector:
|
|
110
|
+
selector: marqueeSelector,
|
|
109
111
|
artboardId,
|
|
112
|
+
index: selectorIndex(document, marqueeSelector, el),
|
|
110
113
|
tag: el.tagName.toLowerCase(),
|
|
111
114
|
classes: (el.getAttribute('class') ?? '')
|
|
112
115
|
.trim()
|
|
@@ -277,6 +280,6 @@ export function applyMarqueeMode(
|
|
|
277
280
|
selSet.replace(next);
|
|
278
281
|
}
|
|
279
282
|
|
|
283
|
+
export type { Mode };
|
|
280
284
|
// Re-export for tests.
|
|
281
285
|
export { modeOf };
|
|
282
|
-
export type { Mode };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file participants-chrome.tsx — top-right avatar stack of live peers
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/participants-chrome.tsx
|
|
4
4
|
* @purpose Phase 8 Task 6 — show who's currently on the canvas. Colored
|
|
5
5
|
* initials in a circle per peer, with a popover for full name +
|
|
6
6
|
* "Follow" button. Follow mode publishes `followTarget` on my
|
|
@@ -8,10 +8,14 @@
|
|
|
8
8
|
// is the virtual `/$bunfs/root` (bun --compile
|
|
9
9
|
// embedded fs) — NOT a real disk path.
|
|
10
10
|
// Walk up from process.execPath until we find
|
|
11
|
-
// the real
|
|
12
|
-
// 3. Compiled binary, marketplace cache:
|
|
13
|
-
//
|
|
14
|
-
// dev-server
|
|
11
|
+
// the real apps/studio/ dir.
|
|
12
|
+
// 3. Compiled binary, marketplace cache: the marketplace clone ships only the
|
|
13
|
+
// plugin markdown (plugins/design/) — the
|
|
14
|
+
// dev-server ships via npm (package.json files),
|
|
15
|
+
// so the runtime is resolved from the npm
|
|
16
|
+
// package layout, never the marketplace cache.
|
|
17
|
+
// Same walk-up logic anchors on http.ts. See
|
|
18
|
+
// DDR-095 for the apps/studio relocation.
|
|
15
19
|
//
|
|
16
20
|
// Why this matters: Phase 19 v0.18.0 used `dirname(fileURLToPath(import.meta.url))`
|
|
17
21
|
// universally. In the compiled binary that's `/$bunfs/root` — a virtual path —
|
|
@@ -28,7 +32,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
34
|
* Real disk path to the dev-server install dir
|
|
31
|
-
* (`
|
|
35
|
+
* (`apps/studio/` inside whatever package layout we're in).
|
|
32
36
|
*
|
|
33
37
|
* Always a directory that contains `http.ts` + `dist/` + (optionally)
|
|
34
38
|
* `node_modules/` and `client/`. Never a virtual `/$bunfs/*` path.
|
|
@@ -86,16 +90,16 @@ function resolveDevServerRoot(): string {
|
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
// (2 + 3) Compiled binary: walk up from process.execPath until we find a dir
|
|
89
|
-
// that *contains* `
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
+
// that *contains* `apps/studio/<canonical files>`. Match the npm install
|
|
94
|
+
// layout (binary at @1agh/maude-<plat>/maude → walk up to @1agh/maude/, which
|
|
95
|
+
// ships apps/studio/ via package.json files). The dev-server is NOT shipped via
|
|
96
|
+
// the marketplace clone, so there is no marketplace-cache anchor (DDR-095).
|
|
93
97
|
let cur = dirname(process.execPath);
|
|
94
98
|
for (let i = 0; i < 10; i++) {
|
|
95
99
|
// Check if cur itself is the dev-server root.
|
|
96
100
|
if (isDevServerDir(cur)) return cur;
|
|
97
|
-
// Check if cur contains
|
|
98
|
-
const nested = join(cur, '
|
|
101
|
+
// Check if cur contains apps/studio/.
|
|
102
|
+
const nested = join(cur, 'apps', 'studio');
|
|
99
103
|
if (isDevServerDir(nested)) return nested;
|
|
100
104
|
const parent = dirname(cur);
|
|
101
105
|
if (parent === cur) break;
|
|
@@ -28,7 +28,7 @@ import { createHttp } from './http.ts';
|
|
|
28
28
|
import { createInspect } from './inspect.ts';
|
|
29
29
|
import { startHeapWatch } from './mem.ts';
|
|
30
30
|
import { createSyncRuntime } from './sync/index.ts';
|
|
31
|
-
import {
|
|
31
|
+
import { createWs, isLoopbackHost, parseCollabSlug, type WsData } from './ws.ts';
|
|
32
32
|
|
|
33
33
|
// Phase 19 / DDR-044 — covers the marketplace-cache-install gap where
|
|
34
34
|
// node_modules/ ships empty (git clone honors .gitignore). Auto-installs +
|
|
@@ -101,11 +101,20 @@ const { port: BASE_PORT, explicit: PORT_EXPLICIT } = resolvePort();
|
|
|
101
101
|
|
|
102
102
|
type BunServer = ReturnType<typeof Bun.serve<WsData, never>>;
|
|
103
103
|
|
|
104
|
+
// Phase 23 security review (DDR-088 follow-up) — hard ceiling on a buffered
|
|
105
|
+
// request body. Without it Bun's 128 MB default applies, so `POST /_api/asset`
|
|
106
|
+
// would buffer up to 128 MB into RAM BEFORE api.saveAsset's 10 MB check runs
|
|
107
|
+
// (memory amplification from the untrusted canvas origin). 16 MB covers every
|
|
108
|
+
// legit body (10 MB asset + 1 MB annotation SVG + small JSON) with headroom and
|
|
109
|
+
// bounds the pre-handler buffer; the authoritative per-route caps still apply.
|
|
110
|
+
const MAX_REQUEST_BODY = 16 * 1024 * 1024;
|
|
111
|
+
|
|
104
112
|
function startServer(port: number): BunServer {
|
|
105
113
|
return Bun.serve<WsData, never>({
|
|
106
114
|
port,
|
|
107
115
|
hostname: '127.0.0.1',
|
|
108
116
|
development: process.env.NODE_ENV !== 'production',
|
|
117
|
+
maxRequestBodySize: MAX_REQUEST_BODY,
|
|
109
118
|
routes: http.routes,
|
|
110
119
|
async fetch(req, srv) {
|
|
111
120
|
const pathname = new URL(req.url).pathname;
|
|
@@ -167,6 +176,9 @@ function startCanvasServer(port: number): BunServer {
|
|
|
167
176
|
port,
|
|
168
177
|
hostname: '127.0.0.1',
|
|
169
178
|
development: process.env.NODE_ENV !== 'production',
|
|
179
|
+
// DDR-088 follow-up — bound the pre-handler request buffer on the UNTRUSTED
|
|
180
|
+
// canvas origin (the asset upload lives here). See MAX_REQUEST_BODY.
|
|
181
|
+
maxRequestBodySize: MAX_REQUEST_BODY,
|
|
170
182
|
// Hard allowlist of route-table endpoints (Bun matches `routes` before
|
|
171
183
|
// `fetch`). Only the collab/display-data endpoints the canvas runtime needs
|
|
172
184
|
// — see http.isCanvasSafeRoute for the trust rationale. The dynamic
|
|
@@ -176,6 +188,12 @@ function startCanvasServer(port: number): BunServer {
|
|
|
176
188
|
'/_api/git-user': http.routes['/_api/git-user'],
|
|
177
189
|
'/_api/canvas-meta': http.routes['/_api/canvas-meta'],
|
|
178
190
|
'/_api/annotations': http.routes['/_api/annotations'],
|
|
191
|
+
// Phase 23 — capped binary image upload (magic-byte sniff + 10 MB +
|
|
192
|
+
// content-addressed name + traversal guard + no-SVG, in api.saveAsset).
|
|
193
|
+
// Bun matches `routes` BEFORE `fetch`, so the route must be listed here
|
|
194
|
+
// explicitly — the CANVAS_SAFE_API entry alone only opens the fetch
|
|
195
|
+
// fall-through (which serves files, not route handlers). See DDR (Task 9).
|
|
196
|
+
'/_api/asset': http.routes['/_api/asset'],
|
|
179
197
|
'/_api/git-committers': http.routes['/_api/git-committers'],
|
|
180
198
|
'/_api/ai': http.routes['/_api/ai'],
|
|
181
199
|
'/_comments': http.routes['/_comments'],
|
|
@@ -29,15 +29,15 @@ import type { Context } from '../context.ts';
|
|
|
29
29
|
import { type CanvasSyncAgent, createCanvasSyncAgent } from './agent.ts';
|
|
30
30
|
import {
|
|
31
31
|
type ConnectionMonitor,
|
|
32
|
-
type ProviderStatus,
|
|
33
32
|
createConnectionMonitor,
|
|
33
|
+
type ProviderStatus,
|
|
34
34
|
} from './connection-state.ts';
|
|
35
|
-
import { type EchoGuard
|
|
36
|
-
import { type FsReader
|
|
35
|
+
import { createEchoGuard, type EchoGuard } from './echo-guard.ts';
|
|
36
|
+
import { createFsReader, type FsReader } from './fs-mirror.ts';
|
|
37
37
|
import { getHubToken } from './hubs-config.ts';
|
|
38
38
|
import { migrateSeed } from './migrate-seed.ts';
|
|
39
|
-
import { type DocProjection
|
|
40
|
-
import { type SyncStatusStore
|
|
39
|
+
import { createDocProjection, type DocProjection } from './projection.ts';
|
|
40
|
+
import { createSyncStatusStore, type SyncStatusStore } from './status.ts';
|
|
41
41
|
import { writeUntrustedMarkers } from './untrusted.ts';
|
|
42
42
|
|
|
43
43
|
/** A minimum-surface stand-in for the HocuspocusProvider's runtime API. */
|
|
@@ -824,7 +824,7 @@ async function defaultProviderFactory(args: {
|
|
|
824
824
|
mod = await import('@hocuspocus/provider');
|
|
825
825
|
} catch (err) {
|
|
826
826
|
throw new Error(
|
|
827
|
-
`@hocuspocus/provider unavailable — install it under
|
|
827
|
+
`@hocuspocus/provider unavailable — install it under apps/studio/. (${err instanceof Error ? err.message : String(err)})`
|
|
828
828
|
);
|
|
829
829
|
}
|
|
830
830
|
// Hocuspocus accepts ws:// or wss://; the linked URL is http(s)://, so swap
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import type * as Y from 'yjs';
|
|
23
23
|
import { Y_TYPES } from '../collab/persistence.ts';
|
|
24
|
-
import {
|
|
24
|
+
import { annotationsFromDoc, commentsFromDoc, Y_SYNC_TYPES } from './codec.ts';
|
|
25
25
|
|
|
26
26
|
export interface CanonicalMaterialization {
|
|
27
27
|
html: string;
|
|
@@ -59,4 +59,4 @@ export function materializeCanonical(doc: Y.Doc): string {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Re-export so a shadow-compare caller has the type names in one import.
|
|
62
|
-
export {
|
|
62
|
+
export { Y_SYNC_TYPES, Y_TYPES };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { describe, expect, test } from 'bun:test';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { createAiActivity, HEARTBEAT_GRACE_MS } from '../collab/ai-activity.ts';
|
|
6
6
|
import { type Context, createBus } from '../context.ts';
|
|
7
7
|
|
|
8
8
|
function makeCtx(): { ctx: Context; events: { file: string; entry: unknown }[] } {
|
|
@@ -8,11 +8,10 @@
|
|
|
8
8
|
// - PUT rejects oversized bodies (>1 MB)
|
|
9
9
|
// - Unknown method → 405
|
|
10
10
|
|
|
11
|
+
import { describe, expect, test } from 'bun:test';
|
|
11
12
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
13
|
import { join } from 'node:path';
|
|
13
14
|
|
|
14
|
-
import { describe, expect, test } from 'bun:test';
|
|
15
|
-
|
|
16
15
|
import { bootServer, killProc, makeSandbox, nextPort } from './_helpers.ts';
|
|
17
16
|
|
|
18
17
|
const SVG_OK =
|
|
@@ -11,23 +11,25 @@ import { describe, expect, test } from 'bun:test';
|
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
type ArrowStroke,
|
|
14
|
+
arrowHeadPoints,
|
|
14
15
|
type EllipseStroke,
|
|
16
|
+
type ImageStroke,
|
|
17
|
+
type LinkStroke,
|
|
15
18
|
type PenStroke,
|
|
16
19
|
type PolygonStroke,
|
|
17
|
-
type RectStroke,
|
|
18
|
-
STICKY_PALETTE,
|
|
19
|
-
type StickyStroke,
|
|
20
|
-
type Stroke,
|
|
21
|
-
type TextStroke,
|
|
22
|
-
arrowHeadPoints,
|
|
23
20
|
penPathD,
|
|
24
21
|
polygonPoints,
|
|
25
22
|
polygonVertices,
|
|
23
|
+
type RectStroke,
|
|
26
24
|
rid,
|
|
25
|
+
STICKY_PALETTE,
|
|
26
|
+
type StickyStroke,
|
|
27
|
+
type Stroke,
|
|
27
28
|
strokeBBox,
|
|
28
29
|
strokeHitTest,
|
|
29
30
|
strokesShallowEqual,
|
|
30
31
|
strokesToSvg,
|
|
32
|
+
type TextStroke,
|
|
31
33
|
} from '../annotations-layer.tsx';
|
|
32
34
|
|
|
33
35
|
describe('annotations-layer / penPathD', () => {
|
|
@@ -696,6 +698,67 @@ describe('annotations-layer / Phase 21 sticky + standalone-text geometry', () =>
|
|
|
696
698
|
});
|
|
697
699
|
});
|
|
698
700
|
|
|
701
|
+
describe('annotations-layer / Phase 23 image + link geometry', () => {
|
|
702
|
+
const image: ImageStroke = {
|
|
703
|
+
id: 'im',
|
|
704
|
+
tool: 'image',
|
|
705
|
+
x: 30,
|
|
706
|
+
y: 40,
|
|
707
|
+
w: 200,
|
|
708
|
+
h: 150,
|
|
709
|
+
href: 'assets/deadbeef.png',
|
|
710
|
+
};
|
|
711
|
+
const link: LinkStroke = {
|
|
712
|
+
id: 'lk',
|
|
713
|
+
tool: 'link',
|
|
714
|
+
x: 30,
|
|
715
|
+
y: 40,
|
|
716
|
+
w: 260,
|
|
717
|
+
h: 76,
|
|
718
|
+
url: 'https://example.com',
|
|
719
|
+
title: 'Example',
|
|
720
|
+
domain: 'example.com',
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
test('image bbox is its rect extent (normalizes negative extent)', () => {
|
|
724
|
+
expect(strokeBBox(image)).toEqual({ x: 30, y: 40, w: 200, h: 150 });
|
|
725
|
+
expect(strokeBBox({ ...image, x: 230, y: 190, w: -200, h: -150 })).toEqual({
|
|
726
|
+
x: 30,
|
|
727
|
+
y: 40,
|
|
728
|
+
w: 200,
|
|
729
|
+
h: 150,
|
|
730
|
+
});
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
test('link bbox is its card extent', () => {
|
|
734
|
+
expect(strokeBBox(link)).toEqual({ x: 30, y: 40, w: 260, h: 76 });
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
test('image + link are filled-card hits anywhere inside', () => {
|
|
738
|
+
expect(strokeHitTest(image, 100, 100, 4)).toBe(true); // interior
|
|
739
|
+
expect(strokeHitTest(image, 30, 40, 4)).toBe(true); // corner
|
|
740
|
+
expect(strokeHitTest(image, 999, 999, 4)).toBe(false); // far outside
|
|
741
|
+
expect(strokeHitTest(link, 100, 60, 4)).toBe(true);
|
|
742
|
+
expect(strokeHitTest(link, 999, 999, 4)).toBe(false);
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
test('image serializes a same-origin <image> with preserveAspectRatio', () => {
|
|
746
|
+
const svg = strokesToSvg([image]);
|
|
747
|
+
expect(svg).toContain('<image');
|
|
748
|
+
expect(svg).toContain('data-tool="image"');
|
|
749
|
+
expect(svg).toContain('preserveAspectRatio="xMidYMid meet"');
|
|
750
|
+
expect(svg).toContain('href="assets/deadbeef.png"');
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
test('link serializes a card <g> carrying its data-* payload', () => {
|
|
754
|
+
const svg = strokesToSvg([link]);
|
|
755
|
+
expect(svg).toContain('data-tool="link"');
|
|
756
|
+
expect(svg).toContain('data-url="https://example.com"');
|
|
757
|
+
expect(svg).toContain('data-domain="example.com"');
|
|
758
|
+
expect(svg).toContain('<rect');
|
|
759
|
+
});
|
|
760
|
+
});
|
|
761
|
+
|
|
699
762
|
describe('annotations-layer / Phase 24 polygon geometry', () => {
|
|
700
763
|
test('polygonVertices span the full bbox for every shape', () => {
|
|
701
764
|
for (const shape of ['diamond', 'triangle', 'triangle-down'] as const) {
|