@dotit/core 1.0.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 +21 -0
- package/README.md +229 -0
- package/dist/aliases.d.ts +1 -0
- package/dist/aliases.js +8 -0
- package/dist/ask.d.ts +7 -0
- package/dist/ask.js +55 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.js +32 -0
- package/dist/diff.d.ts +17 -0
- package/dist/diff.js +179 -0
- package/dist/document-css.d.ts +1 -0
- package/dist/document-css.js +290 -0
- package/dist/executor.d.ts +40 -0
- package/dist/executor.js +501 -0
- package/dist/history.d.ts +10 -0
- package/dist/history.js +297 -0
- package/dist/html-to-it.d.ts +1 -0
- package/dist/html-to-it.js +288 -0
- package/dist/index-builder.d.ts +62 -0
- package/dist/index-builder.js +228 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +94 -0
- package/dist/language-registry.d.ts +39 -0
- package/dist/language-registry.js +530 -0
- package/dist/markdown.d.ts +1 -0
- package/dist/markdown.js +123 -0
- package/dist/merge.d.ts +6 -0
- package/dist/merge.js +255 -0
- package/dist/parser.d.ts +29 -0
- package/dist/parser.js +1562 -0
- package/dist/query.d.ts +32 -0
- package/dist/query.js +293 -0
- package/dist/renderer.d.ts +16 -0
- package/dist/renderer.js +1286 -0
- package/dist/schema.d.ts +47 -0
- package/dist/schema.js +574 -0
- package/dist/source.d.ts +3 -0
- package/dist/source.js +223 -0
- package/dist/theme.d.ts +49 -0
- package/dist/theme.js +113 -0
- package/dist/themes/corporate.json +86 -0
- package/dist/themes/dark.json +64 -0
- package/dist/themes/editorial.json +54 -0
- package/dist/themes/legal.json +57 -0
- package/dist/themes/minimal.json +50 -0
- package/dist/themes/print.json +54 -0
- package/dist/themes/technical.json +59 -0
- package/dist/themes/warm.json +53 -0
- package/dist/trust.d.ts +66 -0
- package/dist/trust.js +200 -0
- package/dist/types.d.ts +234 -0
- package/dist/types.js +19 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +13 -0
- package/dist/validate.d.ts +13 -0
- package/dist/validate.js +711 -0
- package/dist/workflow.d.ts +18 -0
- package/dist/workflow.js +160 -0
- package/package.json +51 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "minimal",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Maximum whitespace, no decorative elements. High contrast.",
|
|
5
|
+
"author": "IntentText",
|
|
6
|
+
"fonts": {
|
|
7
|
+
"body": "system-ui",
|
|
8
|
+
"heading": "system-ui",
|
|
9
|
+
"mono": "ui-monospace",
|
|
10
|
+
"size": "11pt",
|
|
11
|
+
"leading": "1.7"
|
|
12
|
+
},
|
|
13
|
+
"colors": {
|
|
14
|
+
"text": "#111111",
|
|
15
|
+
"heading": "#000000",
|
|
16
|
+
"muted": "#555555",
|
|
17
|
+
"accent": "#111111",
|
|
18
|
+
"border": "#dddddd",
|
|
19
|
+
"background": "#ffffff",
|
|
20
|
+
"code-bg": "#f5f5f5",
|
|
21
|
+
"trust-approved": "#16a34a",
|
|
22
|
+
"trust-signed": "#2563eb",
|
|
23
|
+
"trust-frozen": "#7c3aed",
|
|
24
|
+
"trust-warning": "#dc2626",
|
|
25
|
+
"watermark": "#00000008"
|
|
26
|
+
},
|
|
27
|
+
"spacing": {
|
|
28
|
+
"page-margin": "20mm",
|
|
29
|
+
"section-gap": "2.5em",
|
|
30
|
+
"block-gap": "0.8em",
|
|
31
|
+
"indent": "1em"
|
|
32
|
+
},
|
|
33
|
+
"blocks": {
|
|
34
|
+
"section": {
|
|
35
|
+
"font-weight": "700",
|
|
36
|
+
"margin-top": "2.5em"
|
|
37
|
+
},
|
|
38
|
+
"quote": {
|
|
39
|
+
"padding-left": "1em",
|
|
40
|
+
"font-style": "italic",
|
|
41
|
+
"color": "muted"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"print": {
|
|
45
|
+
"header-font-size": "8pt",
|
|
46
|
+
"footer-font-size": "8pt",
|
|
47
|
+
"header-color": "muted",
|
|
48
|
+
"footer-color": "muted"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "print",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Optimized for black-and-white laser printing. No color, no backgrounds.",
|
|
5
|
+
"author": "IntentText",
|
|
6
|
+
"fonts": {
|
|
7
|
+
"body": "Georgia",
|
|
8
|
+
"heading": "Helvetica",
|
|
9
|
+
"mono": "Courier",
|
|
10
|
+
"size": "11pt",
|
|
11
|
+
"leading": "1.5"
|
|
12
|
+
},
|
|
13
|
+
"colors": {
|
|
14
|
+
"text": "#000000",
|
|
15
|
+
"heading": "#000000",
|
|
16
|
+
"muted": "#333333",
|
|
17
|
+
"accent": "#000000",
|
|
18
|
+
"border": "#000000",
|
|
19
|
+
"background": "#ffffff",
|
|
20
|
+
"code-bg": "#ffffff",
|
|
21
|
+
"trust-approved": "#000000",
|
|
22
|
+
"trust-signed": "#000000",
|
|
23
|
+
"trust-frozen": "#000000",
|
|
24
|
+
"trust-warning": "#000000",
|
|
25
|
+
"watermark": "#00000008"
|
|
26
|
+
},
|
|
27
|
+
"spacing": {
|
|
28
|
+
"page-margin": "25mm",
|
|
29
|
+
"section-gap": "2em",
|
|
30
|
+
"block-gap": "0.75em",
|
|
31
|
+
"indent": "1.5em"
|
|
32
|
+
},
|
|
33
|
+
"blocks": {
|
|
34
|
+
"section": {
|
|
35
|
+
"font-weight": "bold",
|
|
36
|
+
"margin-top": "2em",
|
|
37
|
+
"border-bottom": true
|
|
38
|
+
},
|
|
39
|
+
"quote": {
|
|
40
|
+
"padding-left": "1em",
|
|
41
|
+
"font-style": "italic"
|
|
42
|
+
},
|
|
43
|
+
"warning": {
|
|
44
|
+
"border-left": "3px solid #000",
|
|
45
|
+
"padding-left": "1em"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"print": {
|
|
49
|
+
"header-font-size": "8pt",
|
|
50
|
+
"footer-font-size": "8pt",
|
|
51
|
+
"header-color": "#333333",
|
|
52
|
+
"footer-color": "#333333"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "technical",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Monospace-forward, high contrast — developer docs, agent specs, runbooks",
|
|
5
|
+
"author": "IntentText",
|
|
6
|
+
"fonts": {
|
|
7
|
+
"body": "JetBrains Mono",
|
|
8
|
+
"heading": "JetBrains Mono",
|
|
9
|
+
"mono": "JetBrains Mono",
|
|
10
|
+
"size": "10pt",
|
|
11
|
+
"leading": "1.5"
|
|
12
|
+
},
|
|
13
|
+
"colors": {
|
|
14
|
+
"text": "#1e1e1e",
|
|
15
|
+
"heading": "#0a0a0a",
|
|
16
|
+
"muted": "#6b7280",
|
|
17
|
+
"accent": "#0969da",
|
|
18
|
+
"border": "#30363d",
|
|
19
|
+
"background": "#ffffff",
|
|
20
|
+
"code-bg": "#f0f2f4",
|
|
21
|
+
"trust-approved": "#16a34a",
|
|
22
|
+
"trust-signed": "#0969da",
|
|
23
|
+
"trust-frozen": "#7c3aed",
|
|
24
|
+
"trust-warning": "#dc2626",
|
|
25
|
+
"watermark": "#00000008"
|
|
26
|
+
},
|
|
27
|
+
"spacing": {
|
|
28
|
+
"page-margin": "20mm",
|
|
29
|
+
"section-gap": "1.8em",
|
|
30
|
+
"block-gap": "0.6em",
|
|
31
|
+
"indent": "2em"
|
|
32
|
+
},
|
|
33
|
+
"blocks": {
|
|
34
|
+
"section": {
|
|
35
|
+
"font-weight": "700",
|
|
36
|
+
"margin-top": "1.8em",
|
|
37
|
+
"border-bottom": true
|
|
38
|
+
},
|
|
39
|
+
"code": {
|
|
40
|
+
"background": "code-bg",
|
|
41
|
+
"padding": "0.3em 0.5em",
|
|
42
|
+
"border-radius": "2px",
|
|
43
|
+
"border": "1px solid",
|
|
44
|
+
"border-color": "border"
|
|
45
|
+
},
|
|
46
|
+
"warning": {
|
|
47
|
+
"border-left": "4px solid",
|
|
48
|
+
"border-color": "trust-warning",
|
|
49
|
+
"padding-left": "1em",
|
|
50
|
+
"background": "#fef2f2"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"print": {
|
|
54
|
+
"header-font-size": "7pt",
|
|
55
|
+
"footer-font-size": "7pt",
|
|
56
|
+
"header-color": "muted",
|
|
57
|
+
"footer-color": "muted"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "warm",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Serif body font, warm tones — editorial, journalism, long-form writing",
|
|
5
|
+
"author": "IntentText",
|
|
6
|
+
"fonts": {
|
|
7
|
+
"body": "Georgia",
|
|
8
|
+
"heading": "Georgia",
|
|
9
|
+
"mono": "Menlo",
|
|
10
|
+
"size": "11.5pt",
|
|
11
|
+
"leading": "1.7"
|
|
12
|
+
},
|
|
13
|
+
"colors": {
|
|
14
|
+
"text": "#2c2416",
|
|
15
|
+
"heading": "#1a1208",
|
|
16
|
+
"muted": "#7a6e5e",
|
|
17
|
+
"accent": "#b45309",
|
|
18
|
+
"border": "#d6cfc2",
|
|
19
|
+
"background": "#fafaf8",
|
|
20
|
+
"code-bg": "#f3f0ea",
|
|
21
|
+
"trust-approved": "#3d7a3d",
|
|
22
|
+
"trust-signed": "#4a6fa5",
|
|
23
|
+
"trust-frozen": "#6b4c8a",
|
|
24
|
+
"trust-warning": "#b91c1c",
|
|
25
|
+
"watermark": "#00000008"
|
|
26
|
+
},
|
|
27
|
+
"spacing": {
|
|
28
|
+
"page-margin": "30mm",
|
|
29
|
+
"section-gap": "2em",
|
|
30
|
+
"block-gap": "0.75em",
|
|
31
|
+
"indent": "1.5em"
|
|
32
|
+
},
|
|
33
|
+
"blocks": {
|
|
34
|
+
"section": {
|
|
35
|
+
"border-bottom": true,
|
|
36
|
+
"font-weight": "600",
|
|
37
|
+
"margin-top": "2em"
|
|
38
|
+
},
|
|
39
|
+
"quote": {
|
|
40
|
+
"border-left": "3px solid",
|
|
41
|
+
"border-color": "accent",
|
|
42
|
+
"padding-left": "1.2em",
|
|
43
|
+
"font-style": "italic",
|
|
44
|
+
"color": "muted"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"print": {
|
|
48
|
+
"header-font-size": "8pt",
|
|
49
|
+
"footer-font-size": "8pt",
|
|
50
|
+
"header-color": "muted",
|
|
51
|
+
"footer-color": "muted"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/dist/trust.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { RegistryEntry } from "./types";
|
|
2
|
+
export declare function computeDocumentHash(source: string): string;
|
|
3
|
+
export declare function findHistoryBoundaryInSource(source: string): number;
|
|
4
|
+
export declare function detectHistoryBoundary(lines: string[]): number;
|
|
5
|
+
export declare function generateBlockId(): string;
|
|
6
|
+
export declare function blockFingerprint(content: string): string;
|
|
7
|
+
export declare function matchBlocksToRegistry(blocks: Array<{
|
|
8
|
+
type: string;
|
|
9
|
+
content: string;
|
|
10
|
+
section: string;
|
|
11
|
+
}>, registry: RegistryEntry[]): Map<number, string>;
|
|
12
|
+
export interface BlockSnapshot {
|
|
13
|
+
id: string;
|
|
14
|
+
type: string;
|
|
15
|
+
content: string;
|
|
16
|
+
section: string;
|
|
17
|
+
properties: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export interface TrustDiff {
|
|
20
|
+
added: BlockSnapshot[];
|
|
21
|
+
removed: BlockSnapshot[];
|
|
22
|
+
modified: Array<{
|
|
23
|
+
id: string;
|
|
24
|
+
was: BlockSnapshot;
|
|
25
|
+
now: BlockSnapshot;
|
|
26
|
+
}>;
|
|
27
|
+
moved: Array<{
|
|
28
|
+
id: string;
|
|
29
|
+
wasSection: string;
|
|
30
|
+
nowSection: string;
|
|
31
|
+
block: BlockSnapshot;
|
|
32
|
+
}>;
|
|
33
|
+
unchanged: BlockSnapshot[];
|
|
34
|
+
}
|
|
35
|
+
export declare function computeTrustDiff(before: BlockSnapshot[], after: BlockSnapshot[]): TrustDiff;
|
|
36
|
+
export declare function incrementVersion(current: string, changeType: "major" | "minor"): string;
|
|
37
|
+
export interface SealOptions {
|
|
38
|
+
signer: string;
|
|
39
|
+
role?: string;
|
|
40
|
+
skipSign?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface SealResult {
|
|
43
|
+
success: boolean;
|
|
44
|
+
hash: string;
|
|
45
|
+
source: string;
|
|
46
|
+
at: string;
|
|
47
|
+
error?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function sealDocument(source: string, options: SealOptions): SealResult;
|
|
50
|
+
export interface VerifyResult {
|
|
51
|
+
intact: boolean;
|
|
52
|
+
frozen: boolean;
|
|
53
|
+
frozenAt?: string;
|
|
54
|
+
signers?: Array<{
|
|
55
|
+
signer: string;
|
|
56
|
+
role?: string;
|
|
57
|
+
at: string;
|
|
58
|
+
valid: boolean;
|
|
59
|
+
signedCurrentVersion: boolean;
|
|
60
|
+
}>;
|
|
61
|
+
hash?: string;
|
|
62
|
+
expectedHash?: string;
|
|
63
|
+
error?: string;
|
|
64
|
+
warning?: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function verifyDocument(source: string): VerifyResult;
|
package/dist/trust.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.computeDocumentHash = computeDocumentHash;
|
|
7
|
+
exports.findHistoryBoundaryInSource = findHistoryBoundaryInSource;
|
|
8
|
+
exports.detectHistoryBoundary = detectHistoryBoundary;
|
|
9
|
+
exports.generateBlockId = generateBlockId;
|
|
10
|
+
exports.blockFingerprint = blockFingerprint;
|
|
11
|
+
exports.matchBlocksToRegistry = matchBlocksToRegistry;
|
|
12
|
+
exports.computeTrustDiff = computeTrustDiff;
|
|
13
|
+
exports.incrementVersion = incrementVersion;
|
|
14
|
+
exports.sealDocument = sealDocument;
|
|
15
|
+
exports.verifyDocument = verifyDocument;
|
|
16
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
17
|
+
const parser_1 = require("./parser");
|
|
18
|
+
function computeDocumentHash(source) {
|
|
19
|
+
const boundary = findHistoryBoundaryInSource(source);
|
|
20
|
+
const content = boundary === -1 ? source : source.slice(0, boundary);
|
|
21
|
+
const bodyLines = content
|
|
22
|
+
.split("\n")
|
|
23
|
+
.filter((line) => !line.startsWith("sign:") &&
|
|
24
|
+
!line.startsWith("freeze:") &&
|
|
25
|
+
!line.startsWith("amendment:"));
|
|
26
|
+
const body = bodyLines.join("\n").trim();
|
|
27
|
+
return "sha256:" + crypto_1.default.createHash("sha256").update(body).digest("hex");
|
|
28
|
+
}
|
|
29
|
+
function findHistoryBoundaryInSource(source) {
|
|
30
|
+
const lines = source.split("\n");
|
|
31
|
+
let pos = 0;
|
|
32
|
+
for (let i = 0; i < lines.length; i++) {
|
|
33
|
+
const trimmed = lines[i].trim();
|
|
34
|
+
if (trimmed === "history:" || trimmed === "history: ") {
|
|
35
|
+
return pos;
|
|
36
|
+
}
|
|
37
|
+
if (trimmed === "---" && i < lines.length - 1) {
|
|
38
|
+
const next = lines[i + 1]?.trim();
|
|
39
|
+
if (next === "// history" || next?.startsWith("// history")) {
|
|
40
|
+
return pos;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
pos += lines[i].length + 1;
|
|
44
|
+
}
|
|
45
|
+
return -1;
|
|
46
|
+
}
|
|
47
|
+
function detectHistoryBoundary(lines) {
|
|
48
|
+
for (let i = 0; i < lines.length; i++) {
|
|
49
|
+
const trimmed = lines[i].trim();
|
|
50
|
+
if (trimmed === "history:" || trimmed === "history: ") {
|
|
51
|
+
return i;
|
|
52
|
+
}
|
|
53
|
+
if (trimmed === "---" && i < lines.length - 1) {
|
|
54
|
+
const next = lines[i + 1]?.trim();
|
|
55
|
+
if (next === "// history" || next?.startsWith("// history")) {
|
|
56
|
+
return i;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return -1;
|
|
61
|
+
}
|
|
62
|
+
function generateBlockId() {
|
|
63
|
+
return crypto_1.default.randomBytes(3).toString("hex").slice(0, 5);
|
|
64
|
+
}
|
|
65
|
+
function blockFingerprint(content) {
|
|
66
|
+
return content.toLowerCase().trim().replace(/\s+/g, " ");
|
|
67
|
+
}
|
|
68
|
+
function matchBlocksToRegistry(blocks, registry) {
|
|
69
|
+
const result = new Map();
|
|
70
|
+
const usedIds = new Set();
|
|
71
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
72
|
+
const block = blocks[i];
|
|
73
|
+
const fp = blockFingerprint(block.content);
|
|
74
|
+
const exact = registry.find((r) => !r.dead &&
|
|
75
|
+
!usedIds.has(r.id) &&
|
|
76
|
+
r.blockType === block.type &&
|
|
77
|
+
r.section === block.section &&
|
|
78
|
+
r.fingerprint === fp);
|
|
79
|
+
if (exact) {
|
|
80
|
+
result.set(i, exact.id);
|
|
81
|
+
usedIds.add(exact.id);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const fuzzy = registry.find((r) => !r.dead &&
|
|
85
|
+
!usedIds.has(r.id) &&
|
|
86
|
+
r.blockType === block.type &&
|
|
87
|
+
r.section === block.section &&
|
|
88
|
+
similarity(r.fingerprint, fp) > 0.6);
|
|
89
|
+
if (fuzzy) {
|
|
90
|
+
result.set(i, fuzzy.id);
|
|
91
|
+
usedIds.add(fuzzy.id);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
function similarity(a, b) {
|
|
97
|
+
if (a === b)
|
|
98
|
+
return 1;
|
|
99
|
+
const longer = a.length > b.length ? a : b;
|
|
100
|
+
const shorter = a.length > b.length ? b : a;
|
|
101
|
+
if (longer.length === 0)
|
|
102
|
+
return 1;
|
|
103
|
+
let matches = 0;
|
|
104
|
+
for (const char of shorter) {
|
|
105
|
+
if (longer.includes(char))
|
|
106
|
+
matches++;
|
|
107
|
+
}
|
|
108
|
+
return matches / longer.length;
|
|
109
|
+
}
|
|
110
|
+
function computeTrustDiff(before, after) {
|
|
111
|
+
const result = {
|
|
112
|
+
added: [],
|
|
113
|
+
removed: [],
|
|
114
|
+
modified: [],
|
|
115
|
+
moved: [],
|
|
116
|
+
unchanged: [],
|
|
117
|
+
};
|
|
118
|
+
const beforeById = new Map(before.map((b) => [b.id, b]));
|
|
119
|
+
const afterById = new Map(after.map((b) => [b.id, b]));
|
|
120
|
+
for (const [id, beforeBlock] of beforeById) {
|
|
121
|
+
const afterBlock = afterById.get(id);
|
|
122
|
+
if (!afterBlock) {
|
|
123
|
+
result.removed.push(beforeBlock);
|
|
124
|
+
}
|
|
125
|
+
else if (beforeBlock.content !== afterBlock.content) {
|
|
126
|
+
result.modified.push({ id, was: beforeBlock, now: afterBlock });
|
|
127
|
+
}
|
|
128
|
+
else if (beforeBlock.section !== afterBlock.section) {
|
|
129
|
+
result.moved.push({
|
|
130
|
+
id,
|
|
131
|
+
wasSection: beforeBlock.section,
|
|
132
|
+
nowSection: afterBlock.section,
|
|
133
|
+
block: afterBlock,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
result.unchanged.push(afterBlock);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const [id, afterBlock] of afterById) {
|
|
141
|
+
if (!beforeById.has(id)) {
|
|
142
|
+
result.added.push(afterBlock);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
function incrementVersion(current, changeType) {
|
|
148
|
+
const parts = current.split(".").map(Number);
|
|
149
|
+
if (changeType === "major") {
|
|
150
|
+
return `${parts[0] + 1}.0`;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
return `${parts[0]}.${(parts[1] || 0) + 1}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function sealDocument(source, options) {
|
|
157
|
+
const hash = computeDocumentHash(source);
|
|
158
|
+
const at = new Date().toISOString();
|
|
159
|
+
const boundaryPos = findHistoryBoundaryInSource(source);
|
|
160
|
+
const insertBefore = boundaryPos === -1 ? source.length : boundaryPos;
|
|
161
|
+
const signLine = options.skipSign
|
|
162
|
+
? ""
|
|
163
|
+
: `sign: ${options.signer}${options.role ? ` | role: ${options.role}` : ""} | at: ${at} | hash: ${hash}\n`;
|
|
164
|
+
const freezeLine = `freeze: | at: ${at} | hash: ${hash} | status: locked\n`;
|
|
165
|
+
const insertion = signLine + freezeLine;
|
|
166
|
+
const before = source.slice(0, insertBefore);
|
|
167
|
+
const after = source.slice(insertBefore);
|
|
168
|
+
const needsNewline = before.length > 0 && !before.endsWith("\n");
|
|
169
|
+
const updated = before + (needsNewline ? "\n" : "") + insertion + after;
|
|
170
|
+
return { success: true, hash, source: updated, at };
|
|
171
|
+
}
|
|
172
|
+
function verifyDocument(source) {
|
|
173
|
+
const doc = (0, parser_1.parseIntentText)(source, { includeHistorySection: false });
|
|
174
|
+
if (!doc.metadata?.freeze) {
|
|
175
|
+
return {
|
|
176
|
+
intact: false,
|
|
177
|
+
frozen: false,
|
|
178
|
+
warning: "Document is not sealed. No freeze: block found.",
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const currentHash = computeDocumentHash(source);
|
|
182
|
+
const expectedHash = doc.metadata.freeze.hash;
|
|
183
|
+
const intact = currentHash === expectedHash;
|
|
184
|
+
const signers = doc.metadata.signatures?.map((sig) => ({
|
|
185
|
+
signer: sig.signer,
|
|
186
|
+
role: sig.role,
|
|
187
|
+
at: sig.at,
|
|
188
|
+
valid: sig.hash === expectedHash,
|
|
189
|
+
signedCurrentVersion: sig.hash === currentHash,
|
|
190
|
+
})) || [];
|
|
191
|
+
return {
|
|
192
|
+
intact,
|
|
193
|
+
frozen: true,
|
|
194
|
+
frozenAt: doc.metadata.freeze.at,
|
|
195
|
+
signers,
|
|
196
|
+
hash: currentHash,
|
|
197
|
+
expectedHash,
|
|
198
|
+
error: intact ? undefined : "Document has been modified since sealing.",
|
|
199
|
+
};
|
|
200
|
+
}
|