@agent-teams/engineering-foundation 0.13.0 → 0.14.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/dist/canonical-json.d.ts +12 -0
- package/dist/canonical-json.d.ts.map +1 -0
- package/dist/canonical-json.js +151 -0
- package/dist/canonical-json.js.map +1 -0
- package/dist/document-authoring/adapters/canonical-markdown.d.ts +14 -0
- package/dist/document-authoring/adapters/canonical-markdown.d.ts.map +1 -0
- package/dist/document-authoring/adapters/canonical-markdown.js +354 -0
- package/dist/document-authoring/adapters/canonical-markdown.js.map +1 -0
- package/dist/document-authoring/adapters/node/node-authoring-profile-reader.d.ts.map +1 -1
- package/dist/document-authoring/adapters/node/node-authoring-profile-reader.js +4 -1
- package/dist/document-authoring/adapters/node/node-authoring-profile-reader.js.map +1 -1
- package/dist/document-authoring/adapters/node/read-document-authority-file.d.ts.map +1 -1
- package/dist/document-authoring/adapters/node/read-document-authority-file.js +3 -13
- package/dist/document-authoring/adapters/node/read-document-authority-file.js.map +1 -1
- package/dist/document-authoring/application/policies/authoring-profile-semantics.d.ts +38 -0
- package/dist/document-authoring/application/policies/authoring-profile-semantics.d.ts.map +1 -0
- package/dist/document-authoring/application/policies/authoring-profile-semantics.js +122 -0
- package/dist/document-authoring/application/policies/authoring-profile-semantics.js.map +1 -0
- package/dist/document-authoring/application/policies/document-contract-digests.d.ts +20 -0
- package/dist/document-authoring/application/policies/document-contract-digests.d.ts.map +1 -0
- package/dist/document-authoring/application/policies/document-contract-digests.js +275 -0
- package/dist/document-authoring/application/policies/document-contract-digests.js.map +1 -0
- package/dist/document-authoring/application/policies/document-repository-path.d.ts +1 -0
- package/dist/document-authoring/application/policies/document-repository-path.d.ts.map +1 -1
- package/dist/document-authoring/application/policies/document-repository-path.js +21 -2
- package/dist/document-authoring/application/policies/document-repository-path.js.map +1 -1
- package/dist/document-authoring/application/policies/document-temporary-path.d.ts +7 -0
- package/dist/document-authoring/application/policies/document-temporary-path.d.ts.map +1 -0
- package/dist/document-authoring/application/policies/document-temporary-path.js +34 -0
- package/dist/document-authoring/application/policies/document-temporary-path.js.map +1 -0
- package/dist/document-authoring/application/ports/canonical-document-renderer.d.ts +29 -0
- package/dist/document-authoring/application/ports/canonical-document-renderer.d.ts.map +1 -0
- package/dist/document-authoring/application/ports/canonical-document-renderer.js +2 -0
- package/dist/document-authoring/application/ports/canonical-document-renderer.js.map +1 -0
- package/dist/repository-mutation/adapters/node/node-absent-file-publication.d.ts +31 -0
- package/dist/repository-mutation/adapters/node/node-absent-file-publication.d.ts.map +1 -0
- package/dist/repository-mutation/adapters/node/node-absent-file-publication.js +272 -0
- package/dist/repository-mutation/adapters/node/node-absent-file-publication.js.map +1 -0
- package/dist/repository-mutation/adapters/node/node-bounded-regular-file.d.ts +20 -0
- package/dist/repository-mutation/adapters/node/node-bounded-regular-file.d.ts.map +1 -0
- package/dist/repository-mutation/adapters/node/node-bounded-regular-file.js +123 -0
- package/dist/repository-mutation/adapters/node/node-bounded-regular-file.js.map +1 -0
- package/dist/repository-mutation/adapters/node/node-directory-durability.d.ts +12 -0
- package/dist/repository-mutation/adapters/node/node-directory-durability.d.ts.map +1 -0
- package/dist/repository-mutation/adapters/node/node-directory-durability.js +32 -0
- package/dist/repository-mutation/adapters/node/node-directory-durability.js.map +1 -0
- package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.d.ts +13 -0
- package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.d.ts.map +1 -0
- package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.js +67 -0
- package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.js.map +1 -0
- package/dist/repository-mutation/adapters/node/node-repository-path.d.ts +2 -0
- package/dist/repository-mutation/adapters/node/node-repository-path.d.ts.map +1 -0
- package/dist/repository-mutation/adapters/node/node-repository-path.js +7 -0
- package/dist/repository-mutation/adapters/node/node-repository-path.js.map +1 -0
- package/dist/repository-mutation/application/model/exact-postimage.d.ts +17 -0
- package/dist/repository-mutation/application/model/exact-postimage.d.ts.map +1 -0
- package/dist/repository-mutation/application/model/exact-postimage.js +11 -0
- package/dist/repository-mutation/application/model/exact-postimage.js.map +1 -0
- package/dist/repository-mutation/application/model/path-identity.d.ts +7 -0
- package/dist/repository-mutation/application/model/path-identity.d.ts.map +1 -0
- package/dist/repository-mutation/application/model/path-identity.js +2 -0
- package/dist/repository-mutation/application/model/path-identity.js.map +1 -0
- package/dist/repository-mutation/application/model/repository-path.d.ts +8 -0
- package/dist/repository-mutation/application/model/repository-path.d.ts.map +1 -0
- package/dist/repository-mutation/application/model/repository-path.js +74 -0
- package/dist/repository-mutation/application/model/repository-path.js.map +1 -0
- package/dist/scaffolding/adapters/node/filesystem-file-identity.d.ts +3 -23
- package/dist/scaffolding/adapters/node/filesystem-file-identity.d.ts.map +1 -1
- package/dist/scaffolding/adapters/node/filesystem-file-identity.js +1 -122
- package/dist/scaffolding/adapters/node/filesystem-file-identity.js.map +1 -1
- package/dist/scaffolding/adapters/node/filesystem-operation-state.d.ts +2 -1
- package/dist/scaffolding/adapters/node/filesystem-operation-state.d.ts.map +1 -1
- package/dist/scaffolding/adapters/node/filesystem-operation-state.js +73 -122
- package/dist/scaffolding/adapters/node/filesystem-operation-state.js.map +1 -1
- package/dist/scaffolding/adapters/node/filesystem-path-guard.d.ts.map +1 -1
- package/dist/scaffolding/adapters/node/filesystem-path-guard.js +27 -68
- package/dist/scaffolding/adapters/node/filesystem-path-guard.js.map +1 -1
- package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.d.ts +4 -0
- package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.d.ts.map +1 -0
- package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.js +48 -0
- package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.js.map +1 -0
- package/dist/transaction-coordination/adapters/node/document-temporary-identity.d.ts +4 -0
- package/dist/transaction-coordination/adapters/node/document-temporary-identity.d.ts.map +1 -0
- package/dist/transaction-coordination/adapters/node/document-temporary-identity.js +30 -0
- package/dist/transaction-coordination/adapters/node/document-temporary-identity.js.map +1 -0
- package/dist/transaction-coordination/adapters/node/installed-foundation-build-identity.js +1 -1
- package/dist/transaction-coordination/adapters/node/installed-foundation-build-identity.js.map +1 -1
- package/dist/transaction-coordination/adapters/node/legacy-document-envelope-v2.d.ts +5 -0
- package/dist/transaction-coordination/adapters/node/legacy-document-envelope-v2.d.ts.map +1 -0
- package/dist/transaction-coordination/adapters/node/legacy-document-envelope-v2.js +212 -0
- package/dist/transaction-coordination/adapters/node/legacy-document-envelope-v2.js.map +1 -0
- package/dist/transaction-coordination/adapters/node/node-foundation-operation-lock.d.ts.map +1 -1
- package/dist/transaction-coordination/adapters/node/node-foundation-operation-lock.js +1 -1
- package/dist/transaction-coordination/adapters/node/node-foundation-operation-lock.js.map +1 -1
- package/dist/transaction-coordination/adapters/node/node-foundation-transaction-slot.d.ts.map +1 -1
- package/dist/transaction-coordination/adapters/node/node-foundation-transaction-slot.js +48 -26
- package/dist/transaction-coordination/adapters/node/node-foundation-transaction-slot.js.map +1 -1
- package/package.json +1 -1
- package/schemas/document-authoring-profile/v1.schema.json +64 -15
- package/schemas/document-command-envelope/v1.schema.json +1 -1
- package/schemas/document-intent/v1.schema.json +48 -6
- package/schemas/document-plan/v1.schema.json +20 -4
- package/schemas/document-receipt/v1.schema.json +1 -1
- package/schemas/foundation-transaction-envelope/v2.schema.json +21 -3
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
3
|
import { ContainedFileReadError, readContainedRegularFile } from "../../../filesystem-path-safety.js";
|
|
4
|
+
import { isDocumentRepositoryPath } from "../../application/policies/document-repository-path.js";
|
|
4
5
|
import { DocumentCatalogError } from "../../document-catalog-error.js";
|
|
5
|
-
const WINDOWS_DEVICE_COMPONENT = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu;
|
|
6
6
|
function inputInvalid(message, options) {
|
|
7
7
|
throw new DocumentCatalogError("DOCUMENT_CATALOG_INPUT_INVALID", message, options);
|
|
8
8
|
}
|
|
9
9
|
function assertPortableDocumentAuthorityPath(path) {
|
|
10
|
-
|
|
11
|
-
if (path.length === 0 ||
|
|
12
|
-
path.length > 512 ||
|
|
13
|
-
isAbsolute(path) ||
|
|
14
|
-
path.includes("\\") ||
|
|
15
|
-
!/^[A-Za-z0-9._@/-]+$/u.test(path) ||
|
|
16
|
-
segments.some((segment) => segment.length === 0 ||
|
|
17
|
-
segment === "." ||
|
|
18
|
-
segment === ".." ||
|
|
19
|
-
segment.endsWith(".") ||
|
|
20
|
-
WINDOWS_DEVICE_COMPONENT.test(segment))) {
|
|
10
|
+
if (!isDocumentRepositoryPath(path)) {
|
|
21
11
|
inputInvalid("Document authority paths must use the portable repository-relative path grammar.");
|
|
22
12
|
}
|
|
23
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-document-authority-file.js","sourceRoot":"","sources":["../../../../src/document-authoring/adapters/node/read-document-authority-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"read-document-authority-file.js","sourceRoot":"","sources":["../../../../src/document-authoring/adapters/node/read-document-authority-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
interface PlacementSemantics {
|
|
2
|
+
readonly allowedRoots?: readonly string[];
|
|
3
|
+
readonly kind: string;
|
|
4
|
+
readonly filename?: string;
|
|
5
|
+
readonly minimumSegmentsAfterRequired?: number;
|
|
6
|
+
readonly minimumSegmentsBeforeRequired?: number;
|
|
7
|
+
readonly requiredBasename?: string;
|
|
8
|
+
readonly requiredSegmentsInOrder?: readonly string[];
|
|
9
|
+
readonly root?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ArtifactTypeSemantics {
|
|
12
|
+
readonly identity?: {
|
|
13
|
+
readonly format?: string;
|
|
14
|
+
readonly grammar?: {
|
|
15
|
+
readonly maxSuffixSegments: number;
|
|
16
|
+
readonly minSuffixSegments: number;
|
|
17
|
+
readonly prefixSegments: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
readonly placement: PlacementSemantics;
|
|
21
|
+
readonly type: string;
|
|
22
|
+
}
|
|
23
|
+
export interface AuthoringProfileSemantics {
|
|
24
|
+
readonly authoring: {
|
|
25
|
+
readonly artifactTypes: readonly ArtifactTypeSemantics[];
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export type AuthoringProfileSemanticProblem = "duplicate-artifact-type" | "incompatible-identity-placement" | "invalid-qualified-grammar-range" | "overlapping-placement-roots" | "portable-root-collision";
|
|
29
|
+
export declare class AuthoringProfileSemanticError extends Error {
|
|
30
|
+
readonly problem: AuthoringProfileSemanticProblem;
|
|
31
|
+
constructor(problem: AuthoringProfileSemanticProblem);
|
|
32
|
+
}
|
|
33
|
+
export declare function assertAuthoringProfileSemantics(profile: AuthoringProfileSemantics): void;
|
|
34
|
+
export declare function matchingPlacementRoot(repositoryPath: string, allowedRoots: readonly string[]): string | undefined;
|
|
35
|
+
export declare function hasContiguousRequiredSegments(repositoryPath: string, requiredSegments: readonly string[], matchedRoot?: string): boolean;
|
|
36
|
+
export declare function isRepositoryPathAllowedByPlacement(repositoryPath: string, placement: PlacementSemantics): boolean;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=authoring-profile-semantics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authoring-profile-semantics.d.ts","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/authoring-profile-semantics.ts"],"names":[],"mappings":"AAEA,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,4BAA4B,CAAC,EAAE,MAAM,CAAC;IAC/C,QAAQ,CAAC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAChD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,OAAO,CAAC,EAAE;YACjB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;YACnC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;YACnC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;SAC5C,CAAC;KACH,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,aAAa,EAAE,SAAS,qBAAqB,EAAE,CAAC;KAC1D,CAAC;CACH;AAED,MAAM,MAAM,+BAA+B,GACvC,yBAAyB,GACzB,iCAAiC,GACjC,iCAAiC,GACjC,6BAA6B,GAC7B,yBAAyB,CAAC;AAE9B,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,OAAO,EAAE,+BAA+B,CAAC;IAElD,YAAY,OAAO,EAAE,+BAA+B,EAInD;CACF;AAqBD,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,yBAAyB,GAAG,IAAI,CA+CxF;AAED,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,SAAS,MAAM,EAAE,GAC9B,MAAM,GAAG,SAAS,CAKpB;AAED,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,SAAS,MAAM,EAAE,EACnC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAkBT;AAED,wBAAgB,kCAAkC,CAChD,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,kBAAkB,GAC5B,OAAO,CAsCT"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { isDocumentRepositoryPath } from "./document-repository-path.js";
|
|
2
|
+
export class AuthoringProfileSemanticError extends Error {
|
|
3
|
+
problem;
|
|
4
|
+
constructor(problem) {
|
|
5
|
+
super(`Document authoring profile has invalid semantics: ${problem}.`);
|
|
6
|
+
this.name = "AuthoringProfileSemanticError";
|
|
7
|
+
this.problem = problem;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function portableAsciiIdentity(value) {
|
|
11
|
+
return value.replace(/[A-Z]/gu, (character) => character.toLowerCase());
|
|
12
|
+
}
|
|
13
|
+
function isSegmentBoundaryPrefix(prefix, candidate) {
|
|
14
|
+
return candidate === prefix || candidate.startsWith(`${prefix}/`);
|
|
15
|
+
}
|
|
16
|
+
function hasCompatibleIdentityPlacement(artifactType) {
|
|
17
|
+
const placement = artifactType.placement;
|
|
18
|
+
if (placement.kind === "qualified-leaf-index") {
|
|
19
|
+
return artifactType.identity?.format === "qualified";
|
|
20
|
+
}
|
|
21
|
+
if (placement.kind === "collection" && placement.filename === "numeric-id-slug") {
|
|
22
|
+
return artifactType.identity?.format === "adr-four-digits";
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
export function assertAuthoringProfileSemantics(profile) {
|
|
27
|
+
const types = new Set();
|
|
28
|
+
for (const artifactType of profile.authoring.artifactTypes) {
|
|
29
|
+
const typeIdentity = portableAsciiIdentity(artifactType.type);
|
|
30
|
+
if (types.has(typeIdentity)) {
|
|
31
|
+
throw new AuthoringProfileSemanticError("duplicate-artifact-type");
|
|
32
|
+
}
|
|
33
|
+
types.add(typeIdentity);
|
|
34
|
+
const grammar = artifactType.identity?.grammar;
|
|
35
|
+
if (grammar !== undefined &&
|
|
36
|
+
grammar.minSuffixSegments > grammar.maxSuffixSegments) {
|
|
37
|
+
throw new AuthoringProfileSemanticError("invalid-qualified-grammar-range");
|
|
38
|
+
}
|
|
39
|
+
const placement = artifactType.placement;
|
|
40
|
+
if (!hasCompatibleIdentityPlacement(artifactType)) {
|
|
41
|
+
throw new AuthoringProfileSemanticError("incompatible-identity-placement");
|
|
42
|
+
}
|
|
43
|
+
const roots = placement.kind === "qualified-leaf-index"
|
|
44
|
+
? (placement.root === undefined ? [] : [placement.root])
|
|
45
|
+
: [...(placement.allowedRoots ?? [])];
|
|
46
|
+
const identities = roots.map(portableAsciiIdentity);
|
|
47
|
+
for (const [index, root] of roots.entries()) {
|
|
48
|
+
if (!isDocumentRepositoryPath(root)) {
|
|
49
|
+
throw new AuthoringProfileSemanticError("portable-root-collision");
|
|
50
|
+
}
|
|
51
|
+
for (let other = 0; other < index; other += 1) {
|
|
52
|
+
const previous = identities[other];
|
|
53
|
+
const current = identities[index];
|
|
54
|
+
if (previous === undefined || current === undefined) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (previous === current) {
|
|
58
|
+
throw new AuthoringProfileSemanticError("portable-root-collision");
|
|
59
|
+
}
|
|
60
|
+
if (isSegmentBoundaryPrefix(previous, current) ||
|
|
61
|
+
isSegmentBoundaryPrefix(current, previous)) {
|
|
62
|
+
throw new AuthoringProfileSemanticError("overlapping-placement-roots");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function matchingPlacementRoot(repositoryPath, allowedRoots) {
|
|
69
|
+
const matches = allowedRoots.filter((root) => isSegmentBoundaryPrefix(root, repositoryPath));
|
|
70
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
71
|
+
}
|
|
72
|
+
export function hasContiguousRequiredSegments(repositoryPath, requiredSegments, matchedRoot) {
|
|
73
|
+
if (requiredSegments.length === 0) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
const rootIdentity = matchedRoot;
|
|
77
|
+
if (rootIdentity !== undefined &&
|
|
78
|
+
!isSegmentBoundaryPrefix(rootIdentity, repositoryPath)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const suffix = rootIdentity === undefined
|
|
82
|
+
? repositoryPath
|
|
83
|
+
: repositoryPath.slice(rootIdentity.length).replace(/^\//u, "");
|
|
84
|
+
const segments = suffix.split("/");
|
|
85
|
+
return segments.some((_segment, start) => requiredSegments.every((segment, offset) => segments[start + offset] === segment));
|
|
86
|
+
}
|
|
87
|
+
export function isRepositoryPathAllowedByPlacement(repositoryPath, placement) {
|
|
88
|
+
if (!isDocumentRepositoryPath(repositoryPath)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const segments = repositoryPath.split("/");
|
|
92
|
+
const basename = segments.at(-1);
|
|
93
|
+
if (basename !== placement.requiredBasename) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
if (placement.kind === "qualified-leaf-index") {
|
|
97
|
+
if (placement.root === undefined) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
const rootSegments = placement.root.split("/");
|
|
101
|
+
return isSegmentBoundaryPrefix(placement.root, repositoryPath) &&
|
|
102
|
+
segments.length > rootSegments.length + 1;
|
|
103
|
+
}
|
|
104
|
+
if (placement.kind !== "explicit") {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const root = matchingPlacementRoot(repositoryPath, placement.allowedRoots ?? []);
|
|
108
|
+
const required = placement.requiredSegmentsInOrder ?? [];
|
|
109
|
+
if (root === undefined ||
|
|
110
|
+
required.length === 0 ||
|
|
111
|
+
placement.minimumSegmentsBeforeRequired === undefined ||
|
|
112
|
+
placement.minimumSegmentsAfterRequired === undefined) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
const suffix = repositoryPath.slice(root.length + 1).split("/");
|
|
116
|
+
const directories = suffix.slice(0, -1);
|
|
117
|
+
return directories.some((_segment, start) => start >= placement.minimumSegmentsBeforeRequired &&
|
|
118
|
+
directories.length - start - required.length >=
|
|
119
|
+
placement.minimumSegmentsAfterRequired &&
|
|
120
|
+
required.every((segment, offset) => directories[start + offset] === segment));
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=authoring-profile-semantics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authoring-profile-semantics.js","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/authoring-profile-semantics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type CanonicalJsonValue } from "../../../canonical-json.js";
|
|
2
|
+
type Digest = `sha256:${string}`;
|
|
3
|
+
type JsonObject = Readonly<Record<string, CanonicalJsonValue>>;
|
|
4
|
+
export declare function documentIntentDigest(intent: JsonObject): Digest;
|
|
5
|
+
export declare function documentOwnerMembershipDigest(ownerCatalogDigest: string, ownerId: string): Digest;
|
|
6
|
+
export interface DocumentIdentityDigestEntry {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly repositoryPath: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function documentIdentityProjectionDigest(entries: readonly DocumentIdentityDigestEntry[]): Digest;
|
|
11
|
+
export declare function documentReferencedDocumentDigest(document: {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly path: string;
|
|
14
|
+
}): Digest;
|
|
15
|
+
export declare function documentPlanDigest(plan: JsonObject): Digest;
|
|
16
|
+
export declare function documentReceiptDigest(receipt: JsonObject): Digest;
|
|
17
|
+
export declare function assertDocumentPlanDigests(value: unknown): void;
|
|
18
|
+
export declare function assertDocumentReceiptDigest(value: unknown, planValue?: unknown): void;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=document-contract-digests.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-contract-digests.d.ts","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/document-contract-digests.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,4BAA4B,CAAC;AAIpC,KAAK,MAAM,GAAG,UAAU,MAAM,EAAE,CAAC;AACjC,KAAK,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAyC/D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAE/D;AAED,wBAAgB,6BAA6B,CAC3C,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,MAAM,GACd,MAAM,CAKR;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,SAAS,2BAA2B,EAAE,GAC9C,MAAM,CAcR;AAED,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE;IACzD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAST;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAK3D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAKjE;AAqOD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAU9D;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,EACd,SAAS,CAAC,EAAE,OAAO,GAClB,IAAI,CAoCN"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { compareBinaryStrings } from "../../../binary-string-comparator.js";
|
|
2
|
+
import { canonicalJson, sha256Bytes, sha256Json } from "../../../canonical-json.js";
|
|
3
|
+
import { documentTemporaryPath } from "./document-temporary-path.js";
|
|
4
|
+
import { documentRepositoryParentPath } from "./document-repository-path.js";
|
|
5
|
+
const DOMAIN_PREFIX = "agent-teams.foundation.document-authoring";
|
|
6
|
+
class DocumentContractDigestError extends Error {
|
|
7
|
+
constructor(message, options) {
|
|
8
|
+
super(message, options);
|
|
9
|
+
this.name = "DocumentContractDigestError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function domainDigest(domain, payload) {
|
|
13
|
+
return sha256Json({ domain, payload });
|
|
14
|
+
}
|
|
15
|
+
function withoutOwnDigest(value, field) {
|
|
16
|
+
const snapshot = JSON.parse(canonicalJson(value));
|
|
17
|
+
const result = Object.create(null);
|
|
18
|
+
for (const key of Reflect.ownKeys(snapshot)) {
|
|
19
|
+
if (key === field) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (typeof key !== "string") {
|
|
23
|
+
throw new DocumentContractDigestError("Document digest input must not contain symbolic properties.");
|
|
24
|
+
}
|
|
25
|
+
const descriptor = Object.getOwnPropertyDescriptor(snapshot, key);
|
|
26
|
+
if (descriptor === undefined || !("value" in descriptor)) {
|
|
27
|
+
throw new DocumentContractDigestError("Document digest input must contain only own data properties.");
|
|
28
|
+
}
|
|
29
|
+
result[key] = descriptor.value;
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
export function documentIntentDigest(intent) {
|
|
34
|
+
return domainDigest(`${DOMAIN_PREFIX}/intent/v1`, intent);
|
|
35
|
+
}
|
|
36
|
+
export function documentOwnerMembershipDigest(ownerCatalogDigest, ownerId) {
|
|
37
|
+
return domainDigest(`${DOMAIN_PREFIX}/owner-membership/v1`, {
|
|
38
|
+
ownerCatalogDigest,
|
|
39
|
+
ownerId
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export function documentIdentityProjectionDigest(entries) {
|
|
43
|
+
const snapshot = JSON.parse(canonicalJson(entries));
|
|
44
|
+
const normalized = snapshot
|
|
45
|
+
.map(({ id, repositoryPath }) => ({ id, repositoryPath }))
|
|
46
|
+
.toSorted((left, right) => compareBinaryStrings(left.id, right.id) ||
|
|
47
|
+
compareBinaryStrings(left.repositoryPath, right.repositoryPath));
|
|
48
|
+
return domainDigest(`${DOMAIN_PREFIX}/identity-projection/v1`, {
|
|
49
|
+
entries: normalized
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export function documentReferencedDocumentDigest(document) {
|
|
53
|
+
const snapshot = JSON.parse(canonicalJson(document));
|
|
54
|
+
return domainDigest(`${DOMAIN_PREFIX}/referenced-document/v1`, {
|
|
55
|
+
id: snapshot.id,
|
|
56
|
+
path: snapshot.path
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export function documentPlanDigest(plan) {
|
|
60
|
+
return domainDigest(`${DOMAIN_PREFIX}/plan/v1`, withoutOwnDigest(plan, "planDigest"));
|
|
61
|
+
}
|
|
62
|
+
export function documentReceiptDigest(receipt) {
|
|
63
|
+
return domainDigest(`${DOMAIN_PREFIX}/receipt/v1`, withoutOwnDigest(receipt, "receiptDigest"));
|
|
64
|
+
}
|
|
65
|
+
function record(value, subject) {
|
|
66
|
+
if (value === null || Array.isArray(value) || typeof value !== "object") {
|
|
67
|
+
throw new DocumentContractDigestError(`${subject} must be a JSON object.`);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
function validatedRecord(value, subject) {
|
|
72
|
+
const candidate = record(value, subject);
|
|
73
|
+
try {
|
|
74
|
+
return JSON.parse(canonicalJson(candidate));
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
throw new DocumentContractDigestError(`${subject} must use the closed canonical JSON data model.`, { cause: error });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function assertPublicationBindings(plan) {
|
|
81
|
+
const destination = plan["destination"];
|
|
82
|
+
const expectedParent = record(plan["expectedParent"], "Document Plan expected parent");
|
|
83
|
+
const precondition = record(plan["destinationPrecondition"], "Document Plan destination precondition");
|
|
84
|
+
const capabilities = plan["requiredAdapterCapabilities"];
|
|
85
|
+
let hasTemporaryCapacity = false;
|
|
86
|
+
if (typeof destination === "string" && typeof plan["planDigest"] === "string") {
|
|
87
|
+
try {
|
|
88
|
+
documentTemporaryPath(destination, plan["planDigest"]);
|
|
89
|
+
hasTemporaryCapacity = true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// The single publication error below is the stable public failure surface.
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (typeof destination !== "string" ||
|
|
96
|
+
!hasTemporaryCapacity ||
|
|
97
|
+
expectedParent["path"] !== documentRepositoryParentPath(destination) ||
|
|
98
|
+
expectedParent["state"] !== "directory" ||
|
|
99
|
+
expectedParent["ancestry"] !== "real-directories" ||
|
|
100
|
+
precondition["state"] !== "absent" ||
|
|
101
|
+
!Array.isArray(capabilities) ||
|
|
102
|
+
!capabilities.some((capability) => capability === "create-file-no-replace/v1")) {
|
|
103
|
+
throw new DocumentContractDigestError("Document Plan publication bindings are invalid.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function assertIntentDigest(plan) {
|
|
107
|
+
const intent = record(plan["intent"], "Document Plan Intent");
|
|
108
|
+
if (plan["intentDigest"] !== documentIntentDigest(intent)) {
|
|
109
|
+
throw new DocumentContractDigestError("Document Plan Intent digest is invalid.");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function assertOwnerMembershipDigest(plan) {
|
|
113
|
+
const intent = record(plan["intent"], "Document Plan Intent");
|
|
114
|
+
const authority = record(plan["authority"], "Document Plan authority");
|
|
115
|
+
const ownerCatalog = record(authority["ownerCatalog"], "Document Plan owner catalog authority");
|
|
116
|
+
const selectedOwner = record(plan["selectedOwner"], "Document Plan selected owner");
|
|
117
|
+
if (typeof ownerCatalog["digest"] !== "string" ||
|
|
118
|
+
typeof intent["owner"] !== "string" ||
|
|
119
|
+
typeof selectedOwner["id"] !== "string" ||
|
|
120
|
+
selectedOwner["id"] !== intent["owner"] ||
|
|
121
|
+
selectedOwner["membershipDigest"] !==
|
|
122
|
+
documentOwnerMembershipDigest(ownerCatalog["digest"], selectedOwner["id"])) {
|
|
123
|
+
throw new DocumentContractDigestError("Document Plan owner membership digest is invalid.");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function hasExactCommit(commit, expected) {
|
|
127
|
+
return Object.entries(expected).every(([field, value]) => commit[field] === value);
|
|
128
|
+
}
|
|
129
|
+
function isRecoveryCommit(outcome, commit) {
|
|
130
|
+
const publication = commit["publication"];
|
|
131
|
+
const atomicity = commit["atomicity"];
|
|
132
|
+
return (commit["state"] === outcome &&
|
|
133
|
+
["none", "published", "unknown"].includes(publication) &&
|
|
134
|
+
["not-applicable", "single-file-atomic-create"].includes(atomicity) &&
|
|
135
|
+
(publication !== "published" || atomicity === "single-file-atomic-create") &&
|
|
136
|
+
(publication !== "none" || atomicity === "not-applicable") &&
|
|
137
|
+
commit["recoverability"] === "preserved-for-recovery");
|
|
138
|
+
}
|
|
139
|
+
function assertReceiptOutcomeCommit(receipt) {
|
|
140
|
+
const outcome = receipt["outcome"];
|
|
141
|
+
const commit = record(receipt["commit"], "Document Receipt commit observation");
|
|
142
|
+
const noResultOutcomes = [
|
|
143
|
+
"authority-stale",
|
|
144
|
+
"rejected",
|
|
145
|
+
"failed-before-publication",
|
|
146
|
+
"cancelled"
|
|
147
|
+
];
|
|
148
|
+
const recoveryOutcomes = ["recovery-required", "manual-recovery-required"];
|
|
149
|
+
const applied = outcome === "applied" &&
|
|
150
|
+
typeof receipt["resultDigest"] === "string" &&
|
|
151
|
+
hasExactCommit(commit, {
|
|
152
|
+
state: "committed",
|
|
153
|
+
publication: "published",
|
|
154
|
+
atomicity: "single-file-atomic-create",
|
|
155
|
+
recoverability: "not-required"
|
|
156
|
+
});
|
|
157
|
+
const alreadyApplied = outcome === "already-applied" &&
|
|
158
|
+
typeof receipt["resultDigest"] === "string" &&
|
|
159
|
+
hasExactCommit(commit, {
|
|
160
|
+
state: "committed",
|
|
161
|
+
publication: "preexisting-exact",
|
|
162
|
+
atomicity: "not-applicable",
|
|
163
|
+
recoverability: "not-required"
|
|
164
|
+
});
|
|
165
|
+
const noResult = typeof outcome === "string" &&
|
|
166
|
+
noResultOutcomes.includes(outcome) &&
|
|
167
|
+
receipt["resultDigest"] === undefined &&
|
|
168
|
+
hasExactCommit(commit, {
|
|
169
|
+
state: "not-published",
|
|
170
|
+
publication: "none",
|
|
171
|
+
atomicity: "not-applicable",
|
|
172
|
+
recoverability: "not-required"
|
|
173
|
+
});
|
|
174
|
+
const recovery = typeof outcome === "string" &&
|
|
175
|
+
recoveryOutcomes.includes(outcome) &&
|
|
176
|
+
receipt["resultDigest"] === undefined &&
|
|
177
|
+
isRecoveryCommit(outcome, commit);
|
|
178
|
+
if (!applied && !alreadyApplied && !noResult && !recovery) {
|
|
179
|
+
throw new DocumentContractDigestError("Document Receipt outcome and commit observation are incompatible.");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function assertReferencedDocumentDigests(plan) {
|
|
183
|
+
const references = plan["referencedDocuments"];
|
|
184
|
+
if (!Array.isArray(references)) {
|
|
185
|
+
throw new DocumentContractDigestError("Document Plan referenced documents must be an array.");
|
|
186
|
+
}
|
|
187
|
+
for (const referenceValue of references) {
|
|
188
|
+
const reference = record(referenceValue, "Document Plan referenced document");
|
|
189
|
+
if (typeof reference["id"] !== "string" ||
|
|
190
|
+
typeof reference["path"] !== "string" ||
|
|
191
|
+
reference["projectionDigest"] !==
|
|
192
|
+
documentReferencedDocumentDigest({
|
|
193
|
+
id: reference["id"],
|
|
194
|
+
path: reference["path"]
|
|
195
|
+
})) {
|
|
196
|
+
throw new DocumentContractDigestError("Document Plan referenced-document digest is invalid.");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function assertOutputDigest(plan) {
|
|
201
|
+
const output = record(plan["output"], "Document Plan output");
|
|
202
|
+
if (typeof output["contentBase64"] !== "string") {
|
|
203
|
+
throw new DocumentContractDigestError("Document Plan output content must be canonical Base64.");
|
|
204
|
+
}
|
|
205
|
+
const bytes = Buffer.from(output["contentBase64"], "base64");
|
|
206
|
+
if (bytes.toString("base64") !== output["contentBase64"] ||
|
|
207
|
+
output["size"] !== bytes.byteLength ||
|
|
208
|
+
output["digest"] !== sha256Bytes(bytes)) {
|
|
209
|
+
throw new DocumentContractDigestError("Document Plan output digest is invalid.");
|
|
210
|
+
}
|
|
211
|
+
if (bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) {
|
|
212
|
+
throw new DocumentContractDigestError("Document Plan output must not start with a UTF-8 BOM.");
|
|
213
|
+
}
|
|
214
|
+
let source;
|
|
215
|
+
try {
|
|
216
|
+
source = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
throw new DocumentContractDigestError("Document Plan output is not well-formed UTF-8.", { cause: error });
|
|
220
|
+
}
|
|
221
|
+
if (source.startsWith("\uFEFF") ||
|
|
222
|
+
source.includes("\u0000") ||
|
|
223
|
+
source.includes("\r") ||
|
|
224
|
+
!source.endsWith("\n") ||
|
|
225
|
+
source.endsWith("\n\n") ||
|
|
226
|
+
output["mode"] !== "0644" ||
|
|
227
|
+
output["mediaType"] !== "text/markdown; charset=utf-8") {
|
|
228
|
+
throw new DocumentContractDigestError("Document Plan output violates the canonical Markdown byte contract.");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
export function assertDocumentPlanDigests(value) {
|
|
232
|
+
const plan = validatedRecord(value, "Document Plan");
|
|
233
|
+
assertIntentDigest(plan);
|
|
234
|
+
assertOwnerMembershipDigest(plan);
|
|
235
|
+
assertReferencedDocumentDigests(plan);
|
|
236
|
+
assertOutputDigest(plan);
|
|
237
|
+
assertPublicationBindings(plan);
|
|
238
|
+
if (plan["planDigest"] !== documentPlanDigest(plan)) {
|
|
239
|
+
throw new DocumentContractDigestError("Document Plan digest is invalid.");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
export function assertDocumentReceiptDigest(value, planValue) {
|
|
243
|
+
const receipt = validatedRecord(value, "Document Receipt");
|
|
244
|
+
if (receipt["receiptDigest"] !== documentReceiptDigest(receipt)) {
|
|
245
|
+
throw new DocumentContractDigestError("Document Receipt digest is invalid.");
|
|
246
|
+
}
|
|
247
|
+
assertReceiptOutcomeCommit(receipt);
|
|
248
|
+
if (planValue === undefined) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
assertDocumentPlanDigests(planValue);
|
|
252
|
+
const plan = validatedRecord(planValue, "Document Plan");
|
|
253
|
+
const output = record(plan["output"], "Document Plan output");
|
|
254
|
+
const outcome = receipt["outcome"];
|
|
255
|
+
const hasProvenOutput = outcome === "applied" || outcome === "already-applied";
|
|
256
|
+
const supportedOutcomes = new Set([
|
|
257
|
+
"applied",
|
|
258
|
+
"already-applied",
|
|
259
|
+
"authority-stale",
|
|
260
|
+
"rejected",
|
|
261
|
+
"recovery-required",
|
|
262
|
+
"manual-recovery-required",
|
|
263
|
+
"failed-before-publication",
|
|
264
|
+
"cancelled"
|
|
265
|
+
]);
|
|
266
|
+
if (typeof outcome !== "string" ||
|
|
267
|
+
!supportedOutcomes.has(outcome) ||
|
|
268
|
+
receipt["planDigest"] !== plan["planDigest"] ||
|
|
269
|
+
receipt["destination"] !== plan["destination"] ||
|
|
270
|
+
(hasProvenOutput && receipt["resultDigest"] !== output["digest"]) ||
|
|
271
|
+
(!hasProvenOutput && receipt["resultDigest"] !== undefined)) {
|
|
272
|
+
throw new DocumentContractDigestError("Document Receipt result evidence does not bind the referenced Plan.");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=document-contract-digests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-contract-digests.js","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/document-contract-digests.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-repository-path.d.ts","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/document-repository-path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"document-repository-path.d.ts","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/document-repository-path.ts"],"names":[],"mappings":"AAIA,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAmB9D;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjE"}
|
|
@@ -1,5 +1,24 @@
|
|
|
1
|
-
const
|
|
1
|
+
const DOCUMENT_REPOSITORY_SEGMENT = /^[A-Za-z0-9._@-]+$/u;
|
|
2
|
+
const WINDOWS_RESERVED_NAMES = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu;
|
|
3
|
+
const utf8 = new TextEncoder();
|
|
2
4
|
export function isDocumentRepositoryPath(path) {
|
|
3
|
-
|
|
5
|
+
if (utf8.encode(path).byteLength > 512 ||
|
|
6
|
+
path.startsWith("/") ||
|
|
7
|
+
path.includes("\\")) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const segments = path.split("/");
|
|
11
|
+
return segments.every((segment) => segment.length > 0 &&
|
|
12
|
+
segment !== "." &&
|
|
13
|
+
segment !== ".." &&
|
|
14
|
+
utf8.encode(segment).byteLength <= 255 &&
|
|
15
|
+
!segment.endsWith(".") &&
|
|
16
|
+
!segment.endsWith(" ") &&
|
|
17
|
+
!WINDOWS_RESERVED_NAMES.test(segment) &&
|
|
18
|
+
DOCUMENT_REPOSITORY_SEGMENT.test(segment));
|
|
19
|
+
}
|
|
20
|
+
export function documentRepositoryParentPath(path) {
|
|
21
|
+
const separator = path.lastIndexOf("/");
|
|
22
|
+
return separator === -1 ? "." : path.slice(0, separator);
|
|
4
23
|
}
|
|
5
24
|
//# sourceMappingURL=document-repository-path.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-repository-path.js","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/document-repository-path.ts"],"names":[],"mappings":"AAAA,MAAM,
|
|
1
|
+
{"version":3,"file":"document-repository-path.js","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/document-repository-path.ts"],"names":[],"mappings":"AAAA,MAAM,2BAA2B,GAAG,qBAAqB,CAAC;AAC1D,MAAM,sBAAsB,GAAG,kDAAkD,CAAC;AAClF,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;AAE/B,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,IACE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,GAAG,GAAG;QAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QACpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EACnB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAChC,OAAO,CAAC,MAAM,GAAG,CAAC;QAClB,OAAO,KAAK,GAAG;QACf,OAAO,KAAK,IAAI;QAChB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,IAAI,GAAG;QACtC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACtB,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACtB,CAAC,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC;QACrC,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,CAC1C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,IAAY;IACvD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACxC,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derives the only transaction-owned temporary path for a Document Plan.
|
|
3
|
+
* The name is bounded independently of the destination basename and remains
|
|
4
|
+
* in the destination's already-authorized parent directory.
|
|
5
|
+
*/
|
|
6
|
+
export declare function documentTemporaryPath(destination: string, planDigest: string): string;
|
|
7
|
+
//# sourceMappingURL=document-temporary-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-temporary-path.d.ts","sourceRoot":"","sources":["../../../../src/document-authoring/application/policies/document-temporary-path.ts"],"names":[],"mappings":"AAaA;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,CAyBR"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { isDocumentRepositoryPath } from "./document-repository-path.js";
|
|
2
|
+
const CANONICAL_SHA256_DIGEST = /^sha256:[0-9a-f]{64}$/u;
|
|
3
|
+
const TEMPORARY_PREFIX = ".foundation-document-";
|
|
4
|
+
const TEMPORARY_SUFFIX = ".tmp";
|
|
5
|
+
class DocumentTemporaryPathError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "DocumentTemporaryPathError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Derives the only transaction-owned temporary path for a Document Plan.
|
|
13
|
+
* The name is bounded independently of the destination basename and remains
|
|
14
|
+
* in the destination's already-authorized parent directory.
|
|
15
|
+
*/
|
|
16
|
+
export function documentTemporaryPath(destination, planDigest) {
|
|
17
|
+
if (!isDocumentRepositoryPath(destination)) {
|
|
18
|
+
throw new DocumentTemporaryPathError("Document destination is not a portable repository path.");
|
|
19
|
+
}
|
|
20
|
+
if (!CANONICAL_SHA256_DIGEST.test(planDigest)) {
|
|
21
|
+
throw new DocumentTemporaryPathError("Document Plan digest is not canonical SHA-256.");
|
|
22
|
+
}
|
|
23
|
+
const separator = destination.lastIndexOf("/");
|
|
24
|
+
const parent = separator === -1 ? "" : destination.slice(0, separator);
|
|
25
|
+
const temporaryName = `${TEMPORARY_PREFIX}${planDigest.slice("sha256:".length)}${TEMPORARY_SUFFIX}`;
|
|
26
|
+
const temporaryPath = parent.length === 0
|
|
27
|
+
? temporaryName
|
|
28
|
+
: `${parent}/${temporaryName}`;
|
|
29
|
+
if (!isDocumentRepositoryPath(temporaryPath)) {
|
|
30
|
+
throw new DocumentTemporaryPathError("Document destination parent cannot contain the bounded transaction temporary.");
|
|
31
|
+
}
|
|
32
|
+
return temporaryPath;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=document-temporary-path.js.map
|