API reference › @evolu/common › local‑first/Evolu › EvoluApp
Defined in: packages/common/src/local-first/Evolu.ts:2277
An app whose AppOwners Evolu creates and keeps on this device. Each tab opens one AppOwner, starting with the one opened most recently. An AppOwner's instance stays open until the app is disposed.
Extends
Methods
[asyncDispose]()
[asyncDispose](): PromiseLike<void>;
Defined in: node_modules/@typescript/old/lib/lib.esnext.disposable.d.ts:38
Inherited from
AsyncDisposable.[asyncDispose]
Properties
add
readonly add: (secret: (
| Uint8Array<ArrayBufferLike> & Brand<"Entropy"> & Brand<"Length16">
| Uint8Array<ArrayBufferLike> & Brand<"Entropy"> & Brand<"Length24">
| Uint8Array<ArrayBufferLike> & Brand<"Entropy"> & Brand<"Length32">
| Uint8Array<ArrayBufferLike> & Brand<"Entropy"> & Brand<"Length20">
| Uint8Array<ArrayBufferLike> & Brand<"Entropy"> & Brand<"Length28">) & Brand<"OwnerSecret">, name?: string & Brand<"Trimmed"> & Brand<"MinLength1"> & Brand<"MaxLength100">) => Promise<Result<string & Brand<"Id"> & Brand<"OwnerId">,
| UnknownError
| EvoluDisposedError>>;
Defined in: packages/common/src/local-first/Evolu.ts:2316
Adds an AppOwner, a new one or one restored from its secret, and opens it once the device database stores it, unless this tab opened or added another meanwhile. Adding a secret that is already there updates its entry. An add made while a removal runs waits for it, so an AppOwner added after its removal opens an empty database on this device. It fails when the write, or the read of the AppOwners after it, fails, when the device database is refused, or when the app is disposed; a failed add can still have taken effect, and adding again is safe.
appOwners
readonly appOwners: ReadonlyStore<readonly AppOwnerEntry[]>;
Defined in: packages/common/src/local-first/Evolu.ts:2285
The AppOwners the app can open on this device, the one opened most recently first, then the oldest.
current
readonly current: ReadonlyStore<
| CurrentAppOwner<S>
| null>;
Defined in: packages/common/src/local-first/Evolu.ts:2296
The AppOwner this tab has open, or null while it has none. It starts with
the one opened most recently, or as EvoluAppConfig.startAppOwnerId
says. A removal of the open AppOwner, in any tab, leaves the tab with none,
as does its disappearing from EvoluApp.appOwners, until the app
opens one. The tab never opens another AppOwner on its own, and a deletion
of the open one's database, with Evolu.deleteDatabase, opens it
again, empty, with a new promise.
device
readonly device: DeviceEvolu<D>;
Defined in: packages/common/src/local-first/Evolu.ts:2388
The device database's instance with the app's own device tables.
open
readonly open: (id: string & Brand<"Id"> & Brand<"OwnerId">) => void;
Defined in: packages/common/src/local-first/Evolu.ts:2304
Opens an AppOwner in this tab and records when, so the next start opens it too. Other tabs keep theirs. An AppOwner that isn't listed, such as one another tab just removed, opens nothing, and one this tab still lists after another tab removed it leaves this tab with none open.
remove
readonly remove: (id: string & Brand<"Id"> & Brand<"OwnerId">) => Promise<Result<void, RemoveAppOwnerError>>;
Defined in: packages/common/src/local-first/Evolu.ts:2385
Deletes an AppOwner's data from this device and removes it from this
device's list, so its changes not yet synced are lost for good, while its
data on relays stays. Adding the AppOwner again syncs that data back. An
AppOwner that isn't listed removes nothing. It works also when the
AppOwner's database doesn't open, such as a corrupt one. The tabs that had
the AppOwner open have none open afterwards. When deleting fails, such as
when another context holds the database's files, the AppOwner stays with
the data its database stored, and the tabs that had it open can be left
with none open. After a DatabaseHeldError, its data may already be gone,
and removing it again finishes the removal. When the app's last tab closes
during the removal, the AppOwner can stay listed without its local data,
which syncs again when it's opened, and removing it again finishes the
removal. It fails with the refusal when the device database is refused. The
app's disposal ends the call with EvoluDisposedError, and the removal
still finishes.
To start over with a new AppOwner, add it first, then remove the old one, so a crash between the two leaves two AppOwners rather than none.
Example
import {
AppName,
assertEqual,
assertOk,
createEvoluApp,
createOwnerSecret,
id,
NonEmptyTrimmedString100,
} from "@evolu/common";
import { createEvoluDeps, createRun } from "@evolu/web";
const Schema = {
todo: { id: id("Todo"), title: NonEmptyTrimmedString100 },
};
const run = createRun(createEvoluDeps());
await using app = await run.orThrow(
createEvoluApp(Schema, {
appName: AppName.orThrow("StartOver"),
auth: { type: "InstantStart" },
createFirstAppOwner: true,
transports: [],
}),
);
const [old] = app.appOwners.get();
// Start over: add the new AppOwner first, which opens it, then remove the
// old one.
const added = await app.add(createOwnerSecret(run.deps));
assertOk(added);
assertOk(await app.remove(old.id));
assertEqual(
app.appOwners.get().map(({ id }) => id),
[added.value],
);
assertEqual(app.current.get()?.appOwner.id, added.value);
rename
readonly rename: (id: string & Brand<"Id"> & Brand<"OwnerId">, name:
| string & Brand<"Trimmed"> & Brand<"MinLength1"> & Brand<"MaxLength100">
| null) => void;
Defined in: packages/common/src/local-first/Evolu.ts:2322
Names an AppOwner on this device, or removes its name with null.