@imgly/codesign-mcp 0.1.6 → 0.1.8
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 +5 -10
- package/assets/docs/api/index.d.ts +9 -3
- package/assets/docs/guide/SKILL.md +2 -2
- package/assets/docs/guide/api/node/classes/creativeengine.md +13 -13
- package/assets/docs/guide/edit-image/transform/scale.md +1 -3
- package/assets/docs/guide/filters-and-effects/duotone.md +1 -1
- package/assets/docs/guide/get-started/bun.md +0 -2
- package/assets/docs/guide/get-started/deno.md +0 -1
- package/assets/docs/guide/get-started/vanilla.md +0 -2
- package/assets/docs/guide/import-media/default-assets.md +20 -24
- package/assets/docs/guide/plugins/print-ready-pdf.md +0 -2
- package/assets/docs/guide/serve-assets.md +80 -23
- package/assets/docs/handbook/SKILL.md +6 -7
- package/dist/assets/inline.generated.js +12 -12
- package/dist/assets/inline.generated.js.map +1 -1
- package/dist/cli/http.d.ts.map +1 -1
- package/dist/cli/http.js +29 -5
- package/dist/cli/http.js.map +1 -1
- package/dist/cli/stdio.d.ts.map +1 -1
- package/dist/cli/stdio.js +145 -48
- package/dist/cli/stdio.js.map +1 -1
- package/dist/cli/trial-license.generated.d.ts +1 -1
- package/dist/cli/trial-license.generated.js +1 -1
- package/dist/cli/trial-license.generated.js.map +1 -1
- package/dist/config.d.ts +17 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -1
- package/dist/config.js.map +1 -1
- package/dist/diagnostics/bundle.d.ts +3 -0
- package/dist/diagnostics/bundle.d.ts.map +1 -1
- package/dist/diagnostics/bundle.js +25 -22
- package/dist/diagnostics/bundle.js.map +1 -1
- package/dist/diagnostics/events.d.ts +6 -0
- package/dist/diagnostics/events.d.ts.map +1 -1
- package/dist/diagnostics/events.js.map +1 -1
- package/dist/diagnostics/prompt.d.ts +3 -0
- package/dist/diagnostics/prompt.d.ts.map +1 -0
- package/dist/diagnostics/prompt.js +21 -0
- package/dist/diagnostics/prompt.js.map +1 -0
- package/dist/diagnostics/router.d.ts +12 -0
- package/dist/diagnostics/router.d.ts.map +1 -0
- package/dist/diagnostics/router.js +64 -0
- package/dist/diagnostics/router.js.map +1 -0
- package/dist/diagnostics/spa-assets.generated.d.ts.map +1 -0
- package/dist/diagnostics/spa-assets.generated.js +1231 -0
- package/dist/diagnostics/spa-assets.generated.js.map +1 -0
- package/dist/diagnostics/status.d.ts +38 -0
- package/dist/diagnostics/status.d.ts.map +1 -0
- package/dist/diagnostics/status.js +53 -0
- package/dist/diagnostics/status.js.map +1 -0
- package/dist/diagnostics/summary.d.ts +48 -0
- package/dist/diagnostics/summary.d.ts.map +1 -0
- package/dist/diagnostics/summary.js +116 -0
- package/dist/diagnostics/summary.js.map +1 -0
- package/dist/diagnostics/tool.d.ts +16 -0
- package/dist/diagnostics/tool.d.ts.map +1 -0
- package/dist/diagnostics/tool.js +90 -0
- package/dist/diagnostics/tool.js.map +1 -0
- package/dist/engine/asset-sources.d.ts +8 -0
- package/dist/engine/asset-sources.d.ts.map +1 -1
- package/dist/engine/asset-sources.js +9 -2
- package/dist/engine/asset-sources.js.map +1 -1
- package/dist/engine/cesdk-adapter.d.ts +5 -1
- package/dist/engine/cesdk-adapter.d.ts.map +1 -1
- package/dist/engine/cesdk-adapter.js +8 -1
- package/dist/engine/cesdk-adapter.js.map +1 -1
- package/dist/engine/engine-capacity.d.ts +16 -0
- package/dist/engine/engine-capacity.d.ts.map +1 -0
- package/dist/engine/engine-capacity.js +48 -0
- package/dist/engine/engine-capacity.js.map +1 -0
- package/dist/engine/engine-slots.d.ts +48 -0
- package/dist/engine/engine-slots.d.ts.map +1 -0
- package/dist/engine/engine-slots.js +182 -0
- package/dist/engine/engine-slots.js.map +1 -0
- package/dist/engine/uri-resolver.js.map +1 -1
- package/dist/server.d.ts +25 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +24 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/engine.d.ts +92 -14
- package/dist/tools/engine.d.ts.map +1 -1
- package/dist/tools/engine.js +147 -20
- package/dist/tools/engine.js.map +1 -1
- package/dist/tools/export.d.ts.map +1 -1
- package/dist/tools/export.js +34 -4
- package/dist/tools/export.js.map +1 -1
- package/dist/tools/index.js +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/load.d.ts.map +1 -1
- package/dist/tools/load.js +26 -19
- package/dist/tools/load.js.map +1 -1
- package/dist/tools/preview.d.ts.map +1 -1
- package/dist/tools/preview.js +60 -40
- package/dist/tools/preview.js.map +1 -1
- package/dist/tools/{open-editor.d.ts → view.d.ts} +3 -3
- package/dist/tools/view.d.ts.map +1 -0
- package/dist/tools/{open-editor.js → view.js} +20 -18
- package/dist/tools/view.js.map +1 -0
- package/dist/viewer/listener.d.ts +2 -0
- package/dist/viewer/listener.d.ts.map +1 -1
- package/dist/viewer/listener.js +2 -0
- package/dist/viewer/listener.js.map +1 -1
- package/dist/viewer/presigned-r2-url-builder.d.ts +1 -1
- package/dist/viewer/presigned-r2-url-builder.js +1 -1
- package/dist/viewer/presigned-r2-url-builder.js.map +1 -1
- package/dist/viewer/router.d.ts.map +1 -1
- package/dist/viewer/router.js +8 -17
- package/dist/viewer/router.js.map +1 -1
- package/dist/viewer/session-mount.js.map +1 -1
- package/dist/viewer/spa-assets.generated.d.ts.map +1 -1
- package/dist/viewer/spa-assets.generated.js +750 -869
- package/dist/viewer/spa-assets.generated.js.map +1 -1
- package/dist/viewer/url-builder.d.ts +4 -3
- package/dist/viewer/url-builder.d.ts.map +1 -1
- package/dist/viewer/url-builder.js +4 -4
- package/dist/viewer/url-builder.js.map +1 -1
- package/package.json +7 -6
- package/dist/dashboard/router.d.ts +0 -3
- package/dist/dashboard/router.d.ts.map +0 -1
- package/dist/dashboard/router.js +0 -19
- package/dist/dashboard/router.js.map +0 -1
- package/dist/dashboard/spa-assets.generated.d.ts.map +0 -1
- package/dist/dashboard/spa-assets.generated.js +0 -220
- package/dist/dashboard/spa-assets.generated.js.map +0 -1
- package/dist/metrics/mount.d.ts +0 -11
- package/dist/metrics/mount.d.ts.map +0 -1
- package/dist/metrics/mount.js +0 -13
- package/dist/metrics/mount.js.map +0 -1
- package/dist/metrics/recorder.d.ts +0 -55
- package/dist/metrics/recorder.d.ts.map +0 -1
- package/dist/metrics/recorder.js +0 -97
- package/dist/metrics/recorder.js.map +0 -1
- package/dist/test/scripts/changelog-add.d.ts +0 -8
- package/dist/test/scripts/changelog-add.d.ts.map +0 -1
- package/dist/test/scripts/changelog-add.js +0 -50
- package/dist/test/scripts/changelog-add.js.map +0 -1
- package/dist/test/scripts/changelog-collate.d.ts +0 -38
- package/dist/test/scripts/changelog-collate.d.ts.map +0 -1
- package/dist/test/scripts/changelog-collate.js +0 -171
- package/dist/test/scripts/changelog-collate.js.map +0 -1
- package/dist/test/test/changelog.test.d.ts +0 -2
- package/dist/test/test/changelog.test.d.ts.map +0 -1
- package/dist/test/test/changelog.test.js +0 -293
- package/dist/test/test/changelog.test.js.map +0 -1
- package/dist/test/test/cli/dispatcher.test.d.ts +0 -2
- package/dist/test/test/cli/dispatcher.test.d.ts.map +0 -1
- package/dist/test/test/cli/dispatcher.test.js +0 -54
- package/dist/test/test/cli/dispatcher.test.js.map +0 -1
- package/dist/test/test/cli/redirect-console.test.d.ts +0 -2
- package/dist/test/test/cli/redirect-console.test.d.ts.map +0 -1
- package/dist/test/test/cli/redirect-console.test.js +0 -78
- package/dist/test/test/cli/redirect-console.test.js.map +0 -1
- package/dist/test/test/cli/resolve-license.test.d.ts +0 -2
- package/dist/test/test/cli/resolve-license.test.d.ts.map +0 -1
- package/dist/test/test/cli/resolve-license.test.js +0 -29
- package/dist/test/test/cli/resolve-license.test.js.map +0 -1
- package/dist/test/test/cli/stdio-diagnostics.test.d.ts +0 -2
- package/dist/test/test/cli/stdio-diagnostics.test.d.ts.map +0 -1
- package/dist/test/test/cli/stdio-diagnostics.test.js +0 -31
- package/dist/test/test/cli/stdio-diagnostics.test.js.map +0 -1
- package/dist/test/test/cli/stdio-license.test.d.ts +0 -2
- package/dist/test/test/cli/stdio-license.test.d.ts.map +0 -1
- package/dist/test/test/cli/stdio-license.test.js +0 -19
- package/dist/test/test/cli/stdio-license.test.js.map +0 -1
- package/dist/test/test/config.test.d.ts +0 -2
- package/dist/test/test/config.test.d.ts.map +0 -1
- package/dist/test/test/config.test.js +0 -95
- package/dist/test/test/config.test.js.map +0 -1
- package/dist/test/test/cross-ref.test.d.ts +0 -2
- package/dist/test/test/cross-ref.test.d.ts.map +0 -1
- package/dist/test/test/cross-ref.test.js +0 -39
- package/dist/test/test/cross-ref.test.js.map +0 -1
- package/dist/test/test/diagnostics/bundle.test.d.ts +0 -2
- package/dist/test/test/diagnostics/bundle.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/bundle.test.js +0 -53
- package/dist/test/test/diagnostics/bundle.test.js.map +0 -1
- package/dist/test/test/diagnostics/compose.test.d.ts +0 -2
- package/dist/test/test/diagnostics/compose.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/compose.test.js +0 -31
- package/dist/test/test/diagnostics/compose.test.js.map +0 -1
- package/dist/test/test/diagnostics/file-sink.test.d.ts +0 -2
- package/dist/test/test/diagnostics/file-sink.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/file-sink.test.js +0 -113
- package/dist/test/test/diagnostics/file-sink.test.js.map +0 -1
- package/dist/test/test/diagnostics/redact.test.d.ts +0 -2
- package/dist/test/test/diagnostics/redact.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/redact.test.js +0 -59
- package/dist/test/test/diagnostics/redact.test.js.map +0 -1
- package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts +0 -2
- package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/tool-call-adapter.test.js +0 -34
- package/dist/test/test/diagnostics/tool-call-adapter.test.js.map +0 -1
- package/dist/test/test/engine/asset-sources.test.d.ts +0 -2
- package/dist/test/test/engine/asset-sources.test.d.ts.map +0 -1
- package/dist/test/test/engine/asset-sources.test.js +0 -100
- package/dist/test/test/engine/asset-sources.test.js.map +0 -1
- package/dist/test/test/engine/cesdk-adapter.test.d.ts +0 -2
- package/dist/test/test/engine/cesdk-adapter.test.d.ts.map +0 -1
- package/dist/test/test/engine/cesdk-adapter.test.js +0 -32
- package/dist/test/test/engine/cesdk-adapter.test.js.map +0 -1
- package/dist/test/test/engine/mutex.test.d.ts +0 -2
- package/dist/test/test/engine/mutex.test.d.ts.map +0 -1
- package/dist/test/test/engine/mutex.test.js +0 -63
- package/dist/test/test/engine/mutex.test.js.map +0 -1
- package/dist/test/test/engine/session.test.d.ts +0 -2
- package/dist/test/test/engine/session.test.d.ts.map +0 -1
- package/dist/test/test/engine/session.test.js +0 -159
- package/dist/test/test/engine/session.test.js.map +0 -1
- package/dist/test/test/engine/unsplash-source.test.d.ts +0 -2
- package/dist/test/test/engine/unsplash-source.test.d.ts.map +0 -1
- package/dist/test/test/engine/unsplash-source.test.js +0 -129
- package/dist/test/test/engine/unsplash-source.test.js.map +0 -1
- package/dist/test/test/engine/uri-resolver.test.d.ts +0 -2
- package/dist/test/test/engine/uri-resolver.test.d.ts.map +0 -1
- package/dist/test/test/engine/uri-resolver.test.js +0 -38
- package/dist/test/test/engine/uri-resolver.test.js.map +0 -1
- package/dist/test/test/gateway/hosted-stub.test.d.ts +0 -2
- package/dist/test/test/gateway/hosted-stub.test.d.ts.map +0 -1
- package/dist/test/test/gateway/hosted-stub.test.js +0 -11
- package/dist/test/test/gateway/hosted-stub.test.js.map +0 -1
- package/dist/test/test/gateway/local.test.d.ts +0 -2
- package/dist/test/test/gateway/local.test.d.ts.map +0 -1
- package/dist/test/test/gateway/local.test.js +0 -29
- package/dist/test/test/gateway/local.test.js.map +0 -1
- package/dist/test/test/handbook-contract.test.d.ts +0 -2
- package/dist/test/test/handbook-contract.test.d.ts.map +0 -1
- package/dist/test/test/handbook-contract.test.js +0 -79
- package/dist/test/test/handbook-contract.test.js.map +0 -1
- package/dist/test/test/http/server.test.d.ts +0 -2
- package/dist/test/test/http/server.test.d.ts.map +0 -1
- package/dist/test/test/http/server.test.js +0 -338
- package/dist/test/test/http/server.test.js.map +0 -1
- package/dist/test/test/http/session-id-header.test.d.ts +0 -2
- package/dist/test/test/http/session-id-header.test.d.ts.map +0 -1
- package/dist/test/test/http/session-id-header.test.js +0 -76
- package/dist/test/test/http/session-id-header.test.js.map +0 -1
- package/dist/test/test/http/session-manager.test.d.ts +0 -2
- package/dist/test/test/http/session-manager.test.d.ts.map +0 -1
- package/dist/test/test/http/session-manager.test.js +0 -97
- package/dist/test/test/http/session-manager.test.js.map +0 -1
- package/dist/test/test/http/workspace-auth.test.d.ts +0 -2
- package/dist/test/test/http/workspace-auth.test.d.ts.map +0 -1
- package/dist/test/test/http/workspace-auth.test.js +0 -40
- package/dist/test/test/http/workspace-auth.test.js.map +0 -1
- package/dist/test/test/metrics/mount.test.d.ts +0 -2
- package/dist/test/test/metrics/mount.test.d.ts.map +0 -1
- package/dist/test/test/metrics/mount.test.js +0 -59
- package/dist/test/test/metrics/mount.test.js.map +0 -1
- package/dist/test/test/metrics/recorder.test.d.ts +0 -2
- package/dist/test/test/metrics/recorder.test.d.ts.map +0 -1
- package/dist/test/test/metrics/recorder.test.js +0 -118
- package/dist/test/test/metrics/recorder.test.js.map +0 -1
- package/dist/test/test/revisions/hash.test.d.ts +0 -2
- package/dist/test/test/revisions/hash.test.d.ts.map +0 -1
- package/dist/test/test/revisions/hash.test.js +0 -33
- package/dist/test/test/revisions/hash.test.js.map +0 -1
- package/dist/test/test/revisions/store.test.d.ts +0 -2
- package/dist/test/test/revisions/store.test.d.ts.map +0 -1
- package/dist/test/test/revisions/store.test.js +0 -315
- package/dist/test/test/revisions/store.test.js.map +0 -1
- package/dist/test/test/server.metrics.test.d.ts +0 -2
- package/dist/test/test/server.metrics.test.d.ts.map +0 -1
- package/dist/test/test/server.metrics.test.js +0 -87
- package/dist/test/test/server.metrics.test.js.map +0 -1
- package/dist/test/test/server.test.d.ts +0 -2
- package/dist/test/test/server.test.d.ts.map +0 -1
- package/dist/test/test/server.test.js +0 -146
- package/dist/test/test/server.test.js.map +0 -1
- package/dist/test/test/skill-tools.test.d.ts +0 -2
- package/dist/test/test/skill-tools.test.d.ts.map +0 -1
- package/dist/test/test/skill-tools.test.js +0 -84
- package/dist/test/test/skill-tools.test.js.map +0 -1
- package/dist/test/test/smoke.test.d.ts +0 -2
- package/dist/test/test/smoke.test.d.ts.map +0 -1
- package/dist/test/test/smoke.test.js +0 -8
- package/dist/test/test/smoke.test.js.map +0 -1
- package/dist/test/test/tools/asset-generate.test.d.ts +0 -2
- package/dist/test/test/tools/asset-generate.test.d.ts.map +0 -1
- package/dist/test/test/tools/asset-generate.test.js +0 -66
- package/dist/test/test/tools/asset-generate.test.js.map +0 -1
- package/dist/test/test/tools/asset-search.test.d.ts +0 -2
- package/dist/test/test/tools/asset-search.test.d.ts.map +0 -1
- package/dist/test/test/tools/asset-search.test.js +0 -121
- package/dist/test/test/tools/asset-search.test.js.map +0 -1
- package/dist/test/test/tools/edit-harness.d.ts +0 -14
- package/dist/test/test/tools/edit-harness.d.ts.map +0 -1
- package/dist/test/test/tools/edit-harness.js +0 -30
- package/dist/test/test/tools/edit-harness.js.map +0 -1
- package/dist/test/test/tools/edit.telemetry.test.d.ts +0 -2
- package/dist/test/test/tools/edit.telemetry.test.d.ts.map +0 -1
- package/dist/test/test/tools/edit.telemetry.test.js +0 -46
- package/dist/test/test/tools/edit.telemetry.test.js.map +0 -1
- package/dist/test/test/tools/edit.test.d.ts +0 -2
- package/dist/test/test/tools/edit.test.d.ts.map +0 -1
- package/dist/test/test/tools/edit.test.js +0 -267
- package/dist/test/test/tools/edit.test.js.map +0 -1
- package/dist/test/test/tools/export-harness.d.ts +0 -13
- package/dist/test/test/tools/export-harness.d.ts.map +0 -1
- package/dist/test/test/tools/export-harness.js +0 -27
- package/dist/test/test/tools/export-harness.js.map +0 -1
- package/dist/test/test/tools/export.telemetry.test.d.ts +0 -2
- package/dist/test/test/tools/export.telemetry.test.d.ts.map +0 -1
- package/dist/test/test/tools/export.telemetry.test.js +0 -65
- package/dist/test/test/tools/export.telemetry.test.js.map +0 -1
- package/dist/test/test/tools/export.test.d.ts +0 -2
- package/dist/test/test/tools/export.test.d.ts.map +0 -1
- package/dist/test/test/tools/export.test.js +0 -174
- package/dist/test/test/tools/export.test.js.map +0 -1
- package/dist/test/test/tools/history.test.d.ts +0 -2
- package/dist/test/test/tools/history.test.d.ts.map +0 -1
- package/dist/test/test/tools/history.test.js +0 -29
- package/dist/test/test/tools/history.test.js.map +0 -1
- package/dist/test/test/tools/import.test.d.ts +0 -2
- package/dist/test/test/tools/import.test.d.ts.map +0 -1
- package/dist/test/test/tools/import.test.js +0 -122
- package/dist/test/test/tools/import.test.js.map +0 -1
- package/dist/test/test/tools/index.test.d.ts +0 -2
- package/dist/test/test/tools/index.test.d.ts.map +0 -1
- package/dist/test/test/tools/index.test.js +0 -117
- package/dist/test/test/tools/index.test.js.map +0 -1
- package/dist/test/test/tools/inspect.test.d.ts +0 -2
- package/dist/test/test/tools/inspect.test.d.ts.map +0 -1
- package/dist/test/test/tools/inspect.test.js +0 -62
- package/dist/test/test/tools/inspect.test.js.map +0 -1
- package/dist/test/test/tools/list.test.d.ts +0 -2
- package/dist/test/test/tools/list.test.d.ts.map +0 -1
- package/dist/test/test/tools/list.test.js +0 -23
- package/dist/test/test/tools/list.test.js.map +0 -1
- package/dist/test/test/tools/load.integration.test.d.ts +0 -2
- package/dist/test/test/tools/load.integration.test.d.ts.map +0 -1
- package/dist/test/test/tools/load.integration.test.js +0 -165
- package/dist/test/test/tools/load.integration.test.js.map +0 -1
- package/dist/test/test/tools/load.test.d.ts +0 -2
- package/dist/test/test/tools/load.test.d.ts.map +0 -1
- package/dist/test/test/tools/load.test.js +0 -387
- package/dist/test/test/tools/load.test.js.map +0 -1
- package/dist/test/test/tools/metrics.test.d.ts +0 -2
- package/dist/test/test/tools/metrics.test.d.ts.map +0 -1
- package/dist/test/test/tools/metrics.test.js +0 -29
- package/dist/test/test/tools/metrics.test.js.map +0 -1
- package/dist/test/test/tools/open-editor.test.d.ts +0 -2
- package/dist/test/test/tools/open-editor.test.d.ts.map +0 -1
- package/dist/test/test/tools/open-editor.test.js +0 -53
- package/dist/test/test/tools/open-editor.test.js.map +0 -1
- package/dist/test/test/tools/preview-harness.d.ts +0 -9
- package/dist/test/test/tools/preview-harness.d.ts.map +0 -1
- package/dist/test/test/tools/preview-harness.js +0 -23
- package/dist/test/test/tools/preview-harness.js.map +0 -1
- package/dist/test/test/tools/preview.telemetry.test.d.ts +0 -2
- package/dist/test/test/tools/preview.telemetry.test.d.ts.map +0 -1
- package/dist/test/test/tools/preview.telemetry.test.js +0 -36
- package/dist/test/test/tools/preview.telemetry.test.js.map +0 -1
- package/dist/test/test/tools/preview.test.d.ts +0 -2
- package/dist/test/test/tools/preview.test.d.ts.map +0 -1
- package/dist/test/test/tools/preview.test.js +0 -75
- package/dist/test/test/tools/preview.test.js.map +0 -1
- package/dist/test/test/tools/rename.test.d.ts +0 -2
- package/dist/test/test/tools/rename.test.d.ts.map +0 -1
- package/dist/test/test/tools/rename.test.js +0 -16
- package/dist/test/test/tools/rename.test.js.map +0 -1
- package/dist/test/test/tools/save.test.d.ts +0 -2
- package/dist/test/test/tools/save.test.d.ts.map +0 -1
- package/dist/test/test/tools/save.test.js +0 -137
- package/dist/test/test/tools/save.test.js.map +0 -1
- package/dist/test/test/tools/schema-best-practices.d.ts +0 -13
- package/dist/test/test/tools/schema-best-practices.d.ts.map +0 -1
- package/dist/test/test/tools/schema-best-practices.js +0 -169
- package/dist/test/test/tools/schema-best-practices.js.map +0 -1
- package/dist/test/test/tools/schema-best-practices.test.d.ts +0 -3
- package/dist/test/test/tools/schema-best-practices.test.d.ts.map +0 -1
- package/dist/test/test/tools/schema-best-practices.test.js +0 -194
- package/dist/test/test/tools/schema-best-practices.test.js.map +0 -1
- package/dist/test/test/tools/spans.test.d.ts +0 -2
- package/dist/test/test/tools/spans.test.d.ts.map +0 -1
- package/dist/test/test/tools/spans.test.js +0 -84
- package/dist/test/test/tools/spans.test.js.map +0 -1
- package/dist/test/test/viewer/broadcaster.test.d.ts +0 -2
- package/dist/test/test/viewer/broadcaster.test.d.ts.map +0 -1
- package/dist/test/test/viewer/broadcaster.test.js +0 -53
- package/dist/test/test/viewer/broadcaster.test.js.map +0 -1
- package/dist/test/test/viewer/cesdk-cdn.test.d.ts +0 -2
- package/dist/test/test/viewer/cesdk-cdn.test.d.ts.map +0 -1
- package/dist/test/test/viewer/cesdk-cdn.test.js +0 -19
- package/dist/test/test/viewer/cesdk-cdn.test.js.map +0 -1
- package/dist/test/test/viewer/config-route.test.d.ts +0 -2
- package/dist/test/test/viewer/config-route.test.d.ts.map +0 -1
- package/dist/test/test/viewer/config-route.test.js +0 -28
- package/dist/test/test/viewer/config-route.test.js.map +0 -1
- package/dist/test/test/viewer/resource-route.test.d.ts +0 -2
- package/dist/test/test/viewer/resource-route.test.d.ts.map +0 -1
- package/dist/test/test/viewer/resource-route.test.js +0 -70
- package/dist/test/test/viewer/resource-route.test.js.map +0 -1
- package/dist/test/test/viewer/router.test.d.ts +0 -2
- package/dist/test/test/viewer/router.test.d.ts.map +0 -1
- package/dist/test/test/viewer/router.test.js +0 -227
- package/dist/test/test/viewer/router.test.js.map +0 -1
- package/dist/test/test/viewer/session-mount.test.d.ts +0 -2
- package/dist/test/test/viewer/session-mount.test.d.ts.map +0 -1
- package/dist/test/test/viewer/session-mount.test.js +0 -52
- package/dist/test/test/viewer/session-mount.test.js.map +0 -1
- package/dist/test/test/viewer/spa-version.test.d.ts +0 -2
- package/dist/test/test/viewer/spa-version.test.d.ts.map +0 -1
- package/dist/test/test/viewer/spa-version.test.js +0 -14
- package/dist/test/test/viewer/spa-version.test.js.map +0 -1
- package/dist/test/test/viewer/url-builder.test.d.ts +0 -2
- package/dist/test/test/viewer/url-builder.test.d.ts.map +0 -1
- package/dist/test/test/viewer/url-builder.test.js +0 -98
- package/dist/test/test/viewer/url-builder.test.js.map +0 -1
- package/dist/test/test/workspace/content-hash.test.d.ts +0 -2
- package/dist/test/test/workspace/content-hash.test.d.ts.map +0 -1
- package/dist/test/test/workspace/content-hash.test.js +0 -17
- package/dist/test/test/workspace/content-hash.test.js.map +0 -1
- package/dist/test/test/workspace/hosted-stub.test.d.ts +0 -2
- package/dist/test/test/workspace/hosted-stub.test.d.ts.map +0 -1
- package/dist/test/test/workspace/hosted-stub.test.js +0 -30
- package/dist/test/test/workspace/hosted-stub.test.js.map +0 -1
- package/dist/test/test/workspace/in-memory.test.d.ts +0 -2
- package/dist/test/test/workspace/in-memory.test.d.ts.map +0 -1
- package/dist/test/test/workspace/in-memory.test.js +0 -4
- package/dist/test/test/workspace/in-memory.test.js.map +0 -1
- package/dist/test/test/workspace/node-fs.test.d.ts +0 -2
- package/dist/test/test/workspace/node-fs.test.d.ts.map +0 -1
- package/dist/test/test/workspace/node-fs.test.js +0 -20
- package/dist/test/test/workspace/node-fs.test.js.map +0 -1
- package/dist/test/test/workspace/s3.test.d.ts +0 -2
- package/dist/test/test/workspace/s3.test.d.ts.map +0 -1
- package/dist/test/test/workspace/s3.test.js +0 -153
- package/dist/test/test/workspace/s3.test.js.map +0 -1
- package/dist/test/test/workspace/scoped.test.d.ts +0 -2
- package/dist/test/test/workspace/scoped.test.d.ts.map +0 -1
- package/dist/test/test/workspace/scoped.test.js +0 -59
- package/dist/test/test/workspace/scoped.test.js.map +0 -1
- package/dist/test/test/workspace/shared-contract.d.ts +0 -3
- package/dist/test/test/workspace/shared-contract.d.ts.map +0 -1
- package/dist/test/test/workspace/shared-contract.js +0 -92
- package/dist/test/test/workspace/shared-contract.js.map +0 -1
- package/dist/test/tsconfig.test.tsbuildinfo +0 -1
- package/dist/test/vitest.config.d.ts +0 -3
- package/dist/test/vitest.config.d.ts.map +0 -1
- package/dist/test/vitest.config.js +0 -8
- package/dist/test/vitest.config.js.map +0 -1
- package/dist/tools/metrics.d.ts +0 -11
- package/dist/tools/metrics.d.ts.map +0 -1
- package/dist/tools/metrics.js +0 -28
- package/dist/tools/metrics.js.map +0 -1
- package/dist/tools/open-editor.d.ts.map +0 -1
- package/dist/tools/open-editor.js.map +0 -1
- /package/dist/{dashboard → diagnostics}/spa-assets.generated.d.ts +0 -0
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import { Mutex } from '../../src/engine/mutex.js';
|
|
6
|
-
import { EngineSession } from '../../src/engine/session.js';
|
|
7
|
-
import { RevisionStore } from '../../src/revisions/store.js';
|
|
8
|
-
import { createLoadTool } from '../../src/tools/load.js';
|
|
9
|
-
import { shortHash } from '../../src/workspace/content-hash.js';
|
|
10
|
-
import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
|
|
11
|
-
// Minimal fake engine implementing exactly the slice load.ts touches.
|
|
12
|
-
function makeFakeEngine() {
|
|
13
|
-
const fake = {
|
|
14
|
-
_scene: '',
|
|
15
|
-
_transients: [],
|
|
16
|
-
_resourceBytes: new Map(),
|
|
17
|
-
scene: {
|
|
18
|
-
// Full optional signatures so tests can assert on later positional args
|
|
19
|
-
// (mock.calls tuples are typed from these).
|
|
20
|
-
loadFromArchiveURL: vi.fn(async (_url, _override, _wait) => 1),
|
|
21
|
-
loadFromString: vi.fn(async (content, _override, _wait) => {
|
|
22
|
-
fake._scene = content;
|
|
23
|
-
return 1;
|
|
24
|
-
}),
|
|
25
|
-
saveToString: vi.fn(async (_opts) => 'SCENE_AFTER_RELOCATE')
|
|
26
|
-
},
|
|
27
|
-
editor: {
|
|
28
|
-
findAllTransientResources: vi.fn(() => fake._transients),
|
|
29
|
-
findAllMediaURIs: vi.fn(() => []),
|
|
30
|
-
getResourceData: vi.fn((uri, _chunkSize, onData) => {
|
|
31
|
-
const bytes = fake._resourceBytes.get(uri);
|
|
32
|
-
if (bytes)
|
|
33
|
-
onData(bytes);
|
|
34
|
-
}),
|
|
35
|
-
relocateResource: vi.fn(),
|
|
36
|
-
getMimeType: vi.fn(async () => 'image/png')
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
return fake;
|
|
40
|
-
}
|
|
41
|
-
function makeDeps() {
|
|
42
|
-
const fs = new InMemoryWorkspaceFS();
|
|
43
|
-
const store = new RevisionStore(fs);
|
|
44
|
-
const fakeEngine = makeFakeEngine();
|
|
45
|
-
const adapter = {
|
|
46
|
-
create: () => fakeEngine,
|
|
47
|
-
reset: async (e) => {
|
|
48
|
-
e._scene = '';
|
|
49
|
-
},
|
|
50
|
-
loadFromString: async (e, s) => {
|
|
51
|
-
e._scene = s;
|
|
52
|
-
},
|
|
53
|
-
saveToString: async (e) => e._scene
|
|
54
|
-
};
|
|
55
|
-
const session = new EngineSession({ size: 1, adapter });
|
|
56
|
-
return { fs, store, session, fakeEngine, engineLock: new Mutex() };
|
|
57
|
-
}
|
|
58
|
-
function textOf(result) {
|
|
59
|
-
return result.content[0].text;
|
|
60
|
-
}
|
|
61
|
-
afterEach(() => {
|
|
62
|
-
vi.unstubAllGlobals();
|
|
63
|
-
});
|
|
64
|
-
describe('load tool — schema & validation', () => {
|
|
65
|
-
it('omits the `path` source arm from the schema unless allowPath', () => {
|
|
66
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
67
|
-
const base = { fs, store, session, engineLock };
|
|
68
|
-
const hosted = createLoadTool({ ...base, allowPath: false });
|
|
69
|
-
const local = createLoadTool({ ...base, allowPath: true });
|
|
70
|
-
// `source` is a flat object (no `oneOf`) — the `path` arm is a sibling
|
|
71
|
-
// property present only on Local. See schema-best-practices.test.ts.
|
|
72
|
-
const sourceProps = (s) => JSON.stringify(s.properties.source.properties);
|
|
73
|
-
expect(sourceProps(hosted.inputSchema)).not.toContain('path');
|
|
74
|
-
expect(sourceProps(local.inputSchema)).toContain('path');
|
|
75
|
-
});
|
|
76
|
-
it('errors when source is missing', async () => {
|
|
77
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
78
|
-
const tool = createLoadTool({ fs, store, session, engineLock });
|
|
79
|
-
const result = await tool.call({});
|
|
80
|
-
expect(result.isError).toBe(true);
|
|
81
|
-
expect(textOf(result)).toMatch(/source/i);
|
|
82
|
-
});
|
|
83
|
-
it('rejects `path` when not allowed (hosted)', async () => {
|
|
84
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
85
|
-
const tool = createLoadTool({
|
|
86
|
-
fs,
|
|
87
|
-
store,
|
|
88
|
-
session,
|
|
89
|
-
engineLock,
|
|
90
|
-
allowPath: false
|
|
91
|
-
});
|
|
92
|
-
const result = await tool.call({ source: { path: '/tmp/a.zip' } });
|
|
93
|
-
expect(result.isError).toBe(true);
|
|
94
|
-
expect(textOf(result)).toMatch(/path.*not.*supported/i);
|
|
95
|
-
});
|
|
96
|
-
it('rejects non-http(s) URLs', async () => {
|
|
97
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
98
|
-
const tool = createLoadTool({ fs, store, session, engineLock });
|
|
99
|
-
const result = await tool.call({
|
|
100
|
-
source: { url: 'file:///etc/passwd' }
|
|
101
|
-
});
|
|
102
|
-
expect(result.isError).toBe(true);
|
|
103
|
-
expect(textOf(result)).toMatch(/http/i);
|
|
104
|
-
});
|
|
105
|
-
it('surfaces a fetch failure as a tool error', async () => {
|
|
106
|
-
vi.stubGlobal('fetch', vi.fn(async () => new Response('nope', { status: 404 })));
|
|
107
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
108
|
-
const tool = createLoadTool({ fs, store, session, engineLock });
|
|
109
|
-
const result = await tool.call({
|
|
110
|
-
source: { url: 'https://example.com/missing.zip' }
|
|
111
|
-
});
|
|
112
|
-
expect(result.isError).toBe(true);
|
|
113
|
-
expect(textOf(result)).toMatch(/404/);
|
|
114
|
-
});
|
|
115
|
-
it('surfaces a network-level fetch rejection as a tool error', async () => {
|
|
116
|
-
vi.stubGlobal('fetch', vi.fn(async () => {
|
|
117
|
-
throw new TypeError('fetch failed');
|
|
118
|
-
}));
|
|
119
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
120
|
-
const tool = createLoadTool({ fs, store, session, engineLock });
|
|
121
|
-
const result = await tool.call({
|
|
122
|
-
source: { url: 'https://unreachable.invalid/a.zip' }
|
|
123
|
-
});
|
|
124
|
-
expect(result.isError).toBe(true);
|
|
125
|
-
expect(textOf(result)).toMatch(/fetch failed/);
|
|
126
|
-
});
|
|
127
|
-
it('surfaces a response-body read failure as a tool error', async () => {
|
|
128
|
-
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
129
|
-
ok: true,
|
|
130
|
-
arrayBuffer: async () => {
|
|
131
|
-
throw new Error('read failed');
|
|
132
|
-
}
|
|
133
|
-
})));
|
|
134
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
135
|
-
const tool = createLoadTool({ fs, store, session, engineLock });
|
|
136
|
-
const result = await tool.call({
|
|
137
|
-
source: { url: 'https://example.com/tpl/a.zip' }
|
|
138
|
-
});
|
|
139
|
-
expect(result.isError).toBe(true);
|
|
140
|
-
expect(textOf(result)).toMatch(/read failed/);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
// A file whose first 4 bytes are the zip magic — content is irrelevant to the
|
|
144
|
-
// fake engine, only the sniffing dispatch reads it.
|
|
145
|
-
const FAKE_ZIP = new Uint8Array([0x50, 0x4b, 0x03, 0x04, 0xff]);
|
|
146
|
-
describe('load tool — archive flow', () => {
|
|
147
|
-
it('explodes transients into assets/<sha>.<ext>, relocates, writes a root revision', async () => {
|
|
148
|
-
const { fs, store, session, fakeEngine, engineLock } = makeDeps();
|
|
149
|
-
fakeEngine._transients = [{ URL: 'buffer://tmp/1', size: 3 }];
|
|
150
|
-
fakeEngine._resourceBytes.set('buffer://tmp/1', new Uint8Array([1, 2, 3]));
|
|
151
|
-
const dir = await mkdtemp(join(tmpdir(), 'load-test-'));
|
|
152
|
-
const zipPath = join(dir, 'event_story.zip');
|
|
153
|
-
await writeFile(zipPath, FAKE_ZIP);
|
|
154
|
-
const leafEvents = [];
|
|
155
|
-
const tool = createLoadTool({
|
|
156
|
-
fs,
|
|
157
|
-
store,
|
|
158
|
-
session,
|
|
159
|
-
engineLock,
|
|
160
|
-
allowPath: true,
|
|
161
|
-
onLeafWritten: (e) => {
|
|
162
|
-
leafEvents.push(e);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
const result = await tool.call({ source: { path: zipPath } });
|
|
166
|
-
expect(result.isError).toBeUndefined();
|
|
167
|
-
const body = JSON.parse(textOf(result));
|
|
168
|
-
// Title derived from the filename.
|
|
169
|
-
expect(body.title).toBe('event_story');
|
|
170
|
-
// Engine was driven correctly: file:// staging URL, waitForResources.
|
|
171
|
-
const loadCall = fakeEngine.scene.loadFromArchiveURL.mock.calls[0];
|
|
172
|
-
expect(loadCall[0]).toMatch(/^file:\/\//);
|
|
173
|
-
expect(loadCall[2]).toBe(true);
|
|
174
|
-
// Asset extracted content-addressed…
|
|
175
|
-
const sha = await shortHash(new Uint8Array([1, 2, 3]));
|
|
176
|
-
expect(await fs.exists(`assets/${sha}.png`)).toBe(true);
|
|
177
|
-
// …and relocated to its workspace URI.
|
|
178
|
-
expect(fakeEngine.editor.relocateResource).toHaveBeenCalledWith('buffer://tmp/1', `workspace://assets/${sha}.png`);
|
|
179
|
-
// saveToString allows `workspace` but NOT `buffer`.
|
|
180
|
-
const saveOpts = fakeEngine.scene.saveToString.mock.calls[0][0];
|
|
181
|
-
expect(saveOpts.allowedResourceSchemes).toContain('workspace');
|
|
182
|
-
expect(saveOpts.allowedResourceSchemes).not.toContain('buffer');
|
|
183
|
-
// Root revision persisted with the post-relocation scene.
|
|
184
|
-
const rev = await store.read(body.revision);
|
|
185
|
-
expect(rev.scene).toBe('SCENE_AFTER_RELOCATE');
|
|
186
|
-
expect(rev.meta.parent).toBeNull();
|
|
187
|
-
// Viewer hook fired; a new root is its own rootRevision.
|
|
188
|
-
expect(leafEvents).toEqual([
|
|
189
|
-
{ revision: body.revision, rootRevision: body.revision }
|
|
190
|
-
]);
|
|
191
|
-
// Session is warm at the new revision (next edit pays no reload).
|
|
192
|
-
expect(session.currentSlot()?.currentRevision).toBe(body.revision);
|
|
193
|
-
await rm(dir, { recursive: true, force: true });
|
|
194
|
-
});
|
|
195
|
-
it('drains a duplicate-content transient the engine still holds via onDisallowedResourceScheme', async () => {
|
|
196
|
-
// Two transients carry IDENTICAL bytes (a duplicated font in a premium
|
|
197
|
-
// template). Both relocate to the same content-addressed target, so the
|
|
198
|
-
// engine's relocateResource no-ops on the second and still serializes its
|
|
199
|
-
// buffer:// URL. The plain save then throws SCENE.DISALLOWED_SCHEMES; the
|
|
200
|
-
// tool must retry with a drain callback that rewrites the straggler in the
|
|
201
|
-
// OUTPUT to its already-persisted workspace:// form.
|
|
202
|
-
const { fs, store, session, fakeEngine, engineLock } = makeDeps();
|
|
203
|
-
const fontBytes = new Uint8Array([9, 8, 7]);
|
|
204
|
-
fakeEngine._transients = [
|
|
205
|
-
{ URL: 'buffer://1', size: 3 },
|
|
206
|
-
{ URL: 'buffer://2', size: 3 }
|
|
207
|
-
];
|
|
208
|
-
fakeEngine._resourceBytes.set('buffer://1', fontBytes);
|
|
209
|
-
fakeEngine._resourceBytes.set('buffer://2', fontBytes);
|
|
210
|
-
fakeEngine.editor.getMimeType.mockResolvedValue('font/ttf');
|
|
211
|
-
// Model the real engine: a plain save (no callback) throws because the
|
|
212
|
-
// duplicate straggler still serializes as buffer://2; a save WITH the
|
|
213
|
-
// drain callback invokes it for the straggler and embeds the rewrite.
|
|
214
|
-
fakeEngine.scene.saveToString.mockImplementation(async (opts) => {
|
|
215
|
-
if (!opts?.onDisallowedResourceScheme) {
|
|
216
|
-
const err = new Error('Scene contains disallowed schemes in resource URLs: "buffer"');
|
|
217
|
-
err.code = 'SCENE.DISALLOWED_SCHEMES';
|
|
218
|
-
throw err;
|
|
219
|
-
}
|
|
220
|
-
const rewritten = await opts.onDisallowedResourceScheme('buffer://2', 'hash');
|
|
221
|
-
return `SCENE:${rewritten}`;
|
|
222
|
-
});
|
|
223
|
-
const dir = await mkdtemp(join(tmpdir(), 'load-test-'));
|
|
224
|
-
const zipPath = join(dir, 'event_story.zip');
|
|
225
|
-
await writeFile(zipPath, FAKE_ZIP);
|
|
226
|
-
const tool = createLoadTool({
|
|
227
|
-
fs,
|
|
228
|
-
store,
|
|
229
|
-
session,
|
|
230
|
-
engineLock,
|
|
231
|
-
allowPath: true
|
|
232
|
-
});
|
|
233
|
-
const result = await tool.call({ source: { path: zipPath } });
|
|
234
|
-
expect(result.isError).toBeUndefined();
|
|
235
|
-
const body = JSON.parse(textOf(result));
|
|
236
|
-
// Dedup: identical bytes → a single asset file, regardless of how many
|
|
237
|
-
// callers (relocate loop + drain callback) persisted them.
|
|
238
|
-
const sha = await shortHash(fontBytes);
|
|
239
|
-
expect(await fs.exists(`assets/${sha}.ttf`)).toBe(true);
|
|
240
|
-
const assetFiles = await fs.readdir('assets');
|
|
241
|
-
expect(assetFiles).toEqual([`${sha}.ttf`]);
|
|
242
|
-
// Persisted scene carries the workspace:// rewrite, not the buffer:// URL.
|
|
243
|
-
const rev = await store.read(body.revision);
|
|
244
|
-
expect(rev.scene).toBe(`SCENE:workspace://assets/${sha}.ttf`);
|
|
245
|
-
expect(rev.scene).not.toContain('buffer://2');
|
|
246
|
-
// After draining, the engine's in-memory state is realigned to the drained
|
|
247
|
-
// scene (the warm slot handed to the next edit must match the persisted
|
|
248
|
-
// revision — reloading collapses the duplicate typeface, dropping the
|
|
249
|
-
// un-relocatable buffer:// straggler).
|
|
250
|
-
expect(fakeEngine.scene.loadFromString).toHaveBeenCalledWith(`SCENE:workspace://assets/${sha}.ttf`, false, true);
|
|
251
|
-
await rm(dir, { recursive: true, force: true });
|
|
252
|
-
});
|
|
253
|
-
it('dedupes: an already-present sha is not rewritten', async () => {
|
|
254
|
-
const { fs, store, session, fakeEngine, engineLock } = makeDeps();
|
|
255
|
-
fakeEngine._transients = [{ URL: 'buffer://tmp/1', size: 3 }];
|
|
256
|
-
fakeEngine._resourceBytes.set('buffer://tmp/1', new Uint8Array([1, 2, 3]));
|
|
257
|
-
const sha = await shortHash(new Uint8Array([1, 2, 3]));
|
|
258
|
-
await fs.writeFile(`assets/${sha}.png`, new Uint8Array([1, 2, 3]));
|
|
259
|
-
const writeSpy = vi.spyOn(fs, 'writeFile');
|
|
260
|
-
const dir = await mkdtemp(join(tmpdir(), 'load-test-'));
|
|
261
|
-
const zipPath = join(dir, 'a.zip');
|
|
262
|
-
await writeFile(zipPath, FAKE_ZIP);
|
|
263
|
-
const tool = createLoadTool({
|
|
264
|
-
fs,
|
|
265
|
-
store,
|
|
266
|
-
session,
|
|
267
|
-
engineLock,
|
|
268
|
-
allowPath: true
|
|
269
|
-
});
|
|
270
|
-
const result = await tool.call({ source: { path: zipPath } });
|
|
271
|
-
expect(result.isError).toBeUndefined();
|
|
272
|
-
const assetWrites = writeSpy.mock.calls.filter(([p]) => String(p).startsWith('assets/'));
|
|
273
|
-
expect(assetWrites).toHaveLength(0);
|
|
274
|
-
await rm(dir, { recursive: true, force: true });
|
|
275
|
-
});
|
|
276
|
-
it('marks the engine slot dirty when the engine throws', async () => {
|
|
277
|
-
const { fs, store, session, fakeEngine, engineLock } = makeDeps();
|
|
278
|
-
fakeEngine.scene.loadFromArchiveURL.mockRejectedValueOnce(new Error('corrupt archive'));
|
|
279
|
-
const dir = await mkdtemp(join(tmpdir(), 'load-test-'));
|
|
280
|
-
const zipPath = join(dir, 'a.zip');
|
|
281
|
-
await writeFile(zipPath, FAKE_ZIP);
|
|
282
|
-
const tool = createLoadTool({
|
|
283
|
-
fs,
|
|
284
|
-
store,
|
|
285
|
-
session,
|
|
286
|
-
engineLock,
|
|
287
|
-
allowPath: true
|
|
288
|
-
});
|
|
289
|
-
const result = await tool.call({ source: { path: zipPath } });
|
|
290
|
-
expect(result.isError).toBe(true);
|
|
291
|
-
expect(textOf(result)).toMatch(/corrupt archive/);
|
|
292
|
-
expect(session.currentSlot()).toBeUndefined();
|
|
293
|
-
await rm(dir, { recursive: true, force: true });
|
|
294
|
-
});
|
|
295
|
-
it('loads an archive from a URL (fetched bytes, staged to a file:// URL)', async () => {
|
|
296
|
-
vi.stubGlobal('fetch', vi.fn(async () => new Response(FAKE_ZIP.slice())));
|
|
297
|
-
const { fs, store, session, fakeEngine, engineLock } = makeDeps();
|
|
298
|
-
const tool = createLoadTool({ fs, store, session, engineLock });
|
|
299
|
-
const result = await tool.call({
|
|
300
|
-
source: { url: 'https://example.com/tpl/event_story.zip' },
|
|
301
|
-
title: 'Event Story'
|
|
302
|
-
});
|
|
303
|
-
expect(result.isError).toBeUndefined();
|
|
304
|
-
const body = JSON.parse(textOf(result));
|
|
305
|
-
expect(body.title).toBe('Event Story');
|
|
306
|
-
expect(fakeEngine.scene.loadFromArchiveURL.mock.calls[0][0]).toMatch(/^file:\/\//);
|
|
307
|
-
});
|
|
308
|
-
it('derives a title from a malformed percent-encoded URL basename without throwing', async () => {
|
|
309
|
-
vi.stubGlobal('fetch', vi.fn(async () => new Response(FAKE_ZIP.slice())));
|
|
310
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
311
|
-
const tool = createLoadTool({ fs, store, session, engineLock });
|
|
312
|
-
const result = await tool.call({
|
|
313
|
-
source: { url: 'https://example.com/tpl/a%2.zip' }
|
|
314
|
-
});
|
|
315
|
-
expect(result.isError).toBeUndefined();
|
|
316
|
-
const body = JSON.parse(textOf(result));
|
|
317
|
-
expect(body.title).toBe('a%2');
|
|
318
|
-
});
|
|
319
|
-
it('does not percent-decode a local path — a literal `%` in the filename is preserved', async () => {
|
|
320
|
-
const { fs, store, session, engineLock } = makeDeps();
|
|
321
|
-
const dir = await mkdtemp(join(tmpdir(), 'load-test-'));
|
|
322
|
-
const zipPath = join(dir, 'my%20design.zip');
|
|
323
|
-
await writeFile(zipPath, FAKE_ZIP);
|
|
324
|
-
const tool = createLoadTool({
|
|
325
|
-
fs,
|
|
326
|
-
store,
|
|
327
|
-
session,
|
|
328
|
-
engineLock,
|
|
329
|
-
allowPath: true
|
|
330
|
-
});
|
|
331
|
-
const result = await tool.call({ source: { path: zipPath } });
|
|
332
|
-
expect(result.isError).toBeUndefined();
|
|
333
|
-
const body = JSON.parse(textOf(result));
|
|
334
|
-
expect(body.title).toBe('my%20design');
|
|
335
|
-
await rm(dir, { recursive: true, force: true });
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
describe('load tool — bare .scene flow', () => {
|
|
339
|
-
it('persists the scene as-is and returns a scheme-classified, deduped asset report', async () => {
|
|
340
|
-
const { fs, store, session, fakeEngine, engineLock } = makeDeps();
|
|
341
|
-
// Real-engine shape (verified in CODE-3): durable re-fetchable refs the
|
|
342
|
-
// engine keeps as URLs (http(s)) come back from findAllMediaURIs(); anything
|
|
343
|
-
// it loaded into memory — workspace:// (via our resolver), bundle://
|
|
344
|
-
// fallbacks, buffer: orphans — comes back from findAllTransientResources()
|
|
345
|
-
// carrying its real URI. `shared.png` appears in BOTH lists → must dedupe.
|
|
346
|
-
fakeEngine.editor.findAllMediaURIs.mockReturnValue([
|
|
347
|
-
'https://cdn.example.com/hero.jpg',
|
|
348
|
-
'workspace://assets/shared.png'
|
|
349
|
-
]);
|
|
350
|
-
fakeEngine._transients = [
|
|
351
|
-
{ URL: 'workspace://assets/shared.png', size: 1 },
|
|
352
|
-
{ URL: 'workspace://assets/logo.ttf', size: 2 },
|
|
353
|
-
{ URL: 'bundle://ly.img.cesdk/fonts/x.otf', size: 3 },
|
|
354
|
-
{ URL: 'buffer://orphan', size: 4 },
|
|
355
|
-
{ URL: 'file:///tmp/local.png', size: 5 }
|
|
356
|
-
];
|
|
357
|
-
const dir = await mkdtemp(join(tmpdir(), 'load-test-'));
|
|
358
|
-
const scenePath = join(dir, 'poster.scene');
|
|
359
|
-
await writeFile(scenePath, 'UBQ1BASE64SCENESTRING');
|
|
360
|
-
const tool = createLoadTool({
|
|
361
|
-
fs,
|
|
362
|
-
store,
|
|
363
|
-
session,
|
|
364
|
-
engineLock,
|
|
365
|
-
allowPath: true
|
|
366
|
-
});
|
|
367
|
-
const result = await tool.call({ source: { path: scenePath } });
|
|
368
|
-
expect(result.isError).toBeUndefined();
|
|
369
|
-
const body = JSON.parse(textOf(result));
|
|
370
|
-
expect(body.title).toBe('poster');
|
|
371
|
-
// Engine validated the content (loadFromString), persisted verbatim.
|
|
372
|
-
expect(fakeEngine.scene.loadFromString).toHaveBeenCalledWith('UBQ1BASE64SCENESTRING', false, true);
|
|
373
|
-
expect((await store.read(body.revision)).scene).toBe('UBQ1BASE64SCENESTRING');
|
|
374
|
-
// Classified by scheme; `shared.png` deduped to one entry; a durable-scheme
|
|
375
|
-
// URI (workspace/bundle/file) is NEVER labeled `transient` — only buffer:.
|
|
376
|
-
expect(body.assets).toEqual([
|
|
377
|
-
{ uri: 'https://cdn.example.com/hero.jpg', class: 'external' },
|
|
378
|
-
{ uri: 'workspace://assets/shared.png', class: 'workspace' },
|
|
379
|
-
{ uri: 'workspace://assets/logo.ttf', class: 'workspace' },
|
|
380
|
-
{ uri: 'bundle://ly.img.cesdk/fonts/x.otf', class: 'bundle' },
|
|
381
|
-
{ uri: 'buffer://orphan', class: 'transient' },
|
|
382
|
-
{ uri: 'file:///tmp/local.png', class: 'other' }
|
|
383
|
-
]);
|
|
384
|
-
await rm(dir, { recursive: true, force: true });
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
//# sourceMappingURL=load.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"load.test.js","sourceRoot":"","sources":["../../../../test/tools/load.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\nimport { Mutex } from '../../src/engine/mutex.js';\nimport { type EngineAdapter, EngineSession } from '../../src/engine/session.js';\nimport { RevisionStore } from '../../src/revisions/store.js';\nimport { createLoadTool } from '../../src/tools/load.js';\nimport { shortHash } from '../../src/workspace/content-hash.js';\nimport { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';\n\n// Minimal fake engine implementing exactly the slice load.ts touches.\nfunction makeFakeEngine() {\n const fake = {\n _scene: '',\n _transients: [] as Array<{ URL: string; size: number }>,\n _resourceBytes: new Map<string, Uint8Array>(),\n scene: {\n // Full optional signatures so tests can assert on later positional args\n // (mock.calls tuples are typed from these).\n loadFromArchiveURL: vi.fn(\n async (_url: string, _override?: boolean, _wait?: boolean) => 1\n ),\n loadFromString: vi.fn(\n async (content: string, _override?: boolean, _wait?: boolean) => {\n fake._scene = content;\n return 1;\n }\n ),\n saveToString: vi.fn(\n async (_opts?: {\n allowedResourceSchemes?: string[];\n onDisallowedResourceScheme?: (\n url: string,\n dataHash: string\n ) => Promise<string>;\n }) => 'SCENE_AFTER_RELOCATE'\n )\n },\n editor: {\n findAllTransientResources: vi.fn(() => fake._transients),\n findAllMediaURIs: vi.fn((): string[] => []),\n getResourceData: vi.fn(\n (\n uri: string,\n _chunkSize: number,\n onData: (r: Uint8Array) => boolean\n ) => {\n const bytes = fake._resourceBytes.get(uri);\n if (bytes) onData(bytes);\n }\n ),\n relocateResource: vi.fn(),\n getMimeType: vi.fn(async () => 'image/png')\n }\n };\n return fake;\n}\ntype FakeEngine = ReturnType<typeof makeFakeEngine>;\n\nfunction makeDeps() {\n const fs = new InMemoryWorkspaceFS();\n const store = new RevisionStore(fs);\n const fakeEngine = makeFakeEngine();\n const adapter: EngineAdapter<FakeEngine> = {\n create: () => fakeEngine,\n reset: async (e) => {\n e._scene = '';\n },\n loadFromString: async (e, s) => {\n e._scene = s;\n },\n saveToString: async (e) => e._scene\n };\n const session = new EngineSession<FakeEngine>({ size: 1, adapter });\n return { fs, store, session, fakeEngine, engineLock: new Mutex() };\n}\n\nfunction textOf(result: {\n content: Array<{ type: string } & Record<string, unknown>>;\n}): string {\n return (result.content[0] as unknown as { text: string }).text;\n}\n\nafterEach(() => {\n vi.unstubAllGlobals();\n});\n\ndescribe('load tool — schema & validation', () => {\n it('omits the `path` source arm from the schema unless allowPath', () => {\n const { fs, store, session, engineLock } = makeDeps();\n const base = { fs, store, session, engineLock };\n const hosted = createLoadTool({ ...base, allowPath: false });\n const local = createLoadTool({ ...base, allowPath: true });\n // `source` is a flat object (no `oneOf`) — the `path` arm is a sibling\n // property present only on Local. See schema-best-practices.test.ts.\n const sourceProps = (s: unknown): string =>\n JSON.stringify(\n (\n s as {\n properties: { source: { properties: Record<string, unknown> } };\n }\n ).properties.source.properties\n );\n expect(sourceProps(hosted.inputSchema)).not.toContain('path');\n expect(sourceProps(local.inputSchema)).toContain('path');\n });\n\n it('errors when source is missing', async () => {\n const { fs, store, session, engineLock } = makeDeps();\n const tool = createLoadTool({ fs, store, session, engineLock });\n const result = await tool.call({});\n expect(result.isError).toBe(true);\n expect(textOf(result)).toMatch(/source/i);\n });\n\n it('rejects `path` when not allowed (hosted)', async () => {\n const { fs, store, session, engineLock } = makeDeps();\n const tool = createLoadTool({\n fs,\n store,\n session,\n engineLock,\n allowPath: false\n });\n const result = await tool.call({ source: { path: '/tmp/a.zip' } });\n expect(result.isError).toBe(true);\n expect(textOf(result)).toMatch(/path.*not.*supported/i);\n });\n\n it('rejects non-http(s) URLs', async () => {\n const { fs, store, session, engineLock } = makeDeps();\n const tool = createLoadTool({ fs, store, session, engineLock });\n const result = await tool.call({\n source: { url: 'file:///etc/passwd' }\n });\n expect(result.isError).toBe(true);\n expect(textOf(result)).toMatch(/http/i);\n });\n\n it('surfaces a fetch failure as a tool error', async () => {\n vi.stubGlobal(\n 'fetch',\n vi.fn(async () => new Response('nope', { status: 404 }))\n );\n const { fs, store, session, engineLock } = makeDeps();\n const tool = createLoadTool({ fs, store, session, engineLock });\n const result = await tool.call({\n source: { url: 'https://example.com/missing.zip' }\n });\n expect(result.isError).toBe(true);\n expect(textOf(result)).toMatch(/404/);\n });\n\n it('surfaces a network-level fetch rejection as a tool error', async () => {\n vi.stubGlobal(\n 'fetch',\n vi.fn(async () => {\n throw new TypeError('fetch failed');\n })\n );\n const { fs, store, session, engineLock } = makeDeps();\n const tool = createLoadTool({ fs, store, session, engineLock });\n const result = await tool.call({\n source: { url: 'https://unreachable.invalid/a.zip' }\n });\n expect(result.isError).toBe(true);\n expect(textOf(result)).toMatch(/fetch failed/);\n });\n\n it('surfaces a response-body read failure as a tool error', async () => {\n vi.stubGlobal(\n 'fetch',\n vi.fn(async () => ({\n ok: true,\n arrayBuffer: async () => {\n throw new Error('read failed');\n }\n })) as unknown as typeof fetch\n );\n const { fs, store, session, engineLock } = makeDeps();\n const tool = createLoadTool({ fs, store, session, engineLock });\n const result = await tool.call({\n source: { url: 'https://example.com/tpl/a.zip' }\n });\n expect(result.isError).toBe(true);\n expect(textOf(result)).toMatch(/read failed/);\n });\n});\n\n// A file whose first 4 bytes are the zip magic — content is irrelevant to the\n// fake engine, only the sniffing dispatch reads it.\nconst FAKE_ZIP = new Uint8Array([0x50, 0x4b, 0x03, 0x04, 0xff]);\n\ndescribe('load tool — archive flow', () => {\n it('explodes transients into assets/<sha>.<ext>, relocates, writes a root revision', async () => {\n const { fs, store, session, fakeEngine, engineLock } = makeDeps();\n fakeEngine._transients = [{ URL: 'buffer://tmp/1', size: 3 }];\n fakeEngine._resourceBytes.set('buffer://tmp/1', new Uint8Array([1, 2, 3]));\n const dir = await mkdtemp(join(tmpdir(), 'load-test-'));\n const zipPath = join(dir, 'event_story.zip');\n await writeFile(zipPath, FAKE_ZIP);\n\n const leafEvents: Array<{ revision: string; rootRevision: string }> = [];\n const tool = createLoadTool({\n fs,\n store,\n session,\n engineLock,\n allowPath: true,\n onLeafWritten: (e) => {\n leafEvents.push(e);\n }\n });\n const result = await tool.call({ source: { path: zipPath } });\n expect(result.isError).toBeUndefined();\n const body = JSON.parse(textOf(result)) as {\n revision: string;\n title: string;\n };\n // Title derived from the filename.\n expect(body.title).toBe('event_story');\n\n // Engine was driven correctly: file:// staging URL, waitForResources.\n const loadCall = fakeEngine.scene.loadFromArchiveURL.mock.calls[0];\n expect(loadCall[0]).toMatch(/^file:\\/\\//);\n expect(loadCall[2]).toBe(true);\n\n // Asset extracted content-addressed…\n const sha = await shortHash(new Uint8Array([1, 2, 3]));\n expect(await fs.exists(`assets/${sha}.png`)).toBe(true);\n // …and relocated to its workspace URI.\n expect(fakeEngine.editor.relocateResource).toHaveBeenCalledWith(\n 'buffer://tmp/1',\n `workspace://assets/${sha}.png`\n );\n\n // saveToString allows `workspace` but NOT `buffer`.\n const saveOpts = fakeEngine.scene.saveToString.mock.calls[0][0] as {\n allowedResourceSchemes: string[];\n };\n expect(saveOpts.allowedResourceSchemes).toContain('workspace');\n expect(saveOpts.allowedResourceSchemes).not.toContain('buffer');\n\n // Root revision persisted with the post-relocation scene.\n const rev = await store.read(body.revision);\n expect(rev.scene).toBe('SCENE_AFTER_RELOCATE');\n expect(rev.meta.parent).toBeNull();\n\n // Viewer hook fired; a new root is its own rootRevision.\n expect(leafEvents).toEqual([\n { revision: body.revision, rootRevision: body.revision }\n ]);\n\n // Session is warm at the new revision (next edit pays no reload).\n expect(session.currentSlot()?.currentRevision).toBe(body.revision);\n await rm(dir, { recursive: true, force: true });\n });\n\n it('drains a duplicate-content transient the engine still holds via onDisallowedResourceScheme', async () => {\n // Two transients carry IDENTICAL bytes (a duplicated font in a premium\n // template). Both relocate to the same content-addressed target, so the\n // engine's relocateResource no-ops on the second and still serializes its\n // buffer:// URL. The plain save then throws SCENE.DISALLOWED_SCHEMES; the\n // tool must retry with a drain callback that rewrites the straggler in the\n // OUTPUT to its already-persisted workspace:// form.\n const { fs, store, session, fakeEngine, engineLock } = makeDeps();\n const fontBytes = new Uint8Array([9, 8, 7]);\n fakeEngine._transients = [\n { URL: 'buffer://1', size: 3 },\n { URL: 'buffer://2', size: 3 }\n ];\n fakeEngine._resourceBytes.set('buffer://1', fontBytes);\n fakeEngine._resourceBytes.set('buffer://2', fontBytes);\n fakeEngine.editor.getMimeType.mockResolvedValue('font/ttf');\n // Model the real engine: a plain save (no callback) throws because the\n // duplicate straggler still serializes as buffer://2; a save WITH the\n // drain callback invokes it for the straggler and embeds the rewrite.\n fakeEngine.scene.saveToString.mockImplementation(async (opts) => {\n if (!opts?.onDisallowedResourceScheme) {\n const err = new Error(\n 'Scene contains disallowed schemes in resource URLs: \"buffer\"'\n ) as Error & { code: string };\n err.code = 'SCENE.DISALLOWED_SCHEMES';\n throw err;\n }\n const rewritten = await opts.onDisallowedResourceScheme(\n 'buffer://2',\n 'hash'\n );\n return `SCENE:${rewritten}`;\n });\n\n const dir = await mkdtemp(join(tmpdir(), 'load-test-'));\n const zipPath = join(dir, 'event_story.zip');\n await writeFile(zipPath, FAKE_ZIP);\n const tool = createLoadTool({\n fs,\n store,\n session,\n engineLock,\n allowPath: true\n });\n const result = await tool.call({ source: { path: zipPath } });\n expect(result.isError).toBeUndefined();\n const body = JSON.parse(textOf(result)) as { revision: string };\n\n // Dedup: identical bytes → a single asset file, regardless of how many\n // callers (relocate loop + drain callback) persisted them.\n const sha = await shortHash(fontBytes);\n expect(await fs.exists(`assets/${sha}.ttf`)).toBe(true);\n const assetFiles = await fs.readdir('assets');\n expect(assetFiles).toEqual([`${sha}.ttf`]);\n\n // Persisted scene carries the workspace:// rewrite, not the buffer:// URL.\n const rev = await store.read(body.revision);\n expect(rev.scene).toBe(`SCENE:workspace://assets/${sha}.ttf`);\n expect(rev.scene).not.toContain('buffer://2');\n\n // After draining, the engine's in-memory state is realigned to the drained\n // scene (the warm slot handed to the next edit must match the persisted\n // revision — reloading collapses the duplicate typeface, dropping the\n // un-relocatable buffer:// straggler).\n expect(fakeEngine.scene.loadFromString).toHaveBeenCalledWith(\n `SCENE:workspace://assets/${sha}.ttf`,\n false,\n true\n );\n await rm(dir, { recursive: true, force: true });\n });\n\n it('dedupes: an already-present sha is not rewritten', async () => {\n const { fs, store, session, fakeEngine, engineLock } = makeDeps();\n fakeEngine._transients = [{ URL: 'buffer://tmp/1', size: 3 }];\n fakeEngine._resourceBytes.set('buffer://tmp/1', new Uint8Array([1, 2, 3]));\n const sha = await shortHash(new Uint8Array([1, 2, 3]));\n await fs.writeFile(`assets/${sha}.png`, new Uint8Array([1, 2, 3]));\n const writeSpy = vi.spyOn(fs, 'writeFile');\n\n const dir = await mkdtemp(join(tmpdir(), 'load-test-'));\n const zipPath = join(dir, 'a.zip');\n await writeFile(zipPath, FAKE_ZIP);\n const tool = createLoadTool({\n fs,\n store,\n session,\n engineLock,\n allowPath: true\n });\n const result = await tool.call({ source: { path: zipPath } });\n expect(result.isError).toBeUndefined();\n const assetWrites = writeSpy.mock.calls.filter(([p]) =>\n String(p).startsWith('assets/')\n );\n expect(assetWrites).toHaveLength(0);\n await rm(dir, { recursive: true, force: true });\n });\n\n it('marks the engine slot dirty when the engine throws', async () => {\n const { fs, store, session, fakeEngine, engineLock } = makeDeps();\n fakeEngine.scene.loadFromArchiveURL.mockRejectedValueOnce(\n new Error('corrupt archive')\n );\n const dir = await mkdtemp(join(tmpdir(), 'load-test-'));\n const zipPath = join(dir, 'a.zip');\n await writeFile(zipPath, FAKE_ZIP);\n const tool = createLoadTool({\n fs,\n store,\n session,\n engineLock,\n allowPath: true\n });\n const result = await tool.call({ source: { path: zipPath } });\n expect(result.isError).toBe(true);\n expect(textOf(result)).toMatch(/corrupt archive/);\n expect(session.currentSlot()).toBeUndefined();\n await rm(dir, { recursive: true, force: true });\n });\n\n it('loads an archive from a URL (fetched bytes, staged to a file:// URL)', async () => {\n vi.stubGlobal(\n 'fetch',\n vi.fn(async () => new Response(FAKE_ZIP.slice()))\n );\n const { fs, store, session, fakeEngine, engineLock } = makeDeps();\n const tool = createLoadTool({ fs, store, session, engineLock });\n const result = await tool.call({\n source: { url: 'https://example.com/tpl/event_story.zip' },\n title: 'Event Story'\n });\n expect(result.isError).toBeUndefined();\n const body = JSON.parse(textOf(result)) as { title: string };\n expect(body.title).toBe('Event Story');\n expect(fakeEngine.scene.loadFromArchiveURL.mock.calls[0][0]).toMatch(\n /^file:\\/\\//\n );\n });\n\n it('derives a title from a malformed percent-encoded URL basename without throwing', async () => {\n vi.stubGlobal(\n 'fetch',\n vi.fn(async () => new Response(FAKE_ZIP.slice()))\n );\n const { fs, store, session, engineLock } = makeDeps();\n const tool = createLoadTool({ fs, store, session, engineLock });\n const result = await tool.call({\n source: { url: 'https://example.com/tpl/a%2.zip' }\n });\n expect(result.isError).toBeUndefined();\n const body = JSON.parse(textOf(result)) as { title: string };\n expect(body.title).toBe('a%2');\n });\n\n it('does not percent-decode a local path — a literal `%` in the filename is preserved', async () => {\n const { fs, store, session, engineLock } = makeDeps();\n const dir = await mkdtemp(join(tmpdir(), 'load-test-'));\n const zipPath = join(dir, 'my%20design.zip');\n await writeFile(zipPath, FAKE_ZIP);\n const tool = createLoadTool({\n fs,\n store,\n session,\n engineLock,\n allowPath: true\n });\n const result = await tool.call({ source: { path: zipPath } });\n expect(result.isError).toBeUndefined();\n const body = JSON.parse(textOf(result)) as { title: string };\n expect(body.title).toBe('my%20design');\n await rm(dir, { recursive: true, force: true });\n });\n});\n\ndescribe('load tool — bare .scene flow', () => {\n it('persists the scene as-is and returns a scheme-classified, deduped asset report', async () => {\n const { fs, store, session, fakeEngine, engineLock } = makeDeps();\n // Real-engine shape (verified in CODE-3): durable re-fetchable refs the\n // engine keeps as URLs (http(s)) come back from findAllMediaURIs(); anything\n // it loaded into memory — workspace:// (via our resolver), bundle://\n // fallbacks, buffer: orphans — comes back from findAllTransientResources()\n // carrying its real URI. `shared.png` appears in BOTH lists → must dedupe.\n fakeEngine.editor.findAllMediaURIs.mockReturnValue([\n 'https://cdn.example.com/hero.jpg',\n 'workspace://assets/shared.png'\n ]);\n fakeEngine._transients = [\n { URL: 'workspace://assets/shared.png', size: 1 },\n { URL: 'workspace://assets/logo.ttf', size: 2 },\n { URL: 'bundle://ly.img.cesdk/fonts/x.otf', size: 3 },\n { URL: 'buffer://orphan', size: 4 },\n { URL: 'file:///tmp/local.png', size: 5 }\n ];\n\n const dir = await mkdtemp(join(tmpdir(), 'load-test-'));\n const scenePath = join(dir, 'poster.scene');\n await writeFile(scenePath, 'UBQ1BASE64SCENESTRING');\n const tool = createLoadTool({\n fs,\n store,\n session,\n engineLock,\n allowPath: true\n });\n const result = await tool.call({ source: { path: scenePath } });\n expect(result.isError).toBeUndefined();\n const body = JSON.parse(textOf(result)) as {\n revision: string;\n title: string;\n assets: Array<{ uri: string; class: string }>;\n };\n expect(body.title).toBe('poster');\n // Engine validated the content (loadFromString), persisted verbatim.\n expect(fakeEngine.scene.loadFromString).toHaveBeenCalledWith(\n 'UBQ1BASE64SCENESTRING',\n false,\n true\n );\n expect((await store.read(body.revision)).scene).toBe(\n 'UBQ1BASE64SCENESTRING'\n );\n // Classified by scheme; `shared.png` deduped to one entry; a durable-scheme\n // URI (workspace/bundle/file) is NEVER labeled `transient` — only buffer:.\n expect(body.assets).toEqual([\n { uri: 'https://cdn.example.com/hero.jpg', class: 'external' },\n { uri: 'workspace://assets/shared.png', class: 'workspace' },\n { uri: 'workspace://assets/logo.ttf', class: 'workspace' },\n { uri: 'bundle://ly.img.cesdk/fonts/x.otf', class: 'bundle' },\n { uri: 'buffer://orphan', class: 'transient' },\n { uri: 'file:///tmp/local.png', class: 'other' }\n ]);\n await rm(dir, { recursive: true, force: true });\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.test.d.ts","sourceRoot":"","sources":["../../../../test/tools/metrics.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { MetricsRecorder } from '../../src/metrics/recorder.js';
|
|
3
|
-
import { createMetricsTool } from '../../src/tools/metrics.js';
|
|
4
|
-
describe('metrics tool', () => {
|
|
5
|
-
it('returns the recorder snapshot plus live session facts', async () => {
|
|
6
|
-
const recorder = new MetricsRecorder();
|
|
7
|
-
recorder.record({ tool: 'edit', durationMs: 120, ok: true });
|
|
8
|
-
recorder.record({ tool: 'edit', durationMs: 80, ok: false });
|
|
9
|
-
const tool = createMetricsTool({
|
|
10
|
-
recorder,
|
|
11
|
-
activeSessions: () => 3,
|
|
12
|
-
maxSessions: 5
|
|
13
|
-
});
|
|
14
|
-
expect(tool.name).toBe('metrics');
|
|
15
|
-
const result = await tool.call({});
|
|
16
|
-
const first = result.content[0];
|
|
17
|
-
if (first.type !== 'text')
|
|
18
|
-
throw new Error('expected text content');
|
|
19
|
-
const body = JSON.parse(first.text);
|
|
20
|
-
const edit = body.tools.find((t) => t.tool === 'edit');
|
|
21
|
-
expect(edit?.count).toBe(2);
|
|
22
|
-
expect(edit?.errorCount).toBe(1);
|
|
23
|
-
expect(body.recent).toHaveLength(2);
|
|
24
|
-
expect(body.activeSessions).toBe(3);
|
|
25
|
-
expect(body.maxSessions).toBe(5);
|
|
26
|
-
expect(body.uptimeMs).toBeGreaterThan(0);
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
//# sourceMappingURL=metrics.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.test.js","sourceRoot":"","sources":["../../../../test/tools/metrics.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;QACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,iBAAiB,CAAC;YAC7B,QAAQ;YACR,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;YACvB,WAAW,EAAE,CAAC;SACf,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAElC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAMjC,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { MetricsRecorder } from '../../src/metrics/recorder.js';\nimport { createMetricsTool } from '../../src/tools/metrics.js';\n\ndescribe('metrics tool', () => {\n it('returns the recorder snapshot plus live session facts', async () => {\n const recorder = new MetricsRecorder();\n recorder.record({ tool: 'edit', durationMs: 120, ok: true });\n recorder.record({ tool: 'edit', durationMs: 80, ok: false });\n const tool = createMetricsTool({\n recorder,\n activeSessions: () => 3,\n maxSessions: 5\n });\n expect(tool.name).toBe('metrics');\n\n const result = await tool.call({});\n const first = result.content[0];\n if (first.type !== 'text') throw new Error('expected text content');\n const body = JSON.parse(first.text) as {\n tools: Array<{ tool: string; count: number; errorCount: number }>;\n recent: unknown[];\n activeSessions: number;\n maxSessions: number;\n uptimeMs: number;\n };\n const edit = body.tools.find((t) => t.tool === 'edit');\n expect(edit?.count).toBe(2);\n expect(edit?.errorCount).toBe(1);\n expect(body.recent).toHaveLength(2);\n expect(body.activeSessions).toBe(3);\n expect(body.maxSessions).toBe(5);\n expect(body.uptimeMs).toBeGreaterThan(0);\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"open-editor.test.d.ts","sourceRoot":"","sources":["../../../../test/tools/open-editor.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { RevisionStore } from '../../src/revisions/store.js';
|
|
3
|
-
import { createOpenEditorTool } from '../../src/tools/open-editor.js';
|
|
4
|
-
import { LocalViewerUrlBuilder } from '../../src/viewer/url-builder.js';
|
|
5
|
-
import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
|
|
6
|
-
async function setup() {
|
|
7
|
-
const fs = new InMemoryWorkspaceFS();
|
|
8
|
-
const store = new RevisionStore(fs);
|
|
9
|
-
const root = await store.write({
|
|
10
|
-
scene: 'ROOT_SCENE',
|
|
11
|
-
parent: null,
|
|
12
|
-
title: 'T'
|
|
13
|
-
});
|
|
14
|
-
const child = await store.write({ scene: 'CHILD_SCENE', parent: root.id });
|
|
15
|
-
const tool = createOpenEditorTool({
|
|
16
|
-
urlBuilder: new LocalViewerUrlBuilder({ base: 'http://127.0.0.1:8745' }),
|
|
17
|
-
store
|
|
18
|
-
});
|
|
19
|
-
return { tool, root, child };
|
|
20
|
-
}
|
|
21
|
-
describe('open_editor tool', () => {
|
|
22
|
-
it('returns the stable design URL for a revision (resolved to its root)', async () => {
|
|
23
|
-
const { tool, root, child } = await setup();
|
|
24
|
-
const result = await tool.call({ revision: child.id });
|
|
25
|
-
const body = JSON.parse(result.content[0].text);
|
|
26
|
-
expect(body.url).toBe(`http://127.0.0.1:8745/d/${root.id}`);
|
|
27
|
-
});
|
|
28
|
-
it('returns the stable design URL when called with the root revision directly', async () => {
|
|
29
|
-
const { tool, root } = await setup();
|
|
30
|
-
const result = await tool.call({ revision: root.id });
|
|
31
|
-
const body = JSON.parse(result.content[0].text);
|
|
32
|
-
expect(body.url).toBe(`http://127.0.0.1:8745/d/${root.id}`);
|
|
33
|
-
});
|
|
34
|
-
it('returns a pinned-revision URL when pin is true', async () => {
|
|
35
|
-
const { tool, root, child } = await setup();
|
|
36
|
-
const result = await tool.call({ revision: child.id, pin: true });
|
|
37
|
-
const body = JSON.parse(result.content[0].text);
|
|
38
|
-
expect(body.url).toBe(`http://127.0.0.1:8745/d/${root.id}/${child.id}`);
|
|
39
|
-
});
|
|
40
|
-
it('returns the studio URL when called with no args', async () => {
|
|
41
|
-
const { tool } = await setup();
|
|
42
|
-
const result = await tool.call({});
|
|
43
|
-
const body = JSON.parse(result.content[0].text);
|
|
44
|
-
expect(body.url).toBe('http://127.0.0.1:8745/');
|
|
45
|
-
});
|
|
46
|
-
it('returns an isError result for an unknown revision', async () => {
|
|
47
|
-
const { tool } = await setup();
|
|
48
|
-
const result = await tool.call({ revision: 'ffffffffffff' });
|
|
49
|
-
expect(result.isError).toBe(true);
|
|
50
|
-
expect(result.content[0].text).toContain('unknown revision');
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
//# sourceMappingURL=open-editor.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"open-editor.test.js","sourceRoot":"","sources":["../../../../test/tools/open-editor.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { RevisionStore } from '../../src/revisions/store.js';\nimport { createOpenEditorTool } from '../../src/tools/open-editor.js';\nimport { LocalViewerUrlBuilder } from '../../src/viewer/url-builder.js';\nimport { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';\n\nasync function setup() {\n const fs = new InMemoryWorkspaceFS();\n const store = new RevisionStore(fs);\n const root = await store.write({\n scene: 'ROOT_SCENE',\n parent: null,\n title: 'T'\n });\n const child = await store.write({ scene: 'CHILD_SCENE', parent: root.id });\n const tool = createOpenEditorTool({\n urlBuilder: new LocalViewerUrlBuilder({ base: 'http://127.0.0.1:8745' }),\n store\n });\n return { tool, root, child };\n}\n\ndescribe('open_editor tool', () => {\n it('returns the stable design URL for a revision (resolved to its root)', async () => {\n const { tool, root, child } = await setup();\n const result = await tool.call({ revision: child.id });\n const body = JSON.parse((result.content[0] as { text: string }).text) as {\n url: string;\n };\n expect(body.url).toBe(`http://127.0.0.1:8745/d/${root.id}`);\n });\n\n it('returns the stable design URL when called with the root revision directly', async () => {\n const { tool, root } = await setup();\n const result = await tool.call({ revision: root.id });\n const body = JSON.parse((result.content[0] as { text: string }).text) as {\n url: string;\n };\n expect(body.url).toBe(`http://127.0.0.1:8745/d/${root.id}`);\n });\n\n it('returns a pinned-revision URL when pin is true', async () => {\n const { tool, root, child } = await setup();\n const result = await tool.call({ revision: child.id, pin: true });\n const body = JSON.parse((result.content[0] as { text: string }).text) as {\n url: string;\n };\n expect(body.url).toBe(`http://127.0.0.1:8745/d/${root.id}/${child.id}`);\n });\n\n it('returns the studio URL when called with no args', async () => {\n const { tool } = await setup();\n const result = await tool.call({});\n const body = JSON.parse((result.content[0] as { text: string }).text) as {\n url: string;\n };\n expect(body.url).toBe('http://127.0.0.1:8745/');\n });\n\n it('returns an isError result for an unknown revision', async () => {\n const { tool } = await setup();\n const result = await tool.call({ revision: 'ffffffffffff' });\n expect(result.isError).toBe(true);\n expect((result.content[0] as { text: string }).text).toContain(\n 'unknown revision'\n );\n });\n});\n"]}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Mutex } from '../../src/engine/mutex.js';
|
|
2
|
-
import { EngineSession } from '../../src/engine/session.js';
|
|
3
|
-
import { RevisionStore } from '../../src/revisions/store.js';
|
|
4
|
-
export declare function makePreviewHarness(): {
|
|
5
|
-
store: RevisionStore;
|
|
6
|
-
session: EngineSession<unknown>;
|
|
7
|
-
engineLock: Mutex;
|
|
8
|
-
};
|
|
9
|
-
//# sourceMappingURL=preview-harness.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"preview-harness.d.ts","sourceRoot":"","sources":["../../../../test/tools/preview-harness.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAsB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,wBAAgB,kBAAkB;;;;EAiBjC"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// Shared preview-tool test harness — a plain module (no test registrations) so importing it never re-runs preview.test.ts.
|
|
2
|
-
import { Mutex } from '../../src/engine/mutex.js';
|
|
3
|
-
import { EngineSession } from '../../src/engine/session.js';
|
|
4
|
-
import { RevisionStore } from '../../src/revisions/store.js';
|
|
5
|
-
import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
|
|
6
|
-
export function makePreviewHarness() {
|
|
7
|
-
const fs = new InMemoryWorkspaceFS();
|
|
8
|
-
const store = new RevisionStore(fs);
|
|
9
|
-
const fakeEngine = {
|
|
10
|
-
block: {
|
|
11
|
-
export: async (_id, _mime) => new Blob([new Uint8Array([1, 2, 3, 4])])
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
const adapter = {
|
|
15
|
-
create: () => fakeEngine,
|
|
16
|
-
reset: async () => { },
|
|
17
|
-
loadFromString: async () => { },
|
|
18
|
-
saveToString: async () => ''
|
|
19
|
-
};
|
|
20
|
-
const session = new EngineSession({ size: 1, adapter });
|
|
21
|
-
return { store, session, engineLock: new Mutex() };
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=preview-harness.js.map
|