@imgly/codesign-mcp 0.1.6 → 0.1.7
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/dist/cli/http.d.ts.map +1 -1
- package/dist/cli/http.js +12 -2
- package/dist/cli/http.js.map +1 -1
- package/dist/cli/stdio.d.ts.map +1 -1
- package/dist/cli/stdio.js +103 -35
- package/dist/cli/stdio.js.map +1 -1
- package/dist/config.d.ts +11 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -1
- package/dist/config.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/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/tools/engine.d.ts +13 -0
- package/dist/tools/engine.d.ts.map +1 -1
- package/dist/tools/engine.js +28 -0
- package/dist/tools/engine.js.map +1 -1
- package/package.json +2 -2
- 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 +0 -2
- 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
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
// packages/codesign-mcp/test/tools/schema-best-practices.test.ts
|
|
2
|
-
//
|
|
3
|
-
// Two layers:
|
|
4
|
-
// 1. Unit tests that the linter itself catches / passes the shapes it should.
|
|
5
|
-
// 2. The contract: EVERY tool the server advertises must have ZERO hard-error
|
|
6
|
-
// findings. Warnings are printed (advisory) but don't fail the suite.
|
|
7
|
-
//
|
|
8
|
-
// This is the programmatic guard behind the "keep tool schemas simple" best
|
|
9
|
-
// practices — it would have caught the `load` `oneOf` that made
|
|
10
|
-
// openrouter:xiaomi/mimo-v2.5-pro stringify its arguments on every attempt.
|
|
11
|
-
import { describe, expect, it } from 'vitest';
|
|
12
|
-
import { buildDesignToolRegistrations } from '../../src/tools/index.js';
|
|
13
|
-
import { createAssetGenerateTool } from '../../src/tools/asset-generate.js';
|
|
14
|
-
import { errorsOnly, lintToolSchema } from './schema-best-practices.js';
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// 1. Unit tests: the linter catches the constructs it claims to.
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
describe('lintToolSchema — rule coverage', () => {
|
|
19
|
-
const flatClean = {
|
|
20
|
-
type: 'object',
|
|
21
|
-
properties: {
|
|
22
|
-
source: {
|
|
23
|
-
type: 'object',
|
|
24
|
-
description: 'the source',
|
|
25
|
-
properties: {
|
|
26
|
-
url: { type: 'string', description: 'http(s) url' },
|
|
27
|
-
path: { type: 'string', description: 'local path' }
|
|
28
|
-
},
|
|
29
|
-
additionalProperties: false
|
|
30
|
-
},
|
|
31
|
-
title: { type: 'string', description: 'display name' }
|
|
32
|
-
},
|
|
33
|
-
required: ['source'],
|
|
34
|
-
additionalProperties: false
|
|
35
|
-
};
|
|
36
|
-
it('passes a flat, closed, described object schema', () => {
|
|
37
|
-
expect(errorsOnly(lintToolSchema(flatClean))).toEqual([]);
|
|
38
|
-
});
|
|
39
|
-
it('flags a `oneOf` union (the load/mimo failure mode)', () => {
|
|
40
|
-
const schema = {
|
|
41
|
-
type: 'object',
|
|
42
|
-
properties: {
|
|
43
|
-
source: {
|
|
44
|
-
oneOf: [
|
|
45
|
-
{ type: 'object', properties: { url: { type: 'string' } } },
|
|
46
|
-
{ type: 'object', properties: { path: { type: 'string' } } }
|
|
47
|
-
]
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
additionalProperties: false
|
|
51
|
-
};
|
|
52
|
-
const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);
|
|
53
|
-
expect(rules).toContain('no-oneOf');
|
|
54
|
-
});
|
|
55
|
-
it('flags `allOf`, `$ref`, and `not`', () => {
|
|
56
|
-
for (const key of ['allOf', '$ref', 'not']) {
|
|
57
|
-
const schema = {
|
|
58
|
-
type: 'object',
|
|
59
|
-
properties: { x: { [key]: key === '$ref' ? '#/x' : [] } },
|
|
60
|
-
additionalProperties: false
|
|
61
|
-
};
|
|
62
|
-
const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);
|
|
63
|
-
expect(rules).toContain(`no-${key.replace('$', '')}`);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
it('flags a non-object root', () => {
|
|
67
|
-
const rules = errorsOnly(lintToolSchema({ type: 'string' })).map((f) => f.rule);
|
|
68
|
-
expect(rules).toContain('root-must-be-object');
|
|
69
|
-
});
|
|
70
|
-
it('flags an object missing additionalProperties:false', () => {
|
|
71
|
-
const rules = errorsOnly(lintToolSchema({ type: 'object', properties: {} })).map((f) => f.rule);
|
|
72
|
-
expect(rules).toContain('object-additional-properties-false');
|
|
73
|
-
});
|
|
74
|
-
it('allows the `type: ["string","null"]` nullable idiom', () => {
|
|
75
|
-
const schema = {
|
|
76
|
-
type: 'object',
|
|
77
|
-
properties: {
|
|
78
|
-
parent: {
|
|
79
|
-
type: ['string', 'null'],
|
|
80
|
-
description: 'revision id, or null for a new root'
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
required: ['parent'],
|
|
84
|
-
additionalProperties: false
|
|
85
|
-
};
|
|
86
|
-
expect(errorsOnly(lintToolSchema(schema))).toEqual([]);
|
|
87
|
-
});
|
|
88
|
-
it('allows a scalar `anyOf` but rejects an object arm', () => {
|
|
89
|
-
const scalar = {
|
|
90
|
-
type: 'object',
|
|
91
|
-
properties: {
|
|
92
|
-
x: { anyOf: [{ type: 'string' }, { type: 'null' }], description: 'x' }
|
|
93
|
-
},
|
|
94
|
-
additionalProperties: false
|
|
95
|
-
};
|
|
96
|
-
expect(errorsOnly(lintToolSchema(scalar))).toEqual([]);
|
|
97
|
-
const objectArm = {
|
|
98
|
-
type: 'object',
|
|
99
|
-
properties: {
|
|
100
|
-
x: {
|
|
101
|
-
anyOf: [
|
|
102
|
-
{ type: 'string' },
|
|
103
|
-
{ type: 'object', properties: {}, additionalProperties: false }
|
|
104
|
-
],
|
|
105
|
-
description: 'x'
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
additionalProperties: false
|
|
109
|
-
};
|
|
110
|
-
expect(errorsOnly(lintToolSchema(objectArm)).map((f) => f.rule)).toContain('anyof-scalar-arms-only');
|
|
111
|
-
});
|
|
112
|
-
it('warns (does not error) on a missing property description', () => {
|
|
113
|
-
const findings = lintToolSchema({
|
|
114
|
-
type: 'object',
|
|
115
|
-
properties: { x: { type: 'string' } },
|
|
116
|
-
additionalProperties: false
|
|
117
|
-
});
|
|
118
|
-
expect(errorsOnly(findings)).toEqual([]);
|
|
119
|
-
expect(findings.map((f) => f.rule)).toContain('property-needs-description');
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
|
-
// 2. Contract: every advertised tool schema is clean.
|
|
124
|
-
// ---------------------------------------------------------------------------
|
|
125
|
-
const stub = {};
|
|
126
|
-
function gateway() {
|
|
127
|
-
return {
|
|
128
|
-
available: true,
|
|
129
|
-
generateImage: async () => ({
|
|
130
|
-
bytes: new Uint8Array(),
|
|
131
|
-
mimeType: 'image/png'
|
|
132
|
-
})
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
// Every tool the server can advertise, across both backends (Local exposes the
|
|
136
|
-
// extra `import` tool and `load`/`save`/`export`'s `path`/`outPath` arms), plus
|
|
137
|
-
// asset_generate (beta-hidden today, but its schema still ships in source and
|
|
138
|
-
// will be exposed when the kill-switch flips). Deduped by tool name.
|
|
139
|
-
function allToolSchemas() {
|
|
140
|
-
const byName = new Map();
|
|
141
|
-
for (const allowOutPath of [true, false]) {
|
|
142
|
-
for (const reg of buildDesignToolRegistrations({
|
|
143
|
-
fs: stub,
|
|
144
|
-
store: stub,
|
|
145
|
-
session: stub,
|
|
146
|
-
engineLock: stub,
|
|
147
|
-
gateway: gateway(),
|
|
148
|
-
urlBuilder: stub,
|
|
149
|
-
allowOutPath
|
|
150
|
-
})) {
|
|
151
|
-
byName.set(reg.name, reg.inputSchema);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const assetGen = createAssetGenerateTool({
|
|
155
|
-
gateway: gateway(),
|
|
156
|
-
fs: stub,
|
|
157
|
-
urlBuilder: stub
|
|
158
|
-
});
|
|
159
|
-
byName.set(assetGen.name, assetGen.inputSchema);
|
|
160
|
-
return [...byName].map(([name, schema]) => ({ name, schema }));
|
|
161
|
-
}
|
|
162
|
-
describe('tool input schemas follow LLM tool-calling best practices', () => {
|
|
163
|
-
const tools = allToolSchemas();
|
|
164
|
-
it('advertises a non-trivial set of tools (guards against an empty sweep)', () => {
|
|
165
|
-
expect(tools.length).toBeGreaterThanOrEqual(10);
|
|
166
|
-
});
|
|
167
|
-
it.each(tools)('$name — no hard-error schema findings', ({ schema }) => {
|
|
168
|
-
const errors = errorsOnly(lintToolSchema(schema));
|
|
169
|
-
// Surface a readable message when this fails.
|
|
170
|
-
expect(errors, errors.map((e) => `${e.path}: [${e.rule}] ${e.message}`).join('\n')).toEqual([]);
|
|
171
|
-
});
|
|
172
|
-
it('reports advisory warnings (non-failing) for visibility', () => {
|
|
173
|
-
const warnings = [];
|
|
174
|
-
for (const { name, schema } of tools) {
|
|
175
|
-
for (const f of lintToolSchema(schema)) {
|
|
176
|
-
if (f.severity === 'warn')
|
|
177
|
-
warnings.push(`${name} ${f.path}: [${f.rule}] ${f.message}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
if (warnings.length > 0) {
|
|
181
|
-
// eslint-disable-next-line no-console
|
|
182
|
-
console.warn(`\n[tool-schema best-practice warnings]\n${warnings.join('\n')}\n`);
|
|
183
|
-
}
|
|
184
|
-
// Advisory only — always passes. Kept as a test so the warnings render in
|
|
185
|
-
// CI output rather than being silently discarded.
|
|
186
|
-
expect(Array.isArray(warnings)).toBe(true);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
// Re-exported so a future consumer (a `check` step, a CI gate) can reuse the
|
|
190
|
-
// same sweep without duplicating the wiring.
|
|
191
|
-
export function collectSchemaErrors() {
|
|
192
|
-
return allToolSchemas().flatMap(({ schema }) => errorsOnly(lintToolSchema(schema)));
|
|
193
|
-
}
|
|
194
|
-
//# sourceMappingURL=schema-best-practices.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-best-practices.test.js","sourceRoot":"","sources":["../../../../test/tools/schema-best-practices.test.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/codesign-mcp/test/tools/schema-best-practices.test.ts\n//\n// Two layers:\n// 1. Unit tests that the linter itself catches / passes the shapes it should.\n// 2. The contract: EVERY tool the server advertises must have ZERO hard-error\n// findings. Warnings are printed (advisory) but don't fail the suite.\n//\n// This is the programmatic guard behind the \"keep tool schemas simple\" best\n// practices — it would have caught the `load` `oneOf` that made\n// openrouter:xiaomi/mimo-v2.5-pro stringify its arguments on every attempt.\n\nimport { describe, expect, it } from 'vitest';\nimport type { GatewayClient } from '../../src/gateway/types.js';\nimport { buildDesignToolRegistrations } from '../../src/tools/index.js';\nimport { createAssetGenerateTool } from '../../src/tools/asset-generate.js';\nimport {\n errorsOnly,\n lintToolSchema,\n type SchemaFinding\n} from './schema-best-practices.js';\n\n// ---------------------------------------------------------------------------\n// 1. Unit tests: the linter catches the constructs it claims to.\n// ---------------------------------------------------------------------------\n\ndescribe('lintToolSchema — rule coverage', () => {\n const flatClean = {\n type: 'object',\n properties: {\n source: {\n type: 'object',\n description: 'the source',\n properties: {\n url: { type: 'string', description: 'http(s) url' },\n path: { type: 'string', description: 'local path' }\n },\n additionalProperties: false\n },\n title: { type: 'string', description: 'display name' }\n },\n required: ['source'],\n additionalProperties: false\n };\n\n it('passes a flat, closed, described object schema', () => {\n expect(errorsOnly(lintToolSchema(flatClean))).toEqual([]);\n });\n\n it('flags a `oneOf` union (the load/mimo failure mode)', () => {\n const schema = {\n type: 'object',\n properties: {\n source: {\n oneOf: [\n { type: 'object', properties: { url: { type: 'string' } } },\n { type: 'object', properties: { path: { type: 'string' } } }\n ]\n }\n },\n additionalProperties: false\n };\n const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);\n expect(rules).toContain('no-oneOf');\n });\n\n it('flags `allOf`, `$ref`, and `not`', () => {\n for (const key of ['allOf', '$ref', 'not'] as const) {\n const schema = {\n type: 'object',\n properties: { x: { [key]: key === '$ref' ? '#/x' : [] } },\n additionalProperties: false\n };\n const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);\n expect(rules).toContain(`no-${key.replace('$', '')}`);\n }\n });\n\n it('flags a non-object root', () => {\n const rules = errorsOnly(lintToolSchema({ type: 'string' })).map(\n (f) => f.rule\n );\n expect(rules).toContain('root-must-be-object');\n });\n\n it('flags an object missing additionalProperties:false', () => {\n const rules = errorsOnly(\n lintToolSchema({ type: 'object', properties: {} })\n ).map((f) => f.rule);\n expect(rules).toContain('object-additional-properties-false');\n });\n\n it('allows the `type: [\"string\",\"null\"]` nullable idiom', () => {\n const schema = {\n type: 'object',\n properties: {\n parent: {\n type: ['string', 'null'],\n description: 'revision id, or null for a new root'\n }\n },\n required: ['parent'],\n additionalProperties: false\n };\n expect(errorsOnly(lintToolSchema(schema))).toEqual([]);\n });\n\n it('allows a scalar `anyOf` but rejects an object arm', () => {\n const scalar = {\n type: 'object',\n properties: {\n x: { anyOf: [{ type: 'string' }, { type: 'null' }], description: 'x' }\n },\n additionalProperties: false\n };\n expect(errorsOnly(lintToolSchema(scalar))).toEqual([]);\n\n const objectArm = {\n type: 'object',\n properties: {\n x: {\n anyOf: [\n { type: 'string' },\n { type: 'object', properties: {}, additionalProperties: false }\n ],\n description: 'x'\n }\n },\n additionalProperties: false\n };\n expect(errorsOnly(lintToolSchema(objectArm)).map((f) => f.rule)).toContain(\n 'anyof-scalar-arms-only'\n );\n });\n\n it('warns (does not error) on a missing property description', () => {\n const findings = lintToolSchema({\n type: 'object',\n properties: { x: { type: 'string' } },\n additionalProperties: false\n });\n expect(errorsOnly(findings)).toEqual([]);\n expect(findings.map((f) => f.rule)).toContain('property-needs-description');\n });\n});\n\n// ---------------------------------------------------------------------------\n// 2. Contract: every advertised tool schema is clean.\n// ---------------------------------------------------------------------------\n\nconst stub = {} as never;\n\nfunction gateway(): GatewayClient {\n return {\n available: true,\n generateImage: async () => ({\n bytes: new Uint8Array(),\n mimeType: 'image/png'\n })\n };\n}\n\n// Every tool the server can advertise, across both backends (Local exposes the\n// extra `import` tool and `load`/`save`/`export`'s `path`/`outPath` arms), plus\n// asset_generate (beta-hidden today, but its schema still ships in source and\n// will be exposed when the kill-switch flips). Deduped by tool name.\nfunction allToolSchemas(): { name: string; schema: unknown }[] {\n const byName = new Map<string, unknown>();\n for (const allowOutPath of [true, false]) {\n for (const reg of buildDesignToolRegistrations({\n fs: stub,\n store: stub,\n session: stub,\n engineLock: stub,\n gateway: gateway(),\n urlBuilder: stub,\n allowOutPath\n })) {\n byName.set(reg.name, reg.inputSchema);\n }\n }\n const assetGen = createAssetGenerateTool({\n gateway: gateway(),\n fs: stub,\n urlBuilder: stub\n });\n byName.set(assetGen.name, assetGen.inputSchema);\n return [...byName].map(([name, schema]) => ({ name, schema }));\n}\n\ndescribe('tool input schemas follow LLM tool-calling best practices', () => {\n const tools = allToolSchemas();\n\n it('advertises a non-trivial set of tools (guards against an empty sweep)', () => {\n expect(tools.length).toBeGreaterThanOrEqual(10);\n });\n\n it.each(tools)('$name — no hard-error schema findings', ({ schema }) => {\n const errors = errorsOnly(lintToolSchema(schema));\n // Surface a readable message when this fails.\n expect(\n errors,\n errors.map((e) => `${e.path}: [${e.rule}] ${e.message}`).join('\\n')\n ).toEqual([]);\n });\n\n it('reports advisory warnings (non-failing) for visibility', () => {\n const warnings: string[] = [];\n for (const { name, schema } of tools) {\n for (const f of lintToolSchema(schema)) {\n if (f.severity === 'warn')\n warnings.push(`${name} ${f.path}: [${f.rule}] ${f.message}`);\n }\n }\n if (warnings.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `\\n[tool-schema best-practice warnings]\\n${warnings.join('\\n')}\\n`\n );\n }\n // Advisory only — always passes. Kept as a test so the warnings render in\n // CI output rather than being silently discarded.\n expect(Array.isArray(warnings)).toBe(true);\n });\n});\n\n// Re-exported so a future consumer (a `check` step, a CI gate) can reuse the\n// same sweep without duplicating the wiring.\nexport function collectSchemaErrors(): SchemaFinding[] {\n return allToolSchemas().flatMap(({ schema }) =>\n errorsOnly(lintToolSchema(schema))\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spans.test.d.ts","sourceRoot":"","sources":["../../../../test/tools/spans.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { SpanRecorder, NOOP_TELEMETRY_SINK, summarizeResult, toErrorShape } from '../../src/tools/spans.js';
|
|
3
|
-
describe('SpanRecorder', () => {
|
|
4
|
-
it('records a span per timed phase, in order', async () => {
|
|
5
|
-
const rec = new SpanRecorder();
|
|
6
|
-
const v = await rec.time('a', async () => 41 + 1);
|
|
7
|
-
await rec.time('b', async () => undefined);
|
|
8
|
-
expect(v).toBe(42);
|
|
9
|
-
const spans = rec.list();
|
|
10
|
-
expect(spans.map((s) => s.phase)).toEqual(['a', 'b']);
|
|
11
|
-
expect(spans.every((s) => typeof s.ms === 'number' && s.ms >= 0)).toBe(true);
|
|
12
|
-
});
|
|
13
|
-
it('records a span even when the timed fn throws', async () => {
|
|
14
|
-
const rec = new SpanRecorder();
|
|
15
|
-
await expect(rec.time('boom', async () => {
|
|
16
|
-
throw new Error('x');
|
|
17
|
-
})).rejects.toThrow('x');
|
|
18
|
-
expect(rec.list().map((s) => s.phase)).toEqual(['boom']);
|
|
19
|
-
});
|
|
20
|
-
it('add() appends a manual span; list() returns a copy', () => {
|
|
21
|
-
const rec = new SpanRecorder();
|
|
22
|
-
rec.add('lock_wait', 5);
|
|
23
|
-
const first = rec.list();
|
|
24
|
-
first.push({ phase: 'mutated', ms: 0 });
|
|
25
|
-
expect(rec.list().map((s) => s.phase)).toEqual(['lock_wait']);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
describe('toErrorShape', () => {
|
|
29
|
-
it('maps an Error to message + stack', () => {
|
|
30
|
-
const shape = toErrorShape(new Error('nope'));
|
|
31
|
-
expect(shape.message).toBe('nope');
|
|
32
|
-
expect(typeof shape.stack).toBe('string');
|
|
33
|
-
});
|
|
34
|
-
it('stringifies a non-Error', () => {
|
|
35
|
-
expect(toErrorShape('bad').message).toBe('bad');
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
describe('summarizeResult', () => {
|
|
39
|
-
it('keeps a preview-sized image blob so it can be rendered', () => {
|
|
40
|
-
const img = 'A'.repeat(5000); // well under the image cap
|
|
41
|
-
const out = summarizeResult({
|
|
42
|
-
content: [{ type: 'image', data: img, mimeType: 'image/webp' }]
|
|
43
|
-
});
|
|
44
|
-
expect(out.content[0].data).toBe(img);
|
|
45
|
-
expect(out.content[0].mimeType).toBe('image/webp');
|
|
46
|
-
});
|
|
47
|
-
it('drops an oversized image blob to a marker', () => {
|
|
48
|
-
const huge = 'A'.repeat(200_001);
|
|
49
|
-
const out = summarizeResult({
|
|
50
|
-
content: [{ type: 'image', data: huge, mimeType: 'image/png' }]
|
|
51
|
-
});
|
|
52
|
-
expect(out.content[0].data).toBe('<200001 base64 chars omitted>');
|
|
53
|
-
});
|
|
54
|
-
it('drops a large non-image blob to a marker', () => {
|
|
55
|
-
const blob = 'A'.repeat(5000);
|
|
56
|
-
const out = summarizeResult({
|
|
57
|
-
content: [{ type: 'resource', data: blob, mimeType: 'application/pdf' }]
|
|
58
|
-
});
|
|
59
|
-
expect(out.content[0].data).toBe('<5000 base64 chars omitted>');
|
|
60
|
-
});
|
|
61
|
-
it('passes small text content through untouched', () => {
|
|
62
|
-
const result = {
|
|
63
|
-
content: [{ type: 'text', text: 'https://localhost/r/abc' }]
|
|
64
|
-
};
|
|
65
|
-
expect(summarizeResult(result)).toEqual(result);
|
|
66
|
-
});
|
|
67
|
-
it('returns non-result values as-is', () => {
|
|
68
|
-
expect(summarizeResult(undefined)).toBeUndefined();
|
|
69
|
-
expect(summarizeResult('plain')).toBe('plain');
|
|
70
|
-
expect(summarizeResult({ nope: 1 })).toEqual({ nope: 1 });
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
describe('NOOP_TELEMETRY_SINK', () => {
|
|
74
|
-
it('accepts a report silently', () => {
|
|
75
|
-
const report = {
|
|
76
|
-
tool: 'edit',
|
|
77
|
-
succeeded: true,
|
|
78
|
-
totalMs: 1,
|
|
79
|
-
spans: []
|
|
80
|
-
};
|
|
81
|
-
expect(() => NOOP_TELEMETRY_SINK.record(report)).not.toThrow();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
//# sourceMappingURL=spans.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spans.test.js","sourceRoot":"","sources":["../../../../test/tools/spans.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect } from 'vitest';\nimport {\n SpanRecorder,\n NOOP_TELEMETRY_SINK,\n summarizeResult,\n toErrorShape,\n type ToolCallReport\n} from '../../src/tools/spans.js';\n\ndescribe('SpanRecorder', () => {\n it('records a span per timed phase, in order', async () => {\n const rec = new SpanRecorder();\n const v = await rec.time('a', async () => 41 + 1);\n await rec.time('b', async () => undefined);\n expect(v).toBe(42);\n const spans = rec.list();\n expect(spans.map((s) => s.phase)).toEqual(['a', 'b']);\n expect(spans.every((s) => typeof s.ms === 'number' && s.ms >= 0)).toBe(\n true\n );\n });\n\n it('records a span even when the timed fn throws', async () => {\n const rec = new SpanRecorder();\n await expect(\n rec.time('boom', async () => {\n throw new Error('x');\n })\n ).rejects.toThrow('x');\n expect(rec.list().map((s) => s.phase)).toEqual(['boom']);\n });\n\n it('add() appends a manual span; list() returns a copy', () => {\n const rec = new SpanRecorder();\n rec.add('lock_wait', 5);\n const first = rec.list();\n first.push({ phase: 'mutated', ms: 0 });\n expect(rec.list().map((s) => s.phase)).toEqual(['lock_wait']);\n });\n});\n\ndescribe('toErrorShape', () => {\n it('maps an Error to message + stack', () => {\n const shape = toErrorShape(new Error('nope'));\n expect(shape.message).toBe('nope');\n expect(typeof shape.stack).toBe('string');\n });\n it('stringifies a non-Error', () => {\n expect(toErrorShape('bad').message).toBe('bad');\n });\n});\n\ndescribe('summarizeResult', () => {\n it('keeps a preview-sized image blob so it can be rendered', () => {\n const img = 'A'.repeat(5000); // well under the image cap\n const out = summarizeResult({\n content: [{ type: 'image', data: img, mimeType: 'image/webp' }]\n }) as { content: Array<{ type: string; data: string; mimeType: string }> };\n expect(out.content[0].data).toBe(img);\n expect(out.content[0].mimeType).toBe('image/webp');\n });\n\n it('drops an oversized image blob to a marker', () => {\n const huge = 'A'.repeat(200_001);\n const out = summarizeResult({\n content: [{ type: 'image', data: huge, mimeType: 'image/png' }]\n }) as { content: Array<{ data: string }> };\n expect(out.content[0].data).toBe('<200001 base64 chars omitted>');\n });\n\n it('drops a large non-image blob to a marker', () => {\n const blob = 'A'.repeat(5000);\n const out = summarizeResult({\n content: [{ type: 'resource', data: blob, mimeType: 'application/pdf' }]\n }) as { content: Array<{ data: string }> };\n expect(out.content[0].data).toBe('<5000 base64 chars omitted>');\n });\n\n it('passes small text content through untouched', () => {\n const result = {\n content: [{ type: 'text', text: 'https://localhost/r/abc' }]\n };\n expect(summarizeResult(result)).toEqual(result);\n });\n\n it('returns non-result values as-is', () => {\n expect(summarizeResult(undefined)).toBeUndefined();\n expect(summarizeResult('plain')).toBe('plain');\n expect(summarizeResult({ nope: 1 })).toEqual({ nope: 1 });\n });\n});\n\ndescribe('NOOP_TELEMETRY_SINK', () => {\n it('accepts a report silently', () => {\n const report: ToolCallReport = {\n tool: 'edit',\n succeeded: true,\n totalMs: 1,\n spans: []\n };\n expect(() => NOOP_TELEMETRY_SINK.record(report)).not.toThrow();\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"broadcaster.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/broadcaster.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { SseBroadcaster } from '../../src/viewer/broadcaster.js';
|
|
3
|
-
function fakeRes() {
|
|
4
|
-
const written = [];
|
|
5
|
-
const closeCbs = [];
|
|
6
|
-
return {
|
|
7
|
-
written,
|
|
8
|
-
writeHead: vi.fn(),
|
|
9
|
-
write: vi.fn((chunk) => {
|
|
10
|
-
written.push(chunk);
|
|
11
|
-
return true;
|
|
12
|
-
}),
|
|
13
|
-
end: vi.fn(() => {
|
|
14
|
-
for (const cb of closeCbs)
|
|
15
|
-
cb();
|
|
16
|
-
}),
|
|
17
|
-
on: vi.fn((evt, cb) => {
|
|
18
|
-
if (evt === 'close')
|
|
19
|
-
closeCbs.push(cb);
|
|
20
|
-
})
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
describe('SseBroadcaster', () => {
|
|
24
|
-
it('subscribe writes SSE headers + initial comment', () => {
|
|
25
|
-
const b = new SseBroadcaster();
|
|
26
|
-
const res = fakeRes();
|
|
27
|
-
b.subscribe('root_abc', res);
|
|
28
|
-
expect(res.writeHead).toHaveBeenCalledWith(200, expect.objectContaining({ 'content-type': 'text/event-stream' }));
|
|
29
|
-
expect(res.written.some((s) => s.startsWith(':'))).toBe(true); // ping comment
|
|
30
|
-
});
|
|
31
|
-
it('broadcast sends `data: { revision, rootRevision }\\n\\n` to all subscribers of that root', () => {
|
|
32
|
-
const b = new SseBroadcaster();
|
|
33
|
-
const r1 = fakeRes();
|
|
34
|
-
const r2 = fakeRes();
|
|
35
|
-
const r3 = fakeRes();
|
|
36
|
-
b.subscribe('root_abc', r1);
|
|
37
|
-
b.subscribe('root_abc', r2);
|
|
38
|
-
b.subscribe('root_xyz', r3);
|
|
39
|
-
b.broadcast({ revision: 'rev_1', rootRevision: 'root_abc' });
|
|
40
|
-
expect(r1.written.some((s) => s.includes('rev_1'))).toBe(true);
|
|
41
|
-
expect(r2.written.some((s) => s.includes('rev_1'))).toBe(true);
|
|
42
|
-
expect(r3.written.some((s) => s.includes('rev_1'))).toBe(false);
|
|
43
|
-
});
|
|
44
|
-
it('removes subscribers when their response closes', () => {
|
|
45
|
-
const b = new SseBroadcaster();
|
|
46
|
-
const res = fakeRes();
|
|
47
|
-
b.subscribe('root_abc', res);
|
|
48
|
-
expect(b.subscriberCount('root_abc')).toBe(1);
|
|
49
|
-
res.end(); // triggers "close" callback
|
|
50
|
-
expect(b.subscriberCount('root_abc')).toBe(0);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
//# sourceMappingURL=broadcaster.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"broadcaster.test.js","sourceRoot":"","sources":["../../../../test/viewer/broadcaster.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi } from 'vitest';\nimport { SseBroadcaster } from '../../src/viewer/broadcaster.js';\n\ninterface FakeResponse {\n written: string[];\n writeHead: ReturnType<typeof vi.fn>;\n write: ReturnType<typeof vi.fn>;\n end: ReturnType<typeof vi.fn>;\n on: ReturnType<typeof vi.fn>;\n}\n\nfunction fakeRes(): FakeResponse {\n const written: string[] = [];\n const closeCbs: Array<() => void> = [];\n return {\n written,\n writeHead: vi.fn(),\n write: vi.fn((chunk: string) => {\n written.push(chunk);\n return true;\n }),\n end: vi.fn(() => {\n for (const cb of closeCbs) cb();\n }),\n on: vi.fn((evt: string, cb: () => void) => {\n if (evt === 'close') closeCbs.push(cb);\n })\n };\n}\n\ndescribe('SseBroadcaster', () => {\n it('subscribe writes SSE headers + initial comment', () => {\n const b = new SseBroadcaster();\n const res = fakeRes();\n b.subscribe('root_abc', res as never);\n expect(res.writeHead).toHaveBeenCalledWith(\n 200,\n expect.objectContaining({ 'content-type': 'text/event-stream' })\n );\n expect(res.written.some((s) => s.startsWith(':'))).toBe(true); // ping comment\n });\n\n it('broadcast sends `data: { revision, rootRevision }\\\\n\\\\n` to all subscribers of that root', () => {\n const b = new SseBroadcaster();\n const r1 = fakeRes();\n const r2 = fakeRes();\n const r3 = fakeRes();\n b.subscribe('root_abc', r1 as never);\n b.subscribe('root_abc', r2 as never);\n b.subscribe('root_xyz', r3 as never);\n b.broadcast({ revision: 'rev_1', rootRevision: 'root_abc' });\n expect(r1.written.some((s) => s.includes('rev_1'))).toBe(true);\n expect(r2.written.some((s) => s.includes('rev_1'))).toBe(true);\n expect(r3.written.some((s) => s.includes('rev_1'))).toBe(false);\n });\n\n it('removes subscribers when their response closes', () => {\n const b = new SseBroadcaster();\n const res = fakeRes();\n b.subscribe('root_abc', res as never);\n expect(b.subscriberCount('root_abc')).toBe(1);\n res.end(); // triggers \"close\" callback\n expect(b.subscriberCount('root_abc')).toBe(0);\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cesdk-cdn.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/cesdk-cdn.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { cesdkCdnUrl, installedCesdkVersion } from '../../src/viewer/cesdk-cdn.js';
|
|
3
|
-
describe('cesdkCdnUrl', () => {
|
|
4
|
-
it('uses the plain release path for GA versions', () => {
|
|
5
|
-
expect(cesdkCdnUrl('1.77.0')).toBe('https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0/index.js');
|
|
6
|
-
});
|
|
7
|
-
it('uses the plain release path for rc versions', () => {
|
|
8
|
-
expect(cesdkCdnUrl('1.77.0-rc.4')).toBe('https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0-rc.4/index.js');
|
|
9
|
-
});
|
|
10
|
-
it('uses the /nightlies/ path (version repeated) for nightly versions', () => {
|
|
11
|
-
expect(cesdkCdnUrl('1.78.0-nightly.20260703')).toBe('https://cdn.img.ly/nightlies/1.78.0-nightly.20260703/packages/imgly/cesdk-js/1.78.0-nightly.20260703/index.js');
|
|
12
|
-
});
|
|
13
|
-
});
|
|
14
|
-
describe('installedCesdkVersion', () => {
|
|
15
|
-
it('returns the exact pinned version of the installed engine', () => {
|
|
16
|
-
expect(installedCesdkVersion()).toMatch(/^\d+\.\d+\.\d+(-(rc|nightly)\.\w+)?$/);
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
//# sourceMappingURL=cesdk-cdn.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cesdk-cdn.test.js","sourceRoot":"","sources":["../../../../test/viewer/cesdk-cdn.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AAEvC,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAChC,4DAA4D,CAC7D,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CACrC,iEAAiE,CAClE,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI,CACjD,+GAA+G,CAChH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,qBAAqB,EAAE,CAAC,CAAC,OAAO,CACrC,sCAAsC,CACvC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport {\n cesdkCdnUrl,\n installedCesdkVersion\n} from '../../src/viewer/cesdk-cdn.js';\n\ndescribe('cesdkCdnUrl', () => {\n it('uses the plain release path for GA versions', () => {\n expect(cesdkCdnUrl('1.77.0')).toBe(\n 'https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0/index.js'\n );\n });\n it('uses the plain release path for rc versions', () => {\n expect(cesdkCdnUrl('1.77.0-rc.4')).toBe(\n 'https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0-rc.4/index.js'\n );\n });\n it('uses the /nightlies/ path (version repeated) for nightly versions', () => {\n expect(cesdkCdnUrl('1.78.0-nightly.20260703')).toBe(\n 'https://cdn.img.ly/nightlies/1.78.0-nightly.20260703/packages/imgly/cesdk-js/1.78.0-nightly.20260703/index.js'\n );\n });\n});\n\ndescribe('installedCesdkVersion', () => {\n it('returns the exact pinned version of the installed engine', () => {\n expect(installedCesdkVersion()).toMatch(\n /^\\d+\\.\\d+\\.\\d+(-(rc|nightly)\\.\\w+)?$/\n );\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-route.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/config-route.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import request from 'supertest';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { createViewerRouter } from '../../src/viewer/router.js';
|
|
5
|
-
function fakeDeps() {
|
|
6
|
-
return { store: {}, fs: {}, broadcaster: {} };
|
|
7
|
-
}
|
|
8
|
-
describe('GET /api/config', () => {
|
|
9
|
-
it('serves the explicit cesdkEngineUrl when provided', async () => {
|
|
10
|
-
const app = express();
|
|
11
|
-
app.use(createViewerRouter({
|
|
12
|
-
...fakeDeps(),
|
|
13
|
-
cesdkLicense: 'lic',
|
|
14
|
-
cesdkEngineUrl: 'https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js'
|
|
15
|
-
}));
|
|
16
|
-
const res = await request(app).get('/api/config');
|
|
17
|
-
expect(res.status).toBe(200);
|
|
18
|
-
expect(res.body.cesdkEngineUrl).toBe('https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js');
|
|
19
|
-
expect(res.body.license).toBe('lic');
|
|
20
|
-
});
|
|
21
|
-
it('defaults cesdkEngineUrl to the installed engine version', async () => {
|
|
22
|
-
const app = express();
|
|
23
|
-
app.use(createViewerRouter({ ...fakeDeps() }));
|
|
24
|
-
const res = await request(app).get('/api/config');
|
|
25
|
-
expect(res.body.cesdkEngineUrl).toMatch(/^https:\/\/cdn\.img\.ly\/(nightlies\/[^/]+\/)?packages\/imgly\/cesdk-js\/[^/]+\/index\.js$/);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
//# sourceMappingURL=config-route.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-route.test.js","sourceRoot":"","sources":["../../../../test/viewer/config-route.test.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,OAAO,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,SAAS,QAAQ;IACf,OAAO,EAAE,KAAK,EAAE,EAAW,EAAE,EAAE,EAAE,EAAW,EAAE,WAAW,EAAE,EAAW,EAAE,CAAC;AAC3E,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CACL,kBAAkB,CAAC;YACjB,GAAG,QAAQ,EAAE;YACb,YAAY,EAAE,KAAK;YACnB,cAAc,EACZ,2DAA2D;SAC9D,CAAC,CACH,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAClC,2DAA2D,CAC5D,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,GAAG,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,CACrC,4FAA4F,CAC7F,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import express from 'express';\nimport request from 'supertest';\nimport { describe, expect, it } from 'vitest';\nimport { createViewerRouter } from '../../src/viewer/router.js';\n\nfunction fakeDeps() {\n return { store: {} as never, fs: {} as never, broadcaster: {} as never };\n}\n\ndescribe('GET /api/config', () => {\n it('serves the explicit cesdkEngineUrl when provided', async () => {\n const app = express();\n app.use(\n createViewerRouter({\n ...fakeDeps(),\n cesdkLicense: 'lic',\n cesdkEngineUrl:\n 'https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js'\n })\n );\n const res = await request(app).get('/api/config');\n expect(res.status).toBe(200);\n expect(res.body.cesdkEngineUrl).toBe(\n 'https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js'\n );\n expect(res.body.license).toBe('lic');\n });\n\n it('defaults cesdkEngineUrl to the installed engine version', async () => {\n const app = express();\n app.use(createViewerRouter({ ...fakeDeps() }));\n const res = await request(app).get('/api/config');\n expect(res.body.cesdkEngineUrl).toMatch(\n /^https:\\/\\/cdn\\.img\\.ly\\/(nightlies\\/[^/]+\\/)?packages\\/imgly\\/cesdk-js\\/[^/]+\\/index\\.js$/\n );\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resource-route.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/resource-route.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import express from 'express';
|
|
5
|
-
import request from 'supertest';
|
|
6
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
7
|
-
import { createResourceRoute } from '../../src/viewer/resource-route.js';
|
|
8
|
-
import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
|
|
9
|
-
describe('resource route — object-store backend', () => {
|
|
10
|
-
function makeApp() {
|
|
11
|
-
const fs = new InMemoryWorkspaceFS();
|
|
12
|
-
const app = express();
|
|
13
|
-
app.use(createResourceRoute({ fs, workspaceRoot: '' }));
|
|
14
|
-
return { app, fs };
|
|
15
|
-
}
|
|
16
|
-
it('serves a file under assets/ with its content type', async () => {
|
|
17
|
-
const { app, fs } = makeApp();
|
|
18
|
-
await fs.writeFile('assets/9f2a1c.png', new Uint8Array([1, 2, 3, 4]));
|
|
19
|
-
const res = await request(app).get('/r/assets/9f2a1c.png');
|
|
20
|
-
expect(res.status).toBe(200);
|
|
21
|
-
expect(res.headers['content-type']).toBe('image/png');
|
|
22
|
-
expect(res.headers['content-length']).toBe('4');
|
|
23
|
-
});
|
|
24
|
-
it('serves a file under exports/', async () => {
|
|
25
|
-
const { app, fs } = makeApp();
|
|
26
|
-
await fs.writeFile('exports/ab/cdef012345/pdf.pdf', new Uint8Array([5, 6, 7]));
|
|
27
|
-
const res = await request(app).get('/r/exports/ab/cdef012345/pdf.pdf');
|
|
28
|
-
expect(res.status).toBe(200);
|
|
29
|
-
expect(res.headers['content-type']).toBe('application/pdf');
|
|
30
|
-
});
|
|
31
|
-
it('404s a missing file', async () => {
|
|
32
|
-
const { app } = makeApp();
|
|
33
|
-
const res = await request(app).get('/r/assets/missing.png');
|
|
34
|
-
expect(res.status).toBe(404);
|
|
35
|
-
});
|
|
36
|
-
it('404s a path outside the assets/ + exports/ allowlist', async () => {
|
|
37
|
-
const { app, fs } = makeApp();
|
|
38
|
-
await fs.writeFile('objects/ab/cd.scene', new Uint8Array([9]));
|
|
39
|
-
const res = await request(app).get('/r/objects/ab/cd.scene');
|
|
40
|
-
expect(res.status).toBe(404);
|
|
41
|
-
});
|
|
42
|
-
it('404s a traversal attempt', async () => {
|
|
43
|
-
const { app } = makeApp();
|
|
44
|
-
const res = await request(app).get('/r/assets/%2e%2e/%2e%2e/objects/secret.scene');
|
|
45
|
-
expect(res.status).toBe(404);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('resource route — disk backend (range support)', () => {
|
|
49
|
-
let dir = '';
|
|
50
|
-
afterEach(async () => {
|
|
51
|
-
if (dir)
|
|
52
|
-
await rm(dir, { recursive: true, force: true });
|
|
53
|
-
});
|
|
54
|
-
it('streams from disk and honours Range requests', async () => {
|
|
55
|
-
dir = await mkdtemp(join(tmpdir(), 'resource-route-'));
|
|
56
|
-
await mkdir(join(dir, 'assets'), { recursive: true });
|
|
57
|
-
await writeFile(join(dir, 'assets/v.bin'), Buffer.from([10, 11, 12, 13, 14, 15]));
|
|
58
|
-
const app = express();
|
|
59
|
-
app.use(createResourceRoute({ fs: new InMemoryWorkspaceFS(), workspaceRoot: dir }));
|
|
60
|
-
const full = await request(app).get('/r/assets/v.bin');
|
|
61
|
-
expect(full.status).toBe(200);
|
|
62
|
-
expect(full.headers['accept-ranges']).toBe('bytes');
|
|
63
|
-
const partial = await request(app)
|
|
64
|
-
.get('/r/assets/v.bin')
|
|
65
|
-
.set('Range', 'bytes=0-2');
|
|
66
|
-
expect(partial.status).toBe(206);
|
|
67
|
-
expect(partial.headers['content-length']).toBe('3');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
//# sourceMappingURL=resource-route.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resource-route.test.js","sourceRoot":"","sources":["../../../../test/viewer/resource-route.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport express from 'express';\nimport request from 'supertest';\nimport { afterEach, describe, expect, it } from 'vitest';\nimport { createResourceRoute } from '../../src/viewer/resource-route.js';\nimport { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';\n\ndescribe('resource route — object-store backend', () => {\n function makeApp() {\n const fs = new InMemoryWorkspaceFS();\n const app = express();\n app.use(createResourceRoute({ fs, workspaceRoot: '' }));\n return { app, fs };\n }\n\n it('serves a file under assets/ with its content type', async () => {\n const { app, fs } = makeApp();\n await fs.writeFile('assets/9f2a1c.png', new Uint8Array([1, 2, 3, 4]));\n const res = await request(app).get('/r/assets/9f2a1c.png');\n expect(res.status).toBe(200);\n expect(res.headers['content-type']).toBe('image/png');\n expect(res.headers['content-length']).toBe('4');\n });\n\n it('serves a file under exports/', async () => {\n const { app, fs } = makeApp();\n await fs.writeFile(\n 'exports/ab/cdef012345/pdf.pdf',\n new Uint8Array([5, 6, 7])\n );\n const res = await request(app).get('/r/exports/ab/cdef012345/pdf.pdf');\n expect(res.status).toBe(200);\n expect(res.headers['content-type']).toBe('application/pdf');\n });\n\n it('404s a missing file', async () => {\n const { app } = makeApp();\n const res = await request(app).get('/r/assets/missing.png');\n expect(res.status).toBe(404);\n });\n\n it('404s a path outside the assets/ + exports/ allowlist', async () => {\n const { app, fs } = makeApp();\n await fs.writeFile('objects/ab/cd.scene', new Uint8Array([9]));\n const res = await request(app).get('/r/objects/ab/cd.scene');\n expect(res.status).toBe(404);\n });\n\n it('404s a traversal attempt', async () => {\n const { app } = makeApp();\n const res = await request(app).get(\n '/r/assets/%2e%2e/%2e%2e/objects/secret.scene'\n );\n expect(res.status).toBe(404);\n });\n});\n\ndescribe('resource route — disk backend (range support)', () => {\n let dir = '';\n afterEach(async () => {\n if (dir) await rm(dir, { recursive: true, force: true });\n });\n\n it('streams from disk and honours Range requests', async () => {\n dir = await mkdtemp(join(tmpdir(), 'resource-route-'));\n await mkdir(join(dir, 'assets'), { recursive: true });\n await writeFile(\n join(dir, 'assets/v.bin'),\n Buffer.from([10, 11, 12, 13, 14, 15])\n );\n const app = express();\n app.use(\n createResourceRoute({ fs: new InMemoryWorkspaceFS(), workspaceRoot: dir })\n );\n\n const full = await request(app).get('/r/assets/v.bin');\n expect(full.status).toBe(200);\n expect(full.headers['accept-ranges']).toBe('bytes');\n\n const partial = await request(app)\n .get('/r/assets/v.bin')\n .set('Range', 'bytes=0-2');\n expect(partial.status).toBe(206);\n expect(partial.headers['content-length']).toBe('3');\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/router.test.ts"],"names":[],"mappings":""}
|