On this page
The synchronized runtime ships 14 entity modules with 30 public ESM bindings. This page explains each module's capability and host assumptions. The exact constructor/function/value contracts are canonical in the Arcane shared entity inventory, with later SDK additions documented below and in the current runtime entity inventory.
Entity creation and serialization are usually cross-host. Methods that touch DOM, DBOPFS, local storage, AI, or object URLs require the corresponding browser or native-WebView dependency.
Apps import entities with arcane-os/entities/<file>.js; the SDK-managed
import map resolves these names through the selected runtime routes. Default
root applications use their installed npm package directly. Absolute
/arcane/entities/... examples below assume an explicitly configured physical
or virtual /arcane route. Use the corresponding package specifier in direct
npm applications; entity inputs and behavior are the same.
Canonical inventory
| Module | Exports | Capability | Availability / normalization |
|---|---|---|---|
ApiModelRecord.js |
default |
Frozen HTTP(S) model response snapshot. | Cross-host; normalized. |
Calculation.js |
default |
Frozen bounded expression and finite result. | Cross-host; normalized. |
Chat.js |
default |
Conversation messages, tool exchanges, memories, and optional persistence. | Browser/native WebView; AI/DBOPFS behavior mixed. |
CommunicationMessage.js |
default, communicationChannels |
Frozen provider-neutral message. | Cross-host; normalized. |
CommunicationThread.js |
default |
Frozen provider-neutral thread containing normalized messages. | Cross-host; normalized. |
Document.js |
default |
File entity specialization for the documents table. |
Browser/native WebView; DBOPFS behavior mixed. |
File.js |
default |
MIME-aware file open/save and DBOPFS persistence. | Browser/native WebView; mixed storage/rendering errors. |
Image.js |
default |
Image validation, upload, persistence, data URL, Blob URL, and revocation. | Browser/native WebView; mixed File/Blob/DBOPFS errors. |
IntentEnvelope.js |
six named exports | Immutable canonical intent record, serialization, rehydration, and privacy-safe audit projection. | Cross-host; strict normalized coded errors. |
Preference.js |
default, preferenceSchema |
Boolean, number, select, and text preference definitions. | Cross-host; normalized. |
TerminalSession.js |
default, terminalShells |
Frozen terminal session identity, shell, and state. | Cross-host; normalized. |
Theme.js |
five exports | Semantic theme tokens, conversion, serialization, and DOM application. | Values cross-host; apply/clear need DOM; normalized/mixed. |
User.js |
default, profileUpdateFromSearchParams |
User preferences/profile state and pure URL-query profile mapping. | Browser/native WebView module; mapping itself has no side effects. |
Weather.js |
four classes | Frozen location, observation, day, and snapshot weather entities. | Cross-host; normalized. |
ApiModelRecord.js
Overview
ApiModelRecord freezes an endpoint, fetch time, metadata, and parsed value so
provider reads can be cached or emitted without leaking mutable response state.
Example
import ApiModelRecord from '/arcane/entities/ApiModelRecord.js';
const record = new ApiModelRecord({
endpoint: 'https://example.invalid/model',
fetchedAt: new Date().toISOString(),
metadata: {},
value: {ready: true}
});
Calculation.js
Overview
Calculation owns a bounded expression, finite result, creation time, and
toJSON() projection. Use CalculatorEngine to produce validated instances.
Example
import Calculation from '/arcane/entities/Calculation.js';
console.log(new Calculation({expression: '2 + 2', result: 4}).toJSON());
Chat.js
Overview
ChatEntity owns message history, saved state, tool exchanges, memory lookup,
and optional app-scoped DBOPFS persistence. It installs no independent native
authority; AI and storage dependencies must be available to the host.
Each new chat receives a timestamp plus independently generated random identifier
in its default .jsonl filename, so chats created during the same clock tick do
not share a storage key. Explicit filenames and existing saved files remain
unchanged; no saved records are renamed or migrated.
messages returns provider-facing recurring context. An unresolved structural
call and its matching results remain raw only through their one active provider
continuation. Once that continuation settles, messages replaces the protocol
with complete ordinary visible call, public result, and assistant content.
transcript returns the narrow human-readable projection owned by the durable
storage boundary. User and assistant records contain role, complete
visible content, and their real timestamp. An assistant record may also carry
its application-owned display name. A visible tool record may
additionally carry its public name and plain result status. A requested-call
record uses the call's required user-facing message; a settled tool result
uses its supplied public message. System prompts,
reasoning, provider-extension fields, memory flags, raw tool calls, call IDs,
argument objects, and raw tool returns never enter new DBOPFS writes.
Messages added with persist:false participate only in their current operation;
they are not retained in messages, transcript, memory extraction, or DBOPFS.
Setting chat.persist=false applies the same rule to new additions: the append
returns false before adding records to retained state or starting a write.
Existing retained messages and saved history remain unchanged. An already
accepted persistence write keeps its operation ownership and may finish.
One complete nonblank assistant record is also a durable conversation entry, so
a model-authored opening can be stored and survive maintenance before the first
ordinary user turn. No synthetic user record is required or written.
aiName defaults to an empty string. addAIMessage(text,{name=chat.aiName,...})
and addTurn({name=chat.aiName,...}) capture that application-owned name on the
new assistant record. A nonblank string is preserved exactly; blank or
nonstring names are omitted. Provider message.name never establishes that
display attribution. The name is transcript-only metadata: messages and
memory extraction omit it, including during a pending tool continuation.
Changing aiName affects later messages only; loading existing records does
not rename or rewrite them.
An assistant record may open an ordered array of structural calls with unique
IDs in transient provider state. Until every pending ID receives exactly one
matching nonblank role:'tool' result in the same active session, another
user/provider turn is rejected. The durable transcript keeps only each call's
user-facing message and any normalized tool name or result status. Existing
stored files are not rewritten on load. Persistence failures roll
back the complete turn rather than leaving provider and stored history
divergent.
Example
import Chat from '/arcane/entities/Chat.js';
const chat = new Chat();
chat.addUserMessage('Hello.');
CommunicationMessage.js
Overview
Normalizes one provider message and exports the supported channel values: email, SMS, MMS, RCS, WhatsApp, and other.
Example
import CommunicationMessage from '/arcane/entities/CommunicationMessage.js';
const message = new CommunicationMessage({
id: 'message-1',
channel: 'email',
body: 'Hello'
});
CommunicationThread.js
Overview
Normalizes one conversation thread and its CommunicationMessage records into
a frozen provider-neutral object.
Example
import CommunicationThread from '/arcane/entities/CommunicationThread.js';
const thread = new CommunicationThread({id: 'thread-1', messages: []});
Document.js
Overview
DocumentEntity specializes FileEntity for the app-scoped documents table.
Its persistence methods require the same DBOPFS lifecycle and ownership proof as
the base file entity.
Example
import DocumentEntity from '/arcane/entities/Document.js';
const document = new DocumentEntity();
console.log(document.tableName);
File.js
Overview
FileEntity loads and saves supported file formats through app-scoped DBOPFS
and uses the shared Markdown renderer where appropriate.
Example
import FileEntity from '/arcane/entities/File.js';
const file = new FileEntity();
console.log(file.fileName);
Image.js
Overview
ImageEntity extends FileEntity with image validation, upload, base64 data
URLs, Blob URLs, and explicit Blob URL revocation.
Example
import ImageEntity from '/arcane/entities/Image.js';
console.log(typeof ImageEntity.prototype.revokeBlobURL);
IntentEnvelope.js
Overview
Creates immutable canonical v1 intent records while keeping trusted provenance separate from hostile payload input. Serialization, rehydration, and the audit projection are bounded and deterministic.
Example
import {
createIntentEnvelope,
serializeIntentEnvelope
} from '/arcane/entities/IntentEnvelope.js';
const intent = createIntentEnvelope(
{originalExpression: 'Summarize the record.', normalizedGoal: 'summarize'},
{source: 'example'}
);
console.log(serializeIntentEnvelope(intent));
Preference.js
Overview
Defines preference types, option normalization, value validation, JSON projection, and schema normalization for shared stores and forms.
Example
import Preference from '/arcane/entities/Preference.js';
const preference = new Preference({
key: 'density',
type: 'select',
defaultValue: 'comfortable',
options: ['comfortable', 'compact']
});
TerminalSession.js
Overview
Normalizes terminal session id, shell, state, updates, and JSON projection. The
entity does not start a process; TerminalClient owns the native bridge call.
Example
import TerminalSession from '/arcane/entities/TerminalSession.js';
console.log(TerminalSession.shell('auto'));
Theme.js
Overview
Owns the shared light/dark semantic token sets, color conversion, JSON
projection, DOM application, and clearing. Token work is cross-host; apply()
and clear() require a document root.
Example
import Theme, {arcaneDarkThemeTokens} from '/arcane/entities/Theme.js';
const theme = new Theme({name: 'example', tokens: arcaneDarkThemeTokens});
console.log(theme.toJSON());
User.js
Overview
Owns persisted user preference/profile fields, explicit-preference updates,
fresh reads, saves, and JSON projection. It installs window.user after its
DBLS/DBOPFS lifecycle and emits user-entity-loaded.
AI_name
Saved AI-name preference alongside AI_personality. It is a string with an
empty-string default and preserves the complete supplied text, including
Unicode, whitespace, and an explicitly empty value. The property setter follows
the same persistence setting as AI_personality; non-string assignments throw
Error('AI_name must be string').
explicit, toJSON(), load(), refresh(), and updateExplicit() include
this field through the existing profile schema. Loading an older record that
omits it leaves a new entity's empty default in memory and does not rewrite the
stored record. Partial updates that omit it retain the current value.
await user.updateExplicit(
{AI_name: 'Captain Moonboots'}
);
The application owns naming choices and any mapping to its AI display name;
this preference changes neither the human username nor chat history. No
automatic migration or naming policy runs when it is loaded or saved.
updateExplicit(update)
Accepts an ordinary partial profile object, a JSON string, or a function
current => partialOrNull. It returns Promise<UserEntityData> with the
resulting explicit profile, retaining the existing field setters and their
validation behavior.
The function is called once after the latest durable profile has been read,
inside the existing serialized update and Web Lock. It may return a promise.
Return only the fields to change, or return null to skip the durable write
and receive the fresh profile unchanged. This no-write meaning applies only
to the callback result; ordinary object/string inputs and direct null retain
their existing behavior. With persist=false, the callback uses current
memory and performs no durable read or write.
const displayedName = user.username;
const profile = await user.updateExplicit(function renameTheCaptain(current) {
if (current.username !== displayedName) return null;
return {username: 'Captain Moonboots'};
});
Callbacks compute a patch without mutating current. Do not call or await
updateExplicit(), withFreshExplicit(), or refresh() on the same instance
inside the callback: those operations depend on the current queue entry
finishing. Fetch outside the callback; compare against current at the write
boundary. Rendering and unrelated background work need not await this update.
A thrown or rejected callback causes no save and rejects with the original
error. A failed save restores the fresh baseline in memory and rejects with
the save error. The persistence setting is restored and later queued updates
remain usable. The existing current_time and last_successful_time setters
keep their immediate in-memory assignment, then save only their timestamp
field through this same fresh partial-update owner. This preserves newer
durable profile fields when TimeGuard records a check. Automatic timestamp
save failures are reported through Arcane logging; callers requiring durable
completion use and await updateExplicit({current_time: value}) or the
corresponding last_successful_time partial update.
profileUpdateFromSearchParams(searchParams)
Named export from arcane-os/entities/User.js. Pass an existing
URLSearchParams; the helper returns a new ordinary profile-update record.
| Query parameter | Profile field |
|---|---|
subscription, otherwise subscription_key |
subscription_key |
TWiN (exact case) |
license_key |
name |
username |
email |
email |
phone |
phone |
Presence selects subscription over the fallback, even when its first value
is empty. Missing or empty selected values are omitted. Repeated parameters
use their first value, following URLSearchParams.get(). Normal URL decoding
occurs once when the caller creates the parameters; the helper preserves the
decoded strings, including spaces, Unicode, literal plus signs, and leading
zeros, without trimming, further decoding, or numeric conversion. Whitespace
is a supplied nonempty value. Unknown keys, including zipcode, are ignored;
no extra name fields are inferred.
The helper does not mutate the parameters, read or change the current URL,
hydrate, render, or save. Importing User.js still has its existing browser
singleton lifecycle. Applications own URL capture/removal, manual-draft
protection, readiness, and their awaited user.updateExplicit(update) call.
Example
import {profileUpdateFromSearchParams} from 'arcane-os/entities/User.js';
const params = new URLSearchParams('name=Captain+Moonboots&phone=00123');
const update = profileUpdateFromSearchParams(params);
// {username: 'Captain Moonboots', phone: '00123'}
Weather.js
Overview
Exports four frozen normalized records: WeatherLocation,
WeatherObservation, WeatherDay, and WeatherSnapshot.
Example
import {WeatherLocation} from '/arcane/entities/Weather.js';
const location = new WeatherLocation({name: 'Houston'});
console.log(location.toJSON());
Availability and protocol details
Entity modules are delivered by browser ESM at /arcane/entities/. They do not
cross Core by being imported. Individual persistence, AI, DOM, or native calls
cross the dependency named by that entity. See
availability and normalization and the
deep protocol guide.