@dailephd/my-frontend-observer 0.8.1 → 0.9.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 +74 -0
- package/README.md +109 -7
- package/dist/application/projectWorkflowService.d.ts +18 -1
- package/dist/application/projectWorkflowService.js +40 -2
- package/dist/application/projectWorkflowService.js.map +1 -1
- package/dist/application/visualAnnotationContractPromotionService.d.ts +41 -0
- package/dist/application/visualAnnotationContractPromotionService.js +143 -0
- package/dist/application/visualAnnotationContractPromotionService.js.map +1 -0
- package/dist/application/visualAnnotationPersistenceService.d.ts +34 -0
- package/dist/application/visualAnnotationPersistenceService.js +68 -0
- package/dist/application/visualAnnotationPersistenceService.js.map +1 -0
- package/dist/application/visualAnnotationReferenceMaterializationService.d.ts +53 -0
- package/dist/application/visualAnnotationReferenceMaterializationService.js +194 -0
- package/dist/application/visualAnnotationReferenceMaterializationService.js.map +1 -0
- package/dist/artifacts/visualAnnotationArtifactReader.d.ts +19 -0
- package/dist/artifacts/visualAnnotationArtifactReader.js +66 -0
- package/dist/artifacts/visualAnnotationArtifactReader.js.map +1 -0
- package/dist/artifacts/visualAnnotationArtifactWriter.d.ts +42 -0
- package/dist/artifacts/visualAnnotationArtifactWriter.js +85 -0
- package/dist/artifacts/visualAnnotationArtifactWriter.js.map +1 -0
- package/dist/cli.js +464 -454
- package/dist/cli.js.map +1 -1
- package/dist/domain/visualAnnotation.d.ts +217 -0
- package/dist/domain/visualAnnotation.js +584 -0
- package/dist/domain/visualAnnotation.js.map +1 -0
- package/dist/domain/visualAnnotationIdentity.d.ts +17 -0
- package/dist/domain/visualAnnotationIdentity.js +47 -0
- package/dist/domain/visualAnnotationIdentity.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/projectWorkflow/projectPaths.d.ts +9 -0
- package/dist/projectWorkflow/projectPaths.js +21 -0
- package/dist/projectWorkflow/projectPaths.js.map +1 -1
- package/dist/viewer/assets/{index-CN_yb9Uf.css → index-BN41MI7m.css} +1 -1
- package/dist/viewer/assets/index-CkKXnlrI.js +9 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/sw.js +1 -1
- package/dist/viewerServer/annotationAuthoring.d.ts +64 -0
- package/dist/viewerServer/annotationAuthoring.js +230 -0
- package/dist/viewerServer/annotationAuthoring.js.map +1 -0
- package/dist/viewerServer/annotationContractPromotion.d.ts +51 -0
- package/dist/viewerServer/annotationContractPromotion.js +105 -0
- package/dist/viewerServer/annotationContractPromotion.js.map +1 -0
- package/dist/viewerServer/annotationReferenceMaterialization.d.ts +40 -0
- package/dist/viewerServer/annotationReferenceMaterialization.js +91 -0
- package/dist/viewerServer/annotationReferenceMaterialization.js.map +1 -0
- package/dist/viewerServer/authoringSecurity.d.ts +59 -0
- package/dist/viewerServer/authoringSecurity.js +112 -0
- package/dist/viewerServer/authoringSecurity.js.map +1 -0
- package/dist/viewerServer/evidence/annotationView.d.ts +28 -0
- package/dist/viewerServer/evidence/annotationView.js +43 -0
- package/dist/viewerServer/evidence/annotationView.js.map +1 -0
- package/dist/viewerServer/evidence/classify.d.ts +3 -1
- package/dist/viewerServer/evidence/classify.js +12 -0
- package/dist/viewerServer/evidence/classify.js.map +1 -1
- package/dist/viewerServer/evidence/discovery.d.ts +2 -0
- package/dist/viewerServer/evidence/discovery.js +6 -0
- package/dist/viewerServer/evidence/discovery.js.map +1 -1
- package/dist/viewerServer/evidence/handles.js +1 -0
- package/dist/viewerServer/evidence/handles.js.map +1 -1
- package/dist/viewerServer/evidence/index.d.ts +29 -0
- package/dist/viewerServer/evidence/index.js +43 -1
- package/dist/viewerServer/evidence/index.js.map +1 -1
- package/dist/viewerServer/evidence/mediaResolver.d.ts +1 -1
- package/dist/viewerServer/evidence/mediaResolver.js +28 -2
- package/dist/viewerServer/evidence/mediaResolver.js.map +1 -1
- package/dist/viewerServer/evidence/projection.d.ts +5 -1
- package/dist/viewerServer/evidence/projection.js +19 -0
- package/dist/viewerServer/evidence/projection.js.map +1 -1
- package/dist/viewerServer/httpServer.d.ts +13 -2
- package/dist/viewerServer/httpServer.js +278 -4
- package/dist/viewerServer/httpServer.js.map +1 -1
- package/dist/viewerServer/viewerService.d.ts +8 -0
- package/dist/viewerServer/viewerService.js +38 -2
- package/dist/viewerServer/viewerService.js.map +1 -1
- package/docs/ARCHITECTURE.md +108 -21
- package/docs/CI_CD.md +78 -1
- package/docs/COMMANDS.md +44 -4
- package/docs/CONTRACTS.md +78 -8
- package/docs/CURRENT_STATE.md +224 -35
- package/docs/DEVELOPMENT.md +38 -3
- package/docs/PROJECT_DESCRIPTION.md +4 -1
- package/docs/PROJECT_MILESTONES.md +32 -0
- package/docs/PROJECT_OVERVIEW.md +58 -17
- package/docs/QUICKSTART.md +52 -39
- package/docs/RELEASE.md +17 -11
- package/docs/ROADMAP.md +458 -66
- package/docs/SECURITY.md +71 -14
- package/docs/WORKFLOWS.md +151 -23
- package/docs/plans/v0.9-implementation-plan.md +1529 -0
- package/docs/plans/v0.9.1-implementation-plan.md +468 -0
- package/docs/reports/v0.9-architecture-retrieval.md +567 -0
- package/docs/reports/v0.9-batch1-visual-annotation-foundation.md +351 -0
- package/docs/reports/v0.9-batch2-viewer-annotation-authoring-boundary.md +438 -0
- package/docs/reports/v0.9-batch3-runtime-screenshot-annotation-authoring.md +412 -0
- package/docs/reports/v0.9-batch4-external-reference-annotation-authoring.md +452 -0
- package/docs/reports/v0.9-batch5-runtime-intent-contract-promotion.md +535 -0
- package/docs/reports/v0.9-batch6-reference-materialization.md +514 -0
- package/docs/reports/v0.9-batch7-integrated-acceptance.md +644 -0
- package/docs/reports/v0.9-demo-foundation.md +589 -0
- package/docs/reports/v0.9-final-pre-release-readiness.md +209 -0
- package/docs/reports/v0.9-final-readiness-corrections.md +530 -0
- package/docs/reports/v0.9-pre-release-readiness.md +170 -0
- package/docs/reports/v0.9-tutorial-end-to-end-acceptance.md +980 -0
- package/docs/reports/v0.9-tutorial-integration.md +731 -0
- package/docs/reports/v0.9.1-batch1-pwa-hard-gate-isolation.md +359 -0
- package/docs/reports/v0.9.1-batch2-hard-gate-validation-integration.md +262 -0
- package/docs/reports/v0.9.1-pre-release-readiness.md +206 -0
- package/package.json +3 -2
- package/dist/viewer/assets/index-D98S1_2d.js +0 -9
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotationReferenceMaterialization.js","sourceRoot":"","sources":["../../src/viewerServer/annotationReferenceMaterialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* v0.9 Batch 2 viewer authoring security boundary (frozen plan section 9).
|
|
4
|
+
* The loopback viewer server stays read-only unless it was started for a
|
|
5
|
+
* validated initialized project. In that mode one in-memory session token is
|
|
6
|
+
* generated per server session, never persisted (not in project config,
|
|
7
|
+
* catalog, artifacts, cookies, localStorage, service-worker cache, or URLs),
|
|
8
|
+
* and it expires when the server exits. Every authoring POST must present it
|
|
9
|
+
* together with the exact expected loopback Host and Origin.
|
|
10
|
+
*
|
|
11
|
+
* This is a same-machine, same-origin capability check - not an
|
|
12
|
+
* authentication system for remote users.
|
|
13
|
+
*/
|
|
14
|
+
export declare const VIEWER_AUTHORING_TOKEN_BYTES = 32;
|
|
15
|
+
export declare const VIEWER_AUTHORING_TOKEN_HEADER: "x-frontend-observer-authoring-token";
|
|
16
|
+
export declare const MAX_ANNOTATION_AUTHORING_BODY_BYTES: number;
|
|
17
|
+
export interface ViewerAuthoringSession {
|
|
18
|
+
/** Canonical absolute project root. Server-owned; never sent to the browser. */
|
|
19
|
+
projectRoot: string;
|
|
20
|
+
/** 64 lowercase hex characters. Memory-only. */
|
|
21
|
+
token: string;
|
|
22
|
+
/** `127.0.0.1:<actualPort>`, set once the listener is bound. Empty until then, which matches no request. */
|
|
23
|
+
expectedHost: string;
|
|
24
|
+
/** `http://127.0.0.1:<actualPort>`, set once the listener is bound. Empty until then, which matches no request. */
|
|
25
|
+
expectedOrigin: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function createViewerAuthoringToken(): string;
|
|
28
|
+
export type AuthoringCheckResult = {
|
|
29
|
+
ok: true;
|
|
30
|
+
} | {
|
|
31
|
+
ok: false;
|
|
32
|
+
status: 403 | 413 | 415;
|
|
33
|
+
error: string;
|
|
34
|
+
};
|
|
35
|
+
/** True only for the exact expected loopback Host. An unset expectation never matches. */
|
|
36
|
+
export declare function isExpectedAuthoringHost(req: IncomingMessage, session: ViewerAuthoringSession): boolean;
|
|
37
|
+
/** `application/json`, optionally with exactly a UTF-8 charset parameter; case-insensitive with normal optional whitespace. */
|
|
38
|
+
export declare function isAcceptedJsonContentType(value: string | undefined): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Header-level checks for one authoring POST, in this order: Host, Origin,
|
|
41
|
+
* session token, JSON content type, and content encoding (compressed bodies
|
|
42
|
+
* are not accepted). Failure messages never reveal which part of a token
|
|
43
|
+
* differed.
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkAuthoringRequestHeaders(req: IncomingMessage, session: ViewerAuthoringSession): AuthoringCheckResult;
|
|
46
|
+
export type ReadAuthoringBodyResult = {
|
|
47
|
+
ok: true;
|
|
48
|
+
body: Buffer;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
status: 400 | 413;
|
|
52
|
+
error: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Collects at most `maxBytes` of raw request body. A declared Content-Length
|
|
56
|
+
* above the limit is refused before any body byte is read. An undeclared
|
|
57
|
+
* body that grows past the limit stops being collected immediately.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readBoundedAuthoringBody(req: IncomingMessage, maxBytes?: number): Promise<ReadAuthoringBodyResult>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* v0.9 Batch 2 viewer authoring security boundary (frozen plan section 9).
|
|
4
|
+
* The loopback viewer server stays read-only unless it was started for a
|
|
5
|
+
* validated initialized project. In that mode one in-memory session token is
|
|
6
|
+
* generated per server session, never persisted (not in project config,
|
|
7
|
+
* catalog, artifacts, cookies, localStorage, service-worker cache, or URLs),
|
|
8
|
+
* and it expires when the server exits. Every authoring POST must present it
|
|
9
|
+
* together with the exact expected loopback Host and Origin.
|
|
10
|
+
*
|
|
11
|
+
* This is a same-machine, same-origin capability check - not an
|
|
12
|
+
* authentication system for remote users.
|
|
13
|
+
*/
|
|
14
|
+
export const VIEWER_AUTHORING_TOKEN_BYTES = 32;
|
|
15
|
+
export const VIEWER_AUTHORING_TOKEN_HEADER = 'x-frontend-observer-authoring-token';
|
|
16
|
+
export const MAX_ANNOTATION_AUTHORING_BODY_BYTES = 256 * 1024;
|
|
17
|
+
export function createViewerAuthoringToken() {
|
|
18
|
+
return randomBytes(VIEWER_AUTHORING_TOKEN_BYTES).toString('hex');
|
|
19
|
+
}
|
|
20
|
+
function singleHeader(value) {
|
|
21
|
+
return typeof value === 'string' ? value : undefined;
|
|
22
|
+
}
|
|
23
|
+
/** True only for the exact expected loopback Host. An unset expectation never matches. */
|
|
24
|
+
export function isExpectedAuthoringHost(req, session) {
|
|
25
|
+
return session.expectedHost.length > 0 && singleHeader(req.headers.host) === session.expectedHost;
|
|
26
|
+
}
|
|
27
|
+
function tokensMatch(presented, expected) {
|
|
28
|
+
if (presented === undefined)
|
|
29
|
+
return false;
|
|
30
|
+
const presentedBytes = Buffer.from(presented, 'utf8');
|
|
31
|
+
const expectedBytes = Buffer.from(expected, 'utf8');
|
|
32
|
+
if (presentedBytes.length !== expectedBytes.length)
|
|
33
|
+
return false;
|
|
34
|
+
return timingSafeEqual(presentedBytes, expectedBytes);
|
|
35
|
+
}
|
|
36
|
+
/** `application/json`, optionally with exactly a UTF-8 charset parameter; case-insensitive with normal optional whitespace. */
|
|
37
|
+
export function isAcceptedJsonContentType(value) {
|
|
38
|
+
if (value === undefined)
|
|
39
|
+
return false;
|
|
40
|
+
const [mediaType, ...parameters] = value.split(';').map((part) => part.trim());
|
|
41
|
+
if (mediaType === undefined || mediaType.toLowerCase() !== 'application/json')
|
|
42
|
+
return false;
|
|
43
|
+
return parameters.filter((parameter) => parameter.length > 0).every((parameter) => /^charset\s*=\s*"?utf-8"?$/i.test(parameter));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Header-level checks for one authoring POST, in this order: Host, Origin,
|
|
47
|
+
* session token, JSON content type, and content encoding (compressed bodies
|
|
48
|
+
* are not accepted). Failure messages never reveal which part of a token
|
|
49
|
+
* differed.
|
|
50
|
+
*/
|
|
51
|
+
export function checkAuthoringRequestHeaders(req, session) {
|
|
52
|
+
if (!isExpectedAuthoringHost(req, session))
|
|
53
|
+
return { ok: false, status: 403, error: 'authoring request rejected: unexpected Host' };
|
|
54
|
+
const origin = singleHeader(req.headers.origin);
|
|
55
|
+
if (session.expectedOrigin.length === 0 || origin !== session.expectedOrigin)
|
|
56
|
+
return { ok: false, status: 403, error: 'authoring request rejected: unexpected or missing Origin' };
|
|
57
|
+
if (!tokensMatch(singleHeader(req.headers[VIEWER_AUTHORING_TOKEN_HEADER]), session.token)) {
|
|
58
|
+
return { ok: false, status: 403, error: 'authoring request rejected: missing or invalid authoring session token' };
|
|
59
|
+
}
|
|
60
|
+
if (!isAcceptedJsonContentType(singleHeader(req.headers['content-type']))) {
|
|
61
|
+
return { ok: false, status: 415, error: 'authoring request body must be application/json' };
|
|
62
|
+
}
|
|
63
|
+
const encoding = singleHeader(req.headers['content-encoding']);
|
|
64
|
+
if (req.headers['content-encoding'] !== undefined && (encoding === undefined || encoding.trim().toLowerCase() !== 'identity')) {
|
|
65
|
+
return { ok: false, status: 415, error: 'compressed authoring request bodies are not supported' };
|
|
66
|
+
}
|
|
67
|
+
return { ok: true };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Collects at most `maxBytes` of raw request body. A declared Content-Length
|
|
71
|
+
* above the limit is refused before any body byte is read. An undeclared
|
|
72
|
+
* body that grows past the limit stops being collected immediately.
|
|
73
|
+
*/
|
|
74
|
+
export function readBoundedAuthoringBody(req, maxBytes = MAX_ANNOTATION_AUTHORING_BODY_BYTES) {
|
|
75
|
+
const declared = singleHeader(req.headers['content-length']);
|
|
76
|
+
if (declared !== undefined) {
|
|
77
|
+
const declaredLength = Number(declared);
|
|
78
|
+
if (!Number.isFinite(declaredLength) || declaredLength < 0)
|
|
79
|
+
return Promise.resolve({ ok: false, status: 400, error: 'invalid Content-Length' });
|
|
80
|
+
if (declaredLength > maxBytes)
|
|
81
|
+
return Promise.resolve({ ok: false, status: 413, error: `authoring request body exceeds ${maxBytes} bytes` });
|
|
82
|
+
}
|
|
83
|
+
return new Promise((resolvePromise) => {
|
|
84
|
+
const chunks = [];
|
|
85
|
+
let received = 0;
|
|
86
|
+
let settled = false;
|
|
87
|
+
const settle = (result) => {
|
|
88
|
+
if (settled)
|
|
89
|
+
return;
|
|
90
|
+
settled = true;
|
|
91
|
+
req.off('data', onData);
|
|
92
|
+
req.off('end', onEnd);
|
|
93
|
+
req.off('error', onError);
|
|
94
|
+
resolvePromise(result);
|
|
95
|
+
};
|
|
96
|
+
const onData = (chunk) => {
|
|
97
|
+
received += chunk.length;
|
|
98
|
+
if (received > maxBytes) {
|
|
99
|
+
chunks.length = 0;
|
|
100
|
+
settle({ ok: false, status: 413, error: `authoring request body exceeds ${maxBytes} bytes` });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
chunks.push(chunk);
|
|
104
|
+
};
|
|
105
|
+
const onEnd = () => settle({ ok: true, body: Buffer.concat(chunks) });
|
|
106
|
+
const onError = () => settle({ ok: false, status: 400, error: 'authoring request body could not be read' });
|
|
107
|
+
req.on('data', onData);
|
|
108
|
+
req.on('end', onEnd);
|
|
109
|
+
req.on('error', onError);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=authoringSecurity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authoringSecurity.js","sourceRoot":"","sources":["../../src/viewerServer/authoringSecurity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { VisualAnnotationArtifact } from '../../domain/visualAnnotation.js';
|
|
2
|
+
export type AnnotationSourceView = {
|
|
3
|
+
status: 'available';
|
|
4
|
+
handle: string;
|
|
5
|
+
family: 'observation' | 'external-reference-imported' | 'external-reference-approved';
|
|
6
|
+
mediaRole: 'screenshot' | 'image' | 'source-image';
|
|
7
|
+
} | {
|
|
8
|
+
status: 'unavailable';
|
|
9
|
+
reason: string;
|
|
10
|
+
};
|
|
11
|
+
export type GetAnnotationViewResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
annotation: VisualAnnotationArtifact;
|
|
14
|
+
source: AnnotationSourceView;
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
reason: 'unknown-handle' | 'not-an-annotation' | 'not-currently-loadable';
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* v0.9 Batch 2 inspection-only projection: loads one visual annotation through
|
|
21
|
+
* the canonical handle boundary and resolves its source evidence by exact
|
|
22
|
+
* canonical identity (observationId + requestId, or referenceId +
|
|
23
|
+
* referenceRequestId) within the current evidence root. Never searches by
|
|
24
|
+
* alias or filename, never reinterprets annotation intent, and never lets a
|
|
25
|
+
* missing source invalidate the annotation itself - a missing or ambiguous
|
|
26
|
+
* source is reported as explicitly unavailable.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getAnnotationView(root: string, annotationHandle: string): Promise<GetAnnotationViewResult>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { findExternalReferenceByIdentity, findObservationByIdentity, loadArtifactByHandle } from './index.js';
|
|
2
|
+
/**
|
|
3
|
+
* v0.9 Batch 2 inspection-only projection: loads one visual annotation through
|
|
4
|
+
* the canonical handle boundary and resolves its source evidence by exact
|
|
5
|
+
* canonical identity (observationId + requestId, or referenceId +
|
|
6
|
+
* referenceRequestId) within the current evidence root. Never searches by
|
|
7
|
+
* alias or filename, never reinterprets annotation intent, and never lets a
|
|
8
|
+
* missing source invalidate the annotation itself - a missing or ambiguous
|
|
9
|
+
* source is reported as explicitly unavailable.
|
|
10
|
+
*/
|
|
11
|
+
export async function getAnnotationView(root, annotationHandle) {
|
|
12
|
+
const loaded = await loadArtifactByHandle(root, annotationHandle);
|
|
13
|
+
if (!loaded.ok) {
|
|
14
|
+
if (loaded.reason === 'unknown-handle')
|
|
15
|
+
return { ok: false, reason: 'unknown-handle' };
|
|
16
|
+
return loaded.metadata.family === 'visual-annotation' ? { ok: false, reason: 'not-currently-loadable' } : { ok: false, reason: 'not-an-annotation' };
|
|
17
|
+
}
|
|
18
|
+
if (loaded.detail.family !== 'visual-annotation')
|
|
19
|
+
return { ok: false, reason: 'not-an-annotation' };
|
|
20
|
+
const annotation = loaded.detail.artifact;
|
|
21
|
+
return { ok: true, annotation, source: await resolveAnnotationSource(root, annotation) };
|
|
22
|
+
}
|
|
23
|
+
async function resolveAnnotationSource(root, annotation) {
|
|
24
|
+
const { source } = annotation;
|
|
25
|
+
if (source.kind === 'runtime-observation') {
|
|
26
|
+
const match = await findObservationByIdentity(root, source.observationId, source.requestId);
|
|
27
|
+
if (match === undefined) {
|
|
28
|
+
return { status: 'unavailable', reason: 'the source observation is not present, or not uniquely identifiable, under the current evidence root' };
|
|
29
|
+
}
|
|
30
|
+
return { status: 'available', handle: match.handle, family: 'observation', mediaRole: 'screenshot' };
|
|
31
|
+
}
|
|
32
|
+
const match = await findExternalReferenceByIdentity(root, source.referenceId, source.referenceRequestId);
|
|
33
|
+
if (match === undefined) {
|
|
34
|
+
return { status: 'unavailable', reason: 'the source external reference is not present, or not uniquely identifiable, under the current evidence root' };
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
status: 'available',
|
|
38
|
+
handle: match.handle,
|
|
39
|
+
family: match.family,
|
|
40
|
+
mediaRole: match.family === 'external-reference-approved' ? 'source-image' : 'image',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=annotationView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotationView.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/annotationView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA0B9G;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,gBAAwB;IAC5E,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAClE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,MAAM,KAAK,gBAAgB;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QACvF,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACvJ,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,mBAAmB;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAEpG,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,QAAoC,CAAC;IACtE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED,KAAK,UAAU,uBAAuB,CAAC,IAAY,EAAE,UAAoC;IACvF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,yBAAyB,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QAC5F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,sGAAsG,EAAE,CAAC;QACnJ,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;IACvG,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,+BAA+B,CAAC,IAAI,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACzG,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,6GAA6G,EAAE,CAAC;IAC1J,CAAC;IACD,OAAO;QACL,MAAM,EAAE,WAAW;QACnB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,MAAM,KAAK,6BAA6B,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO;KACrF,CAAC;AACJ,CAAC"}
|
|
@@ -3,7 +3,8 @@ import type { ComparisonArtifact } from '../../domain/comparison.js';
|
|
|
3
3
|
import type { PersistentBaselineContract, PerChangeContract } from '../../domain/frontendContracts.js';
|
|
4
4
|
import type { FrontendContractEvaluationArtifact } from '../../domain/frontendContractEvaluationArtifact.js';
|
|
5
5
|
import type { ExternalReferenceArtifact } from '../../domain/externalReference.js';
|
|
6
|
-
|
|
6
|
+
import type { VisualAnnotationArtifact } from '../../domain/visualAnnotation.js';
|
|
7
|
+
export type ArtifactFamily = 'observation' | 'comparison' | 'baseline-contract' | 'change-contract' | 'contract-evaluation' | 'external-reference-imported' | 'external-reference-approved' | 'visual-annotation';
|
|
7
8
|
/**
|
|
8
9
|
* Honest, independent viewer-loading/support state - deliberately distinct
|
|
9
10
|
* from any artifact's own `completion`/evidence-state semantics (see
|
|
@@ -18,6 +19,7 @@ type FamilyArtifact = {
|
|
|
18
19
|
'contract-evaluation': FrontendContractEvaluationArtifact;
|
|
19
20
|
'external-reference-imported': ExternalReferenceArtifact;
|
|
20
21
|
'external-reference-approved': ExternalReferenceArtifact;
|
|
22
|
+
'visual-annotation': VisualAnnotationArtifact;
|
|
21
23
|
};
|
|
22
24
|
/** Per-family discriminated union (not a generically-indexed field) so switching on `family` correctly narrows `artifact`'s type. */
|
|
23
25
|
type SupportedRecord = {
|
|
@@ -9,6 +9,8 @@ import { EVALUATION_ARTIFACT_KIND, EVALUATION_SCHEMA_VERSION } from '../../domai
|
|
|
9
9
|
import { readFrontendContractEvaluationArtifact } from '../../artifacts/frontendContractEvaluationArtifactReader.js';
|
|
10
10
|
import { EXTERNAL_REFERENCE_ARTIFACT_KIND, EXTERNAL_REFERENCE_SCHEMA_VERSION } from '../../domain/externalReference.js';
|
|
11
11
|
import { readExternalReferenceArtifact } from '../../artifacts/externalReferenceArtifactReader.js';
|
|
12
|
+
import { VISUAL_ANNOTATION_ARTIFACT_KIND, VISUAL_ANNOTATION_SCHEMA_VERSION } from '../../domain/visualAnnotation.js';
|
|
13
|
+
import { readVisualAnnotationArtifact } from '../../artifacts/visualAnnotationArtifactReader.js';
|
|
12
14
|
import { MAX_MANIFEST_CANDIDATE_BYTES } from './limits.js';
|
|
13
15
|
function isPlainObject(value) {
|
|
14
16
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
@@ -112,6 +114,16 @@ export async function classifyManifest(manifestPath) {
|
|
|
112
114
|
const family = read.artifact.lifecycle.state === 'approved' ? 'external-reference-approved' : 'external-reference-imported';
|
|
113
115
|
return { supportState: 'supported', family, artifact: read.artifact };
|
|
114
116
|
}
|
|
117
|
+
case VISUAL_ANNOTATION_ARTIFACT_KIND: {
|
|
118
|
+
if (version !== VISUAL_ANNOTATION_SCHEMA_VERSION) {
|
|
119
|
+
return { supportState: 'unsupported-version', family: 'visual-annotation', foundSchemaVersion: version ?? 'unknown', supportedSchemaVersion: VISUAL_ANNOTATION_SCHEMA_VERSION };
|
|
120
|
+
}
|
|
121
|
+
// v0.9 Batch 2: the canonical annotation reader (manifest validation plus owned-overlay SHA-256 check) remains the sole authority.
|
|
122
|
+
const read = await readVisualAnnotationArtifact(manifestPath);
|
|
123
|
+
if (!read.ok)
|
|
124
|
+
return { supportState: 'invalid-structure', family: 'visual-annotation', reason: read.reason };
|
|
125
|
+
return { supportState: 'supported', family: 'visual-annotation', artifact: read.artifact };
|
|
126
|
+
}
|
|
115
127
|
default:
|
|
116
128
|
// Includes both a genuinely unknown string and the known-but-unreadered
|
|
117
129
|
// `my-frontend-observer/bounded-agent-context` kind (see frozen plan
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/classify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAEvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAEjG,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAEpG,OAAO,EAAE,8BAA8B,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAC;AAC1H,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,oDAAoD,CAAC;AAEzH,OAAO,EAAE,sCAAsC,EAAE,MAAM,6DAA6D,CAAC;AACrH,OAAO,EAAE,gCAAgC,EAAE,iCAAiC,EAAE,MAAM,mCAAmC,CAAC;AAExH,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/classify.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,8 @@ export interface DiscoveryResult {
|
|
|
11
11
|
/** True if MAX_MANIFEST_CANDIDATES, MAX_DIRECTORIES_VISITED, or MAX_DISCOVERY_DEPTH was hit before the walk completed naturally. */
|
|
12
12
|
truncated: boolean;
|
|
13
13
|
}
|
|
14
|
+
/** Prefix every canonical artifact writer uses for its sibling temporary directory (`.tmp-<id>`) before the atomic rename. */
|
|
15
|
+
export declare const WRITER_TEMP_DIRECTORY_PREFIX = ".tmp-";
|
|
14
16
|
/**
|
|
15
17
|
* Bounded, deterministic, symlink-safe walk beneath `root` looking only for
|
|
16
18
|
* files literally named `manifest.json` (the one filename every current
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { readdir } from 'node:fs/promises';
|
|
2
2
|
import { join, relative, sep } from 'node:path';
|
|
3
3
|
import { MAX_DIRECTORIES_VISITED, MAX_DISCOVERY_DEPTH, MAX_MANIFEST_CANDIDATES } from './limits.js';
|
|
4
|
+
/** Prefix every canonical artifact writer uses for its sibling temporary directory (`.tmp-<id>`) before the atomic rename. */
|
|
5
|
+
export const WRITER_TEMP_DIRECTORY_PREFIX = '.tmp-';
|
|
4
6
|
function toPosixRelative(root, absoluteDir) {
|
|
5
7
|
const rel = relative(root, absoluteDir);
|
|
6
8
|
return rel === '' ? '.' : rel.split(sep).join('/');
|
|
@@ -54,6 +56,10 @@ export async function discoverManifests(root) {
|
|
|
54
56
|
if (entry.isSymbolicLink())
|
|
55
57
|
continue; // never follow symlinks/junctions/reparse points, for files or directories
|
|
56
58
|
if (entry.isDirectory()) {
|
|
59
|
+
// v0.9 Batch 5: a writer's sibling `.tmp-<id>` directory is incomplete internal state, never evidence. Skipping it
|
|
60
|
+
// (at any depth) also keeps discovery from holding handles inside it while the writer renames it into place.
|
|
61
|
+
if (entry.name.startsWith(WRITER_TEMP_DIRECTORY_PREFIX))
|
|
62
|
+
continue;
|
|
57
63
|
await walk(join(dir, entry.name), depth + 1);
|
|
58
64
|
continue;
|
|
59
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/discovery.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ const FAMILY_SLUGS = {
|
|
|
6
6
|
'contract-evaluation': 'contract-evaluation',
|
|
7
7
|
'external-reference-imported': 'external-reference-imported',
|
|
8
8
|
'external-reference-approved': 'external-reference-approved',
|
|
9
|
+
'visual-annotation': 'visual-annotation',
|
|
9
10
|
};
|
|
10
11
|
const SLUG_TO_FAMILY = Object.fromEntries(Object.entries(FAMILY_SLUGS).map(([family, slug]) => [slug, family]));
|
|
11
12
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handles.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/handles.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAmC;IACnD,WAAW,EAAE,aAAa;IAC1B,UAAU,EAAE,YAAY;IACxB,mBAAmB,EAAE,mBAAmB;IACxC,iBAAiB,EAAE,iBAAiB;IACpC,qBAAqB,EAAE,qBAAqB;IAC5C,6BAA6B,EAAE,6BAA6B;IAC5D,6BAA6B,EAAE,6BAA6B;
|
|
1
|
+
{"version":3,"file":"handles.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/handles.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAmC;IACnD,WAAW,EAAE,aAAa;IAC1B,UAAU,EAAE,YAAY;IACxB,mBAAmB,EAAE,mBAAmB;IACxC,iBAAiB,EAAE,iBAAiB;IACpC,qBAAqB,EAAE,qBAAqB;IAC5C,6BAA6B,EAAE,6BAA6B;IAC5D,6BAA6B,EAAE,6BAA6B;IAC5D,mBAAmB,EAAE,mBAAmB;CACzC,CAAC;AAEF,MAAM,cAAc,GAAmC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,MAAwB,CAAC,CAAC,CAG/J,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAsB,EAAE,WAAmB;IAC9E,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;AACtE,CAAC;AAID,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,cAAc,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,MAAM,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IAC1E,IAAI,WAAmB,CAAC;IACxB,IAAI,CAAC;QACH,WAAW,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { EvidenceArtifactDetail, EvidenceMetadataRecord } from './projection.js';
|
|
2
|
+
import type { ObservationArtifact } from '../../domain/schema.js';
|
|
3
|
+
import type { ExternalReferenceArtifact } from '../../domain/externalReference.js';
|
|
2
4
|
export interface EvidenceIndexResult {
|
|
3
5
|
records: EvidenceMetadataRecord[];
|
|
4
6
|
truncated: boolean;
|
|
@@ -39,3 +41,30 @@ export declare function loadArtifactByHandle(root: string, handle: string): Prom
|
|
|
39
41
|
* only a logical `referenceId`, not a filesystem path (frozen plan §18).
|
|
40
42
|
*/
|
|
41
43
|
export declare function findImportedReferenceDir(root: string, referenceId: string): Promise<string | undefined>;
|
|
44
|
+
export interface ObservationIdentityMatch {
|
|
45
|
+
handle: string;
|
|
46
|
+
artifact: ObservationArtifact;
|
|
47
|
+
absoluteDir: string;
|
|
48
|
+
}
|
|
49
|
+
export interface ExternalReferenceIdentityMatch {
|
|
50
|
+
handle: string;
|
|
51
|
+
artifact: ExternalReferenceArtifact;
|
|
52
|
+
family: 'external-reference-imported' | 'external-reference-approved';
|
|
53
|
+
absoluteDir: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* v0.9 Batch 2: bounded exact-identity lookup of one supported observation by
|
|
57
|
+
* `observationId` plus `requestId` (both required - never a logical-id-only,
|
|
58
|
+
* alias, folder-name, or filename match). Uses the same bounded
|
|
59
|
+
* discovery/classification as the index. Returns `undefined` when no
|
|
60
|
+
* currently supported observation matches, and also when more than one does:
|
|
61
|
+
* an ambiguous identity is never resolved by silently picking one.
|
|
62
|
+
*/
|
|
63
|
+
export declare function findObservationByIdentity(root: string, observationId: string, requestId: string): Promise<ObservationIdentityMatch | undefined>;
|
|
64
|
+
/**
|
|
65
|
+
* v0.9 Batch 2: bounded exact-identity lookup of one supported imported or
|
|
66
|
+
* approved external reference by `referenceId` plus `referenceRequestId`.
|
|
67
|
+
* Same bounded, never-guess, ambiguity-is-unresolved discipline as
|
|
68
|
+
* `findObservationByIdentity`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function findExternalReferenceByIdentity(root: string, referenceId: string, referenceRequestId: string): Promise<ExternalReferenceIdentityMatch | undefined>;
|
|
@@ -3,7 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { discoverManifests } from './discovery.js';
|
|
4
4
|
import { classifyManifest } from './classify.js';
|
|
5
5
|
import { buildMetadataRecord, buildArtifactDetail } from './projection.js';
|
|
6
|
-
import { decodeArtifactHandle } from './handles.js';
|
|
6
|
+
import { decodeArtifactHandle, encodeArtifactHandle } from './handles.js';
|
|
7
7
|
import { resolveContainedDir } from './pathSafety.js';
|
|
8
8
|
import { MAX_INDEX_RECORDS } from './limits.js';
|
|
9
9
|
/**
|
|
@@ -79,4 +79,46 @@ export async function findImportedReferenceDir(root, referenceId) {
|
|
|
79
79
|
}
|
|
80
80
|
return undefined;
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* v0.9 Batch 2: bounded exact-identity lookup of one supported observation by
|
|
84
|
+
* `observationId` plus `requestId` (both required - never a logical-id-only,
|
|
85
|
+
* alias, folder-name, or filename match). Uses the same bounded
|
|
86
|
+
* discovery/classification as the index. Returns `undefined` when no
|
|
87
|
+
* currently supported observation matches, and also when more than one does:
|
|
88
|
+
* an ambiguous identity is never resolved by silently picking one.
|
|
89
|
+
*/
|
|
90
|
+
export async function findObservationByIdentity(root, observationId, requestId) {
|
|
91
|
+
const discovery = await discoverManifests(root);
|
|
92
|
+
const matches = [];
|
|
93
|
+
for (const manifest of discovery.manifests.slice(0, MAX_INDEX_RECORDS)) {
|
|
94
|
+
const classified = await classifyManifest(manifest.absolutePath);
|
|
95
|
+
if (classified.supportState !== 'supported' || classified.family !== 'observation')
|
|
96
|
+
continue;
|
|
97
|
+
if (classified.artifact.observationId === observationId && classified.artifact.requestId === requestId) {
|
|
98
|
+
matches.push({ handle: encodeArtifactHandle('observation', manifest.relativeDir), artifact: classified.artifact, absoluteDir: manifest.absoluteDir });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* v0.9 Batch 2: bounded exact-identity lookup of one supported imported or
|
|
105
|
+
* approved external reference by `referenceId` plus `referenceRequestId`.
|
|
106
|
+
* Same bounded, never-guess, ambiguity-is-unresolved discipline as
|
|
107
|
+
* `findObservationByIdentity`.
|
|
108
|
+
*/
|
|
109
|
+
export async function findExternalReferenceByIdentity(root, referenceId, referenceRequestId) {
|
|
110
|
+
const discovery = await discoverManifests(root);
|
|
111
|
+
const matches = [];
|
|
112
|
+
for (const manifest of discovery.manifests.slice(0, MAX_INDEX_RECORDS)) {
|
|
113
|
+
const classified = await classifyManifest(manifest.absolutePath);
|
|
114
|
+
if (classified.supportState !== 'supported')
|
|
115
|
+
continue;
|
|
116
|
+
if (classified.family !== 'external-reference-imported' && classified.family !== 'external-reference-approved')
|
|
117
|
+
continue;
|
|
118
|
+
if (classified.artifact.referenceId === referenceId && classified.artifact.referenceRequestId === referenceRequestId) {
|
|
119
|
+
matches.push({ handle: encodeArtifactHandle(classified.family, manifest.relativeDir), artifact: classified.artifact, family: classified.family, absoluteDir: manifest.absoluteDir });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
123
|
+
}
|
|
82
124
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { lstat } from 'node:fs/promises';
|
|
1
|
+
import { lstat, readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { classifyManifest } from './classify.js';
|
|
4
4
|
import { decodeArtifactHandle } from './handles.js';
|
|
5
5
|
import { findImportedReferenceDir } from './index.js';
|
|
6
6
|
import { resolveContainedDir, resolveContainedFile } from './pathSafety.js';
|
|
7
|
+
import { renderVisualAnnotationOverlaySvg } from '../../domain/visualAnnotation.js';
|
|
7
8
|
const IMAGE_FORMAT_MIME = {
|
|
8
9
|
png: 'image/png',
|
|
9
10
|
jpeg: 'image/jpeg',
|
|
10
11
|
webp: 'image/webp',
|
|
11
12
|
};
|
|
12
13
|
function isMediaRole(value) {
|
|
13
|
-
return value === 'screenshot' || value === 'image' || value === 'source-image';
|
|
14
|
+
return value === 'screenshot' || value === 'image' || value === 'source-image' || value === 'annotation-overlay';
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Resolves one known media role owned/referenced by one known, already
|
|
@@ -52,6 +53,31 @@ export async function resolveMedia(root, artifactHandle, role) {
|
|
|
52
53
|
return { ok: false, reason: 'image reference is not a safe bare filename' };
|
|
53
54
|
return checkExists(resolved, IMAGE_FORMAT_MIME[image.format]);
|
|
54
55
|
}
|
|
56
|
+
if (role === 'annotation-overlay') {
|
|
57
|
+
if (classified.family !== 'visual-annotation')
|
|
58
|
+
return { ok: false, reason: 'annotation-overlay is only defined for visual-annotation evidence' };
|
|
59
|
+
const { artifact } = classified;
|
|
60
|
+
// Only the manifest's own owned overlay reference is ever resolved - never a browser-supplied filename.
|
|
61
|
+
const resolved = resolveContainedFile(dir, artifact.overlay.path);
|
|
62
|
+
if (resolved === undefined)
|
|
63
|
+
return { ok: false, reason: 'annotation overlay reference is not a safe bare filename' };
|
|
64
|
+
const exists = await checkExists(resolved, 'image/svg+xml');
|
|
65
|
+
if (!exists.ok)
|
|
66
|
+
return exists;
|
|
67
|
+
// Defense in depth: the canonical reader already verified overlay.sha256, but only an overlay byte-identical to the
|
|
68
|
+
// canonical renderer's output for this artifact is ever served, so no hand-edited SVG (with a matching digest) can
|
|
69
|
+
// reach the browser from the viewer origin.
|
|
70
|
+
try {
|
|
71
|
+
const bytes = await readFile(resolved, 'utf8');
|
|
72
|
+
if (bytes !== renderVisualAnnotationOverlaySvg(artifact.source, artifact.items)) {
|
|
73
|
+
return { ok: false, reason: 'annotation overlay does not match the canonical rendering of its manifest' };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return { ok: false, reason: 'media file not found on disk' };
|
|
78
|
+
}
|
|
79
|
+
return exists;
|
|
80
|
+
}
|
|
55
81
|
// role === 'source-image': only defined for an approved external reference, resolved through the imported
|
|
56
82
|
// artifact it points back to (never assumed to live in the approved artifact's own directory - frozen plan §18).
|
|
57
83
|
if (classified.family !== 'external-reference-approved' || !('sourceReference' in classified.artifact)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaResolver.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/mediaResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"mediaResolver.js","sourceRoot":"","sources":["../../../src/viewerServer/evidence/mediaResolver.ts"],"names":[],"mappings":"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"}
|