@dailephd/my-frontend-observer 0.8.1
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/CHANGELOG.md +397 -0
- package/LICENSE +21 -0
- package/README.md +255 -0
- package/dist/application/browserCaptureService.d.ts +11 -0
- package/dist/application/browserCaptureService.js +12 -0
- package/dist/application/browserCaptureService.js.map +1 -0
- package/dist/application/comparisonService.d.ts +56 -0
- package/dist/application/comparisonService.js +77 -0
- package/dist/application/comparisonService.js.map +1 -0
- package/dist/application/externalReferencePersistenceService.d.ts +75 -0
- package/dist/application/externalReferencePersistenceService.js +182 -0
- package/dist/application/externalReferencePersistenceService.js.map +1 -0
- package/dist/application/frontendContractEvaluationService.d.ts +49 -0
- package/dist/application/frontendContractEvaluationService.js +112 -0
- package/dist/application/frontendContractEvaluationService.js.map +1 -0
- package/dist/application/frontendContractPersistenceService.d.ts +56 -0
- package/dist/application/frontendContractPersistenceService.js +91 -0
- package/dist/application/frontendContractPersistenceService.js.map +1 -0
- package/dist/application/observationPersistence.d.ts +59 -0
- package/dist/application/observationPersistence.js +79 -0
- package/dist/application/observationPersistence.js.map +1 -0
- package/dist/application/projectCheckService.d.ts +3 -0
- package/dist/application/projectCheckService.js +169 -0
- package/dist/application/projectCheckService.js.map +1 -0
- package/dist/application/projectWorkflowService.d.ts +46 -0
- package/dist/application/projectWorkflowService.js +92 -0
- package/dist/application/projectWorkflowService.js.map +1 -0
- package/dist/application/referenceFidelityEvaluationService.d.ts +28 -0
- package/dist/application/referenceFidelityEvaluationService.js +45 -0
- package/dist/application/referenceFidelityEvaluationService.js.map +1 -0
- package/dist/artifacts/artifactReader.d.ts +19 -0
- package/dist/artifacts/artifactReader.js +36 -0
- package/dist/artifacts/artifactReader.js.map +1 -0
- package/dist/artifacts/artifactWriter.d.ts +25 -0
- package/dist/artifacts/artifactWriter.js +68 -0
- package/dist/artifacts/artifactWriter.js.map +1 -0
- package/dist/artifacts/comparisonArtifactReader.d.ts +18 -0
- package/dist/artifacts/comparisonArtifactReader.js +35 -0
- package/dist/artifacts/comparisonArtifactReader.js.map +1 -0
- package/dist/artifacts/comparisonArtifactWriter.d.ts +41 -0
- package/dist/artifacts/comparisonArtifactWriter.js +67 -0
- package/dist/artifacts/comparisonArtifactWriter.js.map +1 -0
- package/dist/artifacts/externalReferenceArtifactReader.d.ts +18 -0
- package/dist/artifacts/externalReferenceArtifactReader.js +35 -0
- package/dist/artifacts/externalReferenceArtifactReader.js.map +1 -0
- package/dist/artifacts/externalReferenceArtifactWriter.d.ts +44 -0
- package/dist/artifacts/externalReferenceArtifactWriter.js +77 -0
- package/dist/artifacts/externalReferenceArtifactWriter.js.map +1 -0
- package/dist/artifacts/frontendContractArtifactReader.d.ts +24 -0
- package/dist/artifacts/frontendContractArtifactReader.js +47 -0
- package/dist/artifacts/frontendContractArtifactReader.js.map +1 -0
- package/dist/artifacts/frontendContractArtifactWriter.d.ts +34 -0
- package/dist/artifacts/frontendContractArtifactWriter.js +70 -0
- package/dist/artifacts/frontendContractArtifactWriter.js.map +1 -0
- package/dist/artifacts/frontendContractEvaluationArtifactReader.d.ts +17 -0
- package/dist/artifacts/frontendContractEvaluationArtifactReader.js +34 -0
- package/dist/artifacts/frontendContractEvaluationArtifactReader.js.map +1 -0
- package/dist/artifacts/frontendContractEvaluationArtifactWriter.d.ts +32 -0
- package/dist/artifacts/frontendContractEvaluationArtifactWriter.js +58 -0
- package/dist/artifacts/frontendContractEvaluationArtifactWriter.js.map +1 -0
- package/dist/artifacts/types.d.ts +17 -0
- package/dist/artifacts/types.js +2 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/browser/chromiumAdapter.d.ts +21 -0
- package/dist/browser/chromiumAdapter.js +204 -0
- package/dist/browser/chromiumAdapter.js.map +1 -0
- package/dist/browser/evidenceCapture.d.ts +62 -0
- package/dist/browser/evidenceCapture.js +500 -0
- package/dist/browser/evidenceCapture.js.map +1 -0
- package/dist/browser/scrollCapture.d.ts +32 -0
- package/dist/browser/scrollCapture.js +163 -0
- package/dist/browser/scrollCapture.js.map +1 -0
- package/dist/browser/types.d.ts +24 -0
- package/dist/browser/types.js +2 -0
- package/dist/browser/types.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +2411 -0
- package/dist/cli.js.map +1 -0
- package/dist/domain/boundedAgentContext.d.ts +226 -0
- package/dist/domain/boundedAgentContext.js +355 -0
- package/dist/domain/boundedAgentContext.js.map +1 -0
- package/dist/domain/boundedAgentContextCorrelation.d.ts +74 -0
- package/dist/domain/boundedAgentContextCorrelation.js +441 -0
- package/dist/domain/boundedAgentContextCorrelation.js.map +1 -0
- package/dist/domain/boundedAgentContextIdentity.d.ts +26 -0
- package/dist/domain/boundedAgentContextIdentity.js +69 -0
- package/dist/domain/boundedAgentContextIdentity.js.map +1 -0
- package/dist/domain/boundedAgentContextProjection.d.ts +71 -0
- package/dist/domain/boundedAgentContextProjection.js +477 -0
- package/dist/domain/boundedAgentContextProjection.js.map +1 -0
- package/dist/domain/comparison.d.ts +220 -0
- package/dist/domain/comparison.js +350 -0
- package/dist/domain/comparison.js.map +1 -0
- package/dist/domain/comparisonEngine.d.ts +76 -0
- package/dist/domain/comparisonEngine.js +734 -0
- package/dist/domain/comparisonEngine.js.map +1 -0
- package/dist/domain/comparisonIdentity.d.ts +13 -0
- package/dist/domain/comparisonIdentity.js +46 -0
- package/dist/domain/comparisonIdentity.js.map +1 -0
- package/dist/domain/completion.d.ts +30 -0
- package/dist/domain/completion.js +22 -0
- package/dist/domain/completion.js.map +1 -0
- package/dist/domain/diagnostics.d.ts +17 -0
- package/dist/domain/diagnostics.js +77 -0
- package/dist/domain/diagnostics.js.map +1 -0
- package/dist/domain/evidence.d.ts +29 -0
- package/dist/domain/evidence.js +59 -0
- package/dist/domain/evidence.js.map +1 -0
- package/dist/domain/explicitState.d.ts +40 -0
- package/dist/domain/explicitState.js +54 -0
- package/dist/domain/explicitState.js.map +1 -0
- package/dist/domain/externalReference.d.ts +158 -0
- package/dist/domain/externalReference.js +167 -0
- package/dist/domain/externalReference.js.map +1 -0
- package/dist/domain/externalReferenceApplicability.d.ts +43 -0
- package/dist/domain/externalReferenceApplicability.js +52 -0
- package/dist/domain/externalReferenceApplicability.js.map +1 -0
- package/dist/domain/externalReferenceCompatibility.d.ts +40 -0
- package/dist/domain/externalReferenceCompatibility.js +48 -0
- package/dist/domain/externalReferenceCompatibility.js.map +1 -0
- package/dist/domain/externalReferenceFidelity.d.ts +171 -0
- package/dist/domain/externalReferenceFidelity.js +419 -0
- package/dist/domain/externalReferenceFidelity.js.map +1 -0
- package/dist/domain/externalReferenceIdentity.d.ts +38 -0
- package/dist/domain/externalReferenceIdentity.js +70 -0
- package/dist/domain/externalReferenceIdentity.js.map +1 -0
- package/dist/domain/externalReferenceImage.d.ts +35 -0
- package/dist/domain/externalReferenceImage.js +160 -0
- package/dist/domain/externalReferenceImage.js.map +1 -0
- package/dist/domain/externalReferenceRegionRelationships.d.ts +63 -0
- package/dist/domain/externalReferenceRegionRelationships.js +98 -0
- package/dist/domain/externalReferenceRegionRelationships.js.map +1 -0
- package/dist/domain/externalReferenceRegions.d.ts +65 -0
- package/dist/domain/externalReferenceRegions.js +105 -0
- package/dist/domain/externalReferenceRegions.js.map +1 -0
- package/dist/domain/externalReferenceRequirementIdentity.d.ts +12 -0
- package/dist/domain/externalReferenceRequirementIdentity.js +35 -0
- package/dist/domain/externalReferenceRequirementIdentity.js.map +1 -0
- package/dist/domain/externalReferenceRequirements.d.ts +215 -0
- package/dist/domain/externalReferenceRequirements.js +401 -0
- package/dist/domain/externalReferenceRequirements.js.map +1 -0
- package/dist/domain/externalReferenceRuntimeBinding.d.ts +146 -0
- package/dist/domain/externalReferenceRuntimeBinding.js +183 -0
- package/dist/domain/externalReferenceRuntimeBinding.js.map +1 -0
- package/dist/domain/frontendContractEvaluation.d.ts +57 -0
- package/dist/domain/frontendContractEvaluation.js +454 -0
- package/dist/domain/frontendContractEvaluation.js.map +1 -0
- package/dist/domain/frontendContractEvaluationArtifact.d.ts +65 -0
- package/dist/domain/frontendContractEvaluationArtifact.js +108 -0
- package/dist/domain/frontendContractEvaluationArtifact.js.map +1 -0
- package/dist/domain/frontendContractIdentity.d.ts +39 -0
- package/dist/domain/frontendContractIdentity.js +70 -0
- package/dist/domain/frontendContractIdentity.js.map +1 -0
- package/dist/domain/frontendContracts.d.ts +188 -0
- package/dist/domain/frontendContracts.js +260 -0
- package/dist/domain/frontendContracts.js.map +1 -0
- package/dist/domain/identity.d.ts +21 -0
- package/dist/domain/identity.js +47 -0
- package/dist/domain/identity.js.map +1 -0
- package/dist/domain/referenceCorrectionIdentity.d.ts +40 -0
- package/dist/domain/referenceCorrectionIdentity.js +77 -0
- package/dist/domain/referenceCorrectionIdentity.js.map +1 -0
- package/dist/domain/referenceCorrectionWorkflow.d.ts +160 -0
- package/dist/domain/referenceCorrectionWorkflow.js +165 -0
- package/dist/domain/referenceCorrectionWorkflow.js.map +1 -0
- package/dist/domain/referenceFidelityProjection.d.ts +65 -0
- package/dist/domain/referenceFidelityProjection.js +135 -0
- package/dist/domain/referenceFidelityProjection.js.map +1 -0
- package/dist/domain/relationships.d.ts +210 -0
- package/dist/domain/relationships.js +352 -0
- package/dist/domain/relationships.js.map +1 -0
- package/dist/domain/schema.d.ts +269 -0
- package/dist/domain/schema.js +442 -0
- package/dist/domain/schema.js.map +1 -0
- package/dist/domain/scrollEvidence.d.ts +51 -0
- package/dist/domain/scrollEvidence.js +134 -0
- package/dist/domain/scrollEvidence.js.map +1 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/projectWorkflow/aliasCatalog.d.ts +21 -0
- package/dist/projectWorkflow/aliasCatalog.js +67 -0
- package/dist/projectWorkflow/aliasCatalog.js.map +1 -0
- package/dist/projectWorkflow/checkAcceptance.d.ts +25 -0
- package/dist/projectWorkflow/checkAcceptance.js +55 -0
- package/dist/projectWorkflow/checkAcceptance.js.map +1 -0
- package/dist/projectWorkflow/checkResult.d.ts +85 -0
- package/dist/projectWorkflow/checkResult.js +101 -0
- package/dist/projectWorkflow/checkResult.js.map +1 -0
- package/dist/projectWorkflow/projectConfig.d.ts +43 -0
- package/dist/projectWorkflow/projectConfig.js +84 -0
- package/dist/projectWorkflow/projectConfig.js.map +1 -0
- package/dist/projectWorkflow/projectDiscovery.d.ts +9 -0
- package/dist/projectWorkflow/projectDiscovery.js +20 -0
- package/dist/projectWorkflow/projectDiscovery.js.map +1 -0
- package/dist/projectWorkflow/projectPaths.d.ts +8 -0
- package/dist/projectWorkflow/projectPaths.js +23 -0
- package/dist/projectWorkflow/projectPaths.js.map +1 -0
- package/dist/request/paths.d.ts +14 -0
- package/dist/request/paths.js +33 -0
- package/dist/request/paths.js.map +1 -0
- package/dist/request/request.d.ts +111 -0
- package/dist/request/request.js +464 -0
- package/dist/request/request.js.map +1 -0
- package/dist/safety/policy.d.ts +14 -0
- package/dist/safety/policy.js +81 -0
- package/dist/safety/policy.js.map +1 -0
- package/dist/viewer/assets/index-CN_yb9Uf.css +1 -0
- package/dist/viewer/assets/index-D98S1_2d.js +9 -0
- package/dist/viewer/icons/icon-192.png +0 -0
- package/dist/viewer/icons/icon-512.png +0 -0
- package/dist/viewer/index.html +15 -0
- package/dist/viewer/manifest.webmanifest +1 -0
- package/dist/viewer/registerSW.js +1 -0
- package/dist/viewer/sw.js +1 -0
- package/dist/viewer/workbox-9c191d2f.js +1 -0
- package/dist/viewerServer/context.d.ts +48 -0
- package/dist/viewerServer/context.js +60 -0
- package/dist/viewerServer/context.js.map +1 -0
- package/dist/viewerServer/evidence/classify.d.ts +59 -0
- package/dist/viewerServer/evidence/classify.js +124 -0
- package/dist/viewerServer/evidence/classify.js.map +1 -0
- package/dist/viewerServer/evidence/comparisonView.d.ts +28 -0
- package/dist/viewerServer/evidence/comparisonView.js +43 -0
- package/dist/viewerServer/evidence/comparisonView.js.map +1 -0
- package/dist/viewerServer/evidence/contextSourceView.d.ts +25 -0
- package/dist/viewerServer/evidence/contextSourceView.js +20 -0
- package/dist/viewerServer/evidence/contextSourceView.js.map +1 -0
- package/dist/viewerServer/evidence/discovery.d.ts +31 -0
- package/dist/viewerServer/evidence/discovery.js +78 -0
- package/dist/viewerServer/evidence/discovery.js.map +1 -0
- package/dist/viewerServer/evidence/evaluationView.d.ts +32 -0
- package/dist/viewerServer/evidence/evaluationView.js +50 -0
- package/dist/viewerServer/evidence/evaluationView.js.map +1 -0
- package/dist/viewerServer/evidence/handles.d.ts +21 -0
- package/dist/viewerServer/evidence/handles.js +43 -0
- package/dist/viewerServer/evidence/handles.js.map +1 -0
- package/dist/viewerServer/evidence/index.d.ts +41 -0
- package/dist/viewerServer/evidence/index.js +82 -0
- package/dist/viewerServer/evidence/index.js.map +1 -0
- package/dist/viewerServer/evidence/limits.d.ts +27 -0
- package/dist/viewerServer/evidence/limits.js +28 -0
- package/dist/viewerServer/evidence/limits.js.map +1 -0
- package/dist/viewerServer/evidence/linkedEvidence.d.ts +43 -0
- package/dist/viewerServer/evidence/linkedEvidence.js +151 -0
- package/dist/viewerServer/evidence/linkedEvidence.js.map +1 -0
- package/dist/viewerServer/evidence/mediaResolver.d.ts +16 -0
- package/dist/viewerServer/evidence/mediaResolver.js +85 -0
- package/dist/viewerServer/evidence/mediaResolver.js.map +1 -0
- package/dist/viewerServer/evidence/observationView.d.ts +29 -0
- package/dist/viewerServer/evidence/observationView.js +46 -0
- package/dist/viewerServer/evidence/observationView.js.map +1 -0
- package/dist/viewerServer/evidence/pathSafety.d.ts +11 -0
- package/dist/viewerServer/evidence/pathSafety.js +31 -0
- package/dist/viewerServer/evidence/pathSafety.js.map +1 -0
- package/dist/viewerServer/evidence/projection.d.ts +55 -0
- package/dist/viewerServer/evidence/projection.js +152 -0
- package/dist/viewerServer/evidence/projection.js.map +1 -0
- package/dist/viewerServer/evidence/referenceView.d.ts +133 -0
- package/dist/viewerServer/evidence/referenceView.js +169 -0
- package/dist/viewerServer/evidence/referenceView.js.map +1 -0
- package/dist/viewerServer/httpServer.d.ts +27 -0
- package/dist/viewerServer/httpServer.js +381 -0
- package/dist/viewerServer/httpServer.js.map +1 -0
- package/dist/viewerServer/openBrowser.d.ts +7 -0
- package/dist/viewerServer/openBrowser.js +32 -0
- package/dist/viewerServer/openBrowser.js.map +1 -0
- package/dist/viewerServer/port.d.ts +16 -0
- package/dist/viewerServer/port.js +19 -0
- package/dist/viewerServer/port.js.map +1 -0
- package/dist/viewerServer/viewerService.d.ts +62 -0
- package/dist/viewerServer/viewerService.js +88 -0
- package/dist/viewerServer/viewerService.js.map +1 -0
- package/docs/ARCHITECTURE.md +1286 -0
- package/docs/CI_CD.md +250 -0
- package/docs/COMMANDS.md +972 -0
- package/docs/CONTRACTS.md +1856 -0
- package/docs/CURRENT_STATE.md +1049 -0
- package/docs/DEVELOPMENT.md +202 -0
- package/docs/DOCUMENTATION_PRESERVATION_POLICY.md +50 -0
- package/docs/PROJECT_DESCRIPTION.md +2221 -0
- package/docs/PROJECT_MILESTONES.md +2526 -0
- package/docs/PROJECT_OVERVIEW.md +150 -0
- package/docs/QUICKSTART.md +83 -0
- package/docs/RELEASE.md +27 -0
- package/docs/ROADMAP.md +641 -0
- package/docs/SECURITY.md +218 -0
- package/docs/WORKFLOWS.md +642 -0
- package/docs/plans/v0.8-implementation-plan.md +655 -0
- package/docs/plans/v0.8.1-cli-usability-patch-plan.md +505 -0
- package/docs/reports/v0.7-bounded-fidelity-context-prompt7.md +243 -0
- package/docs/reports/v0.7-implementation-completeness-documentation-reconciliation.md +497 -0
- package/docs/reports/v0.7-pre-release-readiness.md +337 -0
- package/docs/reports/v0.7-reference-binding-prompt5.md +223 -0
- package/docs/reports/v0.7-reference-compatibility-prompt4.md +234 -0
- package/docs/reports/v0.7-reference-correction-workflow-prompt8.md +222 -0
- package/docs/reports/v0.7-reference-fidelity-prompt6.md +216 -0
- package/docs/reports/v0.7-reference-foundation-prompt1.md +151 -0
- package/docs/reports/v0.7-reference-regions-prompt2.md +195 -0
- package/docs/reports/v0.7-reference-requirements-prompt3.md +217 -0
- package/docs/reports/v0.7-release-prep.md +423 -0
- package/docs/reports/v0.8-binding-fidelity-interaction-batch6.md +279 -0
- package/docs/reports/v0.8-bounded-context-correlation-batch7.md +233 -0
- package/docs/reports/v0.8-comparison-contract-inspection-batch4.md +279 -0
- package/docs/reports/v0.8-evidence-index-readers-batch2.md +247 -0
- package/docs/reports/v0.8-implementation-completeness-documentation-reconciliation.md +741 -0
- package/docs/reports/v0.8-integrated-viewer-acceptance-batch8.md +128 -0
- package/docs/reports/v0.8-observation-svg-inspection-batch3.md +223 -0
- package/docs/reports/v0.8-prerelease-readiness-cross-platform-security-code-rot.md +687 -0
- package/docs/reports/v0.8-reference-candidate-inspection-batch5.md +232 -0
- package/docs/reports/v0.8-viewer-runtime-pwa-batch1.md +278 -0
- package/docs/reports/v0.8.1-check-orchestration-prompt2.md +69 -0
- package/docs/reports/v0.8.1-implementation-completeness-documentation-reconciliation.md +114 -0
- package/docs/reports/v0.8.1-prerelease-readiness-cross-platform-security-code-rot.md +170 -0
- package/docs/reports/v0.8.1-project-workflow-foundation-prompt1.md +66 -0
- package/package.json +58 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { lstat } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { classifyManifest } from './classify.js';
|
|
4
|
+
import { decodeArtifactHandle } from './handles.js';
|
|
5
|
+
import { findImportedReferenceDir } from './index.js';
|
|
6
|
+
import { resolveContainedDir, resolveContainedFile } from './pathSafety.js';
|
|
7
|
+
const IMAGE_FORMAT_MIME = {
|
|
8
|
+
png: 'image/png',
|
|
9
|
+
jpeg: 'image/jpeg',
|
|
10
|
+
webp: 'image/webp',
|
|
11
|
+
};
|
|
12
|
+
function isMediaRole(value) {
|
|
13
|
+
return value === 'screenshot' || value === 'image' || value === 'source-image';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolves one known media role owned/referenced by one known, already
|
|
17
|
+
* indexed-shaped artifact handle - never an arbitrary filesystem path. Every
|
|
18
|
+
* step re-derives and re-validates from the evidence root; nothing here
|
|
19
|
+
* trusts a client-supplied path string beyond the opaque handle/role pair.
|
|
20
|
+
*/
|
|
21
|
+
export async function resolveMedia(root, artifactHandle, role) {
|
|
22
|
+
if (!isMediaRole(role))
|
|
23
|
+
return { ok: false, reason: 'unknown media role' };
|
|
24
|
+
const decoded = decodeArtifactHandle(artifactHandle);
|
|
25
|
+
if (!decoded.ok)
|
|
26
|
+
return { ok: false, reason: 'unknown handle' };
|
|
27
|
+
const dir = resolveContainedDir(root, decoded.relativeDir);
|
|
28
|
+
if (dir === undefined)
|
|
29
|
+
return { ok: false, reason: 'unknown handle' };
|
|
30
|
+
const classified = await classifyManifest(join(dir, 'manifest.json'));
|
|
31
|
+
if (classified.supportState !== 'supported' || classified.family !== decoded.family) {
|
|
32
|
+
return { ok: false, reason: 'handle no longer resolves to a supported artifact' };
|
|
33
|
+
}
|
|
34
|
+
if (role === 'screenshot') {
|
|
35
|
+
if (classified.family !== 'observation')
|
|
36
|
+
return { ok: false, reason: 'screenshot is only defined for observation evidence' };
|
|
37
|
+
const field = classified.artifact.screenshot;
|
|
38
|
+
if (field.state !== 'available' && field.state !== 'partial')
|
|
39
|
+
return { ok: false, reason: 'this observation has no recorded screenshot' };
|
|
40
|
+
const resolved = resolveContainedFile(dir, field.value.path);
|
|
41
|
+
if (resolved === undefined)
|
|
42
|
+
return { ok: false, reason: 'screenshot reference is not a safe bare filename' };
|
|
43
|
+
return checkExists(resolved, 'image/png');
|
|
44
|
+
}
|
|
45
|
+
if (role === 'image') {
|
|
46
|
+
if (classified.family !== 'external-reference-imported' || !('image' in classified.artifact)) {
|
|
47
|
+
return { ok: false, reason: 'image is only defined for an imported external reference' };
|
|
48
|
+
}
|
|
49
|
+
const image = classified.artifact.image;
|
|
50
|
+
const resolved = resolveContainedFile(dir, image.path);
|
|
51
|
+
if (resolved === undefined)
|
|
52
|
+
return { ok: false, reason: 'image reference is not a safe bare filename' };
|
|
53
|
+
return checkExists(resolved, IMAGE_FORMAT_MIME[image.format]);
|
|
54
|
+
}
|
|
55
|
+
// role === 'source-image': only defined for an approved external reference, resolved through the imported
|
|
56
|
+
// artifact it points back to (never assumed to live in the approved artifact's own directory - frozen plan §18).
|
|
57
|
+
if (classified.family !== 'external-reference-approved' || !('sourceReference' in classified.artifact)) {
|
|
58
|
+
return { ok: false, reason: 'source-image is only defined for an approved external reference' };
|
|
59
|
+
}
|
|
60
|
+
const sourceReference = classified.artifact.sourceReference;
|
|
61
|
+
const sourceDir = await findImportedReferenceDir(root, sourceReference.referenceId);
|
|
62
|
+
if (sourceDir === undefined) {
|
|
63
|
+
return { ok: false, reason: 'the imported external-reference artifact that owns this image is not present under the current evidence root' };
|
|
64
|
+
}
|
|
65
|
+
const resolved = resolveContainedFile(sourceDir, sourceReference.image.path);
|
|
66
|
+
if (resolved === undefined)
|
|
67
|
+
return { ok: false, reason: 'source image reference is not a safe bare filename' };
|
|
68
|
+
return checkExists(resolved, IMAGE_FORMAT_MIME[sourceReference.image.format]);
|
|
69
|
+
}
|
|
70
|
+
async function checkExists(absolutePath, mimeType) {
|
|
71
|
+
try {
|
|
72
|
+
// lstat (never stat) - the artifact-directory containment check above only proves the
|
|
73
|
+
// *filename* is contained; it never proves the filename isn't itself a symlink/junction
|
|
74
|
+
// whose target escapes the evidence root. A regular stat() would follow such a link and
|
|
75
|
+
// could serve arbitrary filesystem content. Reject any non-regular-file entry outright.
|
|
76
|
+
const info = await lstat(absolutePath);
|
|
77
|
+
if (!info.isFile())
|
|
78
|
+
return { ok: false, reason: 'media reference does not point at a regular file' };
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return { ok: false, reason: 'media file not found on disk' };
|
|
82
|
+
}
|
|
83
|
+
return { ok: true, absolutePath, mimeType };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=mediaResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediaResolver.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/mediaResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { LayoutRelationshipGraph } from '../../domain/relationships.js';
|
|
2
|
+
export type ObservationRelationshipsResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
graph: LayoutRelationshipGraph;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
reason: 'unknown-handle';
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
reason: 'not-an-observation';
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
reason: 'not-currently-loadable';
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
reason: 'derivation-failed';
|
|
17
|
+
detail: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Batch 3's one additive server-side computation: invokes the existing
|
|
21
|
+
* canonical, pure `deriveLayoutRelationships` (src/domain/relationships.ts)
|
|
22
|
+
* against one already-validated, already-classified `ObservationArtifact` -
|
|
23
|
+
* never a second relationship engine, never computed in React. Mirrors the
|
|
24
|
+
* same handle-decode -> contained-dir-resolve -> re-classify defense-in-depth
|
|
25
|
+
* discipline as `loadArtifactByHandle`/`resolveMedia` (evidence/index.ts,
|
|
26
|
+
* mediaResolver.ts): a handle is never trusted without being re-validated
|
|
27
|
+
* against the evidence root on every request.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getObservationRelationships(root: string, handle: string): Promise<ObservationRelationshipsResult>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { classifyManifest } from './classify.js';
|
|
3
|
+
import { decodeArtifactHandle } from './handles.js';
|
|
4
|
+
import { resolveContainedDir } from './pathSafety.js';
|
|
5
|
+
import { deriveLayoutRelationships } from '../../domain/relationships.js';
|
|
6
|
+
import { stat } from 'node:fs/promises';
|
|
7
|
+
/**
|
|
8
|
+
* Batch 3's one additive server-side computation: invokes the existing
|
|
9
|
+
* canonical, pure `deriveLayoutRelationships` (src/domain/relationships.ts)
|
|
10
|
+
* against one already-validated, already-classified `ObservationArtifact` -
|
|
11
|
+
* never a second relationship engine, never computed in React. Mirrors the
|
|
12
|
+
* same handle-decode -> contained-dir-resolve -> re-classify defense-in-depth
|
|
13
|
+
* discipline as `loadArtifactByHandle`/`resolveMedia` (evidence/index.ts,
|
|
14
|
+
* mediaResolver.ts): a handle is never trusted without being re-validated
|
|
15
|
+
* against the evidence root on every request.
|
|
16
|
+
*/
|
|
17
|
+
export async function getObservationRelationships(root, handle) {
|
|
18
|
+
const decoded = decodeArtifactHandle(handle);
|
|
19
|
+
if (!decoded.ok)
|
|
20
|
+
return { ok: false, reason: 'unknown-handle' };
|
|
21
|
+
if (decoded.family !== 'observation')
|
|
22
|
+
return { ok: false, reason: 'not-an-observation' };
|
|
23
|
+
const dir = resolveContainedDir(root, decoded.relativeDir);
|
|
24
|
+
if (dir === undefined)
|
|
25
|
+
return { ok: false, reason: 'unknown-handle' };
|
|
26
|
+
try {
|
|
27
|
+
const dirInfo = await stat(dir);
|
|
28
|
+
if (!dirInfo.isDirectory())
|
|
29
|
+
return { ok: false, reason: 'unknown-handle' };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { ok: false, reason: 'unknown-handle' };
|
|
33
|
+
}
|
|
34
|
+
const classified = await classifyManifest(join(dir, 'manifest.json'));
|
|
35
|
+
if (classified.supportState !== 'supported') {
|
|
36
|
+
return { ok: false, reason: 'not-currently-loadable' };
|
|
37
|
+
}
|
|
38
|
+
if (classified.family !== 'observation') {
|
|
39
|
+
return { ok: false, reason: 'not-an-observation' };
|
|
40
|
+
}
|
|
41
|
+
const derived = deriveLayoutRelationships(classified.artifact);
|
|
42
|
+
if (!derived.ok)
|
|
43
|
+
return { ok: false, reason: 'derivation-failed', detail: derived.reason };
|
|
44
|
+
return { ok: true, graph: derived.graph };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=observationView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observationView.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/observationView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAE1E,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AASxC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,IAAY,EAAE,MAAc;IAC5E,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,aAAa;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAEzF,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3D,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAEtE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;IACtE,IAAI,UAAU,CAAC,YAAY,KAAK,WAAW,EAAE,CAAC;QAC5C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;QACxC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IACrD,CAAC;IAED,MAAM,OAAO,GAAG,yBAAyB,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/D,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IAC3F,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a root-relative directory string (from a decoded viewer handle,
|
|
3
|
+
* never trusted on its own) against the evidence root, and verifies the
|
|
4
|
+
* result is actually contained within that root. Returns `undefined` on any
|
|
5
|
+
* traversal/escape attempt (`..` segments, an absolute-looking segment that
|
|
6
|
+
* resolves outside root, etc.) - callers must treat that as "unknown
|
|
7
|
+
* handle", never attempt a fallback resolution.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveContainedDir(root: string, relativeDir: string): string | undefined;
|
|
10
|
+
/** Same containment check for a bare filename resolved against an already-contained artifact directory (e.g. a screenshot/image sibling file). Rejects any filename containing a path separator outright - every current media reference is a bare filename by contract (see externalReference.ts's `path` field validation). */
|
|
11
|
+
export declare function resolveContainedFile(containedDir: string, bareFilename: string): string | undefined;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { resolve, sep } from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a root-relative directory string (from a decoded viewer handle,
|
|
4
|
+
* never trusted on its own) against the evidence root, and verifies the
|
|
5
|
+
* result is actually contained within that root. Returns `undefined` on any
|
|
6
|
+
* traversal/escape attempt (`..` segments, an absolute-looking segment that
|
|
7
|
+
* resolves outside root, etc.) - callers must treat that as "unknown
|
|
8
|
+
* handle", never attempt a fallback resolution.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveContainedDir(root, relativeDir) {
|
|
11
|
+
if (relativeDir.includes('\0'))
|
|
12
|
+
return undefined;
|
|
13
|
+
// `root` (e.g. a CLI --root argument) may use forward slashes even on win32; resolve it the same way `candidate`
|
|
14
|
+
// is resolved before comparing, or a purely textual prefix mismatch (backslash-normalized candidate vs. an
|
|
15
|
+
// un-normalized root string) would reject every legitimate path.
|
|
16
|
+
const resolvedRoot = resolve(root);
|
|
17
|
+
const candidate = resolve(resolvedRoot, relativeDir);
|
|
18
|
+
const rootWithSep = resolvedRoot.endsWith(sep) ? resolvedRoot : resolvedRoot + sep;
|
|
19
|
+
if (candidate !== resolvedRoot && !candidate.startsWith(rootWithSep))
|
|
20
|
+
return undefined;
|
|
21
|
+
return candidate;
|
|
22
|
+
}
|
|
23
|
+
/** Same containment check for a bare filename resolved against an already-contained artifact directory (e.g. a screenshot/image sibling file). Rejects any filename containing a path separator outright - every current media reference is a bare filename by contract (see externalReference.ts's `path` field validation). */
|
|
24
|
+
export function resolveContainedFile(containedDir, bareFilename) {
|
|
25
|
+
if (bareFilename.length === 0 || bareFilename.includes('/') || bareFilename.includes('\\') || bareFilename.includes('\0'))
|
|
26
|
+
return undefined;
|
|
27
|
+
if (bareFilename === '.' || bareFilename === '..')
|
|
28
|
+
return undefined;
|
|
29
|
+
return resolve(containedDir, bareFilename);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=pathSafety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathSafety.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/pathSafety.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,WAAmB;IACnE,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACjD,iHAAiH;IACjH,2GAA2G;IAC3G,iEAAiE;IACjE,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,GAAG,GAAG,CAAC;IACnF,IAAI,SAAS,KAAK,YAAY,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,SAAS,CAAC;IACvF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,iUAAiU;AACjU,MAAM,UAAU,oBAAoB,CAAC,YAAoB,EAAE,YAAoB;IAC7E,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5I,IAAI,YAAY,KAAK,GAAG,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpE,OAAO,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { CompletionState } from '../../domain/completion.js';
|
|
2
|
+
import type { OverallVerdict } from '../../domain/frontendContracts.js';
|
|
3
|
+
import type { ComparabilityState } from '../../domain/comparison.js';
|
|
4
|
+
import type { ArtifactFamily, ClassifiedRecord } from './classify.js';
|
|
5
|
+
/** One bounded, UI-facing summary of one recognized media role owned/referenced by an artifact. Never the media bytes themselves. */
|
|
6
|
+
export interface MediaSummary {
|
|
7
|
+
role: 'screenshot' | 'image' | 'source-image';
|
|
8
|
+
available: boolean;
|
|
9
|
+
/** Present only when unavailable, for an honest (never fabricated) reason. */
|
|
10
|
+
reason?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Bounded, UI-facing metadata for one recognized-or-problematic evidence
|
|
14
|
+
* candidate. Deliberately excludes full artifact payloads and media bytes -
|
|
15
|
+
* see docs/plans/v0.8-implementation-plan.md Batch 2 "metadata-first".
|
|
16
|
+
*/
|
|
17
|
+
export interface EvidenceMetadataRecord {
|
|
18
|
+
handle: string;
|
|
19
|
+
family: ArtifactFamily | 'unrecognized';
|
|
20
|
+
supportState: ClassifiedRecord['supportState'];
|
|
21
|
+
relativeDir: string;
|
|
22
|
+
alias?: string;
|
|
23
|
+
logicalId?: string;
|
|
24
|
+
schemaVersion?: string;
|
|
25
|
+
foundSchemaVersion?: string;
|
|
26
|
+
producerVersion?: string;
|
|
27
|
+
completion?: CompletionState;
|
|
28
|
+
lifecycleState?: 'imported' | 'approved';
|
|
29
|
+
contractClass?: 'baseline' | 'change';
|
|
30
|
+
overallVerdict?: OverallVerdict;
|
|
31
|
+
comparability?: ComparabilityState;
|
|
32
|
+
media?: MediaSummary[];
|
|
33
|
+
relatedIds?: Record<string, string>;
|
|
34
|
+
message?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Ephemeral, non-persisted wrapper around one already-validated domain artifact, for the on-demand full-artifact API. Not a new evidence schema - selects/wraps existing canonical fields only. */
|
|
37
|
+
export interface EvidenceArtifactDetail {
|
|
38
|
+
handle: string;
|
|
39
|
+
family: ArtifactFamily;
|
|
40
|
+
artifact: Extract<ClassifiedRecord, {
|
|
41
|
+
supportState: 'supported';
|
|
42
|
+
}>['artifact'];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Builds the bounded metadata record for one classified candidate, including
|
|
46
|
+
* an on-demand media-availability summary (cheap `stat` calls only - never
|
|
47
|
+
* reads media bytes here). `absoluteDir` is the already-contained,
|
|
48
|
+
* already-resolved directory (see discovery.ts) - never a browser-supplied
|
|
49
|
+
* value.
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildMetadataRecord(classified: ClassifiedRecord, relativeDir: string, absoluteDir: string): Promise<EvidenceMetadataRecord>;
|
|
52
|
+
/** Ephemeral, non-persisted full-artifact projection for the on-demand API. */
|
|
53
|
+
export declare function buildArtifactDetail(family: ArtifactFamily, handle: string, artifact: Extract<ClassifiedRecord, {
|
|
54
|
+
supportState: 'supported';
|
|
55
|
+
}>['artifact']): EvidenceArtifactDetail;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { encodeArtifactHandle } from './handles.js';
|
|
3
|
+
import { resolveContainedFile } from './pathSafety.js';
|
|
4
|
+
async function fileAvailable(path) {
|
|
5
|
+
try {
|
|
6
|
+
const info = await stat(path);
|
|
7
|
+
return info.isFile();
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Builds the bounded metadata record for one classified candidate, including
|
|
15
|
+
* an on-demand media-availability summary (cheap `stat` calls only - never
|
|
16
|
+
* reads media bytes here). `absoluteDir` is the already-contained,
|
|
17
|
+
* already-resolved directory (see discovery.ts) - never a browser-supplied
|
|
18
|
+
* value.
|
|
19
|
+
*/
|
|
20
|
+
export async function buildMetadataRecord(classified, relativeDir, absoluteDir) {
|
|
21
|
+
if (classified.supportState === 'unrecognized-kind') {
|
|
22
|
+
return {
|
|
23
|
+
handle: encodeArtifactHandle('observation', relativeDir), // placeholder family slug irrelevant for an unrecognized record; handle is never dereferenced for this state
|
|
24
|
+
family: 'unrecognized',
|
|
25
|
+
supportState: 'unrecognized-kind',
|
|
26
|
+
relativeDir,
|
|
27
|
+
message: classified.foundArtifactKind === undefined ? 'manifest.json does not declare a recognized artifactKind' : `unrecognized artifactKind "${classified.foundArtifactKind}"`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (classified.supportState === 'malformed-json') {
|
|
31
|
+
return {
|
|
32
|
+
handle: encodeArtifactHandle('observation', relativeDir),
|
|
33
|
+
family: 'unrecognized',
|
|
34
|
+
supportState: 'malformed-json',
|
|
35
|
+
relativeDir,
|
|
36
|
+
message: `manifest.json is not valid JSON: ${classified.reason}`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (classified.supportState === 'unreadable') {
|
|
40
|
+
return {
|
|
41
|
+
handle: encodeArtifactHandle('observation', relativeDir),
|
|
42
|
+
family: 'unrecognized',
|
|
43
|
+
supportState: 'unreadable',
|
|
44
|
+
relativeDir,
|
|
45
|
+
message: classified.reason,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (classified.supportState === 'unsupported-version') {
|
|
49
|
+
return {
|
|
50
|
+
handle: encodeArtifactHandle(classified.family, relativeDir),
|
|
51
|
+
family: classified.family,
|
|
52
|
+
supportState: 'unsupported-version',
|
|
53
|
+
relativeDir,
|
|
54
|
+
foundSchemaVersion: classified.foundSchemaVersion,
|
|
55
|
+
schemaVersion: classified.supportedSchemaVersion,
|
|
56
|
+
message: `recognized "${classified.family}" evidence, but schema version "${classified.foundSchemaVersion}" is not the currently supported "${classified.supportedSchemaVersion}"`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (classified.supportState === 'invalid-structure') {
|
|
60
|
+
return {
|
|
61
|
+
handle: encodeArtifactHandle(classified.family ?? 'observation', relativeDir),
|
|
62
|
+
family: classified.family ?? 'unrecognized',
|
|
63
|
+
supportState: 'invalid-structure',
|
|
64
|
+
relativeDir,
|
|
65
|
+
message: classified.reason,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// supported
|
|
69
|
+
const { family, artifact } = classified;
|
|
70
|
+
const handle = encodeArtifactHandle(family, relativeDir);
|
|
71
|
+
const base = { handle, family, supportState: 'supported', relativeDir };
|
|
72
|
+
switch (family) {
|
|
73
|
+
case 'observation': {
|
|
74
|
+
const screenshotPath = artifact.screenshot.state === 'available' || artifact.screenshot.state === 'partial' ? artifact.screenshot.value.path : undefined;
|
|
75
|
+
const resolved = screenshotPath === undefined ? undefined : resolveContainedFile(absoluteDir, screenshotPath);
|
|
76
|
+
const available = resolved !== undefined && (await fileAvailable(resolved));
|
|
77
|
+
return {
|
|
78
|
+
...base,
|
|
79
|
+
logicalId: artifact.observationId,
|
|
80
|
+
schemaVersion: artifact.schemaVersion,
|
|
81
|
+
producerVersion: artifact.producer.version,
|
|
82
|
+
completion: artifact.completion,
|
|
83
|
+
media: [{ role: 'screenshot', available, ...(available ? {} : { reason: screenshotPath === undefined ? 'no screenshot recorded on this observation' : 'screenshot file not found on disk' }) }],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
case 'comparison':
|
|
87
|
+
return {
|
|
88
|
+
...base,
|
|
89
|
+
logicalId: artifact.comparisonId,
|
|
90
|
+
schemaVersion: artifact.schemaVersion,
|
|
91
|
+
producerVersion: artifact.producer.version,
|
|
92
|
+
comparability: artifact.comparability.state,
|
|
93
|
+
relatedIds: { beforeObservationId: artifact.before.observationId, afterObservationId: artifact.after.observationId },
|
|
94
|
+
};
|
|
95
|
+
case 'baseline-contract':
|
|
96
|
+
return {
|
|
97
|
+
...base,
|
|
98
|
+
logicalId: artifact.baselineId,
|
|
99
|
+
schemaVersion: artifact.schemaVersion,
|
|
100
|
+
contractClass: 'baseline',
|
|
101
|
+
relatedIds: { sourceObservationId: artifact.sourceObservation.observationId },
|
|
102
|
+
};
|
|
103
|
+
case 'change-contract':
|
|
104
|
+
return { ...base, logicalId: artifact.contractId, schemaVersion: artifact.schemaVersion, contractClass: 'change' };
|
|
105
|
+
case 'contract-evaluation':
|
|
106
|
+
return {
|
|
107
|
+
...base,
|
|
108
|
+
logicalId: artifact.evaluationId,
|
|
109
|
+
schemaVersion: artifact.schemaVersion,
|
|
110
|
+
producerVersion: artifact.producer.version,
|
|
111
|
+
overallVerdict: artifact.overallVerdict,
|
|
112
|
+
relatedIds: {
|
|
113
|
+
beforeObservationId: artifact.before.observationId,
|
|
114
|
+
afterObservationId: artifact.after.observationId,
|
|
115
|
+
comparisonId: artifact.comparisonId,
|
|
116
|
+
baselineId: artifact.contracts.baselineId,
|
|
117
|
+
contractId: artifact.contracts.contractId,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
case 'external-reference-imported':
|
|
121
|
+
case 'external-reference-approved': {
|
|
122
|
+
const lifecycleState = artifact.lifecycle.state;
|
|
123
|
+
let media;
|
|
124
|
+
if (lifecycleState === 'imported' && 'image' in artifact) {
|
|
125
|
+
const resolved = resolveContainedFile(absoluteDir, artifact.image.path);
|
|
126
|
+
const available = resolved !== undefined && (await fileAvailable(resolved));
|
|
127
|
+
media = [{ role: 'image', available, ...(available ? {} : { reason: 'image file not found on disk' }) }];
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// 'approved': availability of the source-owned image cannot be determined without cross-referencing the imported artifact
|
|
131
|
+
// by sourceReference.referenceId within the current index (see mediaResolver.ts) - reported honestly as unknown here,
|
|
132
|
+
// never fabricated as available.
|
|
133
|
+
media = [{ role: 'source-image', available: false, reason: 'availability determined on demand via /api/media (depends on the owning imported reference being present in this evidence root)' }];
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
...base,
|
|
137
|
+
logicalId: artifact.referenceId,
|
|
138
|
+
schemaVersion: artifact.schemaVersion,
|
|
139
|
+
producerVersion: artifact.producer.version,
|
|
140
|
+
completion: artifact.completion,
|
|
141
|
+
lifecycleState,
|
|
142
|
+
media,
|
|
143
|
+
...(lifecycleState === 'approved' && 'sourceReference' in artifact ? { relatedIds: { sourceReferenceId: artifact.sourceReference.referenceId } } : {}),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/** Ephemeral, non-persisted full-artifact projection for the on-demand API. */
|
|
149
|
+
export function buildArtifactDetail(family, handle, artifact) {
|
|
150
|
+
return { handle, family, artifact };
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { ReferenceRegionRelationshipGraph } from '../../domain/externalReferenceRegionRelationships.js';
|
|
2
|
+
import type { ReferenceRequirementAdequacy } from '../../domain/externalReferenceRequirements.js';
|
|
3
|
+
import type { ReferenceCandidateCompatibilityResult } from '../../domain/externalReferenceCompatibility.js';
|
|
4
|
+
import type { ReferenceRuntimeBindingEvaluation } from '../../domain/externalReferenceRuntimeBinding.js';
|
|
5
|
+
import type { DeriveCoordinateScaleResult, ReferenceCandidateFidelityEvaluation } from '../../domain/externalReferenceFidelity.js';
|
|
6
|
+
export type ReferenceViewResult = {
|
|
7
|
+
ok: true;
|
|
8
|
+
regionRelationships: ReferenceRegionRelationshipGraph | undefined;
|
|
9
|
+
requirementAdequacy: ReferenceRequirementAdequacy | undefined;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
reason: 'unknown-handle';
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
reason: 'not-a-reference';
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
reason: 'not-currently-loadable';
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Batch 5's one additive server-side computation for a selected external
|
|
22
|
+
* reference on its own (no candidate yet): derives the reference's own
|
|
23
|
+
* region-relationship graph (`deriveReferenceRegionRelationships`) and
|
|
24
|
+
* requirement adequacy (`deriveReferenceRequirementAdequacy`) - both pure
|
|
25
|
+
* functions over the artifact's own already-persisted `regions`/
|
|
26
|
+
* `requirements`, never persisted themselves, never a second derivation
|
|
27
|
+
* engine. Mirrors observationView.ts's server-side-derivation pattern
|
|
28
|
+
* (Batch 3) rather than re-deriving in the browser.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getReferenceView(root: string, handle: string): Promise<ReferenceViewResult>;
|
|
31
|
+
export type ReferenceCandidateViewResult = {
|
|
32
|
+
ok: true;
|
|
33
|
+
compatibility: ReferenceCandidateCompatibilityResult;
|
|
34
|
+
evaluationHandles: string[];
|
|
35
|
+
coordinateMapping: DeriveCoordinateScaleResult;
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
reason: 'unknown-reference-handle';
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
reason: 'unknown-candidate-handle';
|
|
42
|
+
} | {
|
|
43
|
+
ok: false;
|
|
44
|
+
reason: 'not-a-reference';
|
|
45
|
+
} | {
|
|
46
|
+
ok: false;
|
|
47
|
+
reason: 'not-an-observation';
|
|
48
|
+
} | {
|
|
49
|
+
ok: false;
|
|
50
|
+
reason: 'not-currently-loadable';
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Batch 5's reference/candidate computation: evaluates page/state-level
|
|
54
|
+
* compatibility through the existing canonical
|
|
55
|
+
* `evaluateReferenceCandidateCompatibility` (never a second, viewer-owned
|
|
56
|
+
* compatibility model), and separately lists every existing
|
|
57
|
+
* `FrontendContractEvaluationArtifact` whose own persisted `after` reference
|
|
58
|
+
* exactly identifies this candidate (frozen plan/task §29) - for the caller
|
|
59
|
+
* to offer as an explicit, never-auto-selected optional context. Batch 6
|
|
60
|
+
* additionally exposes `coordinateMapping` - the exact result of the
|
|
61
|
+
* existing canonical `deriveCoordinateScale(reference)` (exported from
|
|
62
|
+
* `externalReferenceFidelity.ts`, never a second scale/aspect-ratio
|
|
63
|
+
* implementation) - purely a function of the reference (independent of the
|
|
64
|
+
* candidate), used only to gate view-lock eligibility client-side. Neither
|
|
65
|
+
* `evaluateReferenceRuntimeBindings` nor `evaluateReferenceCandidateFidelity`
|
|
66
|
+
* is called anywhere in this function.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getReferenceCandidateView(root: string, referenceHandle: string, candidateHandle: string): Promise<ReferenceCandidateViewResult>;
|
|
69
|
+
export type ReferenceBindingsViewResult = {
|
|
70
|
+
ok: true;
|
|
71
|
+
evaluation: ReferenceRuntimeBindingEvaluation;
|
|
72
|
+
} | {
|
|
73
|
+
ok: false;
|
|
74
|
+
reason: 'unknown-reference-handle';
|
|
75
|
+
} | {
|
|
76
|
+
ok: false;
|
|
77
|
+
reason: 'unknown-candidate-handle';
|
|
78
|
+
} | {
|
|
79
|
+
ok: false;
|
|
80
|
+
reason: 'not-a-reference';
|
|
81
|
+
} | {
|
|
82
|
+
ok: false;
|
|
83
|
+
reason: 'not-an-observation';
|
|
84
|
+
} | {
|
|
85
|
+
ok: false;
|
|
86
|
+
reason: 'not-currently-loadable';
|
|
87
|
+
} | {
|
|
88
|
+
ok: false;
|
|
89
|
+
reason: 'invalid-bindings';
|
|
90
|
+
detail: string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Batch 6: validates the session's explicit binding declarations against
|
|
94
|
+
* THIS specific reference (`isValidReferenceRuntimeBindingDeclarations` -
|
|
95
|
+
* region existence depends on the selected reference, so this can only
|
|
96
|
+
* happen here, never at CLI startup) and, if valid, calls the existing
|
|
97
|
+
* canonical `evaluateReferenceRuntimeBindings` exactly once - never a second
|
|
98
|
+
* binding engine, never a client-side re-verification via geometry/name.
|
|
99
|
+
*/
|
|
100
|
+
export declare function getReferenceBindings(root: string, referenceHandle: string, candidateHandle: string, declarations: readonly unknown[]): Promise<ReferenceBindingsViewResult>;
|
|
101
|
+
export type ReferenceFidelityViewResult = {
|
|
102
|
+
ok: true;
|
|
103
|
+
evaluation: ReferenceCandidateFidelityEvaluation;
|
|
104
|
+
} | {
|
|
105
|
+
ok: false;
|
|
106
|
+
reason: 'unknown-reference-handle';
|
|
107
|
+
} | {
|
|
108
|
+
ok: false;
|
|
109
|
+
reason: 'unknown-candidate-handle';
|
|
110
|
+
} | {
|
|
111
|
+
ok: false;
|
|
112
|
+
reason: 'not-a-reference';
|
|
113
|
+
} | {
|
|
114
|
+
ok: false;
|
|
115
|
+
reason: 'not-an-observation';
|
|
116
|
+
} | {
|
|
117
|
+
ok: false;
|
|
118
|
+
reason: 'not-currently-loadable';
|
|
119
|
+
} | {
|
|
120
|
+
ok: false;
|
|
121
|
+
reason: 'invalid-bindings';
|
|
122
|
+
detail: string;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Batch 6's one on-demand server-side computation for the explicit
|
|
126
|
+
* "Evaluate Fidelity" action: calls the existing canonical
|
|
127
|
+
* `evaluateReferenceCandidateFidelity` exactly once, using the exact same
|
|
128
|
+
* session binding declarations `getReferenceBindings` uses (so the two
|
|
129
|
+
* always structurally agree for the same inputs, being the same pure
|
|
130
|
+
* function applied to the same arguments - never two divergent binding
|
|
131
|
+
* results). Never persists the result; ephemeral per request.
|
|
132
|
+
*/
|
|
133
|
+
export declare function getReferenceFidelity(root: string, referenceHandle: string, candidateHandle: string, declarations: readonly unknown[]): Promise<ReferenceFidelityViewResult>;
|