@imgly/codesign-mcp 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -10
- package/assets/docs/api/index.d.ts +9 -3
- package/assets/docs/guide/SKILL.md +2 -2
- package/assets/docs/guide/api/node/classes/creativeengine.md +13 -13
- package/assets/docs/guide/edit-image/transform/scale.md +1 -3
- package/assets/docs/guide/filters-and-effects/duotone.md +1 -1
- package/assets/docs/guide/get-started/bun.md +0 -2
- package/assets/docs/guide/get-started/deno.md +0 -1
- package/assets/docs/guide/get-started/vanilla.md +0 -2
- package/assets/docs/guide/import-media/default-assets.md +20 -24
- package/assets/docs/guide/plugins/print-ready-pdf.md +0 -2
- package/assets/docs/guide/serve-assets.md +80 -23
- package/assets/docs/handbook/SKILL.md +6 -7
- package/dist/assets/inline.generated.js +12 -12
- package/dist/assets/inline.generated.js.map +1 -1
- package/dist/cli/http.d.ts.map +1 -1
- package/dist/cli/http.js +29 -5
- package/dist/cli/http.js.map +1 -1
- package/dist/cli/stdio.d.ts.map +1 -1
- package/dist/cli/stdio.js +145 -48
- package/dist/cli/stdio.js.map +1 -1
- package/dist/cli/trial-license.generated.d.ts +1 -1
- package/dist/cli/trial-license.generated.js +1 -1
- package/dist/cli/trial-license.generated.js.map +1 -1
- package/dist/config.d.ts +17 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -1
- package/dist/config.js.map +1 -1
- package/dist/diagnostics/bundle.d.ts +3 -0
- package/dist/diagnostics/bundle.d.ts.map +1 -1
- package/dist/diagnostics/bundle.js +25 -22
- package/dist/diagnostics/bundle.js.map +1 -1
- package/dist/diagnostics/events.d.ts +6 -0
- package/dist/diagnostics/events.d.ts.map +1 -1
- package/dist/diagnostics/events.js.map +1 -1
- package/dist/diagnostics/prompt.d.ts +3 -0
- package/dist/diagnostics/prompt.d.ts.map +1 -0
- package/dist/diagnostics/prompt.js +21 -0
- package/dist/diagnostics/prompt.js.map +1 -0
- package/dist/diagnostics/router.d.ts +12 -0
- package/dist/diagnostics/router.d.ts.map +1 -0
- package/dist/diagnostics/router.js +64 -0
- package/dist/diagnostics/router.js.map +1 -0
- package/dist/diagnostics/spa-assets.generated.d.ts.map +1 -0
- package/dist/diagnostics/spa-assets.generated.js +1231 -0
- package/dist/diagnostics/spa-assets.generated.js.map +1 -0
- package/dist/diagnostics/status.d.ts +38 -0
- package/dist/diagnostics/status.d.ts.map +1 -0
- package/dist/diagnostics/status.js +53 -0
- package/dist/diagnostics/status.js.map +1 -0
- package/dist/diagnostics/summary.d.ts +48 -0
- package/dist/diagnostics/summary.d.ts.map +1 -0
- package/dist/diagnostics/summary.js +116 -0
- package/dist/diagnostics/summary.js.map +1 -0
- package/dist/diagnostics/tool.d.ts +16 -0
- package/dist/diagnostics/tool.d.ts.map +1 -0
- package/dist/diagnostics/tool.js +90 -0
- package/dist/diagnostics/tool.js.map +1 -0
- package/dist/engine/asset-sources.d.ts +8 -0
- package/dist/engine/asset-sources.d.ts.map +1 -1
- package/dist/engine/asset-sources.js +9 -2
- package/dist/engine/asset-sources.js.map +1 -1
- package/dist/engine/cesdk-adapter.d.ts +5 -1
- package/dist/engine/cesdk-adapter.d.ts.map +1 -1
- package/dist/engine/cesdk-adapter.js +8 -1
- package/dist/engine/cesdk-adapter.js.map +1 -1
- package/dist/engine/engine-capacity.d.ts +16 -0
- package/dist/engine/engine-capacity.d.ts.map +1 -0
- package/dist/engine/engine-capacity.js +48 -0
- package/dist/engine/engine-capacity.js.map +1 -0
- package/dist/engine/engine-slots.d.ts +48 -0
- package/dist/engine/engine-slots.d.ts.map +1 -0
- package/dist/engine/engine-slots.js +182 -0
- package/dist/engine/engine-slots.js.map +1 -0
- package/dist/engine/uri-resolver.js.map +1 -1
- package/dist/server.d.ts +25 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +24 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/engine.d.ts +92 -14
- package/dist/tools/engine.d.ts.map +1 -1
- package/dist/tools/engine.js +147 -20
- package/dist/tools/engine.js.map +1 -1
- package/dist/tools/export.d.ts.map +1 -1
- package/dist/tools/export.js +34 -4
- package/dist/tools/export.js.map +1 -1
- package/dist/tools/index.js +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/load.d.ts.map +1 -1
- package/dist/tools/load.js +26 -19
- package/dist/tools/load.js.map +1 -1
- package/dist/tools/preview.d.ts.map +1 -1
- package/dist/tools/preview.js +60 -40
- package/dist/tools/preview.js.map +1 -1
- package/dist/tools/{open-editor.d.ts → view.d.ts} +3 -3
- package/dist/tools/view.d.ts.map +1 -0
- package/dist/tools/{open-editor.js → view.js} +20 -18
- package/dist/tools/view.js.map +1 -0
- package/dist/viewer/listener.d.ts +2 -0
- package/dist/viewer/listener.d.ts.map +1 -1
- package/dist/viewer/listener.js +2 -0
- package/dist/viewer/listener.js.map +1 -1
- package/dist/viewer/presigned-r2-url-builder.d.ts +1 -1
- package/dist/viewer/presigned-r2-url-builder.js +1 -1
- package/dist/viewer/presigned-r2-url-builder.js.map +1 -1
- package/dist/viewer/router.d.ts.map +1 -1
- package/dist/viewer/router.js +8 -17
- package/dist/viewer/router.js.map +1 -1
- package/dist/viewer/session-mount.js.map +1 -1
- package/dist/viewer/spa-assets.generated.d.ts.map +1 -1
- package/dist/viewer/spa-assets.generated.js +750 -869
- package/dist/viewer/spa-assets.generated.js.map +1 -1
- package/dist/viewer/url-builder.d.ts +4 -3
- package/dist/viewer/url-builder.d.ts.map +1 -1
- package/dist/viewer/url-builder.js +4 -4
- package/dist/viewer/url-builder.js.map +1 -1
- package/package.json +7 -6
- package/dist/dashboard/router.d.ts +0 -3
- package/dist/dashboard/router.d.ts.map +0 -1
- package/dist/dashboard/router.js +0 -19
- package/dist/dashboard/router.js.map +0 -1
- package/dist/dashboard/spa-assets.generated.d.ts.map +0 -1
- package/dist/dashboard/spa-assets.generated.js +0 -220
- package/dist/dashboard/spa-assets.generated.js.map +0 -1
- package/dist/metrics/mount.d.ts +0 -11
- package/dist/metrics/mount.d.ts.map +0 -1
- package/dist/metrics/mount.js +0 -13
- package/dist/metrics/mount.js.map +0 -1
- package/dist/metrics/recorder.d.ts +0 -55
- package/dist/metrics/recorder.d.ts.map +0 -1
- package/dist/metrics/recorder.js +0 -97
- package/dist/metrics/recorder.js.map +0 -1
- package/dist/test/scripts/changelog-add.d.ts +0 -8
- package/dist/test/scripts/changelog-add.d.ts.map +0 -1
- package/dist/test/scripts/changelog-add.js +0 -50
- package/dist/test/scripts/changelog-add.js.map +0 -1
- package/dist/test/scripts/changelog-collate.d.ts +0 -38
- package/dist/test/scripts/changelog-collate.d.ts.map +0 -1
- package/dist/test/scripts/changelog-collate.js +0 -171
- package/dist/test/scripts/changelog-collate.js.map +0 -1
- package/dist/test/test/changelog.test.d.ts +0 -2
- package/dist/test/test/changelog.test.d.ts.map +0 -1
- package/dist/test/test/changelog.test.js +0 -293
- package/dist/test/test/changelog.test.js.map +0 -1
- package/dist/test/test/cli/dispatcher.test.d.ts +0 -2
- package/dist/test/test/cli/dispatcher.test.d.ts.map +0 -1
- package/dist/test/test/cli/dispatcher.test.js +0 -54
- package/dist/test/test/cli/dispatcher.test.js.map +0 -1
- package/dist/test/test/cli/redirect-console.test.d.ts +0 -2
- package/dist/test/test/cli/redirect-console.test.d.ts.map +0 -1
- package/dist/test/test/cli/redirect-console.test.js +0 -78
- package/dist/test/test/cli/redirect-console.test.js.map +0 -1
- package/dist/test/test/cli/resolve-license.test.d.ts +0 -2
- package/dist/test/test/cli/resolve-license.test.d.ts.map +0 -1
- package/dist/test/test/cli/resolve-license.test.js +0 -29
- package/dist/test/test/cli/resolve-license.test.js.map +0 -1
- package/dist/test/test/cli/stdio-diagnostics.test.d.ts +0 -2
- package/dist/test/test/cli/stdio-diagnostics.test.d.ts.map +0 -1
- package/dist/test/test/cli/stdio-diagnostics.test.js +0 -31
- package/dist/test/test/cli/stdio-diagnostics.test.js.map +0 -1
- package/dist/test/test/cli/stdio-license.test.d.ts +0 -2
- package/dist/test/test/cli/stdio-license.test.d.ts.map +0 -1
- package/dist/test/test/cli/stdio-license.test.js +0 -19
- package/dist/test/test/cli/stdio-license.test.js.map +0 -1
- package/dist/test/test/config.test.d.ts +0 -2
- package/dist/test/test/config.test.d.ts.map +0 -1
- package/dist/test/test/config.test.js +0 -95
- package/dist/test/test/config.test.js.map +0 -1
- package/dist/test/test/cross-ref.test.d.ts +0 -2
- package/dist/test/test/cross-ref.test.d.ts.map +0 -1
- package/dist/test/test/cross-ref.test.js +0 -39
- package/dist/test/test/cross-ref.test.js.map +0 -1
- package/dist/test/test/diagnostics/bundle.test.d.ts +0 -2
- package/dist/test/test/diagnostics/bundle.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/bundle.test.js +0 -53
- package/dist/test/test/diagnostics/bundle.test.js.map +0 -1
- package/dist/test/test/diagnostics/compose.test.d.ts +0 -2
- package/dist/test/test/diagnostics/compose.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/compose.test.js +0 -31
- package/dist/test/test/diagnostics/compose.test.js.map +0 -1
- package/dist/test/test/diagnostics/file-sink.test.d.ts +0 -2
- package/dist/test/test/diagnostics/file-sink.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/file-sink.test.js +0 -113
- package/dist/test/test/diagnostics/file-sink.test.js.map +0 -1
- package/dist/test/test/diagnostics/redact.test.d.ts +0 -2
- package/dist/test/test/diagnostics/redact.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/redact.test.js +0 -59
- package/dist/test/test/diagnostics/redact.test.js.map +0 -1
- package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts +0 -2
- package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts.map +0 -1
- package/dist/test/test/diagnostics/tool-call-adapter.test.js +0 -34
- package/dist/test/test/diagnostics/tool-call-adapter.test.js.map +0 -1
- package/dist/test/test/engine/asset-sources.test.d.ts +0 -2
- package/dist/test/test/engine/asset-sources.test.d.ts.map +0 -1
- package/dist/test/test/engine/asset-sources.test.js +0 -100
- package/dist/test/test/engine/asset-sources.test.js.map +0 -1
- package/dist/test/test/engine/cesdk-adapter.test.d.ts +0 -2
- package/dist/test/test/engine/cesdk-adapter.test.d.ts.map +0 -1
- package/dist/test/test/engine/cesdk-adapter.test.js +0 -32
- package/dist/test/test/engine/cesdk-adapter.test.js.map +0 -1
- package/dist/test/test/engine/mutex.test.d.ts +0 -2
- package/dist/test/test/engine/mutex.test.d.ts.map +0 -1
- package/dist/test/test/engine/mutex.test.js +0 -63
- package/dist/test/test/engine/mutex.test.js.map +0 -1
- package/dist/test/test/engine/session.test.d.ts +0 -2
- package/dist/test/test/engine/session.test.d.ts.map +0 -1
- package/dist/test/test/engine/session.test.js +0 -159
- package/dist/test/test/engine/session.test.js.map +0 -1
- package/dist/test/test/engine/unsplash-source.test.d.ts +0 -2
- package/dist/test/test/engine/unsplash-source.test.d.ts.map +0 -1
- package/dist/test/test/engine/unsplash-source.test.js +0 -129
- package/dist/test/test/engine/unsplash-source.test.js.map +0 -1
- package/dist/test/test/engine/uri-resolver.test.d.ts +0 -2
- package/dist/test/test/engine/uri-resolver.test.d.ts.map +0 -1
- package/dist/test/test/engine/uri-resolver.test.js +0 -38
- package/dist/test/test/engine/uri-resolver.test.js.map +0 -1
- package/dist/test/test/gateway/hosted-stub.test.d.ts +0 -2
- package/dist/test/test/gateway/hosted-stub.test.d.ts.map +0 -1
- package/dist/test/test/gateway/hosted-stub.test.js +0 -11
- package/dist/test/test/gateway/hosted-stub.test.js.map +0 -1
- package/dist/test/test/gateway/local.test.d.ts +0 -2
- package/dist/test/test/gateway/local.test.d.ts.map +0 -1
- package/dist/test/test/gateway/local.test.js +0 -29
- package/dist/test/test/gateway/local.test.js.map +0 -1
- package/dist/test/test/handbook-contract.test.d.ts +0 -2
- package/dist/test/test/handbook-contract.test.d.ts.map +0 -1
- package/dist/test/test/handbook-contract.test.js +0 -79
- package/dist/test/test/handbook-contract.test.js.map +0 -1
- package/dist/test/test/http/server.test.d.ts +0 -2
- package/dist/test/test/http/server.test.d.ts.map +0 -1
- package/dist/test/test/http/server.test.js +0 -338
- package/dist/test/test/http/server.test.js.map +0 -1
- package/dist/test/test/http/session-id-header.test.d.ts +0 -2
- package/dist/test/test/http/session-id-header.test.d.ts.map +0 -1
- package/dist/test/test/http/session-id-header.test.js +0 -76
- package/dist/test/test/http/session-id-header.test.js.map +0 -1
- package/dist/test/test/http/session-manager.test.d.ts +0 -2
- package/dist/test/test/http/session-manager.test.d.ts.map +0 -1
- package/dist/test/test/http/session-manager.test.js +0 -97
- package/dist/test/test/http/session-manager.test.js.map +0 -1
- package/dist/test/test/http/workspace-auth.test.d.ts +0 -2
- package/dist/test/test/http/workspace-auth.test.d.ts.map +0 -1
- package/dist/test/test/http/workspace-auth.test.js +0 -40
- package/dist/test/test/http/workspace-auth.test.js.map +0 -1
- package/dist/test/test/metrics/mount.test.d.ts +0 -2
- package/dist/test/test/metrics/mount.test.d.ts.map +0 -1
- package/dist/test/test/metrics/mount.test.js +0 -59
- package/dist/test/test/metrics/mount.test.js.map +0 -1
- package/dist/test/test/metrics/recorder.test.d.ts +0 -2
- package/dist/test/test/metrics/recorder.test.d.ts.map +0 -1
- package/dist/test/test/metrics/recorder.test.js +0 -118
- package/dist/test/test/metrics/recorder.test.js.map +0 -1
- package/dist/test/test/revisions/hash.test.d.ts +0 -2
- package/dist/test/test/revisions/hash.test.d.ts.map +0 -1
- package/dist/test/test/revisions/hash.test.js +0 -33
- package/dist/test/test/revisions/hash.test.js.map +0 -1
- package/dist/test/test/revisions/store.test.d.ts +0 -2
- package/dist/test/test/revisions/store.test.d.ts.map +0 -1
- package/dist/test/test/revisions/store.test.js +0 -315
- package/dist/test/test/revisions/store.test.js.map +0 -1
- package/dist/test/test/server.metrics.test.d.ts +0 -2
- package/dist/test/test/server.metrics.test.d.ts.map +0 -1
- package/dist/test/test/server.metrics.test.js +0 -87
- package/dist/test/test/server.metrics.test.js.map +0 -1
- package/dist/test/test/server.test.d.ts +0 -2
- package/dist/test/test/server.test.d.ts.map +0 -1
- package/dist/test/test/server.test.js +0 -146
- package/dist/test/test/server.test.js.map +0 -1
- package/dist/test/test/skill-tools.test.d.ts +0 -2
- package/dist/test/test/skill-tools.test.d.ts.map +0 -1
- package/dist/test/test/skill-tools.test.js +0 -84
- package/dist/test/test/skill-tools.test.js.map +0 -1
- package/dist/test/test/smoke.test.d.ts +0 -2
- package/dist/test/test/smoke.test.d.ts.map +0 -1
- package/dist/test/test/smoke.test.js +0 -8
- package/dist/test/test/smoke.test.js.map +0 -1
- package/dist/test/test/tools/asset-generate.test.d.ts +0 -2
- package/dist/test/test/tools/asset-generate.test.d.ts.map +0 -1
- package/dist/test/test/tools/asset-generate.test.js +0 -66
- package/dist/test/test/tools/asset-generate.test.js.map +0 -1
- package/dist/test/test/tools/asset-search.test.d.ts +0 -2
- package/dist/test/test/tools/asset-search.test.d.ts.map +0 -1
- package/dist/test/test/tools/asset-search.test.js +0 -121
- package/dist/test/test/tools/asset-search.test.js.map +0 -1
- package/dist/test/test/tools/edit-harness.d.ts +0 -14
- package/dist/test/test/tools/edit-harness.d.ts.map +0 -1
- package/dist/test/test/tools/edit-harness.js +0 -30
- package/dist/test/test/tools/edit-harness.js.map +0 -1
- package/dist/test/test/tools/edit.telemetry.test.d.ts +0 -2
- package/dist/test/test/tools/edit.telemetry.test.d.ts.map +0 -1
- package/dist/test/test/tools/edit.telemetry.test.js +0 -46
- package/dist/test/test/tools/edit.telemetry.test.js.map +0 -1
- package/dist/test/test/tools/edit.test.d.ts +0 -2
- package/dist/test/test/tools/edit.test.d.ts.map +0 -1
- package/dist/test/test/tools/edit.test.js +0 -267
- package/dist/test/test/tools/edit.test.js.map +0 -1
- package/dist/test/test/tools/export-harness.d.ts +0 -13
- package/dist/test/test/tools/export-harness.d.ts.map +0 -1
- package/dist/test/test/tools/export-harness.js +0 -27
- package/dist/test/test/tools/export-harness.js.map +0 -1
- package/dist/test/test/tools/export.telemetry.test.d.ts +0 -2
- package/dist/test/test/tools/export.telemetry.test.d.ts.map +0 -1
- package/dist/test/test/tools/export.telemetry.test.js +0 -65
- package/dist/test/test/tools/export.telemetry.test.js.map +0 -1
- package/dist/test/test/tools/export.test.d.ts +0 -2
- package/dist/test/test/tools/export.test.d.ts.map +0 -1
- package/dist/test/test/tools/export.test.js +0 -174
- package/dist/test/test/tools/export.test.js.map +0 -1
- package/dist/test/test/tools/history.test.d.ts +0 -2
- package/dist/test/test/tools/history.test.d.ts.map +0 -1
- package/dist/test/test/tools/history.test.js +0 -29
- package/dist/test/test/tools/history.test.js.map +0 -1
- package/dist/test/test/tools/import.test.d.ts +0 -2
- package/dist/test/test/tools/import.test.d.ts.map +0 -1
- package/dist/test/test/tools/import.test.js +0 -122
- package/dist/test/test/tools/import.test.js.map +0 -1
- package/dist/test/test/tools/index.test.d.ts +0 -2
- package/dist/test/test/tools/index.test.d.ts.map +0 -1
- package/dist/test/test/tools/index.test.js +0 -117
- package/dist/test/test/tools/index.test.js.map +0 -1
- package/dist/test/test/tools/inspect.test.d.ts +0 -2
- package/dist/test/test/tools/inspect.test.d.ts.map +0 -1
- package/dist/test/test/tools/inspect.test.js +0 -62
- package/dist/test/test/tools/inspect.test.js.map +0 -1
- package/dist/test/test/tools/list.test.d.ts +0 -2
- package/dist/test/test/tools/list.test.d.ts.map +0 -1
- package/dist/test/test/tools/list.test.js +0 -23
- package/dist/test/test/tools/list.test.js.map +0 -1
- package/dist/test/test/tools/load.integration.test.d.ts +0 -2
- package/dist/test/test/tools/load.integration.test.d.ts.map +0 -1
- package/dist/test/test/tools/load.integration.test.js +0 -165
- package/dist/test/test/tools/load.integration.test.js.map +0 -1
- package/dist/test/test/tools/load.test.d.ts +0 -2
- package/dist/test/test/tools/load.test.d.ts.map +0 -1
- package/dist/test/test/tools/load.test.js +0 -387
- package/dist/test/test/tools/load.test.js.map +0 -1
- package/dist/test/test/tools/metrics.test.d.ts +0 -2
- package/dist/test/test/tools/metrics.test.d.ts.map +0 -1
- package/dist/test/test/tools/metrics.test.js +0 -29
- package/dist/test/test/tools/metrics.test.js.map +0 -1
- package/dist/test/test/tools/open-editor.test.d.ts +0 -2
- package/dist/test/test/tools/open-editor.test.d.ts.map +0 -1
- package/dist/test/test/tools/open-editor.test.js +0 -53
- package/dist/test/test/tools/open-editor.test.js.map +0 -1
- package/dist/test/test/tools/preview-harness.d.ts +0 -9
- package/dist/test/test/tools/preview-harness.d.ts.map +0 -1
- package/dist/test/test/tools/preview-harness.js +0 -23
- package/dist/test/test/tools/preview-harness.js.map +0 -1
- package/dist/test/test/tools/preview.telemetry.test.d.ts +0 -2
- package/dist/test/test/tools/preview.telemetry.test.d.ts.map +0 -1
- package/dist/test/test/tools/preview.telemetry.test.js +0 -36
- package/dist/test/test/tools/preview.telemetry.test.js.map +0 -1
- package/dist/test/test/tools/preview.test.d.ts +0 -2
- package/dist/test/test/tools/preview.test.d.ts.map +0 -1
- package/dist/test/test/tools/preview.test.js +0 -75
- package/dist/test/test/tools/preview.test.js.map +0 -1
- package/dist/test/test/tools/rename.test.d.ts +0 -2
- package/dist/test/test/tools/rename.test.d.ts.map +0 -1
- package/dist/test/test/tools/rename.test.js +0 -16
- package/dist/test/test/tools/rename.test.js.map +0 -1
- package/dist/test/test/tools/save.test.d.ts +0 -2
- package/dist/test/test/tools/save.test.d.ts.map +0 -1
- package/dist/test/test/tools/save.test.js +0 -137
- package/dist/test/test/tools/save.test.js.map +0 -1
- package/dist/test/test/tools/schema-best-practices.d.ts +0 -13
- package/dist/test/test/tools/schema-best-practices.d.ts.map +0 -1
- package/dist/test/test/tools/schema-best-practices.js +0 -169
- package/dist/test/test/tools/schema-best-practices.js.map +0 -1
- package/dist/test/test/tools/schema-best-practices.test.d.ts +0 -3
- package/dist/test/test/tools/schema-best-practices.test.d.ts.map +0 -1
- package/dist/test/test/tools/schema-best-practices.test.js +0 -194
- package/dist/test/test/tools/schema-best-practices.test.js.map +0 -1
- package/dist/test/test/tools/spans.test.d.ts +0 -2
- package/dist/test/test/tools/spans.test.d.ts.map +0 -1
- package/dist/test/test/tools/spans.test.js +0 -84
- package/dist/test/test/tools/spans.test.js.map +0 -1
- package/dist/test/test/viewer/broadcaster.test.d.ts +0 -2
- package/dist/test/test/viewer/broadcaster.test.d.ts.map +0 -1
- package/dist/test/test/viewer/broadcaster.test.js +0 -53
- package/dist/test/test/viewer/broadcaster.test.js.map +0 -1
- package/dist/test/test/viewer/cesdk-cdn.test.d.ts +0 -2
- package/dist/test/test/viewer/cesdk-cdn.test.d.ts.map +0 -1
- package/dist/test/test/viewer/cesdk-cdn.test.js +0 -19
- package/dist/test/test/viewer/cesdk-cdn.test.js.map +0 -1
- package/dist/test/test/viewer/config-route.test.d.ts +0 -2
- package/dist/test/test/viewer/config-route.test.d.ts.map +0 -1
- package/dist/test/test/viewer/config-route.test.js +0 -28
- package/dist/test/test/viewer/config-route.test.js.map +0 -1
- package/dist/test/test/viewer/resource-route.test.d.ts +0 -2
- package/dist/test/test/viewer/resource-route.test.d.ts.map +0 -1
- package/dist/test/test/viewer/resource-route.test.js +0 -70
- package/dist/test/test/viewer/resource-route.test.js.map +0 -1
- package/dist/test/test/viewer/router.test.d.ts +0 -2
- package/dist/test/test/viewer/router.test.d.ts.map +0 -1
- package/dist/test/test/viewer/router.test.js +0 -227
- package/dist/test/test/viewer/router.test.js.map +0 -1
- package/dist/test/test/viewer/session-mount.test.d.ts +0 -2
- package/dist/test/test/viewer/session-mount.test.d.ts.map +0 -1
- package/dist/test/test/viewer/session-mount.test.js +0 -52
- package/dist/test/test/viewer/session-mount.test.js.map +0 -1
- package/dist/test/test/viewer/spa-version.test.d.ts +0 -2
- package/dist/test/test/viewer/spa-version.test.d.ts.map +0 -1
- package/dist/test/test/viewer/spa-version.test.js +0 -14
- package/dist/test/test/viewer/spa-version.test.js.map +0 -1
- package/dist/test/test/viewer/url-builder.test.d.ts +0 -2
- package/dist/test/test/viewer/url-builder.test.d.ts.map +0 -1
- package/dist/test/test/viewer/url-builder.test.js +0 -98
- package/dist/test/test/viewer/url-builder.test.js.map +0 -1
- package/dist/test/test/workspace/content-hash.test.d.ts +0 -2
- package/dist/test/test/workspace/content-hash.test.d.ts.map +0 -1
- package/dist/test/test/workspace/content-hash.test.js +0 -17
- package/dist/test/test/workspace/content-hash.test.js.map +0 -1
- package/dist/test/test/workspace/hosted-stub.test.d.ts +0 -2
- package/dist/test/test/workspace/hosted-stub.test.d.ts.map +0 -1
- package/dist/test/test/workspace/hosted-stub.test.js +0 -30
- package/dist/test/test/workspace/hosted-stub.test.js.map +0 -1
- package/dist/test/test/workspace/in-memory.test.d.ts +0 -2
- package/dist/test/test/workspace/in-memory.test.d.ts.map +0 -1
- package/dist/test/test/workspace/in-memory.test.js +0 -4
- package/dist/test/test/workspace/in-memory.test.js.map +0 -1
- package/dist/test/test/workspace/node-fs.test.d.ts +0 -2
- package/dist/test/test/workspace/node-fs.test.d.ts.map +0 -1
- package/dist/test/test/workspace/node-fs.test.js +0 -20
- package/dist/test/test/workspace/node-fs.test.js.map +0 -1
- package/dist/test/test/workspace/s3.test.d.ts +0 -2
- package/dist/test/test/workspace/s3.test.d.ts.map +0 -1
- package/dist/test/test/workspace/s3.test.js +0 -153
- package/dist/test/test/workspace/s3.test.js.map +0 -1
- package/dist/test/test/workspace/scoped.test.d.ts +0 -2
- package/dist/test/test/workspace/scoped.test.d.ts.map +0 -1
- package/dist/test/test/workspace/scoped.test.js +0 -59
- package/dist/test/test/workspace/scoped.test.js.map +0 -1
- package/dist/test/test/workspace/shared-contract.d.ts +0 -3
- package/dist/test/test/workspace/shared-contract.d.ts.map +0 -1
- package/dist/test/test/workspace/shared-contract.js +0 -92
- package/dist/test/test/workspace/shared-contract.js.map +0 -1
- package/dist/test/tsconfig.test.tsbuildinfo +0 -1
- package/dist/test/vitest.config.d.ts +0 -3
- package/dist/test/vitest.config.d.ts.map +0 -1
- package/dist/test/vitest.config.js +0 -8
- package/dist/test/vitest.config.js.map +0 -1
- package/dist/tools/metrics.d.ts +0 -11
- package/dist/tools/metrics.d.ts.map +0 -1
- package/dist/tools/metrics.js +0 -28
- package/dist/tools/metrics.js.map +0 -1
- package/dist/tools/open-editor.d.ts.map +0 -1
- package/dist/tools/open-editor.js.map +0 -1
- /package/dist/{dashboard → diagnostics}/spa-assets.generated.d.ts +0 -0
|
@@ -1,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":""}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { makeWorkspaceResolver, WorkspaceAuthError } from '../../src/http/workspace-auth.js';
|
|
3
|
-
function cfg(partial) {
|
|
4
|
-
return {
|
|
5
|
-
cesdkLicense: 'x',
|
|
6
|
-
buildId: 'test',
|
|
7
|
-
port: 8080,
|
|
8
|
-
maxEngines: 8,
|
|
9
|
-
idleTimeoutMs: 900_000,
|
|
10
|
-
logLevel: 'info',
|
|
11
|
-
workspace: { backend: 'local', dir: '/data' },
|
|
12
|
-
auth: { mode: 'header', header: 'X-Workspace-Id', ...partial },
|
|
13
|
-
gateway: {}
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function fakeReq(headers) {
|
|
17
|
-
return {
|
|
18
|
-
header: (name) => headers[name.toLowerCase()]
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
describe('makeWorkspaceResolver', () => {
|
|
22
|
-
it('header mode returns the trusted header value (opaque, unmodified)', () => {
|
|
23
|
-
const resolve = makeWorkspaceResolver(cfg({ mode: 'header', header: 'X-Workspace-Id' }));
|
|
24
|
-
const req = fakeReq({ 'x-workspace-id': 'u/usr_8842' });
|
|
25
|
-
expect(resolve(req, 'sess-1')).toBe('u/usr_8842');
|
|
26
|
-
});
|
|
27
|
-
it('header mode throws WorkspaceAuthError when the header is absent', () => {
|
|
28
|
-
const resolve = makeWorkspaceResolver(cfg({ mode: 'header' }));
|
|
29
|
-
expect(() => resolve(fakeReq({}), 'sess-1')).toThrow(WorkspaceAuthError);
|
|
30
|
-
});
|
|
31
|
-
it('session mode derives the ephemeral s/<sessionId> id', () => {
|
|
32
|
-
const resolve = makeWorkspaceResolver(cfg({ mode: 'session' }));
|
|
33
|
-
expect(resolve(fakeReq({}), 'sess-42')).toBe('s/sess-42');
|
|
34
|
-
});
|
|
35
|
-
it('single mode returns the fixed id', () => {
|
|
36
|
-
const resolve = makeWorkspaceResolver(cfg({ mode: 'single', fixedWorkspaceId: 'acme' }));
|
|
37
|
-
expect(resolve(fakeReq({}), 'sess-1')).toBe('acme');
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
//# sourceMappingURL=workspace-auth.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-auth.test.js","sourceRoot":"","sources":["../../../../test/http/workspace-auth.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,kCAAkC,CAAC;AAE1C,SAAS,GAAG,CAAC,OAAsC;IACjD,OAAO;QACL,YAAY,EAAE,GAAG;QACjB,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,CAAC;QACb,aAAa,EAAE,OAAO;QACtB,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE;QAC7C,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,EAAE;QAC9D,OAAO,EAAE,EAAE;KACZ,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,OAA+B;IAC9C,OAAO;QACL,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;KAChC,CAAC;AAC1B,CAAC;AAED,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,OAAO,GAAG,qBAAqB,CACnC,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAClD,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,OAAO,GAAG,qBAAqB,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,OAAO,GAAG,qBAAqB,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,OAAO,GAAG,qBAAqB,CACnC,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAClD,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import type { Request } from 'express';\nimport { describe, expect, it } from 'vitest';\nimport type { ServerConfig } from '../../src/config.js';\nimport {\n makeWorkspaceResolver,\n WorkspaceAuthError\n} from '../../src/http/workspace-auth.js';\n\nfunction cfg(partial: Partial<ServerConfig['auth']>): ServerConfig {\n return {\n cesdkLicense: 'x',\n buildId: 'test',\n port: 8080,\n maxEngines: 8,\n idleTimeoutMs: 900_000,\n logLevel: 'info',\n workspace: { backend: 'local', dir: '/data' },\n auth: { mode: 'header', header: 'X-Workspace-Id', ...partial },\n gateway: {}\n };\n}\n\nfunction fakeReq(headers: Record<string, string>): Request {\n return {\n header: (name: string) => headers[name.toLowerCase()]\n } as unknown as Request;\n}\n\ndescribe('makeWorkspaceResolver', () => {\n it('header mode returns the trusted header value (opaque, unmodified)', () => {\n const resolve = makeWorkspaceResolver(\n cfg({ mode: 'header', header: 'X-Workspace-Id' })\n );\n const req = fakeReq({ 'x-workspace-id': 'u/usr_8842' });\n expect(resolve(req, 'sess-1')).toBe('u/usr_8842');\n });\n\n it('header mode throws WorkspaceAuthError when the header is absent', () => {\n const resolve = makeWorkspaceResolver(cfg({ mode: 'header' }));\n expect(() => resolve(fakeReq({}), 'sess-1')).toThrow(WorkspaceAuthError);\n });\n\n it('session mode derives the ephemeral s/<sessionId> id', () => {\n const resolve = makeWorkspaceResolver(cfg({ mode: 'session' }));\n expect(resolve(fakeReq({}), 'sess-42')).toBe('s/sess-42');\n });\n\n it('single mode returns the fixed id', () => {\n const resolve = makeWorkspaceResolver(\n cfg({ mode: 'single', fixedWorkspaceId: 'acme' })\n );\n expect(resolve(fakeReq({}), 'sess-1')).toBe('acme');\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mount.test.d.ts","sourceRoot":"","sources":["../../../../test/metrics/mount.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import request from 'supertest';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { mountMetricsEndpoints } from '../../src/metrics/mount.js';
|
|
5
|
-
import { MetricsRecorder } from '../../src/metrics/recorder.js';
|
|
6
|
-
describe('mountMetricsEndpoints', () => {
|
|
7
|
-
it('GET /metrics returns the merged snapshot', async () => {
|
|
8
|
-
const recorder = new MetricsRecorder();
|
|
9
|
-
recorder.record({ tool: 'edit', durationMs: 12, ok: true });
|
|
10
|
-
recorder.sampleMemory();
|
|
11
|
-
const app = express();
|
|
12
|
-
mountMetricsEndpoints(app, {
|
|
13
|
-
recorder,
|
|
14
|
-
maxSessions: 8,
|
|
15
|
-
activeSessions: () => 2
|
|
16
|
-
});
|
|
17
|
-
const res = await request(app).get('/metrics');
|
|
18
|
-
expect(res.status).toBe(200);
|
|
19
|
-
expect(res.body.activeSessions).toBe(2);
|
|
20
|
-
expect(res.body.maxSessions).toBe(8);
|
|
21
|
-
expect(typeof res.body.uptimeMs).toBe('number');
|
|
22
|
-
expect(res.body.tools.find((t) => t.tool === 'edit')).toBeDefined();
|
|
23
|
-
expect(res.body.memory).not.toBeNull();
|
|
24
|
-
expect(Array.isArray(res.body.recent)).toBe(true);
|
|
25
|
-
});
|
|
26
|
-
it('reads activeSessions live at request time', async () => {
|
|
27
|
-
const recorder = new MetricsRecorder();
|
|
28
|
-
let live = 0;
|
|
29
|
-
const app = express();
|
|
30
|
-
mountMetricsEndpoints(app, {
|
|
31
|
-
recorder,
|
|
32
|
-
maxSessions: 4,
|
|
33
|
-
activeSessions: () => live
|
|
34
|
-
});
|
|
35
|
-
live = 3;
|
|
36
|
-
const res = await request(app).get('/metrics');
|
|
37
|
-
expect(res.body.activeSessions).toBe(3);
|
|
38
|
-
});
|
|
39
|
-
it('serves the dashboard SPA at /dashboard/ with the metrics URL injected', async () => {
|
|
40
|
-
const recorder = new MetricsRecorder();
|
|
41
|
-
const app = express();
|
|
42
|
-
mountMetricsEndpoints(app, {
|
|
43
|
-
recorder,
|
|
44
|
-
maxSessions: 8,
|
|
45
|
-
activeSessions: () => 0
|
|
46
|
-
});
|
|
47
|
-
const res = await request(app).get('/dashboard/');
|
|
48
|
-
expect(res.status).toBe(200);
|
|
49
|
-
expect(res.type).toBe('text/html');
|
|
50
|
-
expect(res.text).toContain('/metrics');
|
|
51
|
-
expect(res.text).not.toContain('{{METRICS_URL}}');
|
|
52
|
-
});
|
|
53
|
-
it('does not mount /metrics when the mounter is not called (gating)', async () => {
|
|
54
|
-
const app = express();
|
|
55
|
-
const res = await request(app).get('/metrics');
|
|
56
|
-
expect(res.status).toBe(404);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
//# sourceMappingURL=mount.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mount.test.js","sourceRoot":"","sources":["../../../../test/metrics/mount.test.ts"],"names":[],"mappings":"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","sourcesContent":["import express from 'express';\nimport request from 'supertest';\nimport { describe, expect, it } from 'vitest';\nimport { mountMetricsEndpoints } from '../../src/metrics/mount.js';\nimport { MetricsRecorder } from '../../src/metrics/recorder.js';\n\ndescribe('mountMetricsEndpoints', () => {\n it('GET /metrics returns the merged snapshot', async () => {\n const recorder = new MetricsRecorder();\n recorder.record({ tool: 'edit', durationMs: 12, ok: true });\n recorder.sampleMemory();\n const app = express();\n mountMetricsEndpoints(app, {\n recorder,\n maxSessions: 8,\n activeSessions: () => 2\n });\n const res = await request(app).get('/metrics');\n expect(res.status).toBe(200);\n expect(res.body.activeSessions).toBe(2);\n expect(res.body.maxSessions).toBe(8);\n expect(typeof res.body.uptimeMs).toBe('number');\n expect(\n res.body.tools.find((t: { tool: string }) => t.tool === 'edit')\n ).toBeDefined();\n expect(res.body.memory).not.toBeNull();\n expect(Array.isArray(res.body.recent)).toBe(true);\n });\n\n it('reads activeSessions live at request time', async () => {\n const recorder = new MetricsRecorder();\n let live = 0;\n const app = express();\n mountMetricsEndpoints(app, {\n recorder,\n maxSessions: 4,\n activeSessions: () => live\n });\n live = 3;\n const res = await request(app).get('/metrics');\n expect(res.body.activeSessions).toBe(3);\n });\n\n it('serves the dashboard SPA at /dashboard/ with the metrics URL injected', async () => {\n const recorder = new MetricsRecorder();\n const app = express();\n mountMetricsEndpoints(app, {\n recorder,\n maxSessions: 8,\n activeSessions: () => 0\n });\n const res = await request(app).get('/dashboard/');\n expect(res.status).toBe(200);\n expect(res.type).toBe('text/html');\n expect(res.text).toContain('/metrics');\n expect(res.text).not.toContain('{{METRICS_URL}}');\n });\n\n it('does not mount /metrics when the mounter is not called (gating)', async () => {\n const app = express();\n const res = await request(app).get('/metrics');\n expect(res.status).toBe(404);\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.test.d.ts","sourceRoot":"","sources":["../../../../test/metrics/recorder.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { MetricsRecorder } from '../../src/metrics/recorder.js';
|
|
3
|
-
describe('MetricsRecorder.record + snapshot', () => {
|
|
4
|
-
it('aggregates count/errorCount and min/max/mean from the sample', () => {
|
|
5
|
-
const r = new MetricsRecorder();
|
|
6
|
-
r.record({ tool: 'edit', durationMs: 10, ok: true });
|
|
7
|
-
r.record({ tool: 'edit', durationMs: 30, ok: false });
|
|
8
|
-
r.record({ tool: 'edit', durationMs: 20, ok: true });
|
|
9
|
-
const edit = r.snapshot().tools.find((t) => t.tool === 'edit');
|
|
10
|
-
expect(edit).toBeDefined();
|
|
11
|
-
expect(edit.count).toBe(3);
|
|
12
|
-
expect(edit.errorCount).toBe(1);
|
|
13
|
-
expect(edit.min).toBe(10);
|
|
14
|
-
expect(edit.max).toBe(30);
|
|
15
|
-
expect(edit.mean).toBe(20);
|
|
16
|
-
});
|
|
17
|
-
it('computes p50/p95 via nearest-rank over the sample', () => {
|
|
18
|
-
const r = new MetricsRecorder();
|
|
19
|
-
for (const d of [10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
|
|
20
|
-
r.record({ tool: 'x', durationMs: d, ok: true });
|
|
21
|
-
const x = r.snapshot().tools.find((t) => t.tool === 'x');
|
|
22
|
-
// nearest-rank: p50 → idx ceil(0.5*10)-1 = 4 → 50; p95 → idx 9 → 100
|
|
23
|
-
expect(x.p50).toBe(50);
|
|
24
|
-
expect(x.p95).toBe(100);
|
|
25
|
-
});
|
|
26
|
-
it('separates aggregates by tool name', () => {
|
|
27
|
-
const r = new MetricsRecorder();
|
|
28
|
-
r.record({ tool: 'edit', durationMs: 5, ok: true });
|
|
29
|
-
r.record({ tool: 'export', durationMs: 7, ok: true });
|
|
30
|
-
expect(r
|
|
31
|
-
.snapshot()
|
|
32
|
-
.tools.map((t) => t.tool)
|
|
33
|
-
.sort()).toEqual(['edit', 'export']);
|
|
34
|
-
});
|
|
35
|
-
it('evicts oldest recent records beyond recentLimit', () => {
|
|
36
|
-
const r = new MetricsRecorder({ recentLimit: 3 });
|
|
37
|
-
for (let i = 0; i < 5; i++)
|
|
38
|
-
r.record({ tool: 't', durationMs: i, ok: true });
|
|
39
|
-
const recent = r.snapshot().recent;
|
|
40
|
-
expect(recent).toHaveLength(3);
|
|
41
|
-
// newest-last ring: durations 2,3,4 survive
|
|
42
|
-
expect(recent.map((x) => x.durationMs)).toEqual([2, 3, 4]);
|
|
43
|
-
});
|
|
44
|
-
it('bounds the per-tool duration sample to sampleSize (most-recent wins)', () => {
|
|
45
|
-
const r = new MetricsRecorder({ sampleSize: 2 });
|
|
46
|
-
r.record({ tool: 't', durationMs: 1000, ok: true });
|
|
47
|
-
r.record({ tool: 't', durationMs: 1, ok: true });
|
|
48
|
-
r.record({ tool: 't', durationMs: 2, ok: true });
|
|
49
|
-
const t = r.snapshot().tools.find((x) => x.tool === 't');
|
|
50
|
-
// count still counts every call…
|
|
51
|
-
expect(t.count).toBe(3);
|
|
52
|
-
// …but min/max/percentiles come from the bounded sample [1, 2]
|
|
53
|
-
expect(t.min).toBe(1);
|
|
54
|
-
expect(t.max).toBe(2);
|
|
55
|
-
expect(t.p95).toBe(2);
|
|
56
|
-
expect(t.p50).toBe(1);
|
|
57
|
-
});
|
|
58
|
-
it('snapshot has the documented shape', () => {
|
|
59
|
-
const r = new MetricsRecorder();
|
|
60
|
-
r.record({ tool: 't', durationMs: 1, ok: true });
|
|
61
|
-
const snap = r.snapshot();
|
|
62
|
-
expect(snap).toHaveProperty('tools');
|
|
63
|
-
expect(snap).toHaveProperty('recent');
|
|
64
|
-
expect(snap).toHaveProperty('memory');
|
|
65
|
-
expect(Array.isArray(snap.tools)).toBe(true);
|
|
66
|
-
expect(Array.isArray(snap.recent)).toBe(true);
|
|
67
|
-
});
|
|
68
|
-
it('recent records carry tool, durationMs, ok, ts', () => {
|
|
69
|
-
const r = new MetricsRecorder();
|
|
70
|
-
r.record({ tool: 'edit', durationMs: 12, ok: false });
|
|
71
|
-
const rec = r.snapshot().recent[0];
|
|
72
|
-
expect(rec.tool).toBe('edit');
|
|
73
|
-
expect(rec.durationMs).toBe(12);
|
|
74
|
-
expect(rec.ok).toBe(false);
|
|
75
|
-
expect(typeof rec.ts).toBe('number');
|
|
76
|
-
});
|
|
77
|
-
it('memory is null before any sample, populated after sampleMemory()', () => {
|
|
78
|
-
const r = new MetricsRecorder();
|
|
79
|
-
expect(r.snapshot().memory).toBeNull();
|
|
80
|
-
r.sampleMemory();
|
|
81
|
-
const mem = r.snapshot().memory;
|
|
82
|
-
expect(mem).not.toBeNull();
|
|
83
|
-
expect(typeof mem.rss).toBe('number');
|
|
84
|
-
expect(typeof mem.heapUsed).toBe('number');
|
|
85
|
-
expect(typeof mem.external).toBe('number');
|
|
86
|
-
expect(typeof mem.arrayBuffers).toBe('number');
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
describe('MetricsRecorder.start/stop', () => {
|
|
90
|
-
afterEach(() => vi.useRealTimers());
|
|
91
|
-
it('start() seeds an immediate memory sample', () => {
|
|
92
|
-
const r = new MetricsRecorder();
|
|
93
|
-
r.start();
|
|
94
|
-
expect(r.snapshot().memory).not.toBeNull();
|
|
95
|
-
r.stop();
|
|
96
|
-
});
|
|
97
|
-
it('start() samples memory on the interval', () => {
|
|
98
|
-
vi.useFakeTimers();
|
|
99
|
-
const r = new MetricsRecorder({ memorySampleMs: 1000 });
|
|
100
|
-
const spy = vi.spyOn(r, 'sampleMemory');
|
|
101
|
-
r.start(); // one immediate seed
|
|
102
|
-
expect(spy).toHaveBeenCalledTimes(1);
|
|
103
|
-
vi.advanceTimersByTime(3000);
|
|
104
|
-
expect(spy).toHaveBeenCalledTimes(4); // seed + 3 ticks
|
|
105
|
-
r.stop();
|
|
106
|
-
});
|
|
107
|
-
it('stop() is idempotent and clears the timer', () => {
|
|
108
|
-
vi.useFakeTimers();
|
|
109
|
-
const r = new MetricsRecorder({ memorySampleMs: 1000 });
|
|
110
|
-
const spy = vi.spyOn(r, 'sampleMemory');
|
|
111
|
-
r.start();
|
|
112
|
-
r.stop();
|
|
113
|
-
r.stop(); // no throw
|
|
114
|
-
vi.advanceTimersByTime(5000);
|
|
115
|
-
expect(spy).toHaveBeenCalledTimes(1); // only the seed; no ticks after stop
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
//# sourceMappingURL=recorder.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.test.js","sourceRoot":"","sources":["../../../../test/metrics/recorder.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, describe, expect, it, vi } from 'vitest';\nimport { MetricsRecorder } from '../../src/metrics/recorder.js';\n\ndescribe('MetricsRecorder.record + snapshot', () => {\n it('aggregates count/errorCount and min/max/mean from the sample', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 'edit', durationMs: 10, ok: true });\n r.record({ tool: 'edit', durationMs: 30, ok: false });\n r.record({ tool: 'edit', durationMs: 20, ok: true });\n const edit = r.snapshot().tools.find((t) => t.tool === 'edit');\n expect(edit).toBeDefined();\n expect(edit!.count).toBe(3);\n expect(edit!.errorCount).toBe(1);\n expect(edit!.min).toBe(10);\n expect(edit!.max).toBe(30);\n expect(edit!.mean).toBe(20);\n });\n\n it('computes p50/p95 via nearest-rank over the sample', () => {\n const r = new MetricsRecorder();\n for (const d of [10, 20, 30, 40, 50, 60, 70, 80, 90, 100])\n r.record({ tool: 'x', durationMs: d, ok: true });\n const x = r.snapshot().tools.find((t) => t.tool === 'x')!;\n // nearest-rank: p50 → idx ceil(0.5*10)-1 = 4 → 50; p95 → idx 9 → 100\n expect(x.p50).toBe(50);\n expect(x.p95).toBe(100);\n });\n\n it('separates aggregates by tool name', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 'edit', durationMs: 5, ok: true });\n r.record({ tool: 'export', durationMs: 7, ok: true });\n expect(\n r\n .snapshot()\n .tools.map((t) => t.tool)\n .sort()\n ).toEqual(['edit', 'export']);\n });\n\n it('evicts oldest recent records beyond recentLimit', () => {\n const r = new MetricsRecorder({ recentLimit: 3 });\n for (let i = 0; i < 5; i++)\n r.record({ tool: 't', durationMs: i, ok: true });\n const recent = r.snapshot().recent;\n expect(recent).toHaveLength(3);\n // newest-last ring: durations 2,3,4 survive\n expect(recent.map((x) => x.durationMs)).toEqual([2, 3, 4]);\n });\n\n it('bounds the per-tool duration sample to sampleSize (most-recent wins)', () => {\n const r = new MetricsRecorder({ sampleSize: 2 });\n r.record({ tool: 't', durationMs: 1000, ok: true });\n r.record({ tool: 't', durationMs: 1, ok: true });\n r.record({ tool: 't', durationMs: 2, ok: true });\n const t = r.snapshot().tools.find((x) => x.tool === 't')!;\n // count still counts every call…\n expect(t.count).toBe(3);\n // …but min/max/percentiles come from the bounded sample [1, 2]\n expect(t.min).toBe(1);\n expect(t.max).toBe(2);\n expect(t.p95).toBe(2);\n expect(t.p50).toBe(1);\n });\n\n it('snapshot has the documented shape', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 't', durationMs: 1, ok: true });\n const snap = r.snapshot();\n expect(snap).toHaveProperty('tools');\n expect(snap).toHaveProperty('recent');\n expect(snap).toHaveProperty('memory');\n expect(Array.isArray(snap.tools)).toBe(true);\n expect(Array.isArray(snap.recent)).toBe(true);\n });\n\n it('recent records carry tool, durationMs, ok, ts', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 'edit', durationMs: 12, ok: false });\n const rec = r.snapshot().recent[0];\n expect(rec.tool).toBe('edit');\n expect(rec.durationMs).toBe(12);\n expect(rec.ok).toBe(false);\n expect(typeof rec.ts).toBe('number');\n });\n\n it('memory is null before any sample, populated after sampleMemory()', () => {\n const r = new MetricsRecorder();\n expect(r.snapshot().memory).toBeNull();\n r.sampleMemory();\n const mem = r.snapshot().memory;\n expect(mem).not.toBeNull();\n expect(typeof mem!.rss).toBe('number');\n expect(typeof mem!.heapUsed).toBe('number');\n expect(typeof mem!.external).toBe('number');\n expect(typeof mem!.arrayBuffers).toBe('number');\n });\n});\n\ndescribe('MetricsRecorder.start/stop', () => {\n afterEach(() => vi.useRealTimers());\n\n it('start() seeds an immediate memory sample', () => {\n const r = new MetricsRecorder();\n r.start();\n expect(r.snapshot().memory).not.toBeNull();\n r.stop();\n });\n\n it('start() samples memory on the interval', () => {\n vi.useFakeTimers();\n const r = new MetricsRecorder({ memorySampleMs: 1000 });\n const spy = vi.spyOn(r, 'sampleMemory');\n r.start(); // one immediate seed\n expect(spy).toHaveBeenCalledTimes(1);\n vi.advanceTimersByTime(3000);\n expect(spy).toHaveBeenCalledTimes(4); // seed + 3 ticks\n r.stop();\n });\n\n it('stop() is idempotent and clears the timer', () => {\n vi.useFakeTimers();\n const r = new MetricsRecorder({ memorySampleMs: 1000 });\n const spy = vi.spyOn(r, 'sampleMemory');\n r.start();\n r.stop();\n r.stop(); // no throw\n vi.advanceTimersByTime(5000);\n expect(spy).toHaveBeenCalledTimes(1); // only the seed; no ticks after stop\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hash.test.d.ts","sourceRoot":"","sources":["../../../../test/revisions/hash.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { revisionId } from '../../src/revisions/hash.js';
|
|
3
|
-
describe('revisionId', () => {
|
|
4
|
-
it('derives a 12-hex-char id', async () => {
|
|
5
|
-
expect(await revisionId({ scene: 'abc', parent: null })).toMatch(/^[0-9a-f]{12}$/);
|
|
6
|
-
});
|
|
7
|
-
it('is deterministic', async () => {
|
|
8
|
-
const a = await revisionId({
|
|
9
|
-
scene: 'abc',
|
|
10
|
-
parent: 'deadbeef',
|
|
11
|
-
note: 'fix'
|
|
12
|
-
});
|
|
13
|
-
const b = await revisionId({
|
|
14
|
-
scene: 'abc',
|
|
15
|
-
parent: 'deadbeef',
|
|
16
|
-
note: 'fix'
|
|
17
|
-
});
|
|
18
|
-
expect(a).toBe(b);
|
|
19
|
-
});
|
|
20
|
-
it('differs when scene differs', async () => {
|
|
21
|
-
expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(await revisionId({ scene: 'abd', parent: null }));
|
|
22
|
-
});
|
|
23
|
-
it('differs when parent differs', async () => {
|
|
24
|
-
expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(await revisionId({ scene: 'abc', parent: '0000' }));
|
|
25
|
-
});
|
|
26
|
-
it('differs when note differs', async () => {
|
|
27
|
-
expect(await revisionId({ scene: 'abc', parent: null, note: 'v1' })).not.toBe(await revisionId({ scene: 'abc', parent: null, note: 'v2' }));
|
|
28
|
-
});
|
|
29
|
-
it('treats missing note as empty', async () => {
|
|
30
|
-
expect(await revisionId({ scene: 'abc', parent: null, note: '' })).toBe(await revisionId({ scene: 'abc', parent: null }));
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
//# sourceMappingURL=hash.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hash.test.js","sourceRoot":"","sources":["../../../../test/revisions/hash.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAC9D,gBAAgB,CACjB,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC;YACzB,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC;YACzB,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAC/D,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CACjD,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAC/D,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CACnD,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,CACJ,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAC7D,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACrE,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CACjD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { revisionId } from '../../src/revisions/hash.js';\n\ndescribe('revisionId', () => {\n it('derives a 12-hex-char id', async () => {\n expect(await revisionId({ scene: 'abc', parent: null })).toMatch(\n /^[0-9a-f]{12}$/\n );\n });\n it('is deterministic', async () => {\n const a = await revisionId({\n scene: 'abc',\n parent: 'deadbeef',\n note: 'fix'\n });\n const b = await revisionId({\n scene: 'abc',\n parent: 'deadbeef',\n note: 'fix'\n });\n expect(a).toBe(b);\n });\n it('differs when scene differs', async () => {\n expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(\n await revisionId({ scene: 'abd', parent: null })\n );\n });\n it('differs when parent differs', async () => {\n expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(\n await revisionId({ scene: 'abc', parent: '0000' })\n );\n });\n it('differs when note differs', async () => {\n expect(\n await revisionId({ scene: 'abc', parent: null, note: 'v1' })\n ).not.toBe(await revisionId({ scene: 'abc', parent: null, note: 'v2' }));\n });\n it('treats missing note as empty', async () => {\n expect(await revisionId({ scene: 'abc', parent: null, note: '' })).toBe(\n await revisionId({ scene: 'abc', parent: null })\n );\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.test.d.ts","sourceRoot":"","sources":["../../../../test/revisions/store.test.ts"],"names":[],"mappings":""}
|