@zixcel/projection-contracts 0.10.3 → 0.10.4

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/src/producer.mjs CHANGED
@@ -1,180 +1,297 @@
1
- // Hatter 2026: temporal presentation reads only explicit paths in exact visible items.
2
- import {canonical,copy,digest,fail,frozen,limits,list,refs,request,roles,shape,sourceKey,sourceRef,text,unique} from './contract.mjs'
3
- import {validateInputDeclaration} from '@zixcel/interaction/input'
4
- function item(v,source){
5
- shape(v,['id','semanticRef','group','value','evidence','provenance','resolutionRefs','visibility'])
6
- text(v.id);if(v.semanticRef!==null)text(v.semanticRef)
7
- shape(v.group,['kind','ref']);if(!['semantic','structural','presentation'].includes(v.group.kind))fail('InvalidProjection');text(v.group.ref)
8
- if(v.group.kind==='semantic'&&v.group.ref!==v.semanticRef)fail('InvalidProjection')
9
- if(!['visible','redacted','omitted'].includes(v.visibility))fail('InvalidProjection')
10
- refs(v.evidence);refs(v.provenance);refs(v.resolutionRefs)
11
- if(v.visibility==='omitted')return null
12
- if(v.visibility==='redacted')return {id:v.id,semanticRef:null,group:{kind:'presentation',ref:'redacted'},value:null,evidence:[],provenance:[],resolutionRefs:[],visibility:'redacted',sourceRefs:[source]}
13
- return {...copy(v),sourceRefs:[source]}
1
+ // Generated from canonical TypeScript; do not edit.
2
+
3
+ // implementation/produce.mts
4
+ import { canonical as canonical2, fail as fail2, list, request, shape as shape2, sourceKey, sourceRef, unique } from "./contract.mjs";
5
+
6
+ // implementation/source-items.mts
7
+ import { choice, copy, fail, json, refs, shape, text } from "./contract.mjs";
8
+ function item(v, source) {
9
+ shape(v, ["id", "semanticRef", "group", "value", "evidence", "provenance", "resolutionRefs", "visibility"]);
10
+ const id = text(v.id), semanticRef = v.semanticRef === null ? null : text(v.semanticRef);
11
+ shape(v.group, ["kind", "ref"]);
12
+ const group = { kind: choice(v.group.kind, ["semantic", "structural", "presentation"]), ref: text(v.group.ref) };
13
+ if (group.kind === "semantic" && group.ref !== semanticRef) fail("InvalidProjection");
14
+ const visibility = choice(v.visibility, ["visible", "redacted", "omitted"]);
15
+ const evidence = refs(v.evidence), provenance = refs(v.provenance), resolutionRefs = refs(v.resolutionRefs);
16
+ if (visibility === "omitted") return null;
17
+ if (visibility === "redacted") return { id, semanticRef: null, group: { kind: "presentation", ref: "redacted" }, value: null, evidence: [], provenance: [], resolutionRefs: [], visibility: "redacted", sourceRefs: [source] };
18
+ return { ...copy({ id, semanticRef, group, value: json(v.value), evidence, provenance, resolutionRefs, visibility }), sourceRefs: [source] };
14
19
  }
15
- function unresolved(v,source){
16
- shape(v,['id','reason','evidence','contextRefs','actionRefs']);text(v.id);text(v.reason);refs(v.evidence);refs(v.contextRefs);refs(v.actionRefs)
17
- return {...copy(v),sourceRefs:[source]}
20
+ function unresolved(v, source) {
21
+ shape(v, ["id", "reason", "evidence", "contextRefs", "actionRefs"]);
22
+ return { ...copy({ id: text(v.id), reason: text(v.reason), evidence: refs(v.evidence), contextRefs: refs(v.contextRefs), actionRefs: refs(v.actionRefs) }), sourceRefs: [source] };
18
23
  }
19
- function seal(kind,key,lineage,data,maximum){
20
- const body={contract:'projection/0.10.0',kind,key,lineage,data}
21
- const revision='pp:'+digest(body),snapshot={...body,revision}
22
- canonical(snapshot,maximum);return frozen(snapshot)
24
+ function relation(v, source) {
25
+ shape(v, ["id", "from", "to", "relationRef"]);
26
+ return { ...copy({ id: text(v.id), from: text(v.from), to: text(v.to), relationRef: text(v.relationRef) }), sourceRefs: [source] };
23
27
  }
24
- export function produce(input,exactSources){
25
- const r=request(input),l=r.limits
26
- canonical(exactSources);list(exactSources,l.sources)
27
- if(exactSources.length!==r.sources.length)fail('SourceUnavailable')
28
- const sources=new Map()
29
- for(const s of exactSources){
30
- shape(s,['source','items','relations','unresolved','truncated']);sourceRef(s.source)
31
- if(typeof s.truncated!=='boolean')fail('InvalidProjection')
32
- const key=sourceKey(s.source);if(sources.has(key))fail('InvalidSourceRevision');sources.set(key,s)
28
+
29
+ // implementation/seal.mts
30
+ import { canonical, digest, frozen } from "./contract.mjs";
31
+ function seal(kind, key, lineage, data, maximum) {
32
+ const body = { contract: "projection/0.10.0", kind, key, lineage, data };
33
+ const snapshot = { ...body, revision: "pp:" + digest(body) };
34
+ canonical(snapshot, maximum);
35
+ return frozen(snapshot);
36
+ }
37
+
38
+ // implementation/produce.mts
39
+ function produce(input, exactSources) {
40
+ const r = request(input), l = r.limits;
41
+ canonical2(exactSources);
42
+ const values = list(exactSources, l.sources);
43
+ if (values.length !== r.sources.length) fail2("SourceUnavailable");
44
+ const sources = /* @__PURE__ */ new Map();
45
+ for (const value of values) {
46
+ shape2(value, ["source", "items", "relations", "unresolved", "truncated"]);
47
+ sourceRef(value.source);
48
+ if (typeof value.truncated !== "boolean") fail2("InvalidProjection");
49
+ const key = sourceKey(value.source);
50
+ if (sources.has(key)) fail2("InvalidSourceRevision");
51
+ sources.set(key, value);
33
52
  }
34
- const items=[],relations=[],unresolvedItems=[];let truncated=false,omitted=0
35
- for(const ref of r.sources){
36
- const s=sources.get(sourceKey(ref));if(!s)fail('InvalidSourceRevision')
37
- for(const v of list(s.items,l.items)){const next=item(v,ref);if(next)items.push(next);else omitted++}
38
- for(const v of list(s.unresolved,l.unresolved))unresolvedItems.push(unresolved(v,ref))
39
- for(const v of list(s.relations,l.relations)){
40
- shape(v,['id','from','to','relationRef']);Object.values(v).forEach(x=>text(x));relations.push({...copy(v),sourceRefs:[ref]})
53
+ const items = [], relations = [], unresolvedItems = [];
54
+ let truncated = false, omitted = 0;
55
+ for (const ref of r.sources) {
56
+ const s = sources.get(sourceKey(ref));
57
+ if (!s) fail2("InvalidSourceRevision");
58
+ for (const v of list(s.items, l.items)) {
59
+ const next = item(v, ref);
60
+ if (next) items.push(next);
61
+ else omitted++;
41
62
  }
42
- truncated ||= s.truncated
63
+ for (const v of list(s.unresolved, l.unresolved)) unresolvedItems.push(unresolved(v, ref));
64
+ for (const v of list(s.relations, l.relations)) relations.push(relation(v, ref));
65
+ truncated ||= s.truncated === true;
43
66
  }
44
- list(items,l.items);list(relations,l.relations);list(unresolvedItems,l.unresolved)
45
- unique([...items,...unresolvedItems],v=>v.id);unique(relations,v=>v.id)
46
- const ids=new Set(items.filter(v=>v.visibility==='visible').map(v=>v.id))
47
- // Owners must remove relationships to omitted/redacted data in their visibility view.
48
- for(const v of relations)if(!ids.has(v.from)||!ids.has(v.to))fail('InvalidProjection')
49
- const count=items.reduce((n,v)=>n+v.provenance.length,0)+unresolvedItems.reduce((n,v)=>n+v.evidence.length,0)
50
- if(count>l.provenance)fail('ProjectionLimitExceeded')
51
- for(const values of [items,relations,unresolvedItems])values.sort((a,b)=>a.id<b.id?-1:1)
52
- return seal('Data',r.key,{sources:r.sources,producer:r.producer,request:r},
53
- {items,relations,unresolved:unresolvedItems,truncated,omittedByPolicy:omitted},l.snapshotBytes)
67
+ list(items, l.items);
68
+ list(relations, l.relations);
69
+ list(unresolvedItems, l.unresolved);
70
+ unique([...items, ...unresolvedItems], (v) => v.id);
71
+ unique(relations, (v) => v.id);
72
+ const ids = new Set(items.filter((v) => v.visibility === "visible").map((v) => v.id));
73
+ for (const v of relations) if (!ids.has(v.from) || !ids.has(v.to)) fail2("InvalidProjection");
74
+ if (items.reduce((n, v) => n + v.provenance.length, 0) + unresolvedItems.reduce((n, v) => n + v.evidence.length, 0) > l.provenance) fail2("ProjectionLimitExceeded");
75
+ for (const values2 of [items, relations, unresolvedItems]) values2.sort((a, b) => a.id < b.id ? -1 : 1);
76
+ return seal(
77
+ "Data",
78
+ r.key,
79
+ { sources: r.sources, producer: r.producer, request: r },
80
+ { items, relations, unresolved: unresolvedItems, truncated, omittedByPolicy: omitted },
81
+ l.snapshotBytes
82
+ );
54
83
  }
55
- export function validateSnapshot(v){
56
- canonical(v,524288);shape(v,['contract','kind','key','lineage','data','revision'])
57
- if(v.contract!=='projection/0.10.0'||!['Data','Scene'].includes(v.kind))fail('InvalidProjection')
58
- const {revision,...body}=v;if(revision!=='pp:'+digest(body))fail('InvalidProjection')
59
- // Wire objects originate from the closed producer contract. Re-run structure
60
- // validation through its exact input contract; content hash alone is not enough.
61
- shape(v.lineage,['sources','producer','request'],v.kind==='Scene'?['dataProjection','sceneConfiguration']:[])
62
- const r=request(v.lineage.request),l=r.limits;text(v.key);canonical(v,l.snapshotBytes)
63
- if(canonical(v.lineage.sources)!==canonical(v.lineage.request.sources)||canonical(v.lineage.producer)!==canonical(v.lineage.request.producer))fail('InvalidProjection')
64
- const d=v.data
65
- shape(d,['items','relations','unresolved','truncated','omittedByPolicy'],v.kind==='Scene'?['focus','purpose','regions','actions','temporal','presentation']:[])
66
- if(typeof d.truncated!=='boolean'||!Number.isSafeInteger(d.omittedByPolicy)||d.omittedByPolicy<0||d.omittedByPolicy>l.sources*l.items)fail('InvalidProjection')
67
- const known=new Set(r.sources.map(sourceKey))
68
- const checkSource=x=>{list(x.sourceRefs,1);if(x.sourceRefs.length!==1||!known.has(sourceKey(x.sourceRefs[0])))fail('InvalidSourceRevision')}
69
- for(const x of list(d.items,l.items)){
70
- checkSource(x);const {sourceRefs,...body}=x
71
- if(canonical(item(body,sourceRefs[0]))!==canonical(x))fail('InvalidProjection')
72
- }
73
- for(const x of list(d.unresolved,l.unresolved)){
74
- checkSource(x);const {sourceRefs,...body}=x;unresolved(body,sourceRefs[0])
84
+
85
+ // implementation/scene.mts
86
+ import { canonical as canonical4, copy as copy4, fail as fail6, limits as limits2, list as list5, refs as refs3, roles, shape as shape6, text as text5, unique as unique5 } from "./contract.mjs";
87
+
88
+ // implementation/snapshot.mts
89
+ import { canonical as canonical3, digest as digest2, fail as fail3, list as list2, record as record2, request as request2, shape as shape3, sourceKey as sourceKey2, sourceRef as sourceRef2, text as text2, unique as unique2 } from "./contract.mjs";
90
+ function validateSnapshot(v) {
91
+ canonical3(v, 524288);
92
+ shape3(v, ["contract", "kind", "key", "lineage", "data", "revision"]);
93
+ if (v.contract !== "projection/0.10.0" || v.kind !== "Data" && v.kind !== "Scene") fail3("InvalidProjection");
94
+ const { revision, ...body } = v;
95
+ if (revision !== "pp:" + digest2(body)) fail3("InvalidProjection");
96
+ shape3(v.lineage, ["sources", "producer", "request"], v.kind === "Scene" ? ["dataProjection", "sceneConfiguration"] : []);
97
+ const r = request2(v.lineage.request), l = r.limits;
98
+ text2(v.key);
99
+ canonical3(v, l.snapshotBytes);
100
+ const declared = record2(v.lineage.request);
101
+ if (canonical3(v.lineage.sources) !== canonical3(declared.sources) || canonical3(v.lineage.producer) !== canonical3(declared.producer)) fail3("InvalidProjection");
102
+ const d = v.data;
103
+ shape3(d, ["items", "relations", "unresolved", "truncated", "omittedByPolicy"], v.kind === "Scene" ? ["focus", "purpose", "regions", "actions", "temporal", "presentation"] : []);
104
+ if (typeof d.truncated !== "boolean" || typeof d.omittedByPolicy !== "number" || !Number.isSafeInteger(d.omittedByPolicy) || d.omittedByPolicy < 0 || d.omittedByPolicy > l.sources * l.items) fail3("InvalidProjection");
105
+ const known = new Set(r.sources.map(sourceKey2));
106
+ const checkSource = (x) => {
107
+ const refs4 = list2(x.sourceRefs, 1);
108
+ if (refs4.length !== 1 || !known.has(sourceKey2(refs4[0]))) fail3("InvalidSourceRevision");
109
+ return sourceRef2(refs4[0]);
110
+ };
111
+ const items = list2(d.items, l.items).map((value) => {
112
+ const x = record2(value), source = checkSource(x), { sourceRefs, ...body2 } = x;
113
+ const parsed = item(body2, source);
114
+ if (!parsed || canonical3(parsed) !== canonical3(x)) fail3("InvalidProjection");
115
+ return parsed;
116
+ });
117
+ const unresolvedItems = list2(d.unresolved, l.unresolved).map((value) => {
118
+ const x = record2(value), source = checkSource(x), { sourceRefs, ...body2 } = x;
119
+ return unresolved(body2, source);
120
+ });
121
+ unique2([...items, ...unresolvedItems], (x) => x.id);
122
+ const relations = unique2(list2(d.relations, l.relations).map((value) => {
123
+ const x = record2(value), source = checkSource(x), { sourceRefs, ...body2 } = x;
124
+ return relation(body2, source);
125
+ }), (x) => x.id);
126
+ const ids = new Set(items.filter((x) => x.visibility === "visible").map((x) => x.id));
127
+ for (const x of relations) if (!ids.has(x.from) || !ids.has(x.to)) fail3("InvalidProjection");
128
+ if (items.reduce((n, x) => n + x.provenance.length, 0) + unresolvedItems.reduce((n, x) => n + x.evidence.length, 0) > l.provenance) fail3("ProjectionLimitExceeded");
129
+ const data = { items, relations, unresolved: unresolvedItems, truncated: d.truncated, omittedByPolicy: d.omittedByPolicy };
130
+ if (v.kind === "Data") {
131
+ if (v.key !== r.key) fail3("InvalidProjection");
132
+ } else {
133
+ shape3(v.lineage.dataProjection, ["key", "revision"]);
134
+ const base = seal("Data", r.key, { sources: r.sources, producer: r.producer, request: r }, data, l.snapshotBytes);
135
+ if (base.key !== v.lineage.dataProjection.key || base.revision !== v.lineage.dataProjection.revision) fail3("InvalidProjection");
136
+ const rebuilt = buildScene(base, v.lineage.sceneConfiguration);
137
+ if (canonical3(rebuilt) !== canonical3(v)) fail3("InvalidProjection");
75
138
  }
76
- unique([...d.items,...d.unresolved],x=>x.id);unique(list(d.relations,l.relations),x=>x.id)
77
- const ids=new Set(d.items.filter(x=>x.visibility==='visible').map(x=>x.id))
78
- for(const x of d.relations){shape(x,['id','from','to','relationRef','sourceRefs']);checkSource(x)
79
- for(const key of ['id','from','to','relationRef'])text(x[key]);if(!ids.has(x.from)||!ids.has(x.to))fail('InvalidProjection')}
80
- if(d.items.reduce((n,x)=>n+x.provenance.length,0)+d.unresolved.reduce((n,x)=>n+x.evidence.length,0)>l.provenance)fail('ProjectionLimitExceeded')
81
- if(v.kind==='Data'){if(v.key!==r.key)fail('InvalidProjection')}
82
- else{
83
- shape(v.lineage.dataProjection,['key','revision'])
84
- const base=seal('Data',r.key,{sources:r.sources,producer:r.producer,request:r},
85
- {items:d.items,relations:d.relations,unresolved:d.unresolved,truncated:d.truncated,omittedByPolicy:d.omittedByPolicy},l.snapshotBytes)
86
- if(base.key!==v.lineage.dataProjection.key||base.revision!==v.lineage.dataProjection.revision)fail('InvalidProjection')
87
- const rebuilt=scene(base,v.lineage.sceneConfiguration)
88
- if(canonical(rebuilt)!==canonical(v))fail('InvalidProjection')
89
- }
90
- return v
139
+ return v;
91
140
  }
92
- export function scene(data,configuration){
93
- validateSnapshot(data);if(data.kind!=='Data')fail('InvalidProjection')
94
- canonical(configuration);shape(configuration,['key','focus','purpose','regions','actions'],['temporal','presentation'])
95
- text(configuration.key);text(configuration.focus);text(configuration.purpose)
96
- const l=limits(data.lineage.request.limits),ids=new Set([...data.data.items,...data.data.unresolved].map(x=>x.id))
97
- const regions=unique(list(configuration.regions,l.regions).map(v=>{
98
- shape(v,['id','role','itemIds']);text(v.id);if(!roles.includes(v.role))fail('InvalidProjection')
99
- unique(refs(v.itemIds,l.items));if(v.itemIds.some(id=>!ids.has(id)))fail('InvalidProjection');return copy(v)
100
- }),v=>v.id)
101
- const actions=unique(list(configuration.actions,l.actions).map(v=>{
102
- shape(v,['id','targetOwner','commandRef','contextRefs','sourceRefs','label'],['interaction'])
103
- text(v.id);text(v.targetOwner);text(v.commandRef);text(v.label,1024);refs(v.contextRefs)
104
- const expected=new Set(data.lineage.sources.map(sourceKey));list(v.sourceRefs,l.sources).forEach(s=>{if(!expected.has(sourceKey(s)))fail('InvalidSourceRevision')})
105
- if(!v.sourceRefs.length)fail('InvalidSourceRevision')
106
- if(v.interaction!==undefined){
107
- const i=v.interaction
108
- shape(i,['ref','generation','inputContractRef','input'])
109
- text(i.ref);text(i.generation);text(i.inputContractRef)
110
- if(validateInputDeclaration(i.input).length)fail('InvalidProjection')
111
- if(i.input.action.contract_revision!==i.inputContractRef||i.input.action.operation_id!==v.commandRef)fail('InvalidProjection')
141
+
142
+ // implementation/scene-actions.mts
143
+ import { validateInputDeclaration } from "@zixcel/interaction/input";
144
+ import { copy as copy2, fail as fail4, limits, list as list3, refs as refs2, shape as shape4, sourceKey as sourceKey3, sourceRef as sourceRef3, text as text3, unique as unique3 } from "./contract.mjs";
145
+ function actions(value, maximum, data) {
146
+ return unique3(list3(value, maximum).map((v) => {
147
+ shape4(v, ["id", "targetOwner", "commandRef", "contextRefs", "sourceRefs", "label"], ["interaction"]);
148
+ const id = text3(v.id), targetOwner = text3(v.targetOwner), commandRef = text3(v.commandRef), label = text3(v.label, 1024), contextRefs = refs2(v.contextRefs);
149
+ const expected = new Set(data.lineage.sources.map(sourceKey3));
150
+ const sourceRefs = list3(v.sourceRefs, limits(data.lineage.request.limits).sources).map((s) => {
151
+ if (!expected.has(sourceKey3(s))) fail4("InvalidSourceRevision");
152
+ return sourceRef3(s);
153
+ });
154
+ if (!sourceRefs.length) fail4("InvalidSourceRevision");
155
+ let interaction;
156
+ if (v.interaction !== void 0) {
157
+ const i = v.interaction;
158
+ shape4(i, ["ref", "generation", "inputContractRef", "input"]);
159
+ const ref = text3(i.ref), generation = text3(i.generation), inputContractRef = text3(i.inputContractRef);
160
+ if (validateInputDeclaration(i.input).length) fail4("InvalidProjection");
161
+ const input = i.input;
162
+ if (input.action.contract_revision !== inputContractRef || input.action.operation_id !== commandRef) fail4("InvalidProjection");
163
+ interaction = { ref, generation, inputContractRef, input: copy2(input) };
112
164
  }
113
- return copy(v)
114
- }),v=>v.id)
115
- const lineage={...copy(data.lineage),dataProjection:{key:data.key,revision:data.revision},sceneConfiguration:copy(configuration)}
116
- const visibleValue=(itemId,valuePath)=>{
117
- text(itemId);list(valuePath,16).forEach(key=>text(key,256))
118
- const item=data.data.items.find(item=>item.id===itemId&&item.visibility==='visible')
119
- if(!item)fail('InvalidProjection')
120
- let value=item.value
121
- for(const key of valuePath){if(value===null||typeof value!=='object'||!Object.hasOwn(value,key))fail('InvalidProjection');value=value[key]}
122
- return value
123
- }
124
- let presentation
125
- if(configuration.presentation!==undefined)presentation=unique(list(configuration.presentation,l.items).map(binding=>{
126
- shape(binding,['itemId'],['titlePath','title','summaryPath','fields','symbol']);visibleValue(binding.itemId,[])
127
- if(Object.hasOwn(binding,'title')===Object.hasOwn(binding,'titlePath'))fail('InvalidProjection')
128
- const title=Object.hasOwn(binding,'titlePath')?visibleValue(binding.itemId,binding.titlePath):binding.title;text(title,1024)
129
- // Presentation labels never become semantics or permission. Field values are exact visible source paths.
130
- const fields=binding.fields===undefined?undefined:list(binding.fields,16).map(field=>{
131
- shape(field,['label','valuePath']);text(field.label,256)
132
- const value=visibleValue(binding.itemId,field.valuePath)
133
- if(value!==null&&!['string','boolean','number'].includes(typeof value))fail('InvalidProjection')
134
- if(typeof value==='string'&&value.length>4096)fail('ProjectionLimitExceeded')
135
- return {label:field.label,value}
136
- })
137
- if(binding.symbol!==undefined)text(binding.symbol,64)
138
- const summary=binding.summaryPath===undefined?undefined:visibleValue(binding.itemId,binding.summaryPath)
139
- if(summary!==undefined)text(summary,2048)
140
- return {itemId:binding.itemId,title,...(summary===undefined?{}:{summary}),...(fields===undefined?{}:{fields}),...(binding.symbol===undefined?{}:{symbol:binding.symbol})}
141
- }),item=>item.itemId)
142
- let temporal
143
- if(configuration.temporal!==undefined){
144
- const declaration=configuration.temporal;shape(declaration,['label','items']);text(declaration.label,256)
145
- const items=unique(list(declaration.items,l.items).map(binding=>{
146
- shape(binding,['itemId','valuePath','format']);text(binding.itemId);list(binding.valuePath,16).forEach(key=>text(key,256))
147
- if(!['utcInstant','unixMilliseconds'].includes(binding.format))fail('InvalidProjection')
148
- let at=visibleValue(binding.itemId,binding.valuePath)
149
- if(binding.format==='unixMilliseconds'){
150
- if(!Number.isSafeInteger(at)||at<0||at>253402300799999)fail('InvalidProjection')
151
- at=new Date(at).toISOString()
152
- }
153
- // Declared encodings only: no field-name heuristic, coercion or inferred date.
154
- if(typeof at!=='string'||!/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(at)||!Number.isFinite(Date.parse(at))||new Date(at).toISOString()!==at)fail('InvalidProjection')
155
- return {itemId:binding.itemId,at}
156
- }),item=>item.itemId).sort((a,b)=>a.at===b.at?(a.itemId<b.itemId?-1:1):(a.at<b.at?-1:1))
157
- temporal={label:declaration.label,items}
158
- }
159
- return seal('Scene',configuration.key,lineage,{...copy(data.data),focus:configuration.focus,purpose:configuration.purpose,regions,actions,...(temporal?{temporal}:{}),...(presentation?{presentation}:{})},l.snapshotBytes)
165
+ return copy2({ id, targetOwner, commandRef, label, contextRefs, sourceRefs, ...interaction === void 0 ? {} : { interaction } });
166
+ }), (v) => v.id);
167
+ }
168
+
169
+ // implementation/scene-bindings.mts
170
+ import { fail as fail5, list as list4, shape as shape5, text as text4, unique as unique4 } from "./contract.mjs";
171
+ function visibleReader(data) {
172
+ return (itemId, valuePath) => {
173
+ text4(itemId);
174
+ const path = list4(valuePath, 16).map((key) => text4(key, 256));
175
+ const item2 = data.data.items.find((item3) => item3.id === itemId && item3.visibility === "visible");
176
+ if (!item2) fail5("InvalidProjection");
177
+ let value = item2.value;
178
+ for (const key of path) {
179
+ if (value === null || typeof value !== "object" || !Object.hasOwn(value, key)) fail5("InvalidProjection");
180
+ const d = Object.getOwnPropertyDescriptor(value, key);
181
+ if (!d || !("value" in d)) fail5("InvalidProjection");
182
+ value = d.value;
183
+ }
184
+ return value;
185
+ };
160
186
  }
161
- export function rebuild(input,readExact){
162
- const r=request(input)
163
- const sources=r.sources.map(ref=>{
164
- let value;try{value=readExact(ref)}catch{fail('ProjectionRebuildUnavailable')}
165
- if(value?.then){Promise.resolve(value).catch(()=>{});fail('ProjectionRebuildUnavailable')}
166
- if(value==null)fail('ProjectionRebuildUnavailable');return value
167
- })
168
- return produce(r,sources)
187
+ function presentation(value, maximum, visibleValue) {
188
+ if (value === void 0) return void 0;
189
+ return unique4(list4(value, maximum).map((binding) => {
190
+ shape5(binding, ["itemId"], ["titlePath", "title", "summaryPath", "fields", "symbol"]);
191
+ visibleValue(binding.itemId, []);
192
+ if (Object.hasOwn(binding, "title") === Object.hasOwn(binding, "titlePath")) fail5("InvalidProjection");
193
+ const title = text4(Object.hasOwn(binding, "titlePath") ? visibleValue(binding.itemId, binding.titlePath) : binding.title, 1024);
194
+ const fields = binding.fields === void 0 ? void 0 : list4(binding.fields, 16).map((field) => {
195
+ shape5(field, ["label", "valuePath"]);
196
+ const label = text4(field.label, 256);
197
+ const value2 = visibleValue(binding.itemId, field.valuePath);
198
+ if (value2 !== null && typeof value2 !== "string" && typeof value2 !== "boolean" && typeof value2 !== "number") fail5("InvalidProjection");
199
+ if (typeof value2 === "string" && value2.length > 4096) fail5("ProjectionLimitExceeded");
200
+ return { label, value: value2 };
201
+ });
202
+ const symbol = binding.symbol === void 0 ? void 0 : text4(binding.symbol, 64);
203
+ const summary = binding.summaryPath === void 0 ? void 0 : text4(visibleValue(binding.itemId, binding.summaryPath), 2048);
204
+ return { itemId: text4(binding.itemId), title, ...summary === void 0 ? {} : { summary }, ...fields === void 0 ? {} : { fields }, ...symbol === void 0 ? {} : { symbol } };
205
+ }), (item2) => item2.itemId);
206
+ }
207
+ function temporal(value, maximum, visibleValue) {
208
+ if (value === void 0) return void 0;
209
+ shape5(value, ["label", "items"]);
210
+ const label = text4(value.label, 256);
211
+ const items = unique4(list4(value.items, maximum).map((binding) => {
212
+ shape5(binding, ["itemId", "valuePath", "format"]);
213
+ text4(binding.itemId);
214
+ list4(binding.valuePath, 16).forEach((key) => text4(key, 256));
215
+ if (binding.format !== "utcInstant" && binding.format !== "unixMilliseconds") fail5("InvalidProjection");
216
+ let at = visibleValue(binding.itemId, binding.valuePath);
217
+ if (binding.format === "unixMilliseconds") {
218
+ if (typeof at !== "number" || !Number.isSafeInteger(at) || at < 0 || at > 253402300799999) fail5("InvalidProjection");
219
+ at = new Date(at).toISOString();
220
+ }
221
+ if (typeof at !== "string" || !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(at) || !Number.isFinite(Date.parse(at)) || new Date(at).toISOString() !== at) fail5("InvalidProjection");
222
+ return { itemId: text4(binding.itemId), at };
223
+ }), (item2) => item2.itemId).sort((a, b) => a.at === b.at ? a.itemId < b.itemId ? -1 : 1 : a.at < b.at ? -1 : 1);
224
+ return { label, items };
225
+ }
226
+
227
+ // implementation/scene.mts
228
+ function scene(data, configuration) {
229
+ return buildScene(data, configuration);
230
+ }
231
+ function buildScene(value, configuration) {
232
+ const data = validateSnapshot(value);
233
+ if (data.kind !== "Data") fail6("InvalidProjection");
234
+ canonical4(configuration);
235
+ shape6(configuration, ["key", "focus", "purpose", "regions", "actions"], ["temporal", "presentation"]);
236
+ const key = text5(configuration.key), focus = text5(configuration.focus), purpose = text5(configuration.purpose);
237
+ const l = limits2(data.lineage.request.limits), ids = new Set([...data.data.items, ...data.data.unresolved].map((x) => x.id));
238
+ const regions = unique5(list5(configuration.regions, l.regions).map((v) => {
239
+ shape6(v, ["id", "role", "itemIds"]);
240
+ const id = text5(v.id), role = text5(v.role);
241
+ if (!roles.includes(role)) fail6("InvalidProjection");
242
+ const itemIds = unique5(refs3(v.itemIds, l.items));
243
+ if (itemIds.some((id2) => !ids.has(id2))) fail6("InvalidProjection");
244
+ return { id, role, itemIds };
245
+ }), (v) => v.id);
246
+ const actions2 = actions(configuration.actions, l.actions, data), visibleValue = visibleReader(data);
247
+ const presentation2 = presentation(configuration.presentation, l.items, visibleValue), temporal2 = temporal(configuration.temporal, l.items, visibleValue);
248
+ const lineage = { ...copy4(data.lineage), dataProjection: { key: data.key, revision: data.revision }, sceneConfiguration: copy4(configuration) };
249
+ return seal("Scene", key, lineage, { ...copy4(data.data), focus, purpose, regions, actions: actions2, ...temporal2 ? { temporal: temporal2 } : {}, ...presentation2 ? { presentation: presentation2 } : {} }, l.snapshotBytes);
250
+ }
251
+
252
+ // implementation/recovery.mts
253
+ import { canonical as canonical5, fail as fail7, frozen as frozen2, copy as copy5, request as request3, shape as shape7, text as text6 } from "./contract.mjs";
254
+ function rebuild(input, readExact) {
255
+ const r = request3(input);
256
+ const sources = r.sources.map((ref) => {
257
+ let value;
258
+ try {
259
+ value = readExact(ref);
260
+ } catch {
261
+ fail7("ProjectionRebuildUnavailable");
262
+ }
263
+ if (value && typeof value === "object" && "then" in value) {
264
+ try {
265
+ Promise.prototype.then.call(value, void 0, () => {
266
+ });
267
+ } catch {
268
+ }
269
+ fail7("ProjectionRebuildUnavailable");
270
+ }
271
+ if (value == null) fail7("ProjectionRebuildUnavailable");
272
+ return value;
273
+ });
274
+ return produce(r, sources);
169
275
  }
170
- export function recovery(snapshot,receiverRevision){
171
- validateSnapshot(snapshot)
172
- if(receiverRevision!==null)text(receiverRevision)
173
- if(receiverRevision===snapshot.revision)return {kind:'NoChange',revision:snapshot.revision}
174
- return {kind:'Snapshot',revision:snapshot.revision,payload:Buffer.from(canonical(snapshot,524288))}
276
+ function recovery(snapshot, receiverRevision) {
277
+ validateSnapshot(snapshot);
278
+ if (receiverRevision !== null) text6(receiverRevision);
279
+ if (receiverRevision === snapshot.revision) return { kind: "NoChange", revision: snapshot.revision };
280
+ return { kind: "Snapshot", revision: snapshot.revision, payload: Buffer.from(canonical5(snapshot, 524288)) };
175
281
  }
176
- export function adoptSnapshot(snapshot,expected){
177
- shape(expected,['key','revision']);text(expected.key);text(expected.revision);validateSnapshot(snapshot)
178
- if(snapshot.key!==expected.key||snapshot.revision!==expected.revision)fail('InvalidSourceRevision')
179
- return frozen(copy(snapshot))
282
+ function adoptSnapshot(snapshot, expected) {
283
+ shape7(expected, ["key", "revision"]);
284
+ text6(expected.key);
285
+ text6(expected.revision);
286
+ validateSnapshot(snapshot);
287
+ if (snapshot.key !== expected.key || snapshot.revision !== expected.revision) fail7("InvalidSourceRevision");
288
+ return frozen2(copy5(snapshot));
180
289
  }
290
+ export {
291
+ adoptSnapshot,
292
+ produce,
293
+ rebuild,
294
+ recovery,
295
+ scene,
296
+ validateSnapshot
297
+ };
@@ -0,0 +1,15 @@
1
+ import type { Snapshot, PublicationTicket, PublicationReceipt, PendingRepair } from './types/publication.mjs';
2
+ import type { ProjectionRequest, ReadExact } from './types/input.mjs';
3
+ export declare class ProjectionSlot {
4
+ #private;
5
+ constructor(key: string);
6
+ begin(): Readonly<{
7
+ key: string;
8
+ expected: `${string}-${string}-${string}-${string}-${string}`;
9
+ }>;
10
+ publish(ticket: PublicationTicket, snapshot: Snapshot): PublicationReceipt;
11
+ read(): Readonly<Snapshot> | null;
12
+ dropCache(): void;
13
+ }
14
+ export declare function pendingRepair(ticket: PublicationTicket, input: ProjectionRequest, code: PendingRepair['failure']): Readonly<PendingRepair>;
15
+ export declare function repair(slot: ProjectionSlot, pending: PendingRepair, readExact: ReadExact): Readonly<PublicationReceipt>;
@@ -1,36 +1,62 @@
1
- import {randomUUID} from 'node:crypto'
2
- import {copy,fail,frozen,request,shape,text} from './contract.mjs'
3
- import {rebuild,validateSnapshot} from './producer.mjs'
4
- // Executable in-memory publication contract, not a durable scheduler or Graph CAS.
5
- // Head fencing survives disposable cache loss within this slot. Restart requires
6
- // a fresh exact owner rebuild; no durable publication guarantee is claimed here.
7
- export class ProjectionSlot {
8
- #key;#fence=randomUUID();#snapshot=null;#receipt=null
9
- constructor(key){this.#key=text(key)}
10
- begin(){return frozen({key:this.#key,expected:this.#fence})}
11
- publish(ticket,snapshot){
12
- shape(ticket,['key','expected']);validateSnapshot(snapshot)
13
- if(ticket.key!==this.#key||snapshot.key!==this.#key)fail('InvalidProjection')
14
- if(this.#receipt?.expected===ticket.expected&&this.#receipt.revision===snapshot.revision){
15
- if(!this.#snapshot)this.#snapshot=frozen(copy(snapshot))
16
- return this.#receipt
1
+ // Generated from canonical TypeScript; do not edit.
2
+
3
+ // implementation/publication.mts
4
+ import { randomUUID } from "node:crypto";
5
+ import { copy, fail, frozen, request, shape, text } from "./contract.mjs";
6
+ import { rebuild, validateSnapshot } from "./producer.mjs";
7
+ var ProjectionSlot = class {
8
+ #key;
9
+ #fence = randomUUID();
10
+ #snapshot = null;
11
+ #receipt = null;
12
+ constructor(key) {
13
+ this.#key = text(key);
14
+ }
15
+ begin() {
16
+ return frozen({ key: this.#key, expected: this.#fence });
17
+ }
18
+ publish(ticket, snapshot) {
19
+ shape(ticket, ["key", "expected"]);
20
+ validateSnapshot(snapshot);
21
+ if (ticket.key !== this.#key || snapshot.key !== this.#key) fail("InvalidProjection");
22
+ if (this.#receipt?.expected === ticket.expected && this.#receipt.revision === snapshot.revision) {
23
+ if (!this.#snapshot) this.#snapshot = frozen(copy(snapshot));
24
+ return this.#receipt;
17
25
  }
18
- if(ticket.expected!==this.#fence)fail('StaleProjectionPublication')
19
- this.#snapshot=frozen(copy(snapshot));this.#fence=randomUUID()
20
- this.#receipt=frozen({key:this.#key,expected:ticket.expected,publication:this.#fence,revision:snapshot.revision})
21
- return this.#receipt
26
+ if (ticket.expected !== this.#fence) fail("StaleProjectionPublication");
27
+ this.#snapshot = frozen(copy(snapshot));
28
+ this.#fence = randomUUID();
29
+ this.#receipt = frozen({ key: this.#key, expected: ticket.expected, publication: this.#fence, revision: snapshot.revision });
30
+ return this.#receipt;
22
31
  }
23
- read(){if(!this.#snapshot)return null;try{return frozen(copy(validateSnapshot(this.#snapshot)))}catch{fail('ProjectionUnavailable')}}
24
- dropCache(){this.#snapshot=null}
25
- }
26
- export function pendingRepair(ticket,input,code){
27
- shape(ticket,['key','expected']);text(ticket.key);text(ticket.expected)
28
- if(!['ProjectionUnavailable','ProjectionLimitExceeded'].includes(code))fail('InvalidProjection')
29
- const r=request(input);if(r.key!==ticket.key)fail('InvalidProjection')
30
- return frozen({ticket:copy(ticket),request:r,failure:code})
32
+ read() {
33
+ if (!this.#snapshot) return null;
34
+ try {
35
+ return frozen(copy(validateSnapshot(this.#snapshot)));
36
+ } catch {
37
+ fail("ProjectionUnavailable");
38
+ }
39
+ }
40
+ dropCache() {
41
+ this.#snapshot = null;
42
+ }
43
+ };
44
+ function pendingRepair(ticket, input, code) {
45
+ shape(ticket, ["key", "expected"]);
46
+ text(ticket.key);
47
+ text(ticket.expected);
48
+ if (!["ProjectionUnavailable", "ProjectionLimitExceeded"].includes(code)) fail("InvalidProjection");
49
+ const r = request(input);
50
+ if (r.key !== ticket.key) fail("InvalidProjection");
51
+ return frozen({ ticket: copy(ticket), request: r, failure: code });
31
52
  }
32
- export function repair(slot,pending,readExact){
33
- shape(pending,['ticket','request','failure'])
34
- const p=pendingRepair(pending.ticket,pending.request,pending.failure)
35
- return slot.publish(p.ticket,rebuild(p.request,readExact))
53
+ function repair(slot, pending, readExact) {
54
+ shape(pending, ["ticket", "request", "failure"]);
55
+ const p = pendingRepair(pending.ticket, pending.request, pending.failure);
56
+ return slot.publish(p.ticket, rebuild(p.request, readExact));
36
57
  }
58
+ export {
59
+ ProjectionSlot,
60
+ pendingRepair,
61
+ repair
62
+ };
@@ -0,0 +1,16 @@
1
+ import type { ProjectionRequest, ReadExact } from './types/input.mjs';
2
+ import type { DataProjection } from './types/snapshot.mjs';
3
+ import type { Snapshot } from './types/publication.mjs';
4
+ export declare function rebuild(input: ProjectionRequest, readExact: ReadExact): DataProjection;
5
+ export declare function recovery(snapshot: Snapshot, receiverRevision: string | null): {
6
+ kind: 'NoChange';
7
+ revision: string;
8
+ } | {
9
+ kind: 'Snapshot';
10
+ revision: string;
11
+ payload: Uint8Array;
12
+ };
13
+ export declare function adoptSnapshot(snapshot: Snapshot, expected: {
14
+ key: string;
15
+ revision: string;
16
+ }): Readonly<Snapshot>;
@@ -0,0 +1,2 @@
1
+ import type { Action, DataProjection } from './types/snapshot.mjs';
2
+ export declare function actions(value: unknown, maximum: number, data: DataProjection): Action[];
@@ -0,0 +1,6 @@
1
+ import type { DataProjection, Json, SceneProjection } from './types/snapshot.mjs';
2
+ type VisibleReader = (itemId: unknown, valuePath: unknown) => Json;
3
+ export declare function visibleReader(data: DataProjection): VisibleReader;
4
+ export declare function presentation(value: unknown, maximum: number, visibleValue: VisibleReader): NonNullable<SceneProjection['data']['presentation']> | undefined;
5
+ export declare function temporal(value: unknown, maximum: number, visibleValue: VisibleReader): SceneProjection['data']['temporal'];
6
+ export {};