StaticancestorStaticrestoreRe-hydrate a live Stuff host's in-memory state from its current
Template doc. Operates on the existing instance; preserves
identity / stuffId / wired Interactives. Phase 1 setters
overwrite field values; Phase 2 appliers re-fire (e.g.
applyContainer moves the host via compare-and-move).
v1 coordination: developer/admin operation; does NOT synchronize against multiplexed observers.
Throws on missing templatePath, missing Template doc, or hydration failure.
StaticsaveUpsert a Template at path. Looks up an existing Template at the
same path (so the underlying upsert reuses its _id), populates
the four fields, and saves through Document.save(). The
folder/leaf invariant fires through DomainHook against the PM
chokepoint — direct template.save() is equivalent.
Records one append-only AuthoringEvent for path after the save
commits — the authorship ledger the producer stock reads. The author is
derived from the dispatched execution context, not a parameter (so
it can't be spoofed); an unattributable context (programmatic / system
save) records nothing. This is the single chokepoint both the in-world
authoring verbs and the REST CMS funnel through, so it is the one
centralized writer of provenance. See ProvenanceApi.
OptionalhydratorClassPath: stringThe saved Template's MongoDB _id.
StaticsnapshotSnapshot a live Stuff host's persistentFields chain back to its
backing Template doc's data block. Walks the composed mixin
chain via MixinApi.getAllPersistentFields(stuff.constructor);
marshals values per MixinApi.getAllFieldMarshallers; derives
data.container from the live container ref when the host is
Containable; merges over the existing tpl.data (preserves
non-mixin-managed keys).
Pure capture-state: does NOT call tpl.save(). Returns the
mutated Template; the caller decides when to commit. Separating
capture from commit lets callers inspect, batch, or short-
circuit before persisting. Default usage:
const tpl = await TemplateApi.snapshotToTemplate(host);
await tpl.save();
Keyed on stuff.getTemplatePath() — the runtime stamp every
Stuff carries post-clone — NOT on any class-specific helper.
The method is class-shape-agnostic.
Synchronous-prefix-before-first-await ordering. The
persistentFields walk and the container ref read run
synchronously, BEFORE Template.findByPath yields. This is
load-bearing for onDestruct-driven fire-and-forget saves:
they capture pre-cleanup field values even though the MongoDB
write itself is async.
Concurrent calls produce equivalent full-state snapshots — no
in-process coordination. MongoDB's replaceOne resolves
ordering as last-write-wins.
Throws when the host has no templatePath stamp, when no Template exists at the resolved path, or when a marshalled field references an unregistered marshaller.
StaticvalidateValidate a candidate delete against the folder/leaf invariant: a Zone template cannot be deleted while descendants still reference it as a folder.
Used by DomainHook.aroundDelete. Looks up the doc by _id to
discover its path and class — the delete primitive only carries an id.
StaticvalidateValidate a candidate domain-template doc against the folder/leaf
invariant. Used by DomainHook.aroundSave.
Rejects:
/.path or class).P; child templates already exist beneath it."A is a leaf
template, not a zone folder."Zone classification uses the runtime class field via
ZoneApi.isFolderClass — a Zone subclass extends Zone,
regardless of whether anyone registered it in a central
allow-list. hydratorClass is orthogonal to zonehood.
StaticvalidateReject saving a domain-collection Template under an engine-
reserved template-path prefix (see ReservedTemplatePrefixes in
lib/paths.ts). /obj/api/ is owned by the surface-architecture
logic singletons (StuffApi.singletonSync); a Template authored
there would be mis-returned by the singleton lookup as the
wrong-class logic instance, so the namespace must stay DB-free.
Used by DomainHook.aroundSave alongside validateFolderLeafSave
and validateSingletonContainerTarget.
StaticvalidateValidate a candidate domain-template doc's data.container
against the singleton-target constraint:
data.container is absent or non-string.ContainableMixin (a non-Containable declaring container
is a config bug; Phase 2 would fail loudly at hydrate time,
but template-save is the earlier surface).SingletonMixin.Used by DomainHook.aroundSave alongside
validateFolderLeafSave. Per declarative-content-slate
§ container: on Template — singleton-target constraint.
Generate ancestor paths, nearest first:
/a/b/c→['/a/b', '/a']. Root/excluded. Re-exported fromTemplate.ancestorPathsfor symmetry with the validators that use it.