@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,338 +0,0 @@
|
|
|
1
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
-
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
|
-
import request from 'supertest';
|
|
5
|
-
import { createCodesignHttpServer } from '../../src/http/server.js';
|
|
6
|
-
import { WorkspaceAuthError } from '../../src/http/workspace-auth.js';
|
|
7
|
-
import { ScopedWorkspaceFS } from '../../src/workspace/scoped.js';
|
|
8
|
-
import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
|
|
9
|
-
const FIXTURES = {
|
|
10
|
-
'docs/alpha/SKILL.md': '---\nname: alpha\ndescription: First.\n---\n# Alpha'
|
|
11
|
-
};
|
|
12
|
-
let nextEngineId = 0;
|
|
13
|
-
function makeServer() {
|
|
14
|
-
return createCodesignHttpServer({
|
|
15
|
-
assets: FIXTURES,
|
|
16
|
-
maxSessions: 5,
|
|
17
|
-
idleTimeoutMs: 60_000,
|
|
18
|
-
// Replace the real CE.SDK headless bootstrap with a deterministic fake so
|
|
19
|
-
// the integration test runs in milliseconds, not seconds. The fake engine
|
|
20
|
-
// owns its own scriptsRun array, asserting per-session isolation.
|
|
21
|
-
createSession: async () => {
|
|
22
|
-
const engine = { id: nextEngineId++, scriptsRun: [] };
|
|
23
|
-
const tools = [
|
|
24
|
-
{
|
|
25
|
-
name: 'echo',
|
|
26
|
-
description: 'Echo arg back',
|
|
27
|
-
inputSchema: {
|
|
28
|
-
type: 'object',
|
|
29
|
-
properties: { msg: { type: 'string' } },
|
|
30
|
-
required: ['msg']
|
|
31
|
-
},
|
|
32
|
-
call: async (args) => {
|
|
33
|
-
const msg = args.msg;
|
|
34
|
-
return { content: [{ type: 'text', text: msg }] };
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
// Records the input on this session's engine and reads back the
|
|
39
|
-
// list of all scripts seen so far. Used by the isolation test to
|
|
40
|
-
// prove two sessions don't share engine state.
|
|
41
|
-
name: 'engine_record',
|
|
42
|
-
description: 'Record a string into the session engine, return all recorded so far',
|
|
43
|
-
inputSchema: {
|
|
44
|
-
type: 'object',
|
|
45
|
-
properties: { msg: { type: 'string' } },
|
|
46
|
-
required: ['msg']
|
|
47
|
-
},
|
|
48
|
-
call: async (args) => {
|
|
49
|
-
const msg = args.msg;
|
|
50
|
-
engine.scriptsRun.push(msg);
|
|
51
|
-
return {
|
|
52
|
-
content: [
|
|
53
|
-
{ type: 'text', text: engine.scriptsRun.join(',') }
|
|
54
|
-
]
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
];
|
|
59
|
-
return { engine, tools };
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
describe('createCodesignHttpServer', () => {
|
|
64
|
-
let app;
|
|
65
|
-
let baseUrl;
|
|
66
|
-
let server;
|
|
67
|
-
beforeEach(async () => {
|
|
68
|
-
nextEngineId = 0;
|
|
69
|
-
app = await makeServer();
|
|
70
|
-
await new Promise((resolve) => {
|
|
71
|
-
server = app.listen(0, '127.0.0.1', resolve);
|
|
72
|
-
});
|
|
73
|
-
const addr = server.address();
|
|
74
|
-
baseUrl = `http://127.0.0.1:${addr.port}/mcp`;
|
|
75
|
-
});
|
|
76
|
-
afterEach(async () => {
|
|
77
|
-
await new Promise((resolve) => server.close(() => resolve()));
|
|
78
|
-
await app.shutdown();
|
|
79
|
-
});
|
|
80
|
-
async function connect() {
|
|
81
|
-
const transport = new StreamableHTTPClientTransport(new URL(baseUrl));
|
|
82
|
-
const client = new Client({ name: 'test', version: '0' });
|
|
83
|
-
await client.connect(transport);
|
|
84
|
-
return { client, sessionId: transport.sessionId };
|
|
85
|
-
}
|
|
86
|
-
it('initialize creates a new session and returns its id', async () => {
|
|
87
|
-
const { client, sessionId } = await connect();
|
|
88
|
-
expect(sessionId).toMatch(/[0-9a-f-]{36}/i); // uuid shape
|
|
89
|
-
expect(app.sessions.size).toBe(1);
|
|
90
|
-
await client.close();
|
|
91
|
-
});
|
|
92
|
-
it("listResources returns the asset bundle's skill files for that session", async () => {
|
|
93
|
-
const { client } = await connect();
|
|
94
|
-
const list = await client.listResources();
|
|
95
|
-
expect(list.resources.map((r) => r.uri)).toEqual([
|
|
96
|
-
'codesign://docs/alpha/SKILL.md'
|
|
97
|
-
]);
|
|
98
|
-
await client.close();
|
|
99
|
-
});
|
|
100
|
-
it("callTool routes to the session's own engine", async () => {
|
|
101
|
-
const { client } = await connect();
|
|
102
|
-
const result = await client.callTool({
|
|
103
|
-
name: 'echo',
|
|
104
|
-
arguments: { msg: 'hi' }
|
|
105
|
-
});
|
|
106
|
-
expect(result.content).toEqual([{ type: 'text', text: 'hi' }]);
|
|
107
|
-
await client.close();
|
|
108
|
-
});
|
|
109
|
-
it('two parallel clients get distinct sessions and engines', async () => {
|
|
110
|
-
const a = await connect();
|
|
111
|
-
const b = await connect();
|
|
112
|
-
expect(a.sessionId).toBeDefined();
|
|
113
|
-
expect(b.sessionId).toBeDefined();
|
|
114
|
-
expect(a.sessionId).not.toBe(b.sessionId);
|
|
115
|
-
expect(app.sessions.size).toBe(2);
|
|
116
|
-
await a.client.close();
|
|
117
|
-
await b.client.close();
|
|
118
|
-
});
|
|
119
|
-
it('session cap: returns 503 when maxSessions is reached', async () => {
|
|
120
|
-
await app.shutdown(); // dismiss the default 5-session app
|
|
121
|
-
app = await createCodesignHttpServer({
|
|
122
|
-
assets: FIXTURES,
|
|
123
|
-
maxSessions: 2,
|
|
124
|
-
idleTimeoutMs: 60_000,
|
|
125
|
-
createSession: async () => ({
|
|
126
|
-
engine: { id: nextEngineId++, scriptsRun: [] },
|
|
127
|
-
tools: []
|
|
128
|
-
})
|
|
129
|
-
});
|
|
130
|
-
await new Promise((resolve) => server.close(() => resolve()));
|
|
131
|
-
await new Promise((resolve) => {
|
|
132
|
-
server = app.listen(0, '127.0.0.1', resolve);
|
|
133
|
-
});
|
|
134
|
-
const addr = server.address();
|
|
135
|
-
baseUrl = `http://127.0.0.1:${addr.port}/mcp`;
|
|
136
|
-
const a = await connect();
|
|
137
|
-
const b = await connect();
|
|
138
|
-
// 3rd init request should be rejected at the HTTP layer with 503.
|
|
139
|
-
const initBody = {
|
|
140
|
-
jsonrpc: '2.0',
|
|
141
|
-
id: 1,
|
|
142
|
-
method: 'initialize',
|
|
143
|
-
params: {
|
|
144
|
-
protocolVersion: '2025-03-26',
|
|
145
|
-
capabilities: {},
|
|
146
|
-
clientInfo: { name: 't', version: '0' }
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
const r = await fetch(baseUrl, {
|
|
150
|
-
method: 'POST',
|
|
151
|
-
headers: {
|
|
152
|
-
'content-type': 'application/json',
|
|
153
|
-
accept: 'application/json, text/event-stream'
|
|
154
|
-
},
|
|
155
|
-
body: JSON.stringify(initBody)
|
|
156
|
-
});
|
|
157
|
-
expect(r.status).toBe(503);
|
|
158
|
-
expect(r.headers.get('retry-after')).toBe('30');
|
|
159
|
-
const json = (await r.json());
|
|
160
|
-
expect(json.error.code).toBe(-32000);
|
|
161
|
-
expect(json.error.message).toMatch(/session cap/i);
|
|
162
|
-
await a.client.close();
|
|
163
|
-
await b.client.close();
|
|
164
|
-
});
|
|
165
|
-
it('unknown session id: returns 404 with -32001', async () => {
|
|
166
|
-
const r = await fetch(baseUrl, {
|
|
167
|
-
method: 'POST',
|
|
168
|
-
headers: {
|
|
169
|
-
'content-type': 'application/json',
|
|
170
|
-
accept: 'application/json, text/event-stream',
|
|
171
|
-
'mcp-session-id': '00000000-0000-0000-0000-000000000000'
|
|
172
|
-
},
|
|
173
|
-
body: JSON.stringify({
|
|
174
|
-
jsonrpc: '2.0',
|
|
175
|
-
id: 1,
|
|
176
|
-
method: 'tools/list',
|
|
177
|
-
params: {}
|
|
178
|
-
})
|
|
179
|
-
});
|
|
180
|
-
expect(r.status).toBe(404);
|
|
181
|
-
const json = (await r.json());
|
|
182
|
-
expect(json.error.code).toBe(-32001);
|
|
183
|
-
expect(json.error.message).toMatch(/unknown session/);
|
|
184
|
-
});
|
|
185
|
-
it('graceful DELETE /mcp terminates the session and frees its slot', async () => {
|
|
186
|
-
const { sessionId } = await connect();
|
|
187
|
-
expect(sessionId).toBeDefined();
|
|
188
|
-
expect(app.sessions.size).toBe(1);
|
|
189
|
-
const r = await fetch(baseUrl, {
|
|
190
|
-
method: 'DELETE',
|
|
191
|
-
headers: { 'mcp-session-id': sessionId }
|
|
192
|
-
});
|
|
193
|
-
expect(r.status).toBe(200);
|
|
194
|
-
// onsessionclosed → sessionMgr.delete: the slot (and its engine) is
|
|
195
|
-
// reclaimed immediately, not left squatting until idle eviction.
|
|
196
|
-
expect(app.sessions.size).toBe(0);
|
|
197
|
-
// The id is now unknown — a follow-up request 404s.
|
|
198
|
-
const followUp = await fetch(baseUrl, {
|
|
199
|
-
method: 'POST',
|
|
200
|
-
headers: {
|
|
201
|
-
'content-type': 'application/json',
|
|
202
|
-
accept: 'application/json, text/event-stream',
|
|
203
|
-
'mcp-session-id': sessionId
|
|
204
|
-
},
|
|
205
|
-
body: JSON.stringify({
|
|
206
|
-
jsonrpc: '2.0',
|
|
207
|
-
id: 1,
|
|
208
|
-
method: 'tools/list',
|
|
209
|
-
params: {}
|
|
210
|
-
})
|
|
211
|
-
});
|
|
212
|
-
expect(followUp.status).toBe(404);
|
|
213
|
-
});
|
|
214
|
-
it('auth middleware rejects requests with 401 when configured to', async () => {
|
|
215
|
-
await app.shutdown();
|
|
216
|
-
await new Promise((resolve) => server.close(() => resolve()));
|
|
217
|
-
app = await createCodesignHttpServer({
|
|
218
|
-
assets: FIXTURES,
|
|
219
|
-
maxSessions: 5,
|
|
220
|
-
idleTimeoutMs: 60_000,
|
|
221
|
-
createSession: async () => ({
|
|
222
|
-
engine: { id: nextEngineId++, scriptsRun: [] },
|
|
223
|
-
tools: []
|
|
224
|
-
}),
|
|
225
|
-
auth: (req, res, next) => {
|
|
226
|
-
if (req.header('authorization') !== 'Bearer testtoken') {
|
|
227
|
-
res.status(401).json({ error: 'unauthorized' });
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
next();
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
await new Promise((resolve) => {
|
|
234
|
-
server = app.listen(0, '127.0.0.1', resolve);
|
|
235
|
-
});
|
|
236
|
-
const addr = server.address();
|
|
237
|
-
baseUrl = `http://127.0.0.1:${addr.port}/mcp`;
|
|
238
|
-
const r = await fetch(baseUrl, {
|
|
239
|
-
method: 'POST',
|
|
240
|
-
headers: {
|
|
241
|
-
'content-type': 'application/json',
|
|
242
|
-
accept: 'application/json, text/event-stream'
|
|
243
|
-
},
|
|
244
|
-
body: JSON.stringify({
|
|
245
|
-
jsonrpc: '2.0',
|
|
246
|
-
id: 1,
|
|
247
|
-
method: 'initialize',
|
|
248
|
-
params: {}
|
|
249
|
-
})
|
|
250
|
-
});
|
|
251
|
-
expect(r.status).toBe(401);
|
|
252
|
-
});
|
|
253
|
-
it('engine state is isolated per session: mutation in one is invisible to the other', async () => {
|
|
254
|
-
const a = await connect();
|
|
255
|
-
const b = await connect();
|
|
256
|
-
// Record on a — only a should see it.
|
|
257
|
-
const aResult = await a.client.callTool({
|
|
258
|
-
name: 'engine_record',
|
|
259
|
-
arguments: { msg: 'from-a' }
|
|
260
|
-
});
|
|
261
|
-
expect(aResult.content).toEqual([{ type: 'text', text: 'from-a' }]);
|
|
262
|
-
// Record on b — should NOT include from-a.
|
|
263
|
-
const bResult = await b.client.callTool({
|
|
264
|
-
name: 'engine_record',
|
|
265
|
-
arguments: { msg: 'from-b' }
|
|
266
|
-
});
|
|
267
|
-
expect(bResult.content).toEqual([{ type: 'text', text: 'from-b' }]);
|
|
268
|
-
// Re-record on a — should append to a's history, still no b.
|
|
269
|
-
const aResult2 = await a.client.callTool({
|
|
270
|
-
name: 'engine_record',
|
|
271
|
-
arguments: { msg: 'again' }
|
|
272
|
-
});
|
|
273
|
-
expect(aResult2.content).toEqual([{ type: 'text', text: 'from-a,again' }]);
|
|
274
|
-
await a.client.close();
|
|
275
|
-
await b.client.close();
|
|
276
|
-
});
|
|
277
|
-
it('passes the resolved workspaceId to createSession on initialize', async () => {
|
|
278
|
-
const seen = [];
|
|
279
|
-
const testApp = await createCodesignHttpServer({
|
|
280
|
-
assets: {},
|
|
281
|
-
maxSessions: 4,
|
|
282
|
-
idleTimeoutMs: 60_000,
|
|
283
|
-
resolveWorkspaceId: (req) => req.header('x-workspace-id') ?? 'fallback',
|
|
284
|
-
createSession: async ({ workspaceId }) => {
|
|
285
|
-
seen.push(workspaceId);
|
|
286
|
-
return { engine: {}, tools: [] };
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
await request(testApp)
|
|
290
|
-
.post('/mcp')
|
|
291
|
-
.set('x-workspace-id', 'u/acme')
|
|
292
|
-
.set('content-type', 'application/json')
|
|
293
|
-
.send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });
|
|
294
|
-
expect(seen).toEqual(['u/acme']);
|
|
295
|
-
await testApp.shutdown();
|
|
296
|
-
});
|
|
297
|
-
it('returns 401 when resolveWorkspaceId throws WorkspaceAuthError', async () => {
|
|
298
|
-
const testApp = await createCodesignHttpServer({
|
|
299
|
-
assets: {},
|
|
300
|
-
maxSessions: 4,
|
|
301
|
-
idleTimeoutMs: 60_000,
|
|
302
|
-
resolveWorkspaceId: () => {
|
|
303
|
-
throw new WorkspaceAuthError('missing header');
|
|
304
|
-
},
|
|
305
|
-
createSession: async () => ({ engine: {}, tools: [] })
|
|
306
|
-
});
|
|
307
|
-
const res = await request(testApp)
|
|
308
|
-
.post('/mcp')
|
|
309
|
-
.set('content-type', 'application/json')
|
|
310
|
-
.send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });
|
|
311
|
-
expect(res.status).toBe(401);
|
|
312
|
-
expect(res.body.error.code).toBe(-32002);
|
|
313
|
-
expect(res.body.error.message).toBe('missing header');
|
|
314
|
-
await testApp.shutdown();
|
|
315
|
-
});
|
|
316
|
-
it('returns 400 (not a hang) when the resolved workspaceId is malformed', async () => {
|
|
317
|
-
const testApp = await createCodesignHttpServer({
|
|
318
|
-
assets: {},
|
|
319
|
-
maxSessions: 4,
|
|
320
|
-
idleTimeoutMs: 60_000,
|
|
321
|
-
// header mode-style: return an illegal id that ScopedWorkspaceFS will reject
|
|
322
|
-
resolveWorkspaceId: () => '../escape',
|
|
323
|
-
createSession: async ({ workspaceId }) => {
|
|
324
|
-
// mirror cli/http.ts: constructing the scoped fs validates the id
|
|
325
|
-
new ScopedWorkspaceFS(new InMemoryWorkspaceFS(), workspaceId);
|
|
326
|
-
return { engine: {}, tools: [] };
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
const res = await request(testApp)
|
|
330
|
-
.post('/mcp')
|
|
331
|
-
.set('content-type', 'application/json')
|
|
332
|
-
.send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });
|
|
333
|
-
expect(res.status).toBe(400);
|
|
334
|
-
expect(res.body.error.code).toBe(-32602); // invalid params
|
|
335
|
-
await testApp.shutdown();
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
//# sourceMappingURL=server.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server.test.js","sourceRoot":"","sources":["../../../../test/http/server.test.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AddressInfo } from 'node:net';\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport { afterEach, beforeEach, describe, expect, it } from 'vitest';\nimport request from 'supertest';\nimport { createCodesignHttpServer } from '../../src/http/server.js';\nimport { WorkspaceAuthError } from '../../src/http/workspace-auth.js';\nimport { ScopedWorkspaceFS } from '../../src/workspace/scoped.js';\nimport { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';\n\nconst FIXTURES = {\n 'docs/alpha/SKILL.md': '---\\nname: alpha\\ndescription: First.\\n---\\n# Alpha'\n};\n\ninterface FakeEngine {\n id: number;\n scriptsRun: string[];\n}\n\nlet nextEngineId = 0;\n\nfunction makeServer() {\n return createCodesignHttpServer({\n assets: FIXTURES,\n maxSessions: 5,\n idleTimeoutMs: 60_000,\n // Replace the real CE.SDK headless bootstrap with a deterministic fake so\n // the integration test runs in milliseconds, not seconds. The fake engine\n // owns its own scriptsRun array, asserting per-session isolation.\n createSession: async () => {\n const engine: FakeEngine = { id: nextEngineId++, scriptsRun: [] };\n const tools = [\n {\n name: 'echo',\n description: 'Echo arg back',\n inputSchema: {\n type: 'object',\n properties: { msg: { type: 'string' } },\n required: ['msg']\n },\n call: async (args: unknown) => {\n const msg = (args as { msg: string }).msg;\n return { content: [{ type: 'text' as const, text: msg }] };\n }\n },\n {\n // Records the input on this session's engine and reads back the\n // list of all scripts seen so far. Used by the isolation test to\n // prove two sessions don't share engine state.\n name: 'engine_record',\n description:\n 'Record a string into the session engine, return all recorded so far',\n inputSchema: {\n type: 'object',\n properties: { msg: { type: 'string' } },\n required: ['msg']\n },\n call: async (args: unknown) => {\n const msg = (args as { msg: string }).msg;\n engine.scriptsRun.push(msg);\n return {\n content: [\n { type: 'text' as const, text: engine.scriptsRun.join(',') }\n ]\n };\n }\n }\n ];\n return { engine, tools };\n }\n });\n}\n\ndescribe('createCodesignHttpServer', () => {\n let app: Awaited<ReturnType<typeof createCodesignHttpServer>>;\n let baseUrl: string;\n let server: ReturnType<typeof app.listen>;\n\n beforeEach(async () => {\n nextEngineId = 0;\n app = await makeServer();\n await new Promise<void>((resolve) => {\n server = app.listen(0, '127.0.0.1', resolve);\n });\n const addr = server.address() as AddressInfo;\n baseUrl = `http://127.0.0.1:${addr.port}/mcp`;\n });\n\n afterEach(async () => {\n await new Promise<void>((resolve) => server.close(() => resolve()));\n await app.shutdown();\n });\n\n async function connect(): Promise<{\n client: Client;\n sessionId: string | undefined;\n }> {\n const transport = new StreamableHTTPClientTransport(new URL(baseUrl));\n const client = new Client({ name: 'test', version: '0' });\n await client.connect(transport);\n return { client, sessionId: transport.sessionId };\n }\n\n it('initialize creates a new session and returns its id', async () => {\n const { client, sessionId } = await connect();\n expect(sessionId).toMatch(/[0-9a-f-]{36}/i); // uuid shape\n expect(app.sessions.size).toBe(1);\n await client.close();\n });\n\n it(\"listResources returns the asset bundle's skill files for that session\", async () => {\n const { client } = await connect();\n const list = await client.listResources();\n expect(list.resources.map((r) => r.uri)).toEqual([\n 'codesign://docs/alpha/SKILL.md'\n ]);\n await client.close();\n });\n\n it(\"callTool routes to the session's own engine\", async () => {\n const { client } = await connect();\n const result = await client.callTool({\n name: 'echo',\n arguments: { msg: 'hi' }\n });\n expect(result.content).toEqual([{ type: 'text', text: 'hi' }]);\n await client.close();\n });\n\n it('two parallel clients get distinct sessions and engines', async () => {\n const a = await connect();\n const b = await connect();\n expect(a.sessionId).toBeDefined();\n expect(b.sessionId).toBeDefined();\n expect(a.sessionId).not.toBe(b.sessionId);\n expect(app.sessions.size).toBe(2);\n await a.client.close();\n await b.client.close();\n });\n\n it('session cap: returns 503 when maxSessions is reached', async () => {\n await app.shutdown(); // dismiss the default 5-session app\n app = await createCodesignHttpServer({\n assets: FIXTURES,\n maxSessions: 2,\n idleTimeoutMs: 60_000,\n createSession: async () => ({\n engine: { id: nextEngineId++, scriptsRun: [] },\n tools: []\n })\n });\n await new Promise<void>((resolve) => server.close(() => resolve()));\n await new Promise<void>((resolve) => {\n server = app.listen(0, '127.0.0.1', resolve);\n });\n const addr = server.address() as AddressInfo;\n baseUrl = `http://127.0.0.1:${addr.port}/mcp`;\n\n const a = await connect();\n const b = await connect();\n // 3rd init request should be rejected at the HTTP layer with 503.\n const initBody = {\n jsonrpc: '2.0',\n id: 1,\n method: 'initialize',\n params: {\n protocolVersion: '2025-03-26',\n capabilities: {},\n clientInfo: { name: 't', version: '0' }\n }\n };\n const r = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'application/json, text/event-stream'\n },\n body: JSON.stringify(initBody)\n });\n expect(r.status).toBe(503);\n expect(r.headers.get('retry-after')).toBe('30');\n const json = (await r.json()) as {\n error: { code: number; message: string };\n };\n expect(json.error.code).toBe(-32000);\n expect(json.error.message).toMatch(/session cap/i);\n\n await a.client.close();\n await b.client.close();\n });\n\n it('unknown session id: returns 404 with -32001', async () => {\n const r = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'application/json, text/event-stream',\n 'mcp-session-id': '00000000-0000-0000-0000-000000000000'\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'tools/list',\n params: {}\n })\n });\n expect(r.status).toBe(404);\n const json = (await r.json()) as {\n error: { code: number; message: string };\n };\n expect(json.error.code).toBe(-32001);\n expect(json.error.message).toMatch(/unknown session/);\n });\n\n it('graceful DELETE /mcp terminates the session and frees its slot', async () => {\n const { sessionId } = await connect();\n expect(sessionId).toBeDefined();\n expect(app.sessions.size).toBe(1);\n\n const r = await fetch(baseUrl, {\n method: 'DELETE',\n headers: { 'mcp-session-id': sessionId as string }\n });\n expect(r.status).toBe(200);\n // onsessionclosed → sessionMgr.delete: the slot (and its engine) is\n // reclaimed immediately, not left squatting until idle eviction.\n expect(app.sessions.size).toBe(0);\n\n // The id is now unknown — a follow-up request 404s.\n const followUp = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'application/json, text/event-stream',\n 'mcp-session-id': sessionId as string\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'tools/list',\n params: {}\n })\n });\n expect(followUp.status).toBe(404);\n });\n\n it('auth middleware rejects requests with 401 when configured to', async () => {\n await app.shutdown();\n await new Promise<void>((resolve) => server.close(() => resolve()));\n app = await createCodesignHttpServer({\n assets: FIXTURES,\n maxSessions: 5,\n idleTimeoutMs: 60_000,\n createSession: async () => ({\n engine: { id: nextEngineId++, scriptsRun: [] },\n tools: []\n }),\n auth: (req, res, next) => {\n if (req.header('authorization') !== 'Bearer testtoken') {\n res.status(401).json({ error: 'unauthorized' });\n return;\n }\n next();\n }\n });\n await new Promise<void>((resolve) => {\n server = app.listen(0, '127.0.0.1', resolve);\n });\n const addr = server.address() as AddressInfo;\n baseUrl = `http://127.0.0.1:${addr.port}/mcp`;\n\n const r = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'application/json, text/event-stream'\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'initialize',\n params: {}\n })\n });\n expect(r.status).toBe(401);\n });\n\n it('engine state is isolated per session: mutation in one is invisible to the other', async () => {\n const a = await connect();\n const b = await connect();\n\n // Record on a — only a should see it.\n const aResult = await a.client.callTool({\n name: 'engine_record',\n arguments: { msg: 'from-a' }\n });\n expect(aResult.content).toEqual([{ type: 'text', text: 'from-a' }]);\n\n // Record on b — should NOT include from-a.\n const bResult = await b.client.callTool({\n name: 'engine_record',\n arguments: { msg: 'from-b' }\n });\n expect(bResult.content).toEqual([{ type: 'text', text: 'from-b' }]);\n\n // Re-record on a — should append to a's history, still no b.\n const aResult2 = await a.client.callTool({\n name: 'engine_record',\n arguments: { msg: 'again' }\n });\n expect(aResult2.content).toEqual([{ type: 'text', text: 'from-a,again' }]);\n\n await a.client.close();\n await b.client.close();\n });\n\n it('passes the resolved workspaceId to createSession on initialize', async () => {\n const seen: string[] = [];\n const testApp = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n resolveWorkspaceId: (req) => req.header('x-workspace-id') ?? 'fallback',\n createSession: async ({ workspaceId }) => {\n seen.push(workspaceId);\n return { engine: {}, tools: [] };\n }\n });\n await request(testApp)\n .post('/mcp')\n .set('x-workspace-id', 'u/acme')\n .set('content-type', 'application/json')\n .send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });\n expect(seen).toEqual(['u/acme']);\n await testApp.shutdown();\n });\n\n it('returns 401 when resolveWorkspaceId throws WorkspaceAuthError', async () => {\n const testApp = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n resolveWorkspaceId: () => {\n throw new WorkspaceAuthError('missing header');\n },\n createSession: async () => ({ engine: {}, tools: [] })\n });\n const res = await request(testApp)\n .post('/mcp')\n .set('content-type', 'application/json')\n .send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });\n expect(res.status).toBe(401);\n expect(res.body.error.code).toBe(-32002);\n expect(res.body.error.message).toBe('missing header');\n await testApp.shutdown();\n });\n\n it('returns 400 (not a hang) when the resolved workspaceId is malformed', async () => {\n const testApp = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n // header mode-style: return an illegal id that ScopedWorkspaceFS will reject\n resolveWorkspaceId: () => '../escape',\n createSession: async ({ workspaceId }) => {\n // mirror cli/http.ts: constructing the scoped fs validates the id\n new ScopedWorkspaceFS(new InMemoryWorkspaceFS(), workspaceId);\n return { engine: {}, tools: [] };\n }\n });\n const res = await request(testApp)\n .post('/mcp')\n .set('content-type', 'application/json')\n .send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });\n expect(res.status).toBe(400);\n expect(res.body.error.code).toBe(-32602); // invalid params\n await testApp.shutdown();\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-id-header.test.d.ts","sourceRoot":"","sources":["../../../../test/http/session-id-header.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import request from 'supertest';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import { createCodesignHttpServer } from '../../src/http/server.js';
|
|
4
|
-
// The transport echoes the session id it assigned in the `mcp-session-id`
|
|
5
|
-
// response header. We assert that, with `trustedSessionIdHeader` configured,
|
|
6
|
-
// an inbound header value becomes the session id verbatim — and without it,
|
|
7
|
-
// the server still mints its own (a normal uuid, not our injected value).
|
|
8
|
-
const INIT_BODY = {
|
|
9
|
-
jsonrpc: '2.0',
|
|
10
|
-
id: 1,
|
|
11
|
-
method: 'initialize',
|
|
12
|
-
params: {
|
|
13
|
-
protocolVersion: '2024-11-05',
|
|
14
|
-
capabilities: {},
|
|
15
|
-
clientInfo: { name: 'test', version: '0.0.0' }
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
describe('trustedSessionIdHeader', () => {
|
|
19
|
-
it('uses the inbound header value as the session id on initialize', async () => {
|
|
20
|
-
const app = await createCodesignHttpServer({
|
|
21
|
-
assets: {},
|
|
22
|
-
maxSessions: 4,
|
|
23
|
-
idleTimeoutMs: 60_000,
|
|
24
|
-
trustedSessionIdHeader: 'x-mcp-session-id',
|
|
25
|
-
resolveWorkspaceId: (_req, sid) => `s/${sid}`,
|
|
26
|
-
createSession: async () => ({ engine: {}, tools: [] })
|
|
27
|
-
});
|
|
28
|
-
const res = await request(app)
|
|
29
|
-
.post('/mcp')
|
|
30
|
-
.set('accept', 'application/json, text/event-stream')
|
|
31
|
-
.set('content-type', 'application/json')
|
|
32
|
-
.set('x-mcp-session-id', 'worker-minted-123')
|
|
33
|
-
.send(INIT_BODY);
|
|
34
|
-
expect(res.headers['mcp-session-id']).toBe('worker-minted-123');
|
|
35
|
-
await app.shutdown();
|
|
36
|
-
});
|
|
37
|
-
it('mints its own id when the header is absent', async () => {
|
|
38
|
-
const app = await createCodesignHttpServer({
|
|
39
|
-
assets: {},
|
|
40
|
-
maxSessions: 4,
|
|
41
|
-
idleTimeoutMs: 60_000,
|
|
42
|
-
trustedSessionIdHeader: 'x-mcp-session-id',
|
|
43
|
-
resolveWorkspaceId: (_req, sid) => `s/${sid}`,
|
|
44
|
-
createSession: async () => ({ engine: {}, tools: [] })
|
|
45
|
-
});
|
|
46
|
-
const res = await request(app)
|
|
47
|
-
.post('/mcp')
|
|
48
|
-
.set('accept', 'application/json, text/event-stream')
|
|
49
|
-
.set('content-type', 'application/json')
|
|
50
|
-
.send(INIT_BODY);
|
|
51
|
-
expect(res.headers['mcp-session-id']).toBeDefined();
|
|
52
|
-
expect(res.headers['mcp-session-id']).not.toBe('worker-minted-123');
|
|
53
|
-
expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);
|
|
54
|
-
await app.shutdown();
|
|
55
|
-
});
|
|
56
|
-
it('mints its own id when the header is present but empty', async () => {
|
|
57
|
-
const app = await createCodesignHttpServer({
|
|
58
|
-
assets: {},
|
|
59
|
-
maxSessions: 4,
|
|
60
|
-
idleTimeoutMs: 60_000,
|
|
61
|
-
trustedSessionIdHeader: 'x-mcp-session-id',
|
|
62
|
-
resolveWorkspaceId: (_req, sid) => `s/${sid}`,
|
|
63
|
-
createSession: async () => ({ engine: {}, tools: [] })
|
|
64
|
-
});
|
|
65
|
-
const res = await request(app)
|
|
66
|
-
.post('/mcp')
|
|
67
|
-
.set('accept', 'application/json, text/event-stream')
|
|
68
|
-
.set('content-type', 'application/json')
|
|
69
|
-
.set('x-mcp-session-id', '')
|
|
70
|
-
.send(INIT_BODY);
|
|
71
|
-
expect(res.headers['mcp-session-id']).toBeDefined();
|
|
72
|
-
expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);
|
|
73
|
-
await app.shutdown();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
//# sourceMappingURL=session-id-header.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-id-header.test.js","sourceRoot":"","sources":["../../../../test/http/session-id-header.test.ts"],"names":[],"mappings":"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","sourcesContent":["import request from 'supertest';\nimport { describe, expect, it } from 'vitest';\nimport { createCodesignHttpServer } from '../../src/http/server.js';\n\n// The transport echoes the session id it assigned in the `mcp-session-id`\n// response header. We assert that, with `trustedSessionIdHeader` configured,\n// an inbound header value becomes the session id verbatim — and without it,\n// the server still mints its own (a normal uuid, not our injected value).\nconst INIT_BODY = {\n jsonrpc: '2.0',\n id: 1,\n method: 'initialize',\n params: {\n protocolVersion: '2024-11-05',\n capabilities: {},\n clientInfo: { name: 'test', version: '0.0.0' }\n }\n};\n\ndescribe('trustedSessionIdHeader', () => {\n it('uses the inbound header value as the session id on initialize', async () => {\n const app = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n trustedSessionIdHeader: 'x-mcp-session-id',\n resolveWorkspaceId: (_req, sid) => `s/${sid}`,\n createSession: async () => ({ engine: {}, tools: [] })\n });\n const res = await request(app)\n .post('/mcp')\n .set('accept', 'application/json, text/event-stream')\n .set('content-type', 'application/json')\n .set('x-mcp-session-id', 'worker-minted-123')\n .send(INIT_BODY);\n expect(res.headers['mcp-session-id']).toBe('worker-minted-123');\n await app.shutdown();\n });\n\n it('mints its own id when the header is absent', async () => {\n const app = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n trustedSessionIdHeader: 'x-mcp-session-id',\n resolveWorkspaceId: (_req, sid) => `s/${sid}`,\n createSession: async () => ({ engine: {}, tools: [] })\n });\n const res = await request(app)\n .post('/mcp')\n .set('accept', 'application/json, text/event-stream')\n .set('content-type', 'application/json')\n .send(INIT_BODY);\n expect(res.headers['mcp-session-id']).toBeDefined();\n expect(res.headers['mcp-session-id']).not.toBe('worker-minted-123');\n expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);\n await app.shutdown();\n });\n\n it('mints its own id when the header is present but empty', async () => {\n const app = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n trustedSessionIdHeader: 'x-mcp-session-id',\n resolveWorkspaceId: (_req, sid) => `s/${sid}`,\n createSession: async () => ({ engine: {}, tools: [] })\n });\n const res = await request(app)\n .post('/mcp')\n .set('accept', 'application/json, text/event-stream')\n .set('content-type', 'application/json')\n .set('x-mcp-session-id', '')\n .send(INIT_BODY);\n expect(res.headers['mcp-session-id']).toBeDefined();\n expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);\n await app.shutdown();\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.test.d.ts","sourceRoot":"","sources":["../../../../test/http/session-manager.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { SessionCapExceededError, SessionManager, SessionNotFoundError } from '../../src/http/session-manager.js';
|
|
3
|
-
describe('SessionManager', () => {
|
|
4
|
-
let nextEngineId;
|
|
5
|
-
let createdEngines;
|
|
6
|
-
let mgr;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
vi.useFakeTimers();
|
|
9
|
-
vi.setSystemTime(new Date('2026-05-09T00:00:00Z'));
|
|
10
|
-
nextEngineId = 0;
|
|
11
|
-
createdEngines = [];
|
|
12
|
-
mgr = new SessionManager({
|
|
13
|
-
maxSessions: 3,
|
|
14
|
-
idleTimeoutMs: 60_000,
|
|
15
|
-
create: async () => {
|
|
16
|
-
const engine = { id: nextEngineId++, disposed: false };
|
|
17
|
-
createdEngines.push(engine);
|
|
18
|
-
return { id: `s-${engine.id}`, engine };
|
|
19
|
-
},
|
|
20
|
-
destroy: async (s) => {
|
|
21
|
-
s.engine.disposed = true;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
vi.useRealTimers();
|
|
27
|
-
});
|
|
28
|
-
it('create() returns a fresh session and registers it under its id', async () => {
|
|
29
|
-
const s = await mgr.create();
|
|
30
|
-
expect(s.id).toBe('s-0');
|
|
31
|
-
expect(s.engine.id).toBe(0);
|
|
32
|
-
expect(mgr.get(s.id)).toBe(s);
|
|
33
|
-
});
|
|
34
|
-
it('get() returns undefined for unknown ids', () => {
|
|
35
|
-
expect(mgr.get('nope')).toBeUndefined();
|
|
36
|
-
});
|
|
37
|
-
it('touch() updates lastActivityAt so the session survives idle eviction', async () => {
|
|
38
|
-
const a = await mgr.create();
|
|
39
|
-
vi.advanceTimersByTime(50_000);
|
|
40
|
-
mgr.touch(a.id);
|
|
41
|
-
vi.advanceTimersByTime(50_000); // total 100s; without touch a would be evicted
|
|
42
|
-
await mgr.evictIdle();
|
|
43
|
-
expect(mgr.get(a.id)).toBe(a);
|
|
44
|
-
expect(a.engine.disposed).toBe(false);
|
|
45
|
-
});
|
|
46
|
-
it('evictIdle() destroys sessions older than idleTimeoutMs', async () => {
|
|
47
|
-
const a = await mgr.create();
|
|
48
|
-
const b = await mgr.create();
|
|
49
|
-
vi.advanceTimersByTime(30_000);
|
|
50
|
-
mgr.touch(b.id); // bump b only
|
|
51
|
-
vi.advanceTimersByTime(40_000); // a is now 70s idle, b only 40s
|
|
52
|
-
await mgr.evictIdle();
|
|
53
|
-
expect(mgr.get(a.id)).toBeUndefined();
|
|
54
|
-
expect(a.engine.disposed).toBe(true);
|
|
55
|
-
expect(mgr.get(b.id)).toBe(b);
|
|
56
|
-
expect(b.engine.disposed).toBe(false);
|
|
57
|
-
});
|
|
58
|
-
it('create() throws SessionCapExceededError once maxSessions is reached', async () => {
|
|
59
|
-
await mgr.create();
|
|
60
|
-
await mgr.create();
|
|
61
|
-
await mgr.create();
|
|
62
|
-
await expect(mgr.create()).rejects.toBeInstanceOf(SessionCapExceededError);
|
|
63
|
-
});
|
|
64
|
-
it('delete() destroys a session and removes it', async () => {
|
|
65
|
-
const a = await mgr.create();
|
|
66
|
-
await mgr.delete(a.id);
|
|
67
|
-
expect(mgr.get(a.id)).toBeUndefined();
|
|
68
|
-
expect(a.engine.disposed).toBe(true);
|
|
69
|
-
});
|
|
70
|
-
it('delete() of an unknown id throws SessionNotFoundError', async () => {
|
|
71
|
-
await expect(mgr.delete('nope')).rejects.toBeInstanceOf(SessionNotFoundError);
|
|
72
|
-
});
|
|
73
|
-
it('destroyAll() shuts down every active session', async () => {
|
|
74
|
-
const a = await mgr.create();
|
|
75
|
-
const b = await mgr.create();
|
|
76
|
-
await mgr.destroyAll();
|
|
77
|
-
expect(mgr.get(a.id)).toBeUndefined();
|
|
78
|
-
expect(mgr.get(b.id)).toBeUndefined();
|
|
79
|
-
expect(a.engine.disposed).toBe(true);
|
|
80
|
-
expect(b.engine.disposed).toBe(true);
|
|
81
|
-
});
|
|
82
|
-
it('forwards a context object to the create callback', async () => {
|
|
83
|
-
const seen = [];
|
|
84
|
-
const mgr = new SessionManager({
|
|
85
|
-
maxSessions: 10,
|
|
86
|
-
idleTimeoutMs: 60_000,
|
|
87
|
-
create: (ctx) => {
|
|
88
|
-
seen.push(ctx?.workspaceId);
|
|
89
|
-
return { id: ctx?.workspaceId ?? 'none' };
|
|
90
|
-
},
|
|
91
|
-
destroy: () => { }
|
|
92
|
-
});
|
|
93
|
-
await mgr.create({ workspaceId: 'u/a' });
|
|
94
|
-
expect(seen).toEqual(['u/a']);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
//# sourceMappingURL=session-manager.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.test.js","sourceRoot":"","sources":["../../../../test/http/session-manager.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport {\n SessionCapExceededError,\n SessionManager,\n SessionNotFoundError\n} from '../../src/http/session-manager.js';\n\ninterface FakeEngine {\n id: number;\n disposed: boolean;\n}\n\ninterface FakeSession {\n id: string;\n engine: FakeEngine;\n}\n\ndescribe('SessionManager', () => {\n let nextEngineId: number;\n let createdEngines: FakeEngine[];\n let mgr: SessionManager<FakeSession>;\n\n beforeEach(() => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date('2026-05-09T00:00:00Z'));\n nextEngineId = 0;\n createdEngines = [];\n mgr = new SessionManager<FakeSession>({\n maxSessions: 3,\n idleTimeoutMs: 60_000,\n create: async () => {\n const engine: FakeEngine = { id: nextEngineId++, disposed: false };\n createdEngines.push(engine);\n return { id: `s-${engine.id}`, engine };\n },\n destroy: async (s) => {\n s.engine.disposed = true;\n }\n });\n });\n\n afterEach(() => {\n vi.useRealTimers();\n });\n\n it('create() returns a fresh session and registers it under its id', async () => {\n const s = await mgr.create();\n expect(s.id).toBe('s-0');\n expect(s.engine.id).toBe(0);\n expect(mgr.get(s.id)).toBe(s);\n });\n\n it('get() returns undefined for unknown ids', () => {\n expect(mgr.get('nope')).toBeUndefined();\n });\n\n it('touch() updates lastActivityAt so the session survives idle eviction', async () => {\n const a = await mgr.create();\n vi.advanceTimersByTime(50_000);\n mgr.touch(a.id);\n vi.advanceTimersByTime(50_000); // total 100s; without touch a would be evicted\n await mgr.evictIdle();\n expect(mgr.get(a.id)).toBe(a);\n expect(a.engine.disposed).toBe(false);\n });\n\n it('evictIdle() destroys sessions older than idleTimeoutMs', async () => {\n const a = await mgr.create();\n const b = await mgr.create();\n vi.advanceTimersByTime(30_000);\n mgr.touch(b.id); // bump b only\n vi.advanceTimersByTime(40_000); // a is now 70s idle, b only 40s\n await mgr.evictIdle();\n expect(mgr.get(a.id)).toBeUndefined();\n expect(a.engine.disposed).toBe(true);\n expect(mgr.get(b.id)).toBe(b);\n expect(b.engine.disposed).toBe(false);\n });\n\n it('create() throws SessionCapExceededError once maxSessions is reached', async () => {\n await mgr.create();\n await mgr.create();\n await mgr.create();\n await expect(mgr.create()).rejects.toBeInstanceOf(SessionCapExceededError);\n });\n\n it('delete() destroys a session and removes it', async () => {\n const a = await mgr.create();\n await mgr.delete(a.id);\n expect(mgr.get(a.id)).toBeUndefined();\n expect(a.engine.disposed).toBe(true);\n });\n\n it('delete() of an unknown id throws SessionNotFoundError', async () => {\n await expect(mgr.delete('nope')).rejects.toBeInstanceOf(\n SessionNotFoundError\n );\n });\n\n it('destroyAll() shuts down every active session', async () => {\n const a = await mgr.create();\n const b = await mgr.create();\n await mgr.destroyAll();\n expect(mgr.get(a.id)).toBeUndefined();\n expect(mgr.get(b.id)).toBeUndefined();\n expect(a.engine.disposed).toBe(true);\n expect(b.engine.disposed).toBe(true);\n });\n\n it('forwards a context object to the create callback', async () => {\n const seen: Array<string | undefined> = [];\n const mgr = new SessionManager<{ id: string }, { workspaceId: string }>({\n maxSessions: 10,\n idleTimeoutMs: 60_000,\n create: (ctx) => {\n seen.push(ctx?.workspaceId);\n return { id: ctx?.workspaceId ?? 'none' };\n },\n destroy: () => {}\n });\n await mgr.create({ workspaceId: 'u/a' });\n expect(seen).toEqual(['u/a']);\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-auth.test.d.ts","sourceRoot":"","sources":["../../../../test/http/workspace-auth.test.ts"],"names":[],"mappings":""}
|