@action-state-group/capsule-viewer 0.0.0-stage → 0.1.0
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/LICENSE +201 -0
- package/LICENSE-BSD-3-Clause +28 -0
- package/README.md +24 -2
- package/dist/browser.d.ts +4 -0
- package/dist/browser.js +11 -0
- package/dist/browser.js.map +1 -0
- package/dist/compliance-presentation.d.ts +51 -0
- package/dist/compliance-presentation.js +140 -0
- package/dist/compliance-presentation.js.map +1 -0
- package/dist/compliance-styles.d.ts +8 -0
- package/dist/compliance-styles.js +66 -0
- package/dist/compliance-styles.js.map +1 -0
- package/dist/compliance-view.d.ts +6 -0
- package/dist/compliance-view.js +394 -0
- package/dist/compliance-view.js.map +1 -0
- package/dist/compliance.d.ts +92 -0
- package/dist/compliance.js +333 -0
- package/dist/compliance.js.map +1 -0
- package/dist/composed-view.d.ts +24 -0
- package/dist/composed-view.js +179 -0
- package/dist/composed-view.js.map +1 -0
- package/dist/emitter-shell.html +136 -0
- package/dist/emitter.d.ts +69 -0
- package/dist/emitter.js +266 -0
- package/dist/emitter.js.map +1 -0
- package/dist/evidence-graph-view.d.ts +96 -0
- package/dist/evidence-graph-view.js +1480 -0
- package/dist/evidence-graph-view.js.map +1 -0
- package/dist/evidence-graph.iife.js +11373 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/outcome-report-styles.d.ts +16 -0
- package/dist/outcome-report-styles.js +225 -0
- package/dist/outcome-report-styles.js.map +1 -0
- package/dist/outcome-report-view.d.ts +5 -0
- package/dist/outcome-report-view.js +885 -0
- package/dist/outcome-report-view.js.map +1 -0
- package/dist/presentation-builder.d.ts +247 -0
- package/dist/presentation-builder.js +552 -0
- package/dist/presentation-builder.js.map +1 -0
- package/dist/presentation-mount.d.ts +26 -0
- package/dist/presentation-mount.js +45 -0
- package/dist/presentation-mount.js.map +1 -0
- package/package.json +53 -4
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta http-equiv="Content-Security-Policy" content="__CSP_SLOT__" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<title>__TITLE_SLOT__</title>
|
|
8
|
+
<style>
|
|
9
|
+
/*
|
|
10
|
+
* Base shell stylesheet. It owns the page frame only: theme tokens,
|
|
11
|
+
* typography baseline, page width, overflow containment, focus and
|
|
12
|
+
* motion defaults, native details/summary disclosure, the
|
|
13
|
+
* verification-banner area and print defaults. Every rule sits inside
|
|
14
|
+
* :where() so it has zero specificity and any presentation module's
|
|
15
|
+
* own stylesheet wins. No report layout lives here.
|
|
16
|
+
*/
|
|
17
|
+
:root {
|
|
18
|
+
--aac-bg: #ffffff;
|
|
19
|
+
--aac-fg: #1f2733;
|
|
20
|
+
--aac-muted: #6b7482;
|
|
21
|
+
--aac-line: #e3ded3;
|
|
22
|
+
--aac-accent: #232f42;
|
|
23
|
+
--aac-focus: #2b5a85;
|
|
24
|
+
--aac-ok: #2e7d5b;
|
|
25
|
+
--aac-ok-bg: #e3f1ea;
|
|
26
|
+
--aac-bad: #b5462f;
|
|
27
|
+
--aac-bad-bg: #f8e6e1;
|
|
28
|
+
--aac-warn: #8a6a2f;
|
|
29
|
+
--aac-warn-bg: #fbefd9;
|
|
30
|
+
--aac-font: system-ui, sans-serif;
|
|
31
|
+
--aac-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
32
|
+
--aac-line-height: 1.5;
|
|
33
|
+
--aac-page-width: none;
|
|
34
|
+
--aac-gutter: 0;
|
|
35
|
+
--aac-radius: 10px;
|
|
36
|
+
}
|
|
37
|
+
:where(html) {
|
|
38
|
+
-webkit-text-size-adjust: 100%;
|
|
39
|
+
text-size-adjust: 100%;
|
|
40
|
+
}
|
|
41
|
+
:where(body) {
|
|
42
|
+
margin: 0;
|
|
43
|
+
font-family: var(--aac-font);
|
|
44
|
+
line-height: var(--aac-line-height);
|
|
45
|
+
color: var(--aac-fg);
|
|
46
|
+
background: var(--aac-bg);
|
|
47
|
+
overflow-wrap: break-word;
|
|
48
|
+
}
|
|
49
|
+
:where(#app) {
|
|
50
|
+
box-sizing: border-box;
|
|
51
|
+
max-width: var(--aac-page-width);
|
|
52
|
+
margin-inline: auto;
|
|
53
|
+
padding-inline: var(--aac-gutter);
|
|
54
|
+
}
|
|
55
|
+
:where(img, svg, video, canvas) {
|
|
56
|
+
max-width: 100%;
|
|
57
|
+
height: auto;
|
|
58
|
+
}
|
|
59
|
+
:where(pre) {
|
|
60
|
+
overflow-x: auto;
|
|
61
|
+
}
|
|
62
|
+
:where(code, kbd, samp, pre) {
|
|
63
|
+
font-family: var(--aac-mono);
|
|
64
|
+
}
|
|
65
|
+
:where(summary) {
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
}
|
|
68
|
+
:where(:focus-visible) {
|
|
69
|
+
outline: 2px solid var(--aac-focus);
|
|
70
|
+
outline-offset: 2px;
|
|
71
|
+
}
|
|
72
|
+
:where(.aac-banner) {
|
|
73
|
+
display: block;
|
|
74
|
+
margin: 0 0 1rem;
|
|
75
|
+
padding: 0.75rem 1rem;
|
|
76
|
+
border: 1px solid var(--aac-line);
|
|
77
|
+
border-radius: var(--aac-radius);
|
|
78
|
+
}
|
|
79
|
+
:where(.aac-banner[data-state="verified"]) {
|
|
80
|
+
color: var(--aac-ok);
|
|
81
|
+
background: var(--aac-ok-bg);
|
|
82
|
+
}
|
|
83
|
+
:where(.aac-banner[data-state="failed"]) {
|
|
84
|
+
color: var(--aac-bad);
|
|
85
|
+
background: var(--aac-bad-bg);
|
|
86
|
+
}
|
|
87
|
+
:where(.aac-banner[data-state="partial"]) {
|
|
88
|
+
color: var(--aac-warn);
|
|
89
|
+
background: var(--aac-warn-bg);
|
|
90
|
+
}
|
|
91
|
+
@media (max-width: 760px) {
|
|
92
|
+
:where(table) {
|
|
93
|
+
display: block;
|
|
94
|
+
max-width: 100%;
|
|
95
|
+
overflow-x: auto;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
@media (prefers-reduced-motion: reduce) {
|
|
99
|
+
:where(*, *::before, *::after) {
|
|
100
|
+
animation-duration: 0.01ms !important;
|
|
101
|
+
transition-duration: 0.01ms !important;
|
|
102
|
+
scroll-behavior: auto !important;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
@media print {
|
|
106
|
+
:where(body) {
|
|
107
|
+
color: #000;
|
|
108
|
+
background: #fff;
|
|
109
|
+
}
|
|
110
|
+
:where(#app) {
|
|
111
|
+
max-width: none;
|
|
112
|
+
padding: 0;
|
|
113
|
+
}
|
|
114
|
+
:where(summary, h1, h2, h3, h4) {
|
|
115
|
+
break-after: avoid;
|
|
116
|
+
}
|
|
117
|
+
:where(tr, img, svg, figure) {
|
|
118
|
+
break-inside: avoid;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
122
|
+
<!-- prettier-ignore -->
|
|
123
|
+
<style>__THEME_SLOT__</style>
|
|
124
|
+
</head>
|
|
125
|
+
<body>
|
|
126
|
+
<div id="app"></div>
|
|
127
|
+
<!-- prettier-ignore -->
|
|
128
|
+
<script>window.__BUNDLE__ = __BUNDLE_SLOT__;</script>
|
|
129
|
+
<!-- prettier-ignore -->
|
|
130
|
+
<script>__CORE_RUNTIME_SLOT__</script>
|
|
131
|
+
<!-- prettier-ignore -->
|
|
132
|
+
__MODULE_SLOT__
|
|
133
|
+
<!-- prettier-ignore -->
|
|
134
|
+
<script>__BOOTSTRAP_SLOT__</script>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** The page title used when the caller supplies none. */
|
|
2
|
+
export declare const DEFAULT_EVIDENCE_GRAPH_TITLE = "Evidence Graph";
|
|
3
|
+
/** The bootstrap script used when the caller supplies none. */
|
|
4
|
+
export declare const DEFAULT_EVIDENCE_GRAPH_BOOTSTRAP = "renderEvidenceGraph(window.__BUNDLE__, document.getElementById(\"app\"));";
|
|
5
|
+
/**
|
|
6
|
+
* The stylesheets the reference core runtime inserts as `<style>` elements
|
|
7
|
+
* at render time. They are not inline in the emitted bytes, so the CSP lists
|
|
8
|
+
* their hashes explicitly; go/emitter/runtime-style-hashes.txt carries the
|
|
9
|
+
* same list for the Go emitter (a test keeps the two equal).
|
|
10
|
+
*/
|
|
11
|
+
export declare const CORE_RUNTIME_STYLES: readonly string[];
|
|
12
|
+
/** A digest-pinned script the builder knowingly incorporates. */
|
|
13
|
+
export interface EmitterModule {
|
|
14
|
+
/** The script source, inlined byte for byte. */
|
|
15
|
+
readonly code: string;
|
|
16
|
+
/** Lowercase hex SHA-256 of the UTF-8 bytes of `code` (a `.sha256` pin). */
|
|
17
|
+
readonly sha256: string;
|
|
18
|
+
/**
|
|
19
|
+
* Lowercase hex SHA-256 of each stylesheet the module inserts at render
|
|
20
|
+
* time (the manifest's `style_sha256`). Each is added to the page's
|
|
21
|
+
* `style-src`.
|
|
22
|
+
*/
|
|
23
|
+
readonly styleSha256?: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
export interface EmitterOptions {
|
|
26
|
+
/** Page title; HTML-escaped. Empty or absent uses "Evidence Graph". */
|
|
27
|
+
readonly title?: string;
|
|
28
|
+
/** CSS placed in the theme `<style>` element (token overrides). */
|
|
29
|
+
readonly themeCss?: string;
|
|
30
|
+
/** Lowercase hex SHA-256 pin for the core runtime; checked when given. */
|
|
31
|
+
readonly coreRuntimeSha256?: string;
|
|
32
|
+
/** Zero or more digest-pinned module scripts, run after the core runtime. */
|
|
33
|
+
readonly modules?: readonly EmitterModule[];
|
|
34
|
+
/** Bootstrap script; empty or absent uses the renderEvidenceGraph call. */
|
|
35
|
+
readonly bootstrap?: string;
|
|
36
|
+
}
|
|
37
|
+
/** JSON embedded in a script element must not be able to terminate that element. */
|
|
38
|
+
export declare function escapeJsonForHtmlScript(json: string): string;
|
|
39
|
+
/** The CSP hash source for a lowercase hex SHA-256 digest (a `.sha256` pin). */
|
|
40
|
+
export declare function cspHashSourceFromHex(hex: string): string;
|
|
41
|
+
export declare function emitEvidenceGraphHtml(bundle: unknown, browserIIFE: string, options?: EmitterOptions): string;
|
|
42
|
+
/**
|
|
43
|
+
* The stylesheet of the static page's notice (the statement that the page
|
|
44
|
+
* is not self-verifying). Hashed into the static page's CSP like the shell's
|
|
45
|
+
* own stylesheet.
|
|
46
|
+
*/
|
|
47
|
+
export declare const STATIC_NOTICE_CSS = ":where(.aac-static-notice){display:block;margin:0 0 1rem;padding:0.75rem 1rem;border:1px solid var(--aac-line);border-radius:var(--aac-radius);color:var(--aac-warn);background:var(--aac-warn-bg)}:where(.aac-static-notice p){margin:0.25rem 0}";
|
|
48
|
+
/** What a static page carries: markup already rendered, and no code. */
|
|
49
|
+
export interface StaticPageInput {
|
|
50
|
+
/** The rendered page: the children of `#app`, serialized as HTML. */
|
|
51
|
+
readonly appHtml: string;
|
|
52
|
+
/** The text of every `<style>` element in `appHtml`. */
|
|
53
|
+
readonly appStyles: readonly string[];
|
|
54
|
+
/** The value of every `style` attribute in `appHtml`. */
|
|
55
|
+
readonly appStyleAttributes: readonly string[];
|
|
56
|
+
/** The notice placed before `#app`, as HTML. */
|
|
57
|
+
readonly noticeHtml: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Write a static page: the same shell, base stylesheet, title and theme as
|
|
61
|
+
* {@link emitEvidenceGraphHtml}, with already rendered markup in `#app` and
|
|
62
|
+
* no script at all: no bundle element, no runtime, no module, no bootstrap.
|
|
63
|
+
* The CSP allows no script (`script-src 'none'`) and lists every style it
|
|
64
|
+
* carries by hash (style attributes through `'unsafe-hashes'`).
|
|
65
|
+
*
|
|
66
|
+
* The caller guarantees the markup has no script element and no event
|
|
67
|
+
* handler attribute; the CSP would block either anyway.
|
|
68
|
+
*/
|
|
69
|
+
export declare function emitStaticEvidenceGraphHtml(input: StaticPageInput, options?: Pick<EmitterOptions, "title" | "themeCss">): string;
|
package/dist/emitter.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { COMPLIANCE_CSS } from "./compliance-styles.js";
|
|
5
|
+
import { jcs } from "@action-state-group/agent-action-capsule";
|
|
6
|
+
import { OUTCOME_REPORT_CSS } from "./outcome-report-styles.js";
|
|
7
|
+
const cspSlot = "__CSP_SLOT__";
|
|
8
|
+
const titleSlot = "__TITLE_SLOT__";
|
|
9
|
+
const themeSlot = "__THEME_SLOT__";
|
|
10
|
+
const bundleSlot = "__BUNDLE_SLOT__";
|
|
11
|
+
const coreRuntimeSlot = "__CORE_RUNTIME_SLOT__";
|
|
12
|
+
const moduleSlot = "__MODULE_SLOT__";
|
|
13
|
+
const bootstrapSlot = "__BOOTSTRAP_SLOT__";
|
|
14
|
+
const slots = [
|
|
15
|
+
cspSlot,
|
|
16
|
+
titleSlot,
|
|
17
|
+
themeSlot,
|
|
18
|
+
bundleSlot,
|
|
19
|
+
coreRuntimeSlot,
|
|
20
|
+
moduleSlot,
|
|
21
|
+
bootstrapSlot,
|
|
22
|
+
];
|
|
23
|
+
/** The page title used when the caller supplies none. */
|
|
24
|
+
export const DEFAULT_EVIDENCE_GRAPH_TITLE = "Evidence Graph";
|
|
25
|
+
/** The bootstrap script used when the caller supplies none. */
|
|
26
|
+
export const DEFAULT_EVIDENCE_GRAPH_BOOTSTRAP = 'renderEvidenceGraph(window.__BUNDLE__, document.getElementById("app"));';
|
|
27
|
+
/**
|
|
28
|
+
* The stylesheets the reference core runtime inserts as `<style>` elements
|
|
29
|
+
* at render time. They are not inline in the emitted bytes, so the CSP lists
|
|
30
|
+
* their hashes explicitly; go/emitter/runtime-style-hashes.txt carries the
|
|
31
|
+
* same list for the Go emitter (a test keeps the two equal).
|
|
32
|
+
*/
|
|
33
|
+
export const CORE_RUNTIME_STYLES = [
|
|
34
|
+
OUTCOME_REPORT_CSS,
|
|
35
|
+
COMPLIANCE_CSS,
|
|
36
|
+
];
|
|
37
|
+
const shell = readFileSync(new URL("./emitter-shell.html", import.meta.url), "utf8");
|
|
38
|
+
function replaceSingle(template, placeholder, value) {
|
|
39
|
+
const parts = template.split(placeholder);
|
|
40
|
+
if (parts.length !== 2) {
|
|
41
|
+
throw new Error(`emitter shell must contain exactly one ${placeholder} slot`);
|
|
42
|
+
}
|
|
43
|
+
return `${parts[0]}${value}${parts[1]}`;
|
|
44
|
+
}
|
|
45
|
+
/** JSON embedded in a script element must not be able to terminate that element. */
|
|
46
|
+
export function escapeJsonForHtmlScript(json) {
|
|
47
|
+
return json
|
|
48
|
+
.replaceAll("<", "\\u003c")
|
|
49
|
+
.replaceAll(">", "\\u003e")
|
|
50
|
+
.replaceAll("&", "\\u0026")
|
|
51
|
+
.replaceAll("\u2028", "\\u2028")
|
|
52
|
+
.replaceAll("\u2029", "\\u2029");
|
|
53
|
+
}
|
|
54
|
+
function escapeHtmlText(value) {
|
|
55
|
+
return value
|
|
56
|
+
.replaceAll("&", "&")
|
|
57
|
+
.replaceAll("<", "<")
|
|
58
|
+
.replaceAll(">", ">")
|
|
59
|
+
.replaceAll('"', """)
|
|
60
|
+
.replaceAll("'", "'");
|
|
61
|
+
}
|
|
62
|
+
function sha256(value) {
|
|
63
|
+
return createHash("sha256").update(value, "utf8").digest();
|
|
64
|
+
}
|
|
65
|
+
/** The CSP hash source for a lowercase hex SHA-256 digest (a `.sha256` pin). */
|
|
66
|
+
export function cspHashSourceFromHex(hex) {
|
|
67
|
+
if (!/^[0-9a-f]{64}$/u.test(hex)) {
|
|
68
|
+
throw new Error("SHA-256 pin must be 64 lowercase hex characters");
|
|
69
|
+
}
|
|
70
|
+
return `'sha256-${Buffer.from(hex, "hex").toString("base64")}'`;
|
|
71
|
+
}
|
|
72
|
+
function cspHashSource(value) {
|
|
73
|
+
return `'sha256-${sha256(value).toString("base64")}'`;
|
|
74
|
+
}
|
|
75
|
+
// Inline content must reach the browser as the exact bytes hashed: no end
|
|
76
|
+
// tag or comment opener that changes where the element ends, and no CR or
|
|
77
|
+
// NUL that the HTML parser rewrites before the CSP check hashes the text.
|
|
78
|
+
function checkInline(name, value, endTag) {
|
|
79
|
+
const lower = value.toLowerCase();
|
|
80
|
+
if (lower.includes(endTag) || lower.includes("<!--")) {
|
|
81
|
+
throw new Error(`${name} must not contain ${endTag} or <!--`);
|
|
82
|
+
}
|
|
83
|
+
if (value.includes("\r") || value.includes("\0")) {
|
|
84
|
+
throw new Error(`${name} must not contain CR or NUL characters`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Collect the text of every <script> and <style> element in document order.
|
|
88
|
+
// The shell writes both start tags bare, and checkInline guarantees each
|
|
89
|
+
// element's text runs to the first matching end tag.
|
|
90
|
+
function inlineElements(html) {
|
|
91
|
+
const found = { script: [], style: [] };
|
|
92
|
+
let offset = 0;
|
|
93
|
+
for (;;) {
|
|
94
|
+
const script = html.indexOf("<script>", offset);
|
|
95
|
+
const style = html.indexOf("<style>", offset);
|
|
96
|
+
if (script === -1 && style === -1)
|
|
97
|
+
return found;
|
|
98
|
+
const kind = style === -1 || (script !== -1 && script < style) ? "script" : "style";
|
|
99
|
+
const start = (kind === "script" ? script : style) + kind.length + 2;
|
|
100
|
+
const end = html.indexOf(`</${kind}>`, start);
|
|
101
|
+
if (end === -1)
|
|
102
|
+
throw new Error(`unterminated ${kind} element`);
|
|
103
|
+
found[kind].push(html.slice(start, end));
|
|
104
|
+
offset = end + kind.length + 3;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function unique(values) {
|
|
108
|
+
return [...new Set(values)];
|
|
109
|
+
}
|
|
110
|
+
export function emitEvidenceGraphHtml(bundle, browserIIFE, options = {}) {
|
|
111
|
+
const bundleJson = new TextDecoder().decode(jcs(bundle));
|
|
112
|
+
const title = options.title === undefined || options.title === ""
|
|
113
|
+
? DEFAULT_EVIDENCE_GRAPH_TITLE
|
|
114
|
+
: options.title;
|
|
115
|
+
const themeCss = options.themeCss ?? "";
|
|
116
|
+
const modules = options.modules ?? [];
|
|
117
|
+
const bootstrap = options.bootstrap === undefined || options.bootstrap === ""
|
|
118
|
+
? DEFAULT_EVIDENCE_GRAPH_BOOTSTRAP
|
|
119
|
+
: options.bootstrap;
|
|
120
|
+
const inputs = [
|
|
121
|
+
["bundle JSON", bundleJson],
|
|
122
|
+
["browser IIFE", browserIIFE],
|
|
123
|
+
["title", title],
|
|
124
|
+
["theme CSS", themeCss],
|
|
125
|
+
["bootstrap", bootstrap],
|
|
126
|
+
...modules.map((module, index) => [
|
|
127
|
+
`module ${index}`,
|
|
128
|
+
module.code,
|
|
129
|
+
]),
|
|
130
|
+
];
|
|
131
|
+
for (const [name, value] of inputs) {
|
|
132
|
+
if (slots.some((slot) => value.includes(slot))) {
|
|
133
|
+
throw new Error(`${name} must not contain emitter placeholders`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
checkInline("browser IIFE", browserIIFE, "</script");
|
|
137
|
+
checkInline("bootstrap", bootstrap, "</script");
|
|
138
|
+
checkInline("theme CSS", themeCss, "</style");
|
|
139
|
+
if (options.coreRuntimeSha256 !== undefined &&
|
|
140
|
+
cspHashSourceFromHex(options.coreRuntimeSha256) !==
|
|
141
|
+
cspHashSource(browserIIFE)) {
|
|
142
|
+
throw new Error("browser IIFE does not match its SHA-256 pin");
|
|
143
|
+
}
|
|
144
|
+
const moduleStyleSources = [];
|
|
145
|
+
modules.forEach((module, index) => {
|
|
146
|
+
checkInline(`module ${index}`, module.code, "</script");
|
|
147
|
+
if (cspHashSourceFromHex(module.sha256) !== cspHashSource(module.code)) {
|
|
148
|
+
throw new Error(`module ${index} does not match its SHA-256 pin`);
|
|
149
|
+
}
|
|
150
|
+
(module.styleSha256 ?? []).forEach((pin, styleIndex) => {
|
|
151
|
+
try {
|
|
152
|
+
moduleStyleSources.push(cspHashSourceFromHex(pin));
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
throw new Error(`module ${index} style ${styleIndex}: ${error.message}`);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
const embeddedBundleJson = escapeJsonForHtmlScript(bundleJson);
|
|
160
|
+
let html = replaceSingle(shell, titleSlot, escapeHtmlText(title));
|
|
161
|
+
html = replaceSingle(html, themeSlot, themeCss);
|
|
162
|
+
html = replaceSingle(html, bundleSlot, embeddedBundleJson);
|
|
163
|
+
html = replaceSingle(html, coreRuntimeSlot, browserIIFE);
|
|
164
|
+
html = replaceSingle(html, moduleSlot, modules.map((module) => `<script>${module.code}</script>`).join("\n "));
|
|
165
|
+
html = replaceSingle(html, bootstrapSlot, bootstrap);
|
|
166
|
+
const inline = inlineElements(html);
|
|
167
|
+
const scriptSources = unique(inline.script.map(cspHashSource));
|
|
168
|
+
const styleSources = unique([
|
|
169
|
+
...inline.style.map(cspHashSource),
|
|
170
|
+
...CORE_RUNTIME_STYLES.map(cspHashSource),
|
|
171
|
+
...moduleStyleSources,
|
|
172
|
+
]);
|
|
173
|
+
const csp = [
|
|
174
|
+
"default-src 'none'",
|
|
175
|
+
`script-src ${scriptSources.join(" ")}`,
|
|
176
|
+
`style-src ${styleSources.join(" ")}`,
|
|
177
|
+
"img-src data:",
|
|
178
|
+
"connect-src 'none'",
|
|
179
|
+
"base-uri 'none'",
|
|
180
|
+
"form-action 'none'",
|
|
181
|
+
].join("; ");
|
|
182
|
+
html = replaceSingle(html, cspSlot, csp);
|
|
183
|
+
const bundleOffset = html.indexOf(embeddedBundleJson);
|
|
184
|
+
if (slots.some((slot) => html.includes(slot)) ||
|
|
185
|
+
bundleOffset === -1 ||
|
|
186
|
+
html.indexOf(embeddedBundleJson, bundleOffset + embeddedBundleJson.length) !== -1) {
|
|
187
|
+
throw new Error("emitter shell embed invariant failed");
|
|
188
|
+
}
|
|
189
|
+
return html;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The stylesheet of the static page's notice (the statement that the page
|
|
193
|
+
* is not self-verifying). Hashed into the static page's CSP like the shell's
|
|
194
|
+
* own stylesheet.
|
|
195
|
+
*/
|
|
196
|
+
export const STATIC_NOTICE_CSS = ":where(.aac-static-notice){display:block;margin:0 0 1rem;padding:0.75rem 1rem;border:1px solid var(--aac-line);border-radius:var(--aac-radius);color:var(--aac-warn);background:var(--aac-warn-bg)}:where(.aac-static-notice p){margin:0.25rem 0}";
|
|
197
|
+
/**
|
|
198
|
+
* Write a static page: the same shell, base stylesheet, title and theme as
|
|
199
|
+
* {@link emitEvidenceGraphHtml}, with already rendered markup in `#app` and
|
|
200
|
+
* no script at all: no bundle element, no runtime, no module, no bootstrap.
|
|
201
|
+
* The CSP allows no script (`script-src 'none'`) and lists every style it
|
|
202
|
+
* carries by hash (style attributes through `'unsafe-hashes'`).
|
|
203
|
+
*
|
|
204
|
+
* The caller guarantees the markup has no script element and no event
|
|
205
|
+
* handler attribute; the CSP would block either anyway.
|
|
206
|
+
*/
|
|
207
|
+
export function emitStaticEvidenceGraphHtml(input, options = {}) {
|
|
208
|
+
const title = options.title === undefined || options.title === ""
|
|
209
|
+
? DEFAULT_EVIDENCE_GRAPH_TITLE
|
|
210
|
+
: options.title;
|
|
211
|
+
const themeCss = options.themeCss ?? "";
|
|
212
|
+
for (const [name, value] of [
|
|
213
|
+
["title", title],
|
|
214
|
+
["theme CSS", themeCss],
|
|
215
|
+
]) {
|
|
216
|
+
if (slots.some((slot) => value.includes(slot))) {
|
|
217
|
+
throw new Error(`${name} must not contain emitter placeholders`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
checkInline("theme CSS", themeCss, "</style");
|
|
221
|
+
input.appStyles.forEach((style, index) => checkInline(`static style ${index}`, style, "</style"));
|
|
222
|
+
// The head is the shell's, with the notice stylesheet added; the body is
|
|
223
|
+
// replaced whole, so none of the shell's script elements is written. The
|
|
224
|
+
// rendered markup is spliced in last, after every slot is filled, so text
|
|
225
|
+
// in it is never read as a slot.
|
|
226
|
+
let page = replaceSingle(shell, titleSlot, escapeHtmlText(title));
|
|
227
|
+
page = replaceSingle(page, themeSlot, themeCss);
|
|
228
|
+
const headEnd = page.indexOf("</head>");
|
|
229
|
+
const bodyStart = page.indexOf("<body>");
|
|
230
|
+
const bodyEnd = page.lastIndexOf("</body>");
|
|
231
|
+
if (headEnd === -1 || bodyStart < headEnd || bodyEnd < bodyStart) {
|
|
232
|
+
throw new Error("emitter shell has no head or body");
|
|
233
|
+
}
|
|
234
|
+
let head = `${page.slice(0, headEnd)} <style>${STATIC_NOTICE_CSS}</style>\n ${page.slice(headEnd, bodyStart)}`;
|
|
235
|
+
const inline = inlineElements(head);
|
|
236
|
+
if (inline.script.length > 0) {
|
|
237
|
+
throw new Error("static page head must carry no script");
|
|
238
|
+
}
|
|
239
|
+
const styleSources = unique([
|
|
240
|
+
...inline.style.map(cspHashSource),
|
|
241
|
+
...input.appStyles.map(cspHashSource),
|
|
242
|
+
]);
|
|
243
|
+
const attributeSources = unique(input.appStyleAttributes.map(cspHashSource));
|
|
244
|
+
const csp = [
|
|
245
|
+
"default-src 'none'",
|
|
246
|
+
"script-src 'none'",
|
|
247
|
+
`style-src ${[
|
|
248
|
+
...styleSources,
|
|
249
|
+
...(attributeSources.length === 0
|
|
250
|
+
? []
|
|
251
|
+
: ["'unsafe-hashes'", ...attributeSources]),
|
|
252
|
+
].join(" ")}`,
|
|
253
|
+
"img-src data:",
|
|
254
|
+
"connect-src 'none'",
|
|
255
|
+
"base-uri 'none'",
|
|
256
|
+
"form-action 'none'",
|
|
257
|
+
].join("; ");
|
|
258
|
+
head = replaceSingle(head, cspSlot, csp);
|
|
259
|
+
if (slots.some((slot) => head.includes(slot))) {
|
|
260
|
+
throw new Error("emitter shell embed invariant failed");
|
|
261
|
+
}
|
|
262
|
+
const html = `${head}<body>\n ${input.noticeHtml}\n ` +
|
|
263
|
+
`<div id="app">${input.appHtml}</div>\n ${page.slice(bodyEnd)}`;
|
|
264
|
+
return html;
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.js","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,MAAM,OAAO,GAAG,cAAc,CAAC;AAC/B,MAAM,SAAS,GAAG,gBAAgB,CAAC;AACnC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AACnC,MAAM,UAAU,GAAG,iBAAiB,CAAC;AACrC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAChD,MAAM,UAAU,GAAG,iBAAiB,CAAC;AACrC,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAC3C,MAAM,KAAK,GAAG;IACZ,OAAO;IACP,SAAS;IACT,SAAS;IACT,UAAU;IACV,eAAe;IACf,UAAU;IACV,aAAa;CACL,CAAC;AAEX,yDAAyD;AACzD,MAAM,CAAC,MAAM,4BAA4B,GAAG,gBAAgB,CAAC;AAC7D,+DAA+D;AAC/D,MAAM,CAAC,MAAM,gCAAgC,GAC3C,yEAAyE,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,kBAAkB;IAClB,cAAc;CACf,CAAC;AAEF,MAAM,KAAK,GAAG,YAAY,CACxB,IAAI,GAAG,CAAC,sBAAsB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAChD,MAAM,CACP,CAAC;AA6BF,SAAS,aAAa,CACpB,QAAgB,EAChB,WAAmB,EACnB,KAAa;IAEb,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,0CAA0C,WAAW,OAAO,CAC7D,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1C,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,IAAI;SACR,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC;SAC/B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;AAC7D,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,WAAW,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;AAClE,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,OAAO,WAAW,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;AACxD,CAAC;AAED,0EAA0E;AAC1E,0EAA0E;AAC1E,0EAA0E;AAC1E,SAAS,WAAW,CAAC,IAAY,EAAE,KAAa,EAAE,MAAc;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,qBAAqB,MAAM,UAAU,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,wCAAwC,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,yEAAyE;AACzE,qDAAqD;AACrD,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,EAAc,EAAE,KAAK,EAAE,EAAc,EAAE,CAAC;IAChE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,SAAS,CAAC;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,MAAM,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAChD,MAAM,IAAI,GACR,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;QACzE,MAAM,KAAK,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,UAAU,CAAC,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,MAAyB;IACvC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,MAAe,EACf,WAAmB,EACnB,OAAO,GAAmB,EAAE;IAE5B,MAAM,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,MAAM,KAAK,GACT,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,EAAE;QACjD,CAAC,CAAC,4BAA4B;QAC9B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACpB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,MAAM,SAAS,GACb,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS,KAAK,EAAE;QACzD,CAAC,CAAC,gCAAgC;QAClC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAExB,MAAM,MAAM,GAAuB;QACjC,CAAC,aAAa,EAAE,UAAU,CAAC;QAC3B,CAAC,cAAc,EAAE,WAAW,CAAC;QAC7B,CAAC,OAAO,EAAE,KAAK,CAAC;QAChB,CAAC,WAAW,EAAE,QAAQ,CAAC;QACvB,CAAC,WAAW,EAAE,SAAS,CAAC;QACxB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAoB,EAAE,CAAC;YAClD,UAAU,KAAK,EAAE;YACjB,MAAM,CAAC,IAAI;SACZ,CAAC;KACH,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,wCAAwC,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IACD,WAAW,CAAC,cAAc,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IACrD,WAAW,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAChD,WAAW,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9C,IACE,OAAO,CAAC,iBAAiB,KAAK,SAAS;QACvC,oBAAoB,CAAC,OAAO,CAAC,iBAAiB,CAAC;YAC7C,aAAa,CAAC,WAAW,CAAC,EAC5B,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,kBAAkB,GAAa,EAAE,CAAC;IACxC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAChC,WAAW,CAAC,UAAU,KAAK,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACxD,IAAI,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,iCAAiC,CAAC,CAAC;QACpE,CAAC;QACD,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE;YACrD,IAAI,CAAC;gBACH,kBAAkB,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;YACrD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CACb,UAAU,KAAK,UAAU,UAAU,KAAM,KAAe,CAAC,OAAO,EAAE,CACnE,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,kBAAkB,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;IAC/D,IAAI,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAC;IAC3D,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC;IACzD,IAAI,GAAG,aAAa,CAClB,IAAI,EACJ,UAAU,EACV,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,MAAM,CAAC,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAC1E,CAAC;IACF,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAC/D,MAAM,YAAY,GAAG,MAAM,CAAC;QAC1B,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;QAClC,GAAG,mBAAmB,CAAC,GAAG,CAAC,aAAa,CAAC;QACzC,GAAG,kBAAkB;KACtB,CAAC,CAAC;IACH,MAAM,GAAG,GAAG;QACV,oBAAoB;QACpB,cAAc,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACvC,aAAa,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACrC,eAAe;QACf,oBAAoB;QACpB,iBAAiB;QACjB,oBAAoB;KACrB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAEzC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtD,IACE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzC,YAAY,KAAK,CAAC,CAAC;QACnB,IAAI,CAAC,OAAO,CACV,kBAAkB,EAClB,YAAY,GAAG,kBAAkB,CAAC,MAAM,CACzC,KAAK,CAAC,CAAC,EACR,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAC5B,mPAAmP,CAAC;AActP;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CACzC,KAAsB,EACtB,OAAO,GAA+C,EAAE;IAExD,MAAM,KAAK,GACT,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,EAAE;QACjD,CAAC,CAAC,4BAA4B;QAC9B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACpB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI;QAC1B,CAAC,OAAO,EAAE,KAAK,CAAC;QAChB,CAAC,WAAW,EAAE,QAAQ,CAAC;KACf,EAAE,CAAC;QACX,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,wCAAwC,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IACD,WAAW,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9C,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CACvC,WAAW,CAAC,gBAAgB,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,CACvD,CAAC;IAEF,yEAAyE;IACzE,yEAAyE;IACzE,0EAA0E;IAC1E,iCAAiC;IACjC,IAAI,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,SAAS,GAAG,OAAO,IAAI,OAAO,GAAG,SAAS,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,iBAAiB,eAAe,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IACjH,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,MAAM,YAAY,GAAG,MAAM,CAAC;QAC1B,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;QAClC,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC;KACtC,CAAC,CAAC;IACH,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAC7E,MAAM,GAAG,GAAG;QACV,oBAAoB;QACpB,mBAAmB;QACnB,aAAa;YACX,GAAG,YAAY;YACf,GAAG,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC;gBAC/B,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,CAAC,iBAAiB,EAAE,GAAG,gBAAgB,CAAC,CAAC;SAC9C,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACb,eAAe;QACf,oBAAoB;QACpB,iBAAiB;QACjB,oBAAoB;KACrB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACzC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,IAAI,GACR,GAAG,IAAI,eAAe,KAAK,CAAC,UAAU,QAAQ;QAC9C,iBAAiB,KAAK,CAAC,OAAO,aAAa,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;IACnE,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { type VerifiedBundleContext } from "@action-state-group/agent-action-capsule";
|
|
2
|
+
import { type CountersignerSource } from "@action-state-group/agent-action-capsule";
|
|
3
|
+
import type { PresentationDepth, WordingPackInput } from "@action-state-group/agent-action-capsule";
|
|
4
|
+
import { PresentationRegistry, type PresentationFormat, type PresentationModule, type PresentationRegistration, type PresentationResolution, type PresentationResolver, type PresentationRuntime } from "@action-state-group/agent-action-capsule";
|
|
5
|
+
/** The words a page says when this viewer cannot verify the bundle at all. */
|
|
6
|
+
export declare const UNABLE_TO_VERIFY_LINES: {
|
|
7
|
+
readonly banner: "Unable to verify in this viewer";
|
|
8
|
+
readonly reason: "This viewer cannot compute the SHA-256 digests the checks need, so nothing was checked and no records are shown. This is not a failed check: the file may well be valid.";
|
|
9
|
+
readonly command: "To check this file, run:";
|
|
10
|
+
readonly noCommand: "To check this file, open it from a secure (https) page, or check it with a verifier outside this viewer.";
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Render the "unable to verify in this viewer" state into `root`: drawn,
|
|
14
|
+
* in place of any verification result, when this runtime has no SHA-256
|
|
15
|
+
* (`digestCapability() === "none"`). It never says the bundle failed, and
|
|
16
|
+
* it shows no record. `verifyCommand` is the exact command a reader runs
|
|
17
|
+
* to check the file elsewhere; without one, the page says where to check
|
|
18
|
+
* it instead.
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderUnableToVerify(root: HTMLElement, options?: {
|
|
21
|
+
readonly verifyCommand?: string;
|
|
22
|
+
}): void;
|
|
23
|
+
/** The six built-in modules, registered by default. */
|
|
24
|
+
export declare const BUILTIN_PRESENTATIONS: readonly PresentationModule[];
|
|
25
|
+
/** A fresh registry holding the six built-in modules. */
|
|
26
|
+
export declare function createPresentationRegistry(): PresentationRegistry;
|
|
27
|
+
/**
|
|
28
|
+
* The built-in sections: modules resolved after the page module, in their
|
|
29
|
+
* own registry, and rendered after its content. One today, the composition
|
|
30
|
+
* section; see BUILTIN_MANIFEST_COMPOSED for why it is not a page module.
|
|
31
|
+
*/
|
|
32
|
+
export declare const BUILTIN_SECTIONS: readonly PresentationModule[];
|
|
33
|
+
/**
|
|
34
|
+
* A fresh section registry holding the built-in sections. The section
|
|
35
|
+
* registry applies the presentation ABI as the page registry does: under a
|
|
36
|
+
* `runtime` that refuses a section, the section is registered as refused,
|
|
37
|
+
* never drawn, and every page it matches names it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createSectionRegistry(runtime?: PresentationRuntime): PresentationRegistry;
|
|
40
|
+
/**
|
|
41
|
+
* Register a module with the registry `renderEvidenceGraph` uses by default
|
|
42
|
+
* (the module-slot entry point). Throws when its manifest is malformed,
|
|
43
|
+
* dead, a duplicate, or co-matchable with a registered module of its tier.
|
|
44
|
+
* A module whose `presentation_api` this runtime does not implement (or
|
|
45
|
+
* whose `runtime_min` it does not meet) is registered as refused: it is
|
|
46
|
+
* never selected, and every page it would have rendered names it.
|
|
47
|
+
*/
|
|
48
|
+
export declare function registerPresentation(module: PresentationModule): PresentationRegistration;
|
|
49
|
+
/** Resolve over the default registry (spec section 4.3). */
|
|
50
|
+
export declare function resolvePresentation(context: VerifiedBundleContext, audience?: string, format?: PresentationFormat): Promise<PresentationResolution>;
|
|
51
|
+
export interface RenderEvidenceGraphOptions {
|
|
52
|
+
/** Resolves the presentation; the default registry when omitted. */
|
|
53
|
+
readonly registry?: PresentationResolver;
|
|
54
|
+
/** Resolves the section after the page; the built-in sections when omitted. */
|
|
55
|
+
readonly sections?: PresentationResolver;
|
|
56
|
+
readonly audience?: string;
|
|
57
|
+
readonly format?: PresentationFormat;
|
|
58
|
+
/** The opening depth handed to the module's host; "L2" when omitted. */
|
|
59
|
+
readonly depth?: PresentationDepth;
|
|
60
|
+
/**
|
|
61
|
+
* The wording pack the page was built with, carried so the page holds
|
|
62
|
+
* the exact words it was built with (presentation only; contract I3).
|
|
63
|
+
* The built-in modules use the core's own labels and do not read it.
|
|
64
|
+
*/
|
|
65
|
+
readonly wording?: WordingPackInput;
|
|
66
|
+
/**
|
|
67
|
+
* The exact command that checks this file outside the page, shown when
|
|
68
|
+
* this viewer cannot verify it (see {@link renderUnableToVerify}).
|
|
69
|
+
*/
|
|
70
|
+
readonly verifyCommand?: string;
|
|
71
|
+
/**
|
|
72
|
+
* The host's own text for running a full verifier (for example its
|
|
73
|
+
* command line), shown as plain text under the verification page's
|
|
74
|
+
* not-checked list, after the core's neutral pointer. Presentation only:
|
|
75
|
+
* it changes no list and no result. Omitted, only the pointer is shown.
|
|
76
|
+
*/
|
|
77
|
+
readonly verifierHint?: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Render a bundle into `root`. `countersigners` is the stamp's countersigner
|
|
81
|
+
* source: the only way a verified, independent countersignature gets a name.
|
|
82
|
+
* Omitted, the context's own source is used (see
|
|
83
|
+
* `buildVerifiedBundleContext`); with neither, every independent signer
|
|
84
|
+
* renders as unlisted. The emitted report.html shell passes a bare bundle
|
|
85
|
+
* and no list; a host page that holds a list passes it here or builds the
|
|
86
|
+
* context with it (see `pinnedCountersignerSource` to load one against a
|
|
87
|
+
* pinned digest).
|
|
88
|
+
*
|
|
89
|
+
* Given a bundle, it is verified once here; given a context, its one
|
|
90
|
+
* verification run is reused. The page shape comes from the presentation
|
|
91
|
+
* registry: `resolve(context, audience, format)` picks one module by its
|
|
92
|
+
* manifest, and the page is the header, the banner, that module's content
|
|
93
|
+
* and the verification page.
|
|
94
|
+
*/
|
|
95
|
+
export declare function renderEvidenceGraph(context: VerifiedBundleContext, root: HTMLElement, countersigners?: CountersignerSource, options?: RenderEvidenceGraphOptions): Promise<void>;
|
|
96
|
+
export declare function renderEvidenceGraph(bundle: unknown, root: HTMLElement, countersigners?: CountersignerSource, options?: RenderEvidenceGraphOptions): Promise<void>;
|