Allow durable imports and deep copies in certified loading scopes
This commit is contained in:
@@ -10,7 +10,7 @@ const counts=new WeakMap<Document,ReadonlyMap<Id,number>>();
|
||||
function membership(document:Document){let result=counts.get(document);if(!result){const next=new Map<Id,number>();for(const element of document.elements.values())next.set(element.ownerCanvasId,(next.get(element.ownerCanvasId)??0)+1);result=next;counts.set(document,result);}return result;}
|
||||
export function sourceClosed(state:LoadingState,source:Capture){return source.document.elements.size===state.totalElements&&source.document.canvases.size===state.declaredCanvasIds.length;}
|
||||
export function ownerReady(state:LoadingState,source:Capture,document:Document,id:Id){return document.canvases.has(id)&&(!source.versions.has(id)||state.version!==1&&(membership(source.document).get(id)??0)===state.canvasElementCounts[id]);}
|
||||
function born(state:LoadingState,id:Id){return state.version===4&&!Object.hasOwn(state.elementOwners,id);}
|
||||
function born(state:LoadingState,id:Id){return (state.version===4||state.version===5)&&!Object.hasOwn(state.elementOwners,id);}
|
||||
function safeData(data:ElementRecord['data'],registry:Registry,component:Id,document:Document,source?:Document,prior?:ElementRecord['data']){
|
||||
const definition=registry.components.get(component);if(!definition?.copy)return false;
|
||||
for(const key of ['ai','taskId','runId'])if(data[key]!==undefined&&data[key]!==null&&!equal(data[key],prior?.[key]))return false;
|
||||
@@ -21,7 +21,7 @@ function safeData(data:ElementRecord['data'],registry:Registry,component:Id,docu
|
||||
}
|
||||
function references(document:Document,registry:Registry){for(const element of document.elements.values())if(registry.resolve(element)==='known'){const schema=registry.components.get(element.componentId)?.copy;for(const reference of schema?.references??[])for(const id of copyReferenceIds(element.data,reference))if(!(reference.target==='element'?document.elements:document.canvases).has(id))throw fault('loading_reference_incomplete',[element.id,id]);}}
|
||||
export function structuralCommand(command:Command,document:Document,registry:Registry,state:LoadingState,source:Capture):Availability|undefined {
|
||||
if(state.version!==4)return;
|
||||
if(state.version<4)return;
|
||||
const deny:Availability={enabled:false,code:'model_loading',targets:[]},yes:Availability={enabled:true};
|
||||
if(command.type==='element.create'){const element=command.element;return born(state,element.id)&&!source.document.tombstones.has(element.id)&&ownerReady(state,source,document,element.ownerCanvasId)&®istry.resolve(element)==='known'&&safeData(element.data,registry,element.componentId,document,source.document)?yes:deny;}
|
||||
if(command.type==='canvas.create'){const canvas=command.canvas,parent=canvas.parent;return !source.versions.has(canvas.id)&&!!parent&&born(state,parent.entryElementId)&&ownerReady(state,source,document,parent.canvasId)?yes:deny;}
|
||||
@@ -32,7 +32,7 @@ export function structuralCommand(command:Command,document:Document,registry:Reg
|
||||
}
|
||||
/** Actual changes, not a command name, establish the mutation's required closure. */
|
||||
export function assertStructuralChanges(changes:readonly Change[],document:Document,registry:Registry,state:LoadingState,source:Capture):Document {
|
||||
if(state.version!==4)throw fault('model_loading');
|
||||
if(state.version<4)throw fault('model_loading');
|
||||
let cursor=document;const closed=sourceClosed(state,source);
|
||||
for(const change of changes){
|
||||
if(change.kind==='canvas'){
|
||||
|
||||
Reference in New Issue
Block a user