# @ferret/accounts: API

The player's account in the game's own process: sign-in, session, balances, a gateway for `net`.

8 exports. Generated from the source (`packages/accounts/src`), so it matches the code.

## Classes

### AccountService

*class* · `packages/accounts/src/account.ts:32`

```ts
class AccountService implements Service
```

The player's account in the game's own process: what a local helper app (SquirrelCraft's arbiter) used to do for the original.
Sign-in (`user:verify`), keeping and checking the session, signing out, the rewards balances. A guest is a player nobody is
signed in as; the game plays on, and a later sign-in upgrades it. The Camerlengo calls all go through `@ferret/net`'s client.
Events: `account:login` { user }, `account:logout`, `account:guest`, `account:expired`, `account:balance` { currency, balance }.

- `readonly name: "account"`
- `constructor(readonly opts: AccountOptions)`
- `init(world: World)`
- `dispose()`
- `get signedIn(): boolean`
- `session(): string | null` — the session token for calls that need one (voice); null for a guest
- `user(): AccountUser | null`
- `async signIn(user: string, password: string): Promise<void>`
- `signOut()`
- `async valid(session = this.tok): Promise<boolean>` — Is a session still good? (`user:getSessionUser`.) A backend that cannot be reached is "not known to be bad": true.
- `async autoLoginOrGuest(): Promise<boolean>` — At the start: take the session that was given or stored if it is still good, else play as a guest. Resolves with whether the player is signed in. Never throws: a backend that is down leaves a stored session in place (checked again later) or a guest.
- `async check(): Promise<void>` — One session check now; an expired session is renewed with the kept password, else the player is a guest again.
- `async rewards(query: string, params: Record<string, unknown> = {}): Promise<Record<string, any>>` — One rewards query for the signed-in player: `plugin:call` with the scoped key and the session.
- `async balance(currency = 'PIA'): Promise<number>`
- `async balances(): Promise<Record<string, number>>` — every currency the account holds, as plain numbers
- `async adjust(delta: number, reason: string, currency = 'PIA'): Promise<number>` — earn (positive) or spend (negative); resolves with the new balance
- `gateway(currency = 'PIA'): AccountGateway` — The `@ferret/net` account gateway over this service: a guest has no name and 0 balance; spending needs a sign-in.

### HelperStubs

*class* · `packages/accounts/src/helper-stubs.ts:11`

```ts
class HelperStubs implements Service
```

The two calls the original's local helper app (SquirrelCraft's arbiter) accepted and only wrote to its log, because the thing behind
them was never built: the shared "AI teacher" bot of a voice room, and a player coming near to or leaving an artifact. They are kept
as calls with the same names and arguments, so a game that makes them does not change when the real thing exists; for now each
is logged (`log`) and announced as an event, which a game or a backend adapter can listen to:
  `teacher:start` / `teacher:stop` { room, identity }     identity is "npc:<Name>"; one bot per room serves everybody in it
  `artifact:near` / `artifact:far` { artifactId }

- `readonly name: "helper-stubs"`
- `readonly log: string[]` — what was asked, in order (`<event> <json>`), for tests and for looking at what a game does
- `constructor(private opts: { sink?: (line: string) => void } = {})`
- `init(world: World)`
- `teacherAgent(action: 'start' | 'stop', room: string, identity: string)` — Ask for the shared teacher bot of a voice room to start or stop (not a voice join: that is for a player's own presence).
- `artifactNear(artifactId: string)`
- `artifactFar(artifactId: string)`

## Functions

### signInCard

*function* · `packages/accounts/src/sign-in.ts:32`

```ts
function signInCard(account: AccountService, opts: { document?: Document; strings?: Partial<SignInStrings> } = {}): Promise<boolean>
```

A card over the game that asks for the account (the helper app's login dialog, in the page). Resolves when the player has signed
in (true) or chose to play as a guest or closed the card (false); the level keeps running underneath either way.

## Interfaces

### AccountOptions

*interface* · `packages/accounts/src/account.ts:7`

```ts
interface AccountOptions
```

- `client: CamerlengoClient` — the backend client; its `appKey` is the key for `user:verify` / `user:getSessionUser`
- `path?: string` — the user namespace of the sign-in (default "/users")
- `rewardsKey?: string` — a key scoped to `plugin:call` on the rewards plugin only; without it there are no balances
- `rewardsPlugin?: string` — the rewards plugin (default "GameRewards")
- `checkMinutes?: number` — minutes between session checks while signed in (default 30); an expired session is renewed with the password kept in memory
- `store?: KeyValueStore`
- `storeKey?: string`
- `session?: string` — a session obtained elsewhere (a launcher, a link); checked like a stored one

### AccountUser

*interface* · `packages/accounts/src/account.ts:24`

```ts
interface AccountUser
```

- `id: string`
- `name: string`

### KeyValueStore

*interface* · `packages/accounts/src/account.ts:5`

```ts
interface KeyValueStore
```

Where the session is kept between page loads (a `Storage`: localStorage; tests pass a Map-backed stand-in).

- `getItem(k: string): string | null`
- `setItem(k: string, v: string): void`
- `removeItem(k: string): void`

### SignInStrings

*interface* · `packages/accounts/src/sign-in.ts:4`

```ts
interface SignInStrings
```

Text of the sign-in card; a game can translate it.

- `title: string`
- `email: string`
- `password: string`
- `signIn: string`
- `guest: string`
- `close: string`
- `busy: string`
- `wrong: string`
- `down: string`

## Constants

### defaultStrings

*const* · `packages/accounts/src/sign-in.ts:5`

```ts
const defaultStrings: SignInStrings
```

