Saxonberg Server API
    Preparing search index...

    Hierarchy

    • AccessRegistryBase
      • default
    Index

    Constructors

    Properties

    stuffId: string

    Runtime ID for this object (generated using nanoid). This is NOT the MongoDB _id - it's a runtime identifier.

    _mixinName: string = 'PostRegistrationMixin'
    subscribableFields: SubscribableFieldDescriptor[] = ...

    Universal live-query subscribable fields — fields every Stuff exposes regardless of mixin composition. Currently just displayName, a derived render that delegates to Stuff.getPresentation (Named's name or Visible's shortDescription, falling through to the baked-in 'something').

    Declared here rather than in a substrate-private synthetic table because every Stuff genuinely owns the concept — there is no "what if this Stuff has no displayable identity?" case. The descriptor uses dependsOnFields to declare the leaf source fields it depends on (name, shortDescription); the substrate installs precise (FieldChangedEvent, 'field', dep) index entries automatically. Shadow lifecycle support rides on ShadowChangedEvent in changes (declared-but-unfired until the shadow subsystem wires it).

    Mixin layers above Stuff add their own subscribableFields for mixin-owned state; the substrate's prototype-chain walk hasOwnProperty-checks at every level and unions the descriptors.

    Future universal renders (pronoun, articleName, etc.) land here too. Mixin-gated renders go on the mixin that owns the gate.

    Methods

    • Resource-targeted slice walk. Returns true iff subject is in any of the groups owning the resource's zone-tree slice.

      Walk: from resource.getZone() upward via ZoneApi.getEnclosingZone, collecting the closest stamped ownerGroup AND every accessGroups entry along the way. If the walk finds no owners, fall back to the universal 'core' group.

      Action is a free string — this build does not filter ownership by action. Role differentiation lives in canMutateZone().

      Parameters

      • subject: Stuff | null
      • _action: string
      • resource: Stuff | null

      Returns Promise<boolean>

    • Consent seam for the residency (self-eviction) sweep. The sweep asks each idle object whether it may be culled; the object decides, reading its own knowledge. Default is cull ({ ok: true }) — a fresh backing class is reclaimable by default and only becomes sticky when its author deliberately vetoes, the correct bias for a leak-plugger. Return { ok: false, reason } to veto.

      Vetoes layer on the mixin/class that owns the relevant relationship, composed via super.canEvict(context) — base Stuff stays permissive and does not reach into Container/Shadow/Avatar/ Exit knowledge. The relational vetoes derive from the R2.x ref-cleanup rules: an object in an owned/symmetric live-ref relationship vetoes while its anchor is alive (see docs/subsystems/residency.md).

      Distinct from canDestruct: an object that permits eviction can still canDestruct-veto, so the sweep's enforce path tolerates a DestructError (logs + continues). The sweep calls this on the raw target (via RAW_TARGET) so asking never counts as a touch.

      Parameters

      Returns VetoResult

      Invoked by the residency sweep (ResidencyLogic) on idle candidates. Veto seam{ ok: false, reason } keeps the object resident. Override on the owning mixin/class and chain super.canEvict(context) so composed layers run. Public and ungateable (a subclass's super.canEvict() is author code).

    • Role-gated check used when the target IS a Zone Template (transfer ownership, mutate accessGroups, destruct the slice). Requires 'owner' role in the zone's primary (closest) ownerGroup. 'admin' / 'member' roles and members of secondary accessGroups are not authorized for zone-mutation ops in this build.

      Parameters

      Returns Promise<boolean>

    • Destroy this object.

      Locked down by @CallSecurity(ApiOnly) — only callers under mud/api/ (in practice, StuffApi.destruct) may invoke it. @Unshadowable because the unregistration path must always run; a shadow that intercepts and skips it would leak the object into the registry forever. @Final because subclass overrides would defeat the same invariant — the loader hook throws FinalViolationError at import time on any subclass redefinition.

      Subclass cleanup belongs on the optional onDestruct() witness (consulted by StuffApi.destruct while the target is still live); refusal logic belongs on canDestruct(). This terminal destroy() is the unshadowable mark-and-unregister step only.

      Returns void

    • Read the recency timestamp. Read by the residency sweep — which calls it on the raw target (via RAW_TARGET) so the sweep's own introspection never counts as a touch.

      Returns number

    • Self-presentation — the casual-register render string for this object, the answer to "what does this Stuff call itself?" Three- step resolution:

      1. Named.name if present and non-empty — the object's proper name ("Alice", "Excalibur", "Town Square").
      2. Visible.shortDescription if present and non-empty — the object's visual identity ("a heavy oak door").
      3. The baked-in fallback (DEFAULT_PRESENTATION).

      For a Globbable stack (quantity !== 1) the count folds in as an affix — "30 coins" — pluralized via GrammarApi.pluralize (which honors host-side getPluralForm() overrides for irregulars). Named takes precedence over Visible so a Named-with-description renders by its proper name; code that needs the formal register calls getFullName() when typed as Named.

      Viewer-blind by design. This is the shared baseline every Stuff exposes; the viewer-aware naming step (recognition / identification — see docs/subsystems/belief.md) composes on top of it. Left shadowable (NOT @Final) so masking / disguise effects can override the rendered identity via a method shadow.

      Returns string

    • Build the composable Mml fragment for this object's display name — the Mml sibling of getPresentation. Mml.ref (and so every <item> / <name> / … identity tag) renders this, not a raw string, so a name joins the compose chain as a fragment like everything else. The label is the already-resolved, viewer-aware name (recognition runs in the render layer and hands it in).

      Return null for the plain default — Mml.ref then wraps the label in Mml.text, which escapes it exactly once, so player-authored names / status decoration are safe by construction and the fragment is never re-escaped downstream. Override to build a richer fragment (a TPA terminal wraps its name in <color> to tint by state). The plain-string getPresentation stays the surface for non-prose consumers (logs, context.note, MQL scalars).

      Parameters

      • _label: string

      Returns Mml | null

    • Read seam. Instance method, but unwraps via ProxyApi.unwrap before reaching the # slot — this inside an instance method called through the proxy is the proxy, and the # slot lives on the raw target.

      Returns string | null

    • Orthogonal archwizard axis — is the actor in 'archwizards'? Archwizards confer/revoke wizard status (the wizard grant/revoke verb, authorized by the requiresArchwizard validator). Operator/ root-managed for now (env seed + the group verb); the Prime Minister office above them is deferred.

      Parameters

      Returns Promise<boolean>

    • Broad "is the actor a member of any group with content scope?" used by MQL pre-gates that can't be resource-targeted. True for any Avatar whose playerId is in 'core' or any Group that's stamped as a Zone's ownerGroup / accessGroups anywhere in the tree.

      Parameters

      Returns Promise<boolean>

    • Check if this object has been destroyed.

      @Unshadowable: the destroyed-state read is a framework invariant — any shadow that lied about it would let consumers touch a torn-down Stuff. @Final: subclasses overriding this would defeat the same invariant; the loader hook throws FinalViolationError at import time on any subclass that redefines it.

      Returns boolean

    • Orthogonal streamer axis — is the actor in 'streamers'? Gates the livestream control plane (the stream verb and, later, the scene / lower-third / afk mutators). Distinct from the wizard axis: a streamer drives the broadcast overlay without necessarily holding TypeScript-escape capability.

      Parameters

      Returns Promise<boolean>

    • Orthogonal wizard axis — is the actor in 'wizards'? This is the code-trust capability: it determines who can write TypeScript source, run eval, reload modules, AND set the executable code-naming fields (class / hydratorClass / behaviors[].brain) on a content template (see the code-field gate in TemplateLogic). Doesn't matter what slices they own; the question is whether they have escape capability. A non-wizard author is a "protowizard" — content-write access without code trust.

      Parameters

      Returns Promise<boolean>

    • Terminal onDestruct no-op. Exists so subclasses and mixins overriding onDestruct can call super.onDestruct() without the cast-to-optional-callable dance — the chain is guaranteed to bottom out here. StuffApi.destruct invokes the hook via the optional-method dispatcher in api/stuff.ts; that path still works (always finds a function on the prototype).

      Override (not extend with super) at any layer that wants cleanup; chain to super.onDestruct() from the override so intermediate layers in a mixin chain run too.

      Returns void

      Invoked by StuffApi.destruct (and forceDestruct) while the target is still live, after canDestruct passes and before shadow-detach + destroy(). Witness — the return value is ignored (it cannot veto; canDestruct is the veto seam). Override to release resources/listeners and chain super.onDestruct() so mixin layers run.

    • Walk a source-tree path against the template tree most-specific-first, returning the closest extant FolderZone instance. Used by workspace controllers in source/mirror mode to compute the resource zone before calling can().

      lib/lounge/foo.ts → tries /lib/lounge/foo (no match) → walks up to /lib/lounge (match, extant FolderZone) → returns it. lib/security/SecurityPolicies.ts → walks up → no FolderZone match → returns null (caller falls through to 'core').

      Parameters

      • sourcePath: string

      Returns Promise<Stuff | null>

    • Stamp this Stuff's templatePath and re-key the byTemplatePath index so future findByTemplatePath lookups see the new path. No-op when path matches the current value.

      Locked down by @CallSecurity(ApiOnly) because flipping a Stuff's identity post-clone would break FromTemplate policies and any caller-side caching of template-path identity. @Final @Unshadowable because the index update has to run for every successful set — a subclass override that forgot the index call (or a shadow that intercepted) would silently desync byTemplatePath.

      Unwraps via ProxyApi.unwrap so the #-slot access lands on the raw target (see comment on #templatePath above).

      Parameters

      • path: string

      Returns void

    • Narrow-entry mutation: add or remove playerId from the 'wizards' group. Reachable only through AccessApi.setWizardMembership, which carries the FromController(WizardController) policy — the archwizard authorization itself is enforced by the verb's requiresArchwizard validator, not here. Fires managed().fireChange so the lazy wizard cache invalidates. Returns true iff membership changed.

      Parameters

      • playerId: string
      • makeWizard: boolean

      Returns Promise<boolean>

    • Set the spatial zone. Gated by FromSpatialZone — only the SpatialZone class and its subclasses (CartesianZone, SphericalZone) may call this through the proxy. The addLocation / removeLocation chokepoints on the zone side are the legitimate callers; everyone else is rejected.

      Clone-time seeding from StuffApi.#cloneInner doesn't go through this method — it uses the caller-allowlisted _stampZone seam below.

      @Final @Unshadowable because the index of substrate invariants that consult getZone() (containment's cross-zone gate, Mobile.traverse, MQL scope walks) trusts the slot's value; a subclass override or shadow that lied about it could break those invariants. No legitimate subclass needs to extend this anyway — the only legitimate write paths are the SpatialZone chokepoints and clone-time.

      Parameters

      Returns void

    • Get a string representation of this idea (for debugging). Subclasses should override to provide more specific information.

      Returns string

    • Refresh the recency timestamp to now. Timestamp-fixed (no caller-supplied value). Called on the raw target by the security gate on every successful dispatch (Phase 2) and by the residency presence walk.

      Returns void