@1agh/maude 1.0.11 → 1.2.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/apps/studio/acp/bridge.ts +18 -13
- package/apps/studio/acp/transcript-io.ts +394 -0
- package/apps/studio/acp/transcript.ts +103 -38
- package/apps/studio/api.ts +139 -26
- package/apps/studio/bin/_import-figma.mjs +57 -11
- package/apps/studio/bin/_seed-fixture.mjs +163 -0
- package/apps/studio/canvas-imports.ts +89 -0
- package/apps/studio/client/app.jsx +257 -7
- package/apps/studio/client/export-center.jsx +15 -7
- package/apps/studio/client/panels/SyncPanel.jsx +125 -4
- package/apps/studio/client/report-bug.jsx +19 -1
- package/apps/studio/client/styles/3-shell-maude.css +34 -0
- package/apps/studio/client/styles/4-components.css +26 -0
- package/apps/studio/collab/persistence.ts +132 -16
- package/apps/studio/collab/registry.ts +10 -18
- package/apps/studio/debug-bundle.ts +13 -0
- package/apps/studio/dist/client.bundle.js +1128 -1128
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/export-dialog.tsx +54 -0
- package/apps/studio/exporters/degraded.ts +19 -3
- package/apps/studio/exporters/ghostscript.ts +194 -0
- package/apps/studio/exporters/pdf-fonts.ts +261 -0
- package/apps/studio/exporters/pdf.ts +152 -3
- package/apps/studio/exporters/remote.ts +36 -1
- package/apps/studio/fs-watch.ts +45 -1
- package/apps/studio/http.ts +7 -1
- package/apps/studio/mem.ts +45 -9
- package/apps/studio/server.ts +11 -4
- package/apps/studio/sync/agent.ts +136 -29
- package/apps/studio/sync/asset-push.ts +1 -47
- package/apps/studio/sync/codec.ts +122 -31
- package/apps/studio/sync/cold-start-apply.ts +7 -0
- package/apps/studio/sync/cold-start.ts +118 -22
- package/apps/studio/sync/comment-identity.ts +68 -0
- package/apps/studio/sync/connection-state.ts +15 -1
- package/apps/studio/sync/file-ledger.ts +117 -0
- package/apps/studio/sync/file-plane.ts +623 -27
- package/apps/studio/sync/index.ts +711 -20
- package/apps/studio/sync/journal-client.ts +13 -1
- package/apps/studio/sync/migrate-seed.ts +40 -3
- package/apps/studio/sync/presentation.ts +26 -3
- package/apps/studio/sync/retry-after.ts +169 -0
- package/apps/studio/sync/seed-progress.ts +218 -0
- package/apps/studio/sync/status.ts +122 -5
- package/apps/studio/sync/transport-error.ts +111 -0
- package/apps/studio/whats-new.json +72 -0
- package/cli/bin/maude.mjs +2 -0
- package/cli/commands/codex.mjs +191 -0
- package/cli/commands/harness.mjs +1051 -0
- package/cli/commands/help.mjs +13 -0
- package/cli/lib/design-link.mjs +190 -2
- package/cli/lib/harness/capabilities.mjs +302 -0
- package/cli/lib/harness/codex-runtime.mjs +889 -0
- package/cli/lib/harness/compatibility.mjs +27 -0
- package/cli/lib/harness/discover-claude.mjs +1393 -0
- package/cli/lib/harness/managed-state.mjs +1296 -0
- package/cli/lib/harness/model.mjs +86 -0
- package/cli/lib/harness/secrets.mjs +390 -0
- package/cli/lib/harness/targets/codex.mjs +1141 -0
- package/cli/lib/harness/targets/opencode.mjs +807 -0
- package/cli/lib/harness/transaction.mjs +1099 -0
- package/cli/lib/hubs-config.mjs +35 -8
- package/cli/templates/harness/opencode/maude-projector.ts +58 -0
- package/docs/harness-capability-matrix.md +125 -0
- package/docs/harness-environment-projection.md +95 -0
- package/package.json +32 -9
- package/plugins/flow/.claude-plugin/config.schema.json +8 -0
- package/apps/studio/.ai/cache/_stats.json +0 -7
- package/apps/studio/bin/_agent-browser-safe.test.mjs +0 -165
- package/apps/studio/bin/_curl-local.test.mjs +0 -280
- package/apps/studio/bin/_pw-launch.test.mjs +0 -90
- package/apps/studio/bin/_smart-frames.test.mjs +0 -195
- package/apps/studio/bin/_transcribe.test.mjs +0 -80
- package/apps/studio/bun.lock +0 -928
- package/apps/studio/draw/test/animate.test.ts +0 -172
- package/apps/studio/draw/test/brush.test.ts +0 -213
- package/apps/studio/draw/test/composition.test.ts +0 -141
- package/apps/studio/draw/test/geometry.test.ts +0 -199
- package/apps/studio/draw/test/gradient.test.ts +0 -167
- package/apps/studio/draw/test/layout.test.ts +0 -120
- package/apps/studio/draw/test/morph.test.ts +0 -107
- package/apps/studio/draw/test/optimize.test.ts +0 -40
- package/apps/studio/draw/test/palette.test.ts +0 -123
- package/apps/studio/draw/test/primitives.test.ts +0 -129
- package/apps/studio/draw/test/serialize-animate.test.ts +0 -142
- package/apps/studio/draw/test/serialize.test.ts +0 -105
- package/apps/studio/figma/assets.test.ts +0 -464
- package/apps/studio/figma/client.test.ts +0 -395
- package/apps/studio/figma/codegen-client.test.ts +0 -276
- package/apps/studio/figma/codegen-fonts.test.ts +0 -103
- package/apps/studio/figma/codegen-values.test.ts +0 -179
- package/apps/studio/figma/comments-to-strokes.test.ts +0 -194
- package/apps/studio/figma/fig-decode.test.ts +0 -788
- package/apps/studio/figma/fig-differential.test.ts +0 -182
- package/apps/studio/figma/fig-translator.test.ts +0 -192
- package/apps/studio/figma/fig-vector.test.ts +0 -113
- package/apps/studio/figma/from-codegen.test.ts +0 -408
- package/apps/studio/figma/sanitize.test.ts +0 -325
- package/apps/studio/figma/tailwind-map.test.ts +0 -142
- package/apps/studio/figma/to-artboard.test.ts +0 -808
- package/apps/studio/figma/to-render.test.ts +0 -180
- package/apps/studio/figma/to-strokes-roundtrip.test.ts +0 -152
- package/apps/studio/figma/to-strokes.test.ts +0 -705
- package/apps/studio/figma/to-tokens.test.ts +0 -321
- package/apps/studio/figma/url.test.ts +0 -167
- package/apps/studio/footage/schema.test.ts +0 -287
- package/apps/studio/generation/adapters/groq.test.ts +0 -80
- package/apps/studio/generation/audio-library.test.ts +0 -95
- package/apps/studio/generation/captions.test.ts +0 -78
- package/apps/studio/generation/elevenlabs.test.ts +0 -223
- package/apps/studio/generation/gemini.test.ts +0 -350
- package/apps/studio/generation/jobs.test.ts +0 -128
- package/apps/studio/generation/keys.test.ts +0 -75
- package/apps/studio/generation/prefs.test.ts +0 -95
- package/apps/studio/generation/types.test.ts +0 -123
- package/apps/studio/generation/whisper-models.test.ts +0 -179
- package/apps/studio/test/_helpers.ts +0 -108
- package/apps/studio/test/acp-activity-endpoint.test.ts +0 -183
- package/apps/studio/test/acp-activity.test.ts +0 -154
- package/apps/studio/test/acp-ai-activity.test.ts +0 -182
- package/apps/studio/test/acp-attachment-serve.test.ts +0 -74
- package/apps/studio/test/acp-bootstrap-brief.test.ts +0 -178
- package/apps/studio/test/acp-branch-guard.test.ts +0 -123
- package/apps/studio/test/acp-bridge-lifetime.test.ts +0 -475
- package/apps/studio/test/acp-bridge.test.ts +0 -545
- package/apps/studio/test/acp-capabilities.test.ts +0 -123
- package/apps/studio/test/acp-caps-bridge.test.ts +0 -279
- package/apps/studio/test/acp-commands.test.ts +0 -119
- package/apps/studio/test/acp-elicitation-bridge.test.ts +0 -480
- package/apps/studio/test/acp-elicitation.test.ts +0 -251
- package/apps/studio/test/acp-env.test.ts +0 -95
- package/apps/studio/test/acp-mode-banner.test.ts +0 -45
- package/apps/studio/test/acp-origin-gate.test.ts +0 -160
- package/apps/studio/test/acp-permission-prompt.test.ts +0 -251
- package/apps/studio/test/acp-permission.test.ts +0 -278
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +0 -89
- package/apps/studio/test/acp-session-allowed-tools.test.ts +0 -235
- package/apps/studio/test/acp-session-plugins.test.ts +0 -209
- package/apps/studio/test/acp-toolgroup.test.ts +0 -76
- package/apps/studio/test/acp-transcript-view.test.ts +0 -71
- package/apps/studio/test/acp-transcript.test.ts +0 -238
- package/apps/studio/test/acp-usage-bridge.test.ts +0 -141
- package/apps/studio/test/acp-usage.test.ts +0 -143
- package/apps/studio/test/acp-write-gate.test.ts +0 -323
- package/apps/studio/test/acp-write-scope.test.ts +0 -533
- package/apps/studio/test/active-state.test.ts +0 -186
- package/apps/studio/test/activity.test.ts +0 -189
- package/apps/studio/test/ai-activity.test.ts +0 -113
- package/apps/studio/test/annotate-write.test.ts +0 -1074
- package/apps/studio/test/annotation-strokes-command.test.ts +0 -166
- package/apps/studio/test/annotations-align.test.ts +0 -88
- package/apps/studio/test/annotations-api.test.ts +0 -145
- package/apps/studio/test/annotations-bindings.test.ts +0 -262
- package/apps/studio/test/annotations-draw-modifiers.test.ts +0 -206
- package/apps/studio/test/annotations-groups.test.ts +0 -231
- package/apps/studio/test/annotations-layer.test.ts +0 -1011
- package/apps/studio/test/annotations-roundtrip.test.ts +0 -663
- package/apps/studio/test/annotations-snap.test.ts +0 -135
- package/apps/studio/test/annotations-text-format.test.ts +0 -396
- package/apps/studio/test/artboard-activity-overlay.test.tsx +0 -56
- package/apps/studio/test/artboard-guides-overlay.test.tsx +0 -152
- package/apps/studio/test/artboard-hug-commit.test.ts +0 -36
- package/apps/studio/test/artboard-kinds.test.tsx +0 -83
- package/apps/studio/test/artboard-selection-attrs.test.ts +0 -69
- package/apps/studio/test/asset-api.test.ts +0 -149
- package/apps/studio/test/assets-s3.test.ts +0 -249
- package/apps/studio/test/binary-smoke.test.ts +0 -47
- package/apps/studio/test/boot-self-heal.test.ts +0 -87
- package/apps/studio/test/browse-posture.test.tsx +0 -107
- package/apps/studio/test/bundle-smoke.test.ts +0 -46
- package/apps/studio/test/camera-reveal.test.tsx +0 -173
- package/apps/studio/test/canvas-artifacts.test.ts +0 -125
- package/apps/studio/test/canvas-build-sandbox.test.ts +0 -69
- package/apps/studio/test/canvas-build.test.ts +0 -141
- package/apps/studio/test/canvas-create-api.test.ts +0 -676
- package/apps/studio/test/canvas-cursors.test.ts +0 -164
- package/apps/studio/test/canvas-edit.test.ts +0 -470
- package/apps/studio/test/canvas-freshness-deps.test.ts +0 -64
- package/apps/studio/test/canvas-header.test.ts +0 -127
- package/apps/studio/test/canvas-hide-chrome.test.ts +0 -88
- package/apps/studio/test/canvas-hmr-runtime.test.tsx +0 -114
- package/apps/studio/test/canvas-lib-inline.test.ts +0 -146
- package/apps/studio/test/canvas-lib-motion.test.ts +0 -131
- package/apps/studio/test/canvas-lib-resolver.test.ts +0 -111
- package/apps/studio/test/canvas-list-watch.test.ts +0 -388
- package/apps/studio/test/canvas-media-drop.test.ts +0 -187
- package/apps/studio/test/canvas-meta-api.test.ts +0 -707
- package/apps/studio/test/canvas-move-api.test.ts +0 -587
- package/apps/studio/test/canvas-origin-gate.test.ts +0 -417
- package/apps/studio/test/canvas-pipeline.test.ts +0 -180
- package/apps/studio/test/canvas-rects.test.ts +0 -198
- package/apps/studio/test/canvas-reorder.test.ts +0 -211
- package/apps/studio/test/canvas-route.test.ts +0 -179
- package/apps/studio/test/canvas-shell-base.test.ts +0 -107
- package/apps/studio/test/canvas-shell-build-error.test.ts +0 -52
- package/apps/studio/test/canvas-url.test.ts +0 -138
- package/apps/studio/test/canvas-wheel-delta.test.ts +0 -42
- package/apps/studio/test/canvas-zoom-floor.test.ts +0 -73
- package/apps/studio/test/capture-core.test.ts +0 -32
- package/apps/studio/test/capture-determinism-shape.test.ts +0 -135
- package/apps/studio/test/chat-attachments.test.ts +0 -117
- package/apps/studio/test/chat-context.test.ts +0 -129
- package/apps/studio/test/chat-markdown.test.tsx +0 -58
- package/apps/studio/test/clip-addressing.test.ts +0 -738
- package/apps/studio/test/clip-ops.test.ts +0 -922
- package/apps/studio/test/cloud-build.test.ts +0 -95
- package/apps/studio/test/cloud-connect-note.test.ts +0 -135
- package/apps/studio/test/cloud-endpoints.test.ts +0 -590
- package/apps/studio/test/cloud-history-hardening.test.ts +0 -165
- package/apps/studio/test/cloud-history-posture.test.ts +0 -230
- package/apps/studio/test/cloud-managed-save-surfaces.test.ts +0 -90
- package/apps/studio/test/cloud-renew.test.ts +0 -205
- package/apps/studio/test/cloud-session-role.test.ts +0 -161
- package/apps/studio/test/cloud-shell-surfaces.test.ts +0 -170
- package/apps/studio/test/cold-start-apply.test.ts +0 -303
- package/apps/studio/test/collab-annotations-bridge.test.ts +0 -55
- package/apps/studio/test/collab-awareness-bridge.test.ts +0 -223
- package/apps/studio/test/collab-bridge.test.ts +0 -79
- package/apps/studio/test/collab-loopback.test.ts +0 -63
- package/apps/studio/test/collab-origin-gate.test.ts +0 -323
- package/apps/studio/test/collab-protocol.test.ts +0 -146
- package/apps/studio/test/collab-readonly-gate.test.ts +0 -194
- package/apps/studio/test/collab-reseed-guard.test.ts +0 -78
- package/apps/studio/test/collab-room.test.ts +0 -188
- package/apps/studio/test/collab-session-survival.test.tsx +0 -176
- package/apps/studio/test/collab-stress.test.ts +0 -129
- package/apps/studio/test/comment-mount.test.ts +0 -97
- package/apps/studio/test/comment-relay-origin-gate.test.ts +0 -117
- package/apps/studio/test/comments-api.test.ts +0 -277
- package/apps/studio/test/comments-fs-rebroadcast.test.ts +0 -155
- package/apps/studio/test/comments-overlay.test.ts +0 -117
- package/apps/studio/test/compile-entry.test.ts +0 -133
- package/apps/studio/test/component-map.test.ts +0 -48
- package/apps/studio/test/config-projection.test.ts +0 -104
- package/apps/studio/test/config-reload.test.ts +0 -230
- package/apps/studio/test/config-version.test.ts +0 -88
- package/apps/studio/test/context-resolve-tokens.test.ts +0 -97
- package/apps/studio/test/convert-to-absolute.test.ts +0 -333
- package/apps/studio/test/credential-grammar.test.ts +0 -107
- package/apps/studio/test/csp-canvas-shell.test.ts +0 -62
- package/apps/studio/test/csrf-write-guard.test.ts +0 -141
- package/apps/studio/test/debug-bundle.test.ts +0 -105
- package/apps/studio/test/design-setup-readiness.test.ts +0 -155
- package/apps/studio/test/detach-component.test.ts +0 -94
- package/apps/studio/test/dns-rebinding-guard.test.ts +0 -101
- package/apps/studio/test/dom-selection.test.ts +0 -198
- package/apps/studio/test/dynamic-text-edit.test.ts +0 -162
- package/apps/studio/test/edit-css-occurrence.test.ts +0 -81
- package/apps/studio/test/edit-persistence.test.ts +0 -91
- package/apps/studio/test/edit-scope-api.test.ts +0 -119
- package/apps/studio/test/edit-source-command.test.ts +0 -142
- package/apps/studio/test/edit-suppress.test.ts +0 -170
- package/apps/studio/test/editing-presence.test.ts +0 -103
- package/apps/studio/test/element-resize.test.ts +0 -136
- package/apps/studio/test/element-structural-api.test.ts +0 -434
- package/apps/studio/test/element-structural-edit.test.ts +0 -750
- package/apps/studio/test/ensure-browser.test.ts +0 -92
- package/apps/studio/test/equal-spacing-detector.test.ts +0 -257
- package/apps/studio/test/export-assemble.test.ts +0 -53
- package/apps/studio/test/export-browser-lane.test.ts +0 -126
- package/apps/studio/test/export-capture-fidelity.test.ts +0 -146
- package/apps/studio/test/export-capture-hygiene.test.ts +0 -675
- package/apps/studio/test/export-center.test.tsx +0 -287
- package/apps/studio/test/export-e2e-lanes.test.ts +0 -857
- package/apps/studio/test/export-format-scope-coherence.test.ts +0 -89
- package/apps/studio/test/export-lane.test.ts +0 -245
- package/apps/studio/test/export-shim-multi-capture.test.ts +0 -83
- package/apps/studio/test/exporters/canva.test.ts +0 -63
- package/apps/studio/test/exporters/degraded-propagation.test.ts +0 -123
- package/apps/studio/test/exporters/endpoint.test.ts +0 -121
- package/apps/studio/test/exporters/history.test.ts +0 -107
- package/apps/studio/test/exporters/html.test.ts +0 -26
- package/apps/studio/test/exporters/jobs.test.ts +0 -342
- package/apps/studio/test/exporters/pdf.test.ts +0 -85
- package/apps/studio/test/exporters/png.test.ts +0 -103
- package/apps/studio/test/exporters/pptx-deck.test.ts +0 -112
- package/apps/studio/test/exporters/pptx.test.ts +0 -31
- package/apps/studio/test/exporters/pw-launch.test.ts +0 -49
- package/apps/studio/test/exporters/runtime.test.ts +0 -59
- package/apps/studio/test/exporters/scope.test.ts +0 -292
- package/apps/studio/test/exporters/svg.test.ts +0 -29
- package/apps/studio/test/exporters/unsupported-media.test.ts +0 -123
- package/apps/studio/test/exporters/zip.test.ts +0 -104
- package/apps/studio/test/fetch-asset-gate.test.ts +0 -189
- package/apps/studio/test/figjam-v3-model.test.ts +0 -342
- package/apps/studio/test/figma-explode.test.ts +0 -438
- package/apps/studio/test/figma-provenance.test.ts +0 -108
- package/apps/studio/test/figma-routes.test.ts +0 -294
- package/apps/studio/test/file-lock.test.ts +0 -84
- package/apps/studio/test/fixtures/backgrounding-claude-auth.sh +0 -12
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +0 -23
- package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +0 -1
- package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +0 -158
- package/apps/studio/test/fixtures/mock-acp-agent-commands.mjs +0 -44
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +0 -46
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +0 -42
- package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +0 -63
- package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +0 -51
- package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +0 -50
- package/apps/studio/test/fixtures/mock-acp-agent-slow.mjs +0 -45
- package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +0 -56
- package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +0 -37
- package/apps/studio/test/fixtures/mock-acp-agent-write.mjs +0 -118
- package/apps/studio/test/fixtures/mock-acp-agent.mjs +0 -69
- package/apps/studio/test/fixtures/noisy-claude-auth.mjs +0 -27
- package/apps/studio/test/fixtures/perf-canvas.mjs +0 -201
- package/apps/studio/test/fixtures/phase-20-annotations.svg +0 -1
- package/apps/studio/test/fixtures/phase-21-annotations.svg +0 -1
- package/apps/studio/test/fixtures/tiny-subset.woff2 +0 -0
- package/apps/studio/test/fixtures/video-comp-fixture.tsx +0 -82
- package/apps/studio/test/fixtures/wedged-claude-auth.sh +0 -11
- package/apps/studio/test/footage-store.test.ts +0 -100
- package/apps/studio/test/fs-mkdir-api.test.ts +0 -248
- package/apps/studio/test/fs-watch.test.ts +0 -41
- package/apps/studio/test/gemma-models.test.ts +0 -245
- package/apps/studio/test/generate-route.test.ts +0 -106
- package/apps/studio/test/git-api.test.ts +0 -0
- package/apps/studio/test/git-branches.test.ts +0 -341
- package/apps/studio/test/git-cloud-posture.test.ts +0 -59
- package/apps/studio/test/git-grouping.test.ts +0 -106
- package/apps/studio/test/git-lifecycle.test.ts +0 -100
- package/apps/studio/test/git-log-format.test.ts +0 -95
- package/apps/studio/test/git-safe-rel.test.ts +0 -132
- package/apps/studio/test/git-system-engine.test.ts +0 -135
- package/apps/studio/test/git-watch.test.ts +0 -97
- package/apps/studio/test/github-api.test.ts +0 -577
- package/apps/studio/test/grid-track-handles.test.ts +0 -160
- package/apps/studio/test/handoff-static-frames.test.ts +0 -215
- package/apps/studio/test/handoff.test.ts +0 -329
- package/apps/studio/test/history-rollback.test.ts +0 -88
- package/apps/studio/test/hmr-broadcast.test.ts +0 -236
- package/apps/studio/test/hmr-classify.test.ts +0 -87
- package/apps/studio/test/hub-link.test.ts +0 -80
- package/apps/studio/test/identity-cache.test.ts +0 -83
- package/apps/studio/test/import-asset-browser.test.ts +0 -64
- package/apps/studio/test/import-asset-route.test.ts +0 -71
- package/apps/studio/test/import-asset.test.ts +0 -427
- package/apps/studio/test/import-brand-browser.test.ts +0 -88
- package/apps/studio/test/import-brand-route.test.ts +0 -120
- package/apps/studio/test/import-brand.test.ts +0 -206
- package/apps/studio/test/import-figma.test.ts +0 -667
- package/apps/studio/test/import-tokens.test.ts +0 -722
- package/apps/studio/test/index-data-canvas-ds.test.ts +0 -97
- package/apps/studio/test/input-router.test.ts +0 -757
- package/apps/studio/test/inspect-script-syntax.test.ts +0 -53
- package/apps/studio/test/inspect-selections.test.ts +0 -219
- package/apps/studio/test/knob-props-authored.test.ts +0 -87
- package/apps/studio/test/layers-synthetic-groups.test.ts +0 -96
- package/apps/studio/test/locator.test.ts +0 -214
- package/apps/studio/test/marquee-overlay.test.ts +0 -94
- package/apps/studio/test/media-commit-chain.test.ts +0 -210
- package/apps/studio/test/mode-toggle.test.tsx +0 -226
- package/apps/studio/test/motion-sample.test.ts +0 -35
- package/apps/studio/test/move-artboards-command.test.ts +0 -108
- package/apps/studio/test/participants-chrome.test.ts +0 -65
- package/apps/studio/test/paths.test.ts +0 -88
- package/apps/studio/test/pdf-print-boxes.test.ts +0 -359
- package/apps/studio/test/peer-selection-follows-camera.test.tsx +0 -131
- package/apps/studio/test/perf-harness.ts +0 -193
- package/apps/studio/test/phase-3.6-smoke.test.ts +0 -79
- package/apps/studio/test/photo-bg-remove-validation.test.ts +0 -71
- package/apps/studio/test/photo-canvas-bundle.test.ts +0 -79
- package/apps/studio/test/photo-edit-api.test.ts +0 -201
- package/apps/studio/test/photo-filters.test.ts +0 -149
- package/apps/studio/test/photo-pipeline.test.ts +0 -106
- package/apps/studio/test/photo-taxonomy.test.ts +0 -96
- package/apps/studio/test/print-marks.test.ts +0 -113
- package/apps/studio/test/print-units.test.ts +0 -173
- package/apps/studio/test/read-annotations.test.ts +0 -727
- package/apps/studio/test/read-only-gate.test.ts +0 -188
- package/apps/studio/test/read-only-role.test.ts +0 -95
- package/apps/studio/test/readiness.test.ts +0 -337
- package/apps/studio/test/remote-ahead-behind-cache.test.ts +0 -89
- package/apps/studio/test/reorder-api.test.ts +0 -210
- package/apps/studio/test/repo-concurrency.test.ts +0 -146
- package/apps/studio/test/repo-lock.test.ts +0 -350
- package/apps/studio/test/report-proxy.test.ts +0 -125
- package/apps/studio/test/ripple.test.ts +0 -197
- package/apps/studio/test/runtime-bundle-error-mapping.test.ts +0 -43
- package/apps/studio/test/runtime-bundle.test.ts +0 -69
- package/apps/studio/test/sanitize-annotation-svg.test.ts +0 -238
- package/apps/studio/test/scaffold-design.test.ts +0 -122
- package/apps/studio/test/server-lifecycle.test.ts +0 -38
- package/apps/studio/test/session-runtime-state.test.ts +0 -226
- package/apps/studio/test/session-scope.test.ts +0 -100
- package/apps/studio/test/shared-doc-cell-pairing.test.ts +0 -642
- package/apps/studio/test/shared-doc-convergence.test.ts +0 -265
- package/apps/studio/test/shared-doc-foundation.test.ts +0 -63
- package/apps/studio/test/shared-doc-migrate.test.ts +0 -369
- package/apps/studio/test/shared-doc-projection.test.ts +0 -238
- package/apps/studio/test/shell-importmap.test.ts +0 -56
- package/apps/studio/test/sizing-mode.test.ts +0 -102
- package/apps/studio/test/slash-commands.test.ts +0 -117
- package/apps/studio/test/snap-distance-pill.test.ts +0 -68
- package/apps/studio/test/spacing-handles.test.ts +0 -138
- package/apps/studio/test/specimen-select.test.ts +0 -88
- package/apps/studio/test/sync-agent.test.ts +0 -660
- package/apps/studio/test/sync-annotations-cold-start.test.ts +0 -302
- package/apps/studio/test/sync-asset-push.test.ts +0 -931
- package/apps/studio/test/sync-atomic-write.test.ts +0 -62
- package/apps/studio/test/sync-attach-incremental.test.ts +0 -527
- package/apps/studio/test/sync-autocommit.test.ts +0 -537
- package/apps/studio/test/sync-canvas-path.test.ts +0 -200
- package/apps/studio/test/sync-cell-write-nudge.test.ts +0 -346
- package/apps/studio/test/sync-codec.test.ts +0 -230
- package/apps/studio/test/sync-cold-seed-dedup.test.ts +0 -187
- package/apps/studio/test/sync-cold-start.test.ts +0 -304
- package/apps/studio/test/sync-connect-honesty.test.ts +0 -114
- package/apps/studio/test/sync-connection-state.test.ts +0 -337
- package/apps/studio/test/sync-ctl-channel.test.ts +0 -508
- package/apps/studio/test/sync-decide-file.test.ts +0 -420
- package/apps/studio/test/sync-doc-name.test.ts +0 -281
- package/apps/studio/test/sync-echo-guard.test.ts +0 -96
- package/apps/studio/test/sync-file-ledger.test.ts +0 -334
- package/apps/studio/test/sync-file-membership.test.ts +0 -347
- package/apps/studio/test/sync-file-plane.test.ts +0 -976
- package/apps/studio/test/sync-file-pull.test.ts +0 -333
- package/apps/studio/test/sync-fresh-link-parity.test.ts +0 -267
- package/apps/studio/test/sync-fs-mirror.test.ts +0 -181
- package/apps/studio/test/sync-hardening.test.ts +0 -586
- package/apps/studio/test/sync-hub-listing.test.ts +0 -46
- package/apps/studio/test/sync-hubs-config.test.ts +0 -133
- package/apps/studio/test/sync-incident-replay.test.ts +0 -211
- package/apps/studio/test/sync-journal.test.ts +0 -176
- package/apps/studio/test/sync-meta-codec.test.ts +0 -199
- package/apps/studio/test/sync-migrate-flat-fallback.test.ts +0 -98
- package/apps/studio/test/sync-move-retirement.test.ts +0 -231
- package/apps/studio/test/sync-panel-surface.test.ts +0 -153
- package/apps/studio/test/sync-path-pull.test.ts +0 -531
- package/apps/studio/test/sync-presentation.test.ts +0 -262
- package/apps/studio/test/sync-pull-budget.test.ts +0 -169
- package/apps/studio/test/sync-remote-docs.test.ts +0 -333
- package/apps/studio/test/sync-resync-routes.test.ts +0 -168
- package/apps/studio/test/sync-runtime.test.ts +0 -1675
- package/apps/studio/test/sync-seed-defers-to-hub.test.ts +0 -83
- package/apps/studio/test/sync-settings-routes.test.ts +0 -195
- package/apps/studio/test/sync-settings.test.ts +0 -151
- package/apps/studio/test/sync-status.test.ts +0 -261
- package/apps/studio/test/sync-supervisor.test.ts +0 -262
- package/apps/studio/test/sync-tombstone-apply.test.ts +0 -111
- package/apps/studio/test/sync-trash.test.ts +0 -132
- package/apps/studio/test/sync-two-peer-discovery.test.ts +0 -343
- package/apps/studio/test/sync-untrusted.test.ts +0 -103
- package/apps/studio/test/system-endpoint.test.ts +0 -144
- package/apps/studio/test/text-editability-stamp.test.ts +0 -131
- package/apps/studio/test/timeline-comp-target.test.ts +0 -139
- package/apps/studio/test/timeline-media-cache.test.ts +0 -41
- package/apps/studio/test/timeline-parse.test.ts +0 -184
- package/apps/studio/test/timeline-scale.test.ts +0 -65
- package/apps/studio/test/timeline-snap.test.ts +0 -85
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +0 -86
- package/apps/studio/test/tool-palette.test.tsx +0 -55
- package/apps/studio/test/tour-overlay.test.tsx +0 -90
- package/apps/studio/test/trusted-request-host.test.ts +0 -66
- package/apps/studio/test/undo-sequence-byte-compare.test.ts +0 -211
- package/apps/studio/test/undo-stack.test.ts +0 -244
- package/apps/studio/test/use-agent-presence.test.tsx +0 -117
- package/apps/studio/test/use-annotation-resize.test.ts +0 -402
- package/apps/studio/test/use-annotation-selection.test.tsx +0 -77
- package/apps/studio/test/use-artboard-drag.test.ts +0 -324
- package/apps/studio/test/use-canvas-activity.test.tsx +0 -206
- package/apps/studio/test/use-collab.test.ts +0 -0
- package/apps/studio/test/use-cursor-modifiers.test.ts +0 -59
- package/apps/studio/test/use-keyboard-discipline.test.ts +0 -27
- package/apps/studio/test/use-selection-set.test.tsx +0 -166
- package/apps/studio/test/use-snap-guides.test.ts +0 -271
- package/apps/studio/test/use-tool-mode.test.tsx +0 -186
- package/apps/studio/test/use-undo-stack.test.tsx +0 -223
- package/apps/studio/test/video-asset.test.ts +0 -163
- package/apps/studio/test/video-comp-fixture.test.ts +0 -50
- package/apps/studio/test/video-comp.test.ts +0 -270
- package/apps/studio/test/video-encode-lib.test.ts +0 -63
- package/apps/studio/test/video-render-bridge.test.ts +0 -171
- package/apps/studio/test/whats-new.test.ts +0 -113
- package/apps/studio/test/whisper-setup.test.ts +0 -97
- package/apps/studio/test/workspace-containment.test.ts +0 -382
- package/apps/studio/test/workspace-signin.test.ts +0 -292
- package/apps/studio/test/ws-handshake.test.ts +0 -33
- package/cli/commands/cache.test.mjs +0 -166
- package/cli/commands/design-link.test.mjs +0 -419
- package/cli/commands/design.test.mjs +0 -240
- package/cli/commands/doctor.test.mjs +0 -237
- package/cli/commands/hub-workspace.test.mjs +0 -275
- package/cli/commands/hub.test.mjs +0 -225
- package/cli/commands/kg.test.mjs +0 -142
- package/cli/commands/preflight.test.mjs +0 -46
- package/cli/lib/argv.test.mjs +0 -46
- package/cli/lib/cache.test.mjs +0 -303
- package/cli/lib/cell-plan.test.mjs +0 -225
- package/cli/lib/config-lint.test.mjs +0 -117
- package/cli/lib/ddr-to-kgai.test.mjs +0 -118
- package/cli/lib/design-ownership.test.mjs +0 -329
- package/cli/lib/fetch-asset.test.mjs +0 -213
- package/cli/lib/figma-codegen-reachability.test.mjs +0 -104
- package/cli/lib/figma-import-controls.test.mjs +0 -70
- package/cli/lib/flow-design-integration.test.mjs +0 -165
- package/cli/lib/gitignore-block.test.mjs +0 -136
- package/cli/lib/gitignore-drift.test.mjs +0 -156
- package/cli/lib/hubs-config.test.mjs +0 -165
- package/cli/lib/pkg-root.test.mjs +0 -111
- package/cli/lib/plugin-cli-reachability.test.mjs +0 -57
- package/cli/lib/plugin-name-namespace.test.mjs +0 -71
- package/cli/lib/reconstruct-toolset.test.mjs +0 -194
- package/cli/lib/stack-detect.test.mjs +0 -121
- package/cli/lib/update-check.test.mjs +0 -32
- package/cli/lib/workspace-plan.test.mjs +0 -699
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
// use-undo-stack — Provider runner contract. SSR-capture pattern + ref-as-
|
|
2
|
-
// store means most of the interesting state lives outside React renders,
|
|
3
|
-
// so we exercise the action closures directly. Pure reducer is covered in
|
|
4
|
-
// undo-stack.test.ts.
|
|
5
|
-
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test';
|
|
7
|
-
|
|
8
|
-
import { renderToStaticMarkup } from 'react-dom/server';
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
_clearBuilderRegistry,
|
|
12
|
-
_clearStackStore,
|
|
13
|
-
type CommandRecord,
|
|
14
|
-
type CommandSinks,
|
|
15
|
-
registerCommand,
|
|
16
|
-
} from '../undo-stack.ts';
|
|
17
|
-
import {
|
|
18
|
-
UndoStackProvider,
|
|
19
|
-
useUndoSinks,
|
|
20
|
-
useUndoStack,
|
|
21
|
-
useUndoStackOptional,
|
|
22
|
-
} from '../use-undo-stack.tsx';
|
|
23
|
-
|
|
24
|
-
// Shared spy plumbing for record-builder tests below.
|
|
25
|
-
let doSpy: ReturnType<typeof mock>;
|
|
26
|
-
let undoSpy: ReturnType<typeof mock>;
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
_clearStackStore();
|
|
30
|
-
_clearBuilderRegistry();
|
|
31
|
-
doSpy = mock(() => {});
|
|
32
|
-
undoSpy = mock(() => {});
|
|
33
|
-
// A single "test" command kind shared across this file. The builder reads
|
|
34
|
-
// `sinks.layoutPatchFn` as a generic "trigger" — when present, do() and
|
|
35
|
-
// undo() fire the spies; when absent, rebuild returns null.
|
|
36
|
-
registerCommand('test', (record, sinks) => {
|
|
37
|
-
if (!sinks.layoutPatchFn) return null;
|
|
38
|
-
return {
|
|
39
|
-
kind: record.kind,
|
|
40
|
-
label: record.label,
|
|
41
|
-
do() {
|
|
42
|
-
doSpy(record.payload);
|
|
43
|
-
},
|
|
44
|
-
undo() {
|
|
45
|
-
undoSpy(record.payload);
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
afterEach(() => {
|
|
52
|
-
_clearStackStore();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
function rec(label: string, payload: unknown = null): CommandRecord {
|
|
56
|
-
return { kind: 'test', label, payload };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function capture<T>(useHook: () => T, tree: (consumer: React.ReactElement) => React.ReactElement) {
|
|
60
|
-
let captured: T | null = null;
|
|
61
|
-
function Consumer() {
|
|
62
|
-
captured = useHook();
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
renderToStaticMarkup(tree(<Consumer />));
|
|
66
|
-
if (!captured) throw new Error('hook did not capture a value');
|
|
67
|
-
return captured;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Render a provider tree and capture both the stack value and the sinks API.
|
|
72
|
-
* Sinks are bound during the same SSR render via a sibling capture, so the
|
|
73
|
-
* runner's first push() sees the registered sink.
|
|
74
|
-
*/
|
|
75
|
-
function captureProvider(canvasFile?: string, sinks?: Partial<CommandSinks>) {
|
|
76
|
-
let stack: ReturnType<typeof useUndoStack> | null = null;
|
|
77
|
-
function Inner() {
|
|
78
|
-
stack = useUndoStack();
|
|
79
|
-
const undoSinks = useUndoSinks();
|
|
80
|
-
if (sinks) {
|
|
81
|
-
for (const [k, v] of Object.entries(sinks)) {
|
|
82
|
-
// biome-ignore lint/suspicious/noExplicitAny: setSink generic indexing
|
|
83
|
-
undoSinks.setSink(k as never, v as any);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
renderToStaticMarkup(
|
|
89
|
-
<UndoStackProvider canvasFile={canvasFile}>
|
|
90
|
-
<Inner />
|
|
91
|
-
</UndoStackProvider>
|
|
92
|
-
);
|
|
93
|
-
if (!stack) throw new Error('no provider value captured');
|
|
94
|
-
return stack;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
describe('use-undo-stack / contract outside provider', () => {
|
|
98
|
-
test('useUndoStack() throws outside provider', () => {
|
|
99
|
-
function Bare() {
|
|
100
|
-
useUndoStack();
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
expect(() => renderToStaticMarkup(<Bare />)).toThrow(
|
|
104
|
-
/useUndoStack must be used inside <UndoStackProvider>/
|
|
105
|
-
);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('useUndoStackOptional() returns no-op value outside provider', () => {
|
|
109
|
-
const value = capture(useUndoStackOptional, (child) => <>{child}</>);
|
|
110
|
-
expect(value.canUndo).toBe(false);
|
|
111
|
-
expect(value.canRedo).toBe(false);
|
|
112
|
-
expect(value.lastLabel).toBeNull();
|
|
113
|
-
expect(() => value.clear()).not.toThrow();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('useUndoSinks() outside provider is a silent no-op', () => {
|
|
117
|
-
const value = capture(useUndoSinks, (child) => <>{child}</>);
|
|
118
|
-
expect(() => value.setSink('layoutPatchFn', () => {})).not.toThrow();
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('use-undo-stack / runner side-effects', () => {
|
|
123
|
-
test('push() invokes rebuilt cmd.do() exactly once', async () => {
|
|
124
|
-
const v = captureProvider(undefined, { layoutPatchFn: () => {} });
|
|
125
|
-
await v.push(rec('move 1'));
|
|
126
|
-
expect(doSpy).toHaveBeenCalledTimes(1);
|
|
127
|
-
expect(undoSpy).toHaveBeenCalledTimes(0);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test('undo() invokes cmd.undo() on the most recently pushed record', async () => {
|
|
131
|
-
const v = captureProvider(undefined, { layoutPatchFn: () => {} });
|
|
132
|
-
await v.push(rec('a', 'A'));
|
|
133
|
-
await v.push(rec('b', 'B'));
|
|
134
|
-
await v.undo();
|
|
135
|
-
expect(undoSpy).toHaveBeenCalledTimes(1);
|
|
136
|
-
expect(undoSpy.mock.calls[0]?.[0]).toBe('B');
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test('redo() re-invokes cmd.do() on the most recently undone record', async () => {
|
|
140
|
-
const v = captureProvider(undefined, { layoutPatchFn: () => {} });
|
|
141
|
-
await v.push(rec('a', 'A'));
|
|
142
|
-
await v.undo();
|
|
143
|
-
await v.redo();
|
|
144
|
-
expect(doSpy).toHaveBeenCalledTimes(2);
|
|
145
|
-
expect(doSpy.mock.calls[1]?.[0]).toBe('A');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test('push without a registered sink skips the do() call (rebuild returned null)', async () => {
|
|
149
|
-
const v = captureProvider(undefined, {}); // no sinks → builder returns null
|
|
150
|
-
await v.push(rec('lonely'));
|
|
151
|
-
// doSpy is the only observable signal here — `lastLabel` is React
|
|
152
|
-
// state that doesn't refresh under SSR-capture.
|
|
153
|
-
expect(doSpy).toHaveBeenCalledTimes(0);
|
|
154
|
-
expect(undoSpy).toHaveBeenCalledTimes(0);
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
describe('use-undo-stack / record (already-applied edits)', () => {
|
|
159
|
-
test('record() appends WITHOUT running do()', async () => {
|
|
160
|
-
const v = captureProvider(undefined, { layoutPatchFn: () => {} });
|
|
161
|
-
v.record(rec('inline-edit', 'X'));
|
|
162
|
-
// undo() is enqueued after record(), so awaiting it flushes record first.
|
|
163
|
-
await v.undo();
|
|
164
|
-
expect(doSpy).toHaveBeenCalledTimes(0); // record never runs do()
|
|
165
|
-
expect(undoSpy).toHaveBeenCalledTimes(1);
|
|
166
|
-
expect(undoSpy.mock.calls[0]?.[0]).toBe('X');
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test('record() then redo() (after undo) re-runs do()', async () => {
|
|
170
|
-
const v = captureProvider(undefined, { layoutPatchFn: () => {} });
|
|
171
|
-
v.record(rec('e', 'Y'));
|
|
172
|
-
await v.undo();
|
|
173
|
-
await v.redo();
|
|
174
|
-
expect(doSpy).toHaveBeenCalledTimes(1); // only redo's do(), not the record
|
|
175
|
-
expect(doSpy.mock.calls[0]?.[0]).toBe('Y');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test('record() clears the redo future', async () => {
|
|
179
|
-
const v = captureProvider(undefined, { layoutPatchFn: () => {} });
|
|
180
|
-
await v.push(rec('a', 'A')); // doSpy: 1
|
|
181
|
-
await v.undo(); // future = [a]
|
|
182
|
-
v.record(rec('b', 'B')); // clears future
|
|
183
|
-
await v.redo(); // future empty → no-op, no extra do()
|
|
184
|
-
expect(doSpy).toHaveBeenCalledTimes(1);
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
describe('use-undo-stack / cross-canvas persistence', () => {
|
|
189
|
-
test('history under a canvasFile survives a fresh provider mount with the same canvasFile', async () => {
|
|
190
|
-
// First mount: push 2 records.
|
|
191
|
-
{
|
|
192
|
-
const v = captureProvider('ui/Foo.tsx', { layoutPatchFn: () => {} });
|
|
193
|
-
await v.push(rec('e1'));
|
|
194
|
-
await v.push(rec('e2'));
|
|
195
|
-
}
|
|
196
|
-
// Second mount (simulates iframe destroy + remount for same canvas).
|
|
197
|
-
const v2 = captureProvider('ui/Foo.tsx', { layoutPatchFn: () => {} });
|
|
198
|
-
expect(v2.canUndo).toBe(true);
|
|
199
|
-
expect(v2.lastLabel).toBeNull(); // labels are per-mount session
|
|
200
|
-
// Undo the top — should fire spy with rec('e2') payload.
|
|
201
|
-
await v2.undo();
|
|
202
|
-
expect(undoSpy).toHaveBeenCalledTimes(1);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
test('switching canvases keeps each history independent', async () => {
|
|
206
|
-
{
|
|
207
|
-
const v = captureProvider('ui/Foo.tsx', { layoutPatchFn: () => {} });
|
|
208
|
-
await v.push(rec('foo-1'));
|
|
209
|
-
await v.push(rec('foo-2'));
|
|
210
|
-
}
|
|
211
|
-
{
|
|
212
|
-
const v = captureProvider('ui/Bar.tsx', { layoutPatchFn: () => {} });
|
|
213
|
-
await v.push(rec('bar-1'));
|
|
214
|
-
}
|
|
215
|
-
// Come back to Foo.
|
|
216
|
-
const v2 = captureProvider('ui/Foo.tsx', { layoutPatchFn: () => {} });
|
|
217
|
-
expect(v2.canUndo).toBe(true);
|
|
218
|
-
await v2.undo();
|
|
219
|
-
// The spy was called for foo-2 last (LIFO).
|
|
220
|
-
const lastCall = undoSpy.mock.calls[undoSpy.mock.calls.length - 1]?.[0];
|
|
221
|
-
expect(lastCall).toBeNull(); // payload is null in `rec(label)` default
|
|
222
|
-
});
|
|
223
|
-
});
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
// POST /_api/asset — DDR-148 video/audio widening of the Phase 23 asset route.
|
|
2
|
-
//
|
|
3
|
-
// Two layers (mirroring asset-api.test.ts):
|
|
4
|
-
// (1) the pure magic-byte sniff (`sniffAssetType`) — the ONE gate that decides
|
|
5
|
-
// the stored type AND category (→ which cap applies); a header lie / SVG /
|
|
6
|
-
// script is caught here;
|
|
7
|
-
// (2) the streaming POST endpoint (boots a real server) — video/audio happy
|
|
8
|
-
// path, per-category cap (image stays tighter than video; video honors
|
|
9
|
-
// the MAUDE_ASSET_MAX_VIDEO_BYTES override), content-addressed dedupe.
|
|
10
|
-
|
|
11
|
-
import { describe, expect, test } from 'bun:test';
|
|
12
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
13
|
-
import { join } from 'node:path';
|
|
14
|
-
|
|
15
|
-
import { ASSET_MAX_BYTES, assetCapForCategory, sniffAssetType } from '../api.ts';
|
|
16
|
-
import { bootServer, killProc, makeSandbox, nextPort } from './_helpers.ts';
|
|
17
|
-
|
|
18
|
-
// ── Minimal valid magic-byte headers (padded so the ≥12-byte sniff has data). ──
|
|
19
|
-
const pad = (header: number[], len = 64): Uint8Array => {
|
|
20
|
-
const out = new Uint8Array(len);
|
|
21
|
-
out.set(header, 0);
|
|
22
|
-
return out;
|
|
23
|
-
};
|
|
24
|
-
const ascii = (s: string): number[] => [...s].map((c) => c.charCodeAt(0));
|
|
25
|
-
|
|
26
|
-
const MP4 = pad([0, 0, 0, 0x18, ...ascii('ftyp'), ...ascii('isom')]);
|
|
27
|
-
const MOV = pad([0, 0, 0, 0x14, ...ascii('ftyp'), ...ascii('qt ')]);
|
|
28
|
-
const M4A = pad([0, 0, 0, 0x18, ...ascii('ftyp'), ...ascii('M4A ')]);
|
|
29
|
-
const WEBM = pad([0x1a, 0x45, 0xdf, 0xa3]);
|
|
30
|
-
const MP3_ID3 = pad([...ascii('ID3'), 0x03, 0x00]);
|
|
31
|
-
const MP3_SYNC = pad([0xff, 0xfb, 0x90, 0x00]);
|
|
32
|
-
const WAV = pad([...ascii('RIFF'), 0, 0, 0, 0, ...ascii('WAVE')]);
|
|
33
|
-
const PNG = pad([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
34
|
-
const SVG = new TextEncoder().encode('<svg xmlns="http://www.w3.org/2000/svg"><script/></svg>');
|
|
35
|
-
|
|
36
|
-
describe('video-asset / sniffAssetType (the widened type gate)', () => {
|
|
37
|
-
test('recognizes video containers by magic bytes', () => {
|
|
38
|
-
expect(sniffAssetType(MP4)).toEqual({ ext: 'mp4', category: 'video' });
|
|
39
|
-
expect(sniffAssetType(MOV)).toEqual({ ext: 'mov', category: 'video' });
|
|
40
|
-
expect(sniffAssetType(WEBM)).toEqual({ ext: 'webm', category: 'video' });
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('recognizes audio containers by magic bytes', () => {
|
|
44
|
-
expect(sniffAssetType(M4A)).toEqual({ ext: 'm4a', category: 'audio' });
|
|
45
|
-
expect(sniffAssetType(MP3_ID3)).toEqual({ ext: 'mp3', category: 'audio' });
|
|
46
|
-
expect(sniffAssetType(MP3_SYNC)).toEqual({ ext: 'mp3', category: 'audio' });
|
|
47
|
-
expect(sniffAssetType(WAV)).toEqual({ ext: 'wav', category: 'audio' });
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('images still resolve through the same superset sniff', () => {
|
|
51
|
-
expect(sniffAssetType(PNG)).toEqual({ ext: 'png', category: 'image' });
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('rejects SVG / script / text / empty (no script-bearing vector rides in)', () => {
|
|
55
|
-
expect(sniffAssetType(SVG)).toBeNull();
|
|
56
|
-
expect(sniffAssetType(new TextEncoder().encode('not media at all'))).toBeNull();
|
|
57
|
-
expect(sniffAssetType(new Uint8Array(0))).toBeNull();
|
|
58
|
-
// "RIFF" without "WAVE" (or "WEBP") must NOT match a media/image type.
|
|
59
|
-
expect(sniffAssetType(pad([...ascii('RIFF'), 0, 0, 0, 0, ...ascii('AVI ')]))).toBeNull();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test('caps: image stays tight, video/audio share the larger cap', () => {
|
|
63
|
-
expect(assetCapForCategory('image')).toBe(ASSET_MAX_BYTES);
|
|
64
|
-
expect(assetCapForCategory('video')).toBeGreaterThan(assetCapForCategory('image'));
|
|
65
|
-
expect(assetCapForCategory('audio')).toBe(assetCapForCategory('video'));
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe('video-asset / POST /_api/asset (streaming endpoint)', () => {
|
|
70
|
-
async function withServer(
|
|
71
|
-
fn: (port: number, designRoot: string) => Promise<void>,
|
|
72
|
-
extraEnv?: Record<string, string>
|
|
73
|
-
) {
|
|
74
|
-
const sandbox = makeSandbox();
|
|
75
|
-
const port = nextPort();
|
|
76
|
-
const proc = await bootServer(sandbox.root, port, extraEnv);
|
|
77
|
-
try {
|
|
78
|
-
await fn(port, sandbox.designRoot);
|
|
79
|
-
} finally {
|
|
80
|
-
await killProc(proc);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const postAsset = (port: number, body: Uint8Array) =>
|
|
85
|
-
fetch(`http://localhost:${port}/_api/asset`, {
|
|
86
|
-
method: 'POST',
|
|
87
|
-
headers: { 'Content-Type': 'application/octet-stream' },
|
|
88
|
-
body,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('writes valid mp4/mov/webm/mp3/wav/m4a with the sniffed ext', async () => {
|
|
92
|
-
await withServer(async (port, designRoot) => {
|
|
93
|
-
for (const [bytes, ext] of [
|
|
94
|
-
[MP4, 'mp4'],
|
|
95
|
-
[MOV, 'mov'],
|
|
96
|
-
[WEBM, 'webm'],
|
|
97
|
-
[MP3_ID3, 'mp3'],
|
|
98
|
-
[WAV, 'wav'],
|
|
99
|
-
[M4A, 'm4a'],
|
|
100
|
-
] as const) {
|
|
101
|
-
const res = await postAsset(port, bytes);
|
|
102
|
-
expect(res.status).toBe(201);
|
|
103
|
-
const json = (await res.json()) as { path: string };
|
|
104
|
-
expect(json.path).toMatch(new RegExp(`^assets/[0-9a-f]{8}\\.${ext}$`));
|
|
105
|
-
expect(existsSync(join(designRoot, json.path))).toBe(true);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('bytes decide the ext, never the (octet-stream) upload header', async () => {
|
|
111
|
-
await withServer(async (port) => {
|
|
112
|
-
const res = await postAsset(port, MP4);
|
|
113
|
-
expect(res.status).toBe(201);
|
|
114
|
-
const json = (await res.json()) as { path: string };
|
|
115
|
-
expect(json.path.endsWith('.mp4')).toBe(true);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test('rejects an SVG upload (script-bearing) with 415 even on the media route', async () => {
|
|
120
|
-
await withServer(async (port) => {
|
|
121
|
-
expect((await postAsset(port, SVG)).status).toBe(415);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test('honors the MAUDE_ASSET_MAX_VIDEO_BYTES per-file cap (streamed → 413)', async () => {
|
|
126
|
-
await withServer(
|
|
127
|
-
async (port) => {
|
|
128
|
-
const big = new Uint8Array(2048);
|
|
129
|
-
big.set([0, 0, 0, 0x18, ...ascii('ftyp'), ...ascii('isom')], 0); // valid mp4 head
|
|
130
|
-
expect((await postAsset(port, big)).status).toBe(413);
|
|
131
|
-
// A small mp4 under the cap still writes.
|
|
132
|
-
expect((await postAsset(port, MP4)).status).toBe(201);
|
|
133
|
-
},
|
|
134
|
-
{ MAUDE_ASSET_MAX_VIDEO_BYTES: '1024' }
|
|
135
|
-
);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test('identical media bytes dedupe to ONE content-addressed file', async () => {
|
|
139
|
-
await withServer(async (port, designRoot) => {
|
|
140
|
-
const a = await (await postAsset(port, MP4)).json();
|
|
141
|
-
const b = await (await postAsset(port, MP4)).json();
|
|
142
|
-
expect(a.path).toBe(b.path);
|
|
143
|
-
const files = readdirSync(join(designRoot, 'assets')).filter((f) => !f.startsWith('.tmp-'));
|
|
144
|
-
expect(files.length).toBe(1);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test('a rejected oversize upload leaves NO temp file behind (clean disk)', async () => {
|
|
149
|
-
await withServer(
|
|
150
|
-
async (port, designRoot) => {
|
|
151
|
-
const big = new Uint8Array(2048);
|
|
152
|
-
big.set([0, 0, 0, 0x18, ...ascii('ftyp'), ...ascii('isom')], 0);
|
|
153
|
-
expect((await postAsset(port, big)).status).toBe(413);
|
|
154
|
-
const assetsDir = join(designRoot, 'assets');
|
|
155
|
-
const leftover = existsSync(assetsDir)
|
|
156
|
-
? readdirSync(assetsDir).filter((f) => f.startsWith('.tmp-'))
|
|
157
|
-
: [];
|
|
158
|
-
expect(leftover).toEqual([]);
|
|
159
|
-
},
|
|
160
|
-
{ MAUDE_ASSET_MAX_VIDEO_BYTES: '1024' }
|
|
161
|
-
);
|
|
162
|
-
});
|
|
163
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// video-comp-fixture — DDR-148 end-to-end build guard (CI-safe, no browser).
|
|
2
|
-
//
|
|
3
|
-
// The heavy render/scrub/export path is verified live via agent-browser + the
|
|
4
|
-
// determinism smoke; here we lock the CI-cheap invariant the whole feature
|
|
5
|
-
// rests on: a real video-comp canvas (the canonical fixture) BUILDS through the
|
|
6
|
-
// production canvas pipeline (buildCanvasModule) with `remotion`,
|
|
7
|
-
// `@remotion/transitions`, and the `fade` presentation externalised to the
|
|
8
|
-
// importmap (RUNTIME_PACKAGES) — never inlined (which would resolve against a
|
|
9
|
-
// non-existent user node_modules on an npm/marketplace install) — and with the
|
|
10
|
-
// <VideoComp> wrapper inlined from @maude/canvas-lib.
|
|
11
|
-
|
|
12
|
-
import { describe, expect, test } from 'bun:test';
|
|
13
|
-
import { readFileSync } from 'node:fs';
|
|
14
|
-
|
|
15
|
-
import { buildCanvasModule } from '../canvas-build.ts';
|
|
16
|
-
|
|
17
|
-
const FIXTURE = new URL('./fixtures/video-comp-fixture.tsx', import.meta.url).pathname;
|
|
18
|
-
|
|
19
|
-
describe('video-comp fixture — production build guard', () => {
|
|
20
|
-
test('builds through buildCanvasModule with the Remotion runtime externalised', async () => {
|
|
21
|
-
const src = readFileSync(FIXTURE, 'utf8');
|
|
22
|
-
const r = await buildCanvasModule(FIXTURE, src);
|
|
23
|
-
expect(r.js.length).toBeGreaterThan(1000);
|
|
24
|
-
|
|
25
|
-
const externals = new Set(
|
|
26
|
-
[...r.js.matchAll(/from\s*["']([^"'.][^"']*)["']/g)].map((m) => m[1])
|
|
27
|
-
);
|
|
28
|
-
// The comp's Remotion imports MUST stay external (importmap → pre-built
|
|
29
|
-
// /_canvas-runtime bundles), or an end-user install can't resolve them.
|
|
30
|
-
expect(externals.has('remotion')).toBe(true);
|
|
31
|
-
expect(externals.has('@remotion/transitions')).toBe(true);
|
|
32
|
-
expect(externals.has('@remotion/transitions/fade')).toBe(true);
|
|
33
|
-
expect(externals.has('react')).toBe(true);
|
|
34
|
-
|
|
35
|
-
// <VideoComp> (+ the seek-bridge) is inlined from @maude/canvas-lib.
|
|
36
|
-
expect(r.js).toContain('VideoComp');
|
|
37
|
-
expect(r.js).toContain('__maude_seek__');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('every Remotion specifier the fixture imports is a known RUNTIME_PACKAGE', async () => {
|
|
41
|
-
const { RUNTIME_PACKAGES } = await import('../runtime-bundle.ts');
|
|
42
|
-
const known = new Set<string>(RUNTIME_PACKAGES);
|
|
43
|
-
const src = readFileSync(FIXTURE, 'utf8');
|
|
44
|
-
const imported = [...src.matchAll(/from\s*["'](@?remotion[^"']*)["']/g)].map((m) => m[1]);
|
|
45
|
-
expect(imported.length).toBeGreaterThan(0);
|
|
46
|
-
for (const spec of imported) {
|
|
47
|
-
expect(known.has(spec)).toBe(true);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
});
|