@weatherboard/cms 0.8.0 → 0.10.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/README.md CHANGED
@@ -42,10 +42,14 @@ when names match. The host keeps its repository data and chooses how to display
42
42
  the source. `menuQuery`, `parseMenuDocument` and `menuTags` remain the menu API.
43
43
 
44
44
  `openVacanciesQuery`, `parseVacancies` and `parseVacancyDocument` require the
45
- consumer's validator. The consumer can enforce its work-location choices and
46
- the note required for an `Other` choice. The package supplies no site-specific
47
- default. A-2463 will replace those choices with references to the client's
48
- `location` documents.
45
+ consumer's validator, which receives each raw projected entry before display
46
+ fields are derived. The query resolves `workLocation` to `{ _id, name }` and
47
+ depends on both vacancy and location tags. The display label uses the resolved
48
+ name, then a non-`Other` legacy `location`, then `locationNote`; a dangling
49
+ reference falls through to the legacy fields. `locationId` is the resolved
50
+ location's ID or `null`. An entry with no display label is structurally dropped.
51
+ Legacy documents remain readable. Consumers whose validators require the legacy
52
+ string must update them before migrating documents to references.
49
53
 
50
54
  ## Site hero
51
55
 
@@ -240,9 +244,11 @@ from a later caller read. The returned objects share no caller-owned data.
240
244
  CMS has no runtime dependency on the unpublished menu or schema packages.
241
245
  Compatibility is exercised with a copied, neutral café saved-shape fixture;
242
246
  there is no schema devDependency or menu test-fixture import. Publication tests
243
- resolve imports in source, all eight entry bundles and their build input paths,
247
+ resolve imports in source, all ten entry bundles and their build input paths,
244
248
  including relative imports into either forbidden package root and type specifiers.
245
249
  Type-only test imports are refused too because the copied-fixture option was used.
250
+ When adding a public entry, run the package's whole suite (`pnpm --filter @weatherboard/cms test`)
251
+ and release smoke (`pnpm --filter @weatherboard/cms smoke`) before publication (A-553).
246
252
 
247
253
  ```ts
248
254
  import { menuQuery, menuTags } from '@weatherboard/cms';
@@ -0,0 +1,163 @@
1
+ /** Public contracts only. Evidence and approval identities never enter the CMS document. */
2
+ export declare const FACT_TYPES: readonly ["integer", "decimal", "boolean", "date", "string", "enum", "reference"];
3
+ export declare const FACT_DISPLAY_RULES: readonly ["identity/v1", "floorHundredsPlus/v1"];
4
+ export type FactDisplayRule = typeof FACT_DISPLAY_RULES[number];
5
+ export declare const FACT_KEY: RegExp;
6
+ export declare const FACT_ALIASES: Readonly<Record<string, string>>;
7
+ export type FactValue = {
8
+ type: "integer";
9
+ value: number;
10
+ } | {
11
+ type: "decimal";
12
+ value: string;
13
+ } | {
14
+ type: "boolean";
15
+ value: boolean;
16
+ } | {
17
+ type: "date" | "string";
18
+ value: string;
19
+ } | {
20
+ type: "enum";
21
+ value: string;
22
+ allowedValues: readonly string[];
23
+ } | {
24
+ type: "reference";
25
+ value: {
26
+ documentId: string;
27
+ documentRevision: string;
28
+ };
29
+ };
30
+ export type FactSource = {
31
+ kind: "computed" | "observed" | "attested";
32
+ definition: string;
33
+ version: string;
34
+ };
35
+ export type BusinessFact = {
36
+ key: string;
37
+ publicValue: FactValue;
38
+ unit: string | null;
39
+ timezone: string | null;
40
+ displayRule: FactDisplayRule;
41
+ source: FactSource;
42
+ accountableOwner: string;
43
+ freshness: "computed" | "operational" | "technical";
44
+ optional: boolean;
45
+ surfaces: readonly {
46
+ id: string;
47
+ semantics: "current" | "historical";
48
+ asOf: string | null;
49
+ }[];
50
+ };
51
+ export declare const FACT_EXPIRY_MS: {
52
+ readonly computed: number;
53
+ readonly operational: number;
54
+ readonly technical: number;
55
+ };
56
+ export type FactEvidence = {
57
+ reference: string;
58
+ digest: string;
59
+ observedAt: string;
60
+ expiresAt: string;
61
+ complete: boolean;
62
+ runId: string;
63
+ };
64
+ export type FactRevision = {
65
+ projectId: string;
66
+ revision: number;
67
+ baseRevision: number | null;
68
+ fact: BusinessFact;
69
+ evidence: FactEvidence;
70
+ effectiveAt: string;
71
+ expiresAt: string;
72
+ };
73
+ export type ApprovedFactRevision = FactRevision & {
74
+ hash: string;
75
+ approvedAt: string;
76
+ approval: {
77
+ kind: "signer";
78
+ signerId: string;
79
+ } | {
80
+ kind: "policy";
81
+ policyVersion: string;
82
+ };
83
+ };
84
+ export type FactPublicationReceipt = {
85
+ intentId: string;
86
+ projectId: string;
87
+ revision: number;
88
+ hash: string;
89
+ destination: {
90
+ projectId: string;
91
+ dataset: string;
92
+ };
93
+ expectedDocumentRevision: string | null;
94
+ cms: {
95
+ transactionId: string;
96
+ documentRevision: string;
97
+ readBackHash: string;
98
+ at: string;
99
+ } | null;
100
+ invalidation: {
101
+ deliveryKey: string;
102
+ target: string;
103
+ type: "businessFact";
104
+ id: string;
105
+ at: string;
106
+ } | null;
107
+ render: {
108
+ url: string;
109
+ deploymentId: string;
110
+ revision: number;
111
+ hash: string;
112
+ at: string;
113
+ } | null;
114
+ };
115
+ export type PublicBusinessFact = Pick<BusinessFact, "key" | "publicValue" | "unit" | "timezone" | "displayRule"> & {
116
+ _type: "businessFact";
117
+ _id: string;
118
+ approvedRevision: number;
119
+ approvedHash: string;
120
+ effectiveAt: string;
121
+ expiresAt: string;
122
+ provenanceSummary: string;
123
+ };
124
+ /** A request supplies one snapshot to every surface. Missing and unavailable are distinct from an empty snapshot. */
125
+ export type FactSnapshot = Readonly<Record<string, PublicBusinessFact>>;
126
+ export type FactReadResult = {
127
+ status: "available";
128
+ snapshot: FactSnapshot;
129
+ } | {
130
+ status: "unavailable";
131
+ reason: string;
132
+ };
133
+ export type FactReader = () => Promise<FactReadResult>;
134
+ export type FactPlaceholderContext = "htmlText" | "htmlAttribute" | "json";
135
+ /** Stored Sanity projection: scalar unions use named slots, never private revision fields. */
136
+ export type StoredFactValue = {
137
+ type: FactValue["type"];
138
+ numberValue?: number;
139
+ textValue?: string;
140
+ booleanValue?: boolean;
141
+ allowedValues?: readonly string[];
142
+ documentId?: string;
143
+ documentRevision?: string;
144
+ };
145
+ export declare function parseStoredFactValue(input: unknown): FactValue;
146
+ export declare function storeFactValue(input: FactValue): StoredFactValue;
147
+ export type StoredBusinessFact = Omit<PublicBusinessFact, "publicValue"> & {
148
+ publicValue: StoredFactValue;
149
+ };
150
+ export declare function assertFactKey(key: string): void;
151
+ export declare function businessFactId(key: string): string;
152
+ export declare function parseFactValue(input: unknown): FactValue;
153
+ export declare function parseFactDisplayRule(input: unknown): FactDisplayRule;
154
+ export declare function formatFact(input: FactValue, rule: FactDisplayRule): string;
155
+ /** Escape each replacement, not the surrounding trusted template. JSON returns string content without quotes;
156
+ * callers serialize complete structured objects and keep numeric properties as exact values. Attributes must be quoted.
157
+ * Raw text/React children use the formatter directly; never HTML-unescape an expanded string.
158
+ */
159
+ export declare function expandFactPlaceholders(template: string, values: Readonly<Record<string, string>>, context: FactPlaceholderContext): string;
160
+ /** Fixed JSON domain, sorted object keys, array order preserved, finite numbers only. */
161
+ export declare function canonicalFactJson(value: unknown): string;
162
+ /** SHA-256 of contract fields only; unknown fields and approval are ignored. Instants use UTC milliseconds. */
163
+ export declare function hashFactRevision(revision: FactRevision): Promise<string>;
@@ -0,0 +1,163 @@
1
+ /** Public contracts only. Evidence and approval identities never enter the CMS document. */
2
+ export declare const FACT_TYPES: readonly ["integer", "decimal", "boolean", "date", "string", "enum", "reference"];
3
+ export declare const FACT_DISPLAY_RULES: readonly ["identity/v1", "floorHundredsPlus/v1"];
4
+ export type FactDisplayRule = typeof FACT_DISPLAY_RULES[number];
5
+ export declare const FACT_KEY: RegExp;
6
+ export declare const FACT_ALIASES: Readonly<Record<string, string>>;
7
+ export type FactValue = {
8
+ type: "integer";
9
+ value: number;
10
+ } | {
11
+ type: "decimal";
12
+ value: string;
13
+ } | {
14
+ type: "boolean";
15
+ value: boolean;
16
+ } | {
17
+ type: "date" | "string";
18
+ value: string;
19
+ } | {
20
+ type: "enum";
21
+ value: string;
22
+ allowedValues: readonly string[];
23
+ } | {
24
+ type: "reference";
25
+ value: {
26
+ documentId: string;
27
+ documentRevision: string;
28
+ };
29
+ };
30
+ export type FactSource = {
31
+ kind: "computed" | "observed" | "attested";
32
+ definition: string;
33
+ version: string;
34
+ };
35
+ export type BusinessFact = {
36
+ key: string;
37
+ publicValue: FactValue;
38
+ unit: string | null;
39
+ timezone: string | null;
40
+ displayRule: FactDisplayRule;
41
+ source: FactSource;
42
+ accountableOwner: string;
43
+ freshness: "computed" | "operational" | "technical";
44
+ optional: boolean;
45
+ surfaces: readonly {
46
+ id: string;
47
+ semantics: "current" | "historical";
48
+ asOf: string | null;
49
+ }[];
50
+ };
51
+ export declare const FACT_EXPIRY_MS: {
52
+ readonly computed: number;
53
+ readonly operational: number;
54
+ readonly technical: number;
55
+ };
56
+ export type FactEvidence = {
57
+ reference: string;
58
+ digest: string;
59
+ observedAt: string;
60
+ expiresAt: string;
61
+ complete: boolean;
62
+ runId: string;
63
+ };
64
+ export type FactRevision = {
65
+ projectId: string;
66
+ revision: number;
67
+ baseRevision: number | null;
68
+ fact: BusinessFact;
69
+ evidence: FactEvidence;
70
+ effectiveAt: string;
71
+ expiresAt: string;
72
+ };
73
+ export type ApprovedFactRevision = FactRevision & {
74
+ hash: string;
75
+ approvedAt: string;
76
+ approval: {
77
+ kind: "signer";
78
+ signerId: string;
79
+ } | {
80
+ kind: "policy";
81
+ policyVersion: string;
82
+ };
83
+ };
84
+ export type FactPublicationReceipt = {
85
+ intentId: string;
86
+ projectId: string;
87
+ revision: number;
88
+ hash: string;
89
+ destination: {
90
+ projectId: string;
91
+ dataset: string;
92
+ };
93
+ expectedDocumentRevision: string | null;
94
+ cms: {
95
+ transactionId: string;
96
+ documentRevision: string;
97
+ readBackHash: string;
98
+ at: string;
99
+ } | null;
100
+ invalidation: {
101
+ deliveryKey: string;
102
+ target: string;
103
+ type: "businessFact";
104
+ id: string;
105
+ at: string;
106
+ } | null;
107
+ render: {
108
+ url: string;
109
+ deploymentId: string;
110
+ revision: number;
111
+ hash: string;
112
+ at: string;
113
+ } | null;
114
+ };
115
+ export type PublicBusinessFact = Pick<BusinessFact, "key" | "publicValue" | "unit" | "timezone" | "displayRule"> & {
116
+ _type: "businessFact";
117
+ _id: string;
118
+ approvedRevision: number;
119
+ approvedHash: string;
120
+ effectiveAt: string;
121
+ expiresAt: string;
122
+ provenanceSummary: string;
123
+ };
124
+ /** A request supplies one snapshot to every surface. Missing and unavailable are distinct from an empty snapshot. */
125
+ export type FactSnapshot = Readonly<Record<string, PublicBusinessFact>>;
126
+ export type FactReadResult = {
127
+ status: "available";
128
+ snapshot: FactSnapshot;
129
+ } | {
130
+ status: "unavailable";
131
+ reason: string;
132
+ };
133
+ export type FactReader = () => Promise<FactReadResult>;
134
+ export type FactPlaceholderContext = "htmlText" | "htmlAttribute" | "json";
135
+ /** Stored Sanity projection: scalar unions use named slots, never private revision fields. */
136
+ export type StoredFactValue = {
137
+ type: FactValue["type"];
138
+ numberValue?: number;
139
+ textValue?: string;
140
+ booleanValue?: boolean;
141
+ allowedValues?: readonly string[];
142
+ documentId?: string;
143
+ documentRevision?: string;
144
+ };
145
+ export declare function parseStoredFactValue(input: unknown): FactValue;
146
+ export declare function storeFactValue(input: FactValue): StoredFactValue;
147
+ export type StoredBusinessFact = Omit<PublicBusinessFact, "publicValue"> & {
148
+ publicValue: StoredFactValue;
149
+ };
150
+ export declare function assertFactKey(key: string): void;
151
+ export declare function businessFactId(key: string): string;
152
+ export declare function parseFactValue(input: unknown): FactValue;
153
+ export declare function parseFactDisplayRule(input: unknown): FactDisplayRule;
154
+ export declare function formatFact(input: FactValue, rule: FactDisplayRule): string;
155
+ /** Escape each replacement, not the surrounding trusted template. JSON returns string content without quotes;
156
+ * callers serialize complete structured objects and keep numeric properties as exact values. Attributes must be quoted.
157
+ * Raw text/React children use the formatter directly; never HTML-unescape an expanded string.
158
+ */
159
+ export declare function expandFactPlaceholders(template: string, values: Readonly<Record<string, string>>, context: FactPlaceholderContext): string;
160
+ /** Fixed JSON domain, sorted object keys, array order preserved, finite numbers only. */
161
+ export declare function canonicalFactJson(value: unknown): string;
162
+ /** SHA-256 of contract fields only; unknown fields and approval are ignored. Instants use UTC milliseconds. */
163
+ export declare function hashFactRevision(revision: FactRevision): Promise<string>;
@@ -0,0 +1,163 @@
1
+ /** Public contracts only. Evidence and approval identities never enter the CMS document. */
2
+ export declare const FACT_TYPES: readonly ["integer", "decimal", "boolean", "date", "string", "enum", "reference"];
3
+ export declare const FACT_DISPLAY_RULES: readonly ["identity/v1", "floorHundredsPlus/v1"];
4
+ export type FactDisplayRule = typeof FACT_DISPLAY_RULES[number];
5
+ export declare const FACT_KEY: RegExp;
6
+ export declare const FACT_ALIASES: Readonly<Record<string, string>>;
7
+ export type FactValue = {
8
+ type: "integer";
9
+ value: number;
10
+ } | {
11
+ type: "decimal";
12
+ value: string;
13
+ } | {
14
+ type: "boolean";
15
+ value: boolean;
16
+ } | {
17
+ type: "date" | "string";
18
+ value: string;
19
+ } | {
20
+ type: "enum";
21
+ value: string;
22
+ allowedValues: readonly string[];
23
+ } | {
24
+ type: "reference";
25
+ value: {
26
+ documentId: string;
27
+ documentRevision: string;
28
+ };
29
+ };
30
+ export type FactSource = {
31
+ kind: "computed" | "observed" | "attested";
32
+ definition: string;
33
+ version: string;
34
+ };
35
+ export type BusinessFact = {
36
+ key: string;
37
+ publicValue: FactValue;
38
+ unit: string | null;
39
+ timezone: string | null;
40
+ displayRule: FactDisplayRule;
41
+ source: FactSource;
42
+ accountableOwner: string;
43
+ freshness: "computed" | "operational" | "technical";
44
+ optional: boolean;
45
+ surfaces: readonly {
46
+ id: string;
47
+ semantics: "current" | "historical";
48
+ asOf: string | null;
49
+ }[];
50
+ };
51
+ export declare const FACT_EXPIRY_MS: {
52
+ readonly computed: number;
53
+ readonly operational: number;
54
+ readonly technical: number;
55
+ };
56
+ export type FactEvidence = {
57
+ reference: string;
58
+ digest: string;
59
+ observedAt: string;
60
+ expiresAt: string;
61
+ complete: boolean;
62
+ runId: string;
63
+ };
64
+ export type FactRevision = {
65
+ projectId: string;
66
+ revision: number;
67
+ baseRevision: number | null;
68
+ fact: BusinessFact;
69
+ evidence: FactEvidence;
70
+ effectiveAt: string;
71
+ expiresAt: string;
72
+ };
73
+ export type ApprovedFactRevision = FactRevision & {
74
+ hash: string;
75
+ approvedAt: string;
76
+ approval: {
77
+ kind: "signer";
78
+ signerId: string;
79
+ } | {
80
+ kind: "policy";
81
+ policyVersion: string;
82
+ };
83
+ };
84
+ export type FactPublicationReceipt = {
85
+ intentId: string;
86
+ projectId: string;
87
+ revision: number;
88
+ hash: string;
89
+ destination: {
90
+ projectId: string;
91
+ dataset: string;
92
+ };
93
+ expectedDocumentRevision: string | null;
94
+ cms: {
95
+ transactionId: string;
96
+ documentRevision: string;
97
+ readBackHash: string;
98
+ at: string;
99
+ } | null;
100
+ invalidation: {
101
+ deliveryKey: string;
102
+ target: string;
103
+ type: "businessFact";
104
+ id: string;
105
+ at: string;
106
+ } | null;
107
+ render: {
108
+ url: string;
109
+ deploymentId: string;
110
+ revision: number;
111
+ hash: string;
112
+ at: string;
113
+ } | null;
114
+ };
115
+ export type PublicBusinessFact = Pick<BusinessFact, "key" | "publicValue" | "unit" | "timezone" | "displayRule"> & {
116
+ _type: "businessFact";
117
+ _id: string;
118
+ approvedRevision: number;
119
+ approvedHash: string;
120
+ effectiveAt: string;
121
+ expiresAt: string;
122
+ provenanceSummary: string;
123
+ };
124
+ /** A request supplies one snapshot to every surface. Missing and unavailable are distinct from an empty snapshot. */
125
+ export type FactSnapshot = Readonly<Record<string, PublicBusinessFact>>;
126
+ export type FactReadResult = {
127
+ status: "available";
128
+ snapshot: FactSnapshot;
129
+ } | {
130
+ status: "unavailable";
131
+ reason: string;
132
+ };
133
+ export type FactReader = () => Promise<FactReadResult>;
134
+ export type FactPlaceholderContext = "htmlText" | "htmlAttribute" | "json";
135
+ /** Stored Sanity projection: scalar unions use named slots, never private revision fields. */
136
+ export type StoredFactValue = {
137
+ type: FactValue["type"];
138
+ numberValue?: number;
139
+ textValue?: string;
140
+ booleanValue?: boolean;
141
+ allowedValues?: readonly string[];
142
+ documentId?: string;
143
+ documentRevision?: string;
144
+ };
145
+ export declare function parseStoredFactValue(input: unknown): FactValue;
146
+ export declare function storeFactValue(input: FactValue): StoredFactValue;
147
+ export type StoredBusinessFact = Omit<PublicBusinessFact, "publicValue"> & {
148
+ publicValue: StoredFactValue;
149
+ };
150
+ export declare function assertFactKey(key: string): void;
151
+ export declare function businessFactId(key: string): string;
152
+ export declare function parseFactValue(input: unknown): FactValue;
153
+ export declare function parseFactDisplayRule(input: unknown): FactDisplayRule;
154
+ export declare function formatFact(input: FactValue, rule: FactDisplayRule): string;
155
+ /** Escape each replacement, not the surrounding trusted template. JSON returns string content without quotes;
156
+ * callers serialize complete structured objects and keep numeric properties as exact values. Attributes must be quoted.
157
+ * Raw text/React children use the formatter directly; never HTML-unescape an expanded string.
158
+ */
159
+ export declare function expandFactPlaceholders(template: string, values: Readonly<Record<string, string>>, context: FactPlaceholderContext): string;
160
+ /** Fixed JSON domain, sorted object keys, array order preserved, finite numbers only. */
161
+ export declare function canonicalFactJson(value: unknown): string;
162
+ /** SHA-256 of contract fields only; unknown fields and approval are ignored. Instants use UTC milliseconds. */
163
+ export declare function hashFactRevision(revision: FactRevision): Promise<string>;
@@ -0,0 +1,2 @@
1
+ "use strict";var n=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var o=(s,t)=>{for(var e in t)n(s,e,{get:t[e],enumerable:!0})},g=(s,t,e,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of c(t))!l.call(s,r)&&r!==e&&n(s,r,{get:()=>t[r],enumerable:!(a=i(t,r))||a.enumerable});return s};var d=s=>g(n({},"__esModule",{value:!0}),s);var f={};o(f,{FACT_SURFACE_MANIFEST_VERSION:()=>y});module.exports=d(f);var y=1;0&&(module.exports={FACT_SURFACE_MANIFEST_VERSION});
2
+ //# sourceMappingURL=fact-guard.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/fact-guard.ts"],
4
+ "sourcesContent": ["/** Registration seam for the later manifest guard; historical exclusions require evidence. */\nexport const FACT_SURFACE_MANIFEST_VERSION = 1 as const;\nexport type FactSurfaceManifest = {\n facts: readonly { key: string; literals: readonly string[] }[];\n surfaces: readonly { id: string; path: string; semantics: \"current\" | \"historical\" }[];\n exclusions: readonly { path: string; literal: string; asOf: string; evidence: string }[];\n};\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mCAAAE,IAAA,eAAAC,EAAAH,GACO,IAAME,EAAgC",
6
+ "names": ["fact_guard_exports", "__export", "FACT_SURFACE_MANIFEST_VERSION", "__toCommonJS"]
7
+ }
@@ -0,0 +1,19 @@
1
+ /** Registration seam for the later manifest guard; historical exclusions require evidence. */
2
+ export declare const FACT_SURFACE_MANIFEST_VERSION: 1;
3
+ export type FactSurfaceManifest = {
4
+ facts: readonly {
5
+ key: string;
6
+ literals: readonly string[];
7
+ }[];
8
+ surfaces: readonly {
9
+ id: string;
10
+ path: string;
11
+ semantics: "current" | "historical";
12
+ }[];
13
+ exclusions: readonly {
14
+ path: string;
15
+ literal: string;
16
+ asOf: string;
17
+ evidence: string;
18
+ }[];
19
+ };
@@ -0,0 +1,19 @@
1
+ /** Registration seam for the later manifest guard; historical exclusions require evidence. */
2
+ export declare const FACT_SURFACE_MANIFEST_VERSION: 1;
3
+ export type FactSurfaceManifest = {
4
+ facts: readonly {
5
+ key: string;
6
+ literals: readonly string[];
7
+ }[];
8
+ surfaces: readonly {
9
+ id: string;
10
+ path: string;
11
+ semantics: "current" | "historical";
12
+ }[];
13
+ exclusions: readonly {
14
+ path: string;
15
+ literal: string;
16
+ asOf: string;
17
+ evidence: string;
18
+ }[];
19
+ };
@@ -0,0 +1,19 @@
1
+ /** Registration seam for the later manifest guard; historical exclusions require evidence. */
2
+ export declare const FACT_SURFACE_MANIFEST_VERSION: 1;
3
+ export type FactSurfaceManifest = {
4
+ facts: readonly {
5
+ key: string;
6
+ literals: readonly string[];
7
+ }[];
8
+ surfaces: readonly {
9
+ id: string;
10
+ path: string;
11
+ semantics: "current" | "historical";
12
+ }[];
13
+ exclusions: readonly {
14
+ path: string;
15
+ literal: string;
16
+ asOf: string;
17
+ evidence: string;
18
+ }[];
19
+ };
@@ -0,0 +1,2 @@
1
+ var t=1;export{t as FACT_SURFACE_MANIFEST_VERSION};
2
+ //# sourceMappingURL=fact-guard.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/fact-guard.ts"],
4
+ "sourcesContent": ["/** Registration seam for the later manifest guard; historical exclusions require evidence. */\nexport const FACT_SURFACE_MANIFEST_VERSION = 1 as const;\nexport type FactSurfaceManifest = {\n facts: readonly { key: string; literals: readonly string[] }[];\n surfaces: readonly { id: string; path: string; semantics: \"current\" | \"historical\" }[];\n exclusions: readonly { path: string; literal: string; asOf: string; evidence: string }[];\n};\n"],
5
+ "mappings": "AACO,IAAMA,EAAgC",
6
+ "names": ["FACT_SURFACE_MANIFEST_VERSION"]
7
+ }
package/dist/facts.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var d=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var S=(e,t)=>{for(var n in t)d(e,n,{get:t[n],enumerable:!0})},w=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of R(t))!A.call(e,a)&&a!==n&&d(e,a,{get:()=>t[a],enumerable:!(r=x(t,a))||r.enumerable});return e};var h=e=>w(d({},"__esModule",{value:!0}),e);var k={};S(k,{FACT_ALIASES:()=>g,FACT_DISPLAY_RULES:()=>I,FACT_EXPIRY_MS:()=>m,FACT_KEY:()=>y,FACT_TYPES:()=>V,assertFactKey:()=>p,businessFactId:()=>D,canonicalFactJson:()=>l,expandFactPlaceholders:()=>P,formatFact:()=>v,hashFactRevision:()=>_,parseFactDisplayRule:()=>b,parseFactValue:()=>c,parseStoredFactValue:()=>O,storeFactValue:()=>j});module.exports=h(k);var V=["integer","decimal","boolean","date","string","enum","reference"],I=["identity/v1","floorHundredsPlus/v1"],y=/^[a-z][a-zA-Z0-9]*(?:\.[a-zA-Z][a-zA-Z0-9]*)*$/,g={pubCount:"coverage.pubCount"},m={computed:72*36e5,operational:30*864e5,technical:90*864e5};function O(e){let t=f(e),n=t.type==="integer"?t.numberValue:t.type==="boolean"?t.booleanValue:t.type==="reference"?{documentId:t.documentId,documentRevision:t.documentRevision}:t.textValue;return c({type:t.type,value:n,allowedValues:t.allowedValues})}function j(e){let t=c(e);return t.type==="integer"?{type:t.type,numberValue:t.value}:t.type==="boolean"?{type:t.type,booleanValue:t.value}:t.type==="reference"?{type:t.type,...t.value}:t.type==="enum"?{type:t.type,textValue:t.value,allowedValues:t.allowedValues}:{type:t.type,textValue:t.value}}function s(){throw new Error("Invalid business fact contract")}function f(e){return!e||typeof e!="object"||Array.isArray(e)?s():e}function o(e){return typeof e=="string"&&e.trim()!==""?e:s()}function p(e){(e.length>48||!y.test(e))&&s()}function D(e){return p(e),"businessFact-"+Array.from(new TextEncoder().encode(e),t=>t.toString(16).padStart(2,"0")).join("")}function c(e){let t=f(e),n=t.value;switch(t.type){case"integer":return Number.isSafeInteger(n)?{type:"integer",value:n}:s();case"decimal":return typeof n=="string"&&/^(?:0|-?[1-9]\d*)(?:\.\d*[1-9])?$|^-0\.\d*[1-9]$/.test(n)?{type:"decimal",value:n}:s();case"boolean":return typeof n=="boolean"?{type:"boolean",value:n}:s();case"string":return typeof n=="string"?{type:"string",value:n}:s();case"date":return typeof n=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(n)&&!Number.isNaN(Date.parse(n))&&new Date(n).toISOString().slice(0,10)===n?{type:"date",value:n}:s();case"enum":{let r=t.allowedValues;return!Array.isArray(r)||!r.length||!r.every(a=>typeof a=="string"&&a!=="")||new Set(r).size!==r.length||!r.includes(n)?s():{type:"enum",value:o(n),allowedValues:[...r].sort()}}case"reference":{let r=f(n);return{type:"reference",value:{documentId:o(r.documentId),documentRevision:o(r.documentRevision)}}}default:return s()}}function b(e){return e!=="identity/v1"&&e!=="floorHundredsPlus/v1"?s():e}function v(e,t){let n=c(e);return b(t)==="floorHundredsPlus/v1"?n.type!=="integer"||n.value<0?s():n.value<100?String(n.value):`${(Math.floor(n.value/100)*100).toLocaleString("en-GB")}+`:n.type==="reference"?n.value.documentId:String(n.value)}function P(e,t,n){return["htmlText","htmlAttribute","json"].includes(n)?e.replace(/\{([^{}]*)\}/g,(r,a)=>{p(a);let u=Object.hasOwn(g,a)?g[a]:a;if(!Object.hasOwn(t,u))throw new Error(`Unknown fact placeholder: ${a}`);let i=t[u];return n==="json"?JSON.stringify(i).slice(1,-1).replace(/</g,"\\u003c").replace(/>/g,"\\u003e").replace(/&/g,"\\u0026").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029"):i.replace(/[&<>"']/g,F=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[F])}):s()}function l(e){return e===null||typeof e=="boolean"||typeof e=="string"||typeof e=="number"&&Number.isFinite(e)?JSON.stringify(e):Array.isArray(e)?`[${Array.from(e,l).join(",")}]`:typeof e!="object"||e===null||Object.getPrototypeOf(e)!==Object.prototype?s():`{${Object.entries(e).sort(([t],[n])=>t<n?-1:t>n?1:0).map(([t,n])=>`${JSON.stringify(t)}:${l(n)}`).join(",")}}`}async function _(e){let t=e.fact;p(t.key);let n=c(t.publicValue);v(n,t.displayRule),(!Number.isSafeInteger(e.revision)||e.revision<1||e.baseRevision!==null&&(!Number.isSafeInteger(e.baseRevision)||e.baseRevision<1||e.baseRevision>=e.revision))&&s(),o(e.projectId),o(t.accountableOwner),o(t.source.definition),o(t.source.version),(!["computed","observed","attested"].includes(t.source.kind)||!Object.hasOwn(m,t.freshness)||typeof t.optional!="boolean"||t.unit!==null&&typeof t.unit!="string")&&s(),t.timezone!==null&&new Intl.DateTimeFormat("en-GB",{timeZone:o(t.timezone)});let r=i=>((!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(i)||!Number.isFinite(Date.parse(i))||new Date(i).toISOString()!==i.replace(/(?<=:\d{2})Z$/,".000Z"))&&s(),Date.parse(i));(r(e.expiresAt)<=r(e.effectiveAt)||r(e.evidence.expiresAt)<=r(e.evidence.observedAt)||!/^[0-9a-f]{64}$/.test(e.evidence.digest)||typeof e.evidence.complete!="boolean")&&s(),o(e.evidence.reference),o(e.evidence.runId);for(let i of t.surfaces)o(i.id),i.semantics==="historical"?c({type:"date",value:i.asOf}):(i.semantics!=="current"||i.asOf!==null)&&s();let a={projectId:e.projectId,revision:e.revision,baseRevision:e.baseRevision,fact:{key:t.key,publicValue:n,unit:t.unit,timezone:t.timezone,displayRule:t.displayRule,source:{kind:t.source.kind,definition:t.source.definition,version:t.source.version},accountableOwner:t.accountableOwner,freshness:t.freshness,optional:t.optional,surfaces:t.surfaces.map(i=>({id:i.id,semantics:i.semantics,asOf:i.asOf}))},evidence:{reference:e.evidence.reference,digest:e.evidence.digest,complete:e.evidence.complete,runId:e.evidence.runId,observedAt:new Date(r(e.evidence.observedAt)).toISOString(),expiresAt:new Date(r(e.evidence.expiresAt)).toISOString()},effectiveAt:new Date(r(e.effectiveAt)).toISOString(),expiresAt:new Date(r(e.expiresAt)).toISOString()},u=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(l(a)));return Array.from(new Uint8Array(u),i=>i.toString(16).padStart(2,"0")).join("")}0&&(module.exports={FACT_ALIASES,FACT_DISPLAY_RULES,FACT_EXPIRY_MS,FACT_KEY,FACT_TYPES,assertFactKey,businessFactId,canonicalFactJson,expandFactPlaceholders,formatFact,hashFactRevision,parseFactDisplayRule,parseFactValue,parseStoredFactValue,storeFactValue});
2
+ //# sourceMappingURL=facts.cjs.map