@irtio/runtime 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-3DQHT4CM.js → chunk-FA4IOC2Z.js} +1 -1
- package/dist/{chunk-X5S364FY.js → chunk-GKMD3ICD.js} +888 -31
- package/dist/{contract-BhD88PGb.d.ts → contract-B8QSO0MH.d.ts} +86 -2
- package/dist/index.d.ts +39 -8
- package/dist/index.js +18 -2
- package/dist/room-BfALTh7M.d.ts +431 -0
- package/dist/test/index.d.ts +59 -2
- package/dist/test/index.js +142 -7
- package/dist/worker/index.d.ts +40 -2
- package/dist/worker/index.js +35 -4
- package/package.json +5 -4
- package/dist/room-CBsSCueH.d.ts +0 -246
|
@@ -7,7 +7,7 @@ import { RoomDefinition, Room, LeaveReason } from '@irtio/server';
|
|
|
7
7
|
* the room's state plus a ring of recent events. Always on; recording is O(1) per event.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
type RoomEventKind = 'join' | 'leave' | 'write' | 'write-rejected' | 'correct' | 'call' | 'reply' | 'msg' | 'error';
|
|
10
|
+
type RoomEventKind = 'join' | 'leave' | 'write' | 'write-rejected' | 'correct' | 'call' | 'reply' | 'msg' | 'alarm' | 'error';
|
|
11
11
|
interface RoomEvent {
|
|
12
12
|
readonly tick: number;
|
|
13
13
|
readonly kind: RoomEventKind;
|
|
@@ -24,6 +24,45 @@ interface RoomInspection {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
type LogLevel = 'info' | 'warn' | 'error';
|
|
27
|
+
/**
|
|
28
|
+
* Week 12: host-side async work a room asked for — a save generation (D24) or a player-KV
|
|
29
|
+
* operation (D25). Room handlers are synchronous and there is no way to block one on I/O, so
|
|
30
|
+
* every one of these is started by `RoomHost.hostCall` and *finished* by the host calling
|
|
31
|
+
* `RoomCoreApi.completeHostCall` — the same way an inbound frame arrives. That is what makes
|
|
32
|
+
* "the continuation runs as its own event between ticks" a structural property of the seam
|
|
33
|
+
* rather than a promise the runtime makes and hopes the host keeps.
|
|
34
|
+
*/
|
|
35
|
+
type HostCall = {
|
|
36
|
+
readonly kind: 'save';
|
|
37
|
+
} | {
|
|
38
|
+
readonly kind: 'kvGet';
|
|
39
|
+
readonly playerId: string;
|
|
40
|
+
readonly key: string;
|
|
41
|
+
} | {
|
|
42
|
+
readonly kind: 'kvSet';
|
|
43
|
+
readonly playerId: string;
|
|
44
|
+
readonly key: string;
|
|
45
|
+
readonly value: string;
|
|
46
|
+
} | {
|
|
47
|
+
readonly kind: 'kvDelete';
|
|
48
|
+
readonly playerId: string;
|
|
49
|
+
readonly key: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* What a `HostCall` produced. `value` carries the save id for `save` and the stored string for
|
|
53
|
+
* `kvGet` (absent = the key was never written, which resolves `undefined` rather than rejecting).
|
|
54
|
+
* A failure carries a named `E_*` code so the room can tell a size limit from an outage.
|
|
55
|
+
*/
|
|
56
|
+
type HostCallResult = {
|
|
57
|
+
readonly ok: true;
|
|
58
|
+
readonly value?: string;
|
|
59
|
+
} | {
|
|
60
|
+
readonly ok: false;
|
|
61
|
+
readonly code: string;
|
|
62
|
+
readonly message: string;
|
|
63
|
+
};
|
|
64
|
+
/** How long a `HostCall` may stay outstanding before the runtime rejects it itself. */
|
|
65
|
+
declare const HOST_CALL_TIMEOUT_MS = 10000;
|
|
27
66
|
/** Everything the room needs from the outside world. No timers, sockets, clocks, or console inside. */
|
|
28
67
|
interface RoomHost {
|
|
29
68
|
/** Monotonic ms. Fake in the harness. */
|
|
@@ -41,6 +80,19 @@ interface RoomHost {
|
|
|
41
80
|
log(level: LogLevel, args: unknown[]): void;
|
|
42
81
|
/** N consecutive tick throws; the runtime does not recover itself. */
|
|
43
82
|
crashed(reason: string): void;
|
|
83
|
+
/**
|
|
84
|
+
* Week 12: start host-side async work (D24 save, D25 KV). The host **must** deliver the
|
|
85
|
+
* outcome by calling `RoomCoreApi.completeHostCall(reqId, result)` from its own event loop
|
|
86
|
+
* turn, never synchronously from inside this call — a handler is on the stack.
|
|
87
|
+
*/
|
|
88
|
+
hostCall(reqId: number, call: HostCall): void;
|
|
89
|
+
/**
|
|
90
|
+
* D26: arm the durable alarm `name` for `atMs`, or cancel it when `atMs` is `undefined`.
|
|
91
|
+
* Arming a name that is already armed replaces its due time. Alarm state is the **host's**,
|
|
92
|
+
* not the room's: nothing about it goes into the hibernation blob, and the host fires one by
|
|
93
|
+
* calling `RoomCoreApi.fireAlarm(name)`.
|
|
94
|
+
*/
|
|
95
|
+
setAlarm(name: string, atMs: number | undefined): void;
|
|
44
96
|
}
|
|
45
97
|
interface RoomCoreOptions {
|
|
46
98
|
readonly roomId: string;
|
|
@@ -57,6 +109,13 @@ interface JoinOptions {
|
|
|
57
109
|
readonly name?: string;
|
|
58
110
|
/** A resumed session: presence record kept, `ctx.reconnecting = true`. */
|
|
59
111
|
readonly reconnecting?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* D25: the identity `ctx.playerId` reports and `room.kv` is meant to be keyed by. Defaults to
|
|
114
|
+
* `clientId`, which — because a resume token carries the client id across a reconnect — is
|
|
115
|
+
* exactly the resume-token identity, and no more stable than that token. Week 13 (D27) passes
|
|
116
|
+
* a JWT subject here instead without anything else changing.
|
|
117
|
+
*/
|
|
118
|
+
readonly playerId?: string;
|
|
60
119
|
}
|
|
61
120
|
interface JoinResult {
|
|
62
121
|
readonly tick: number;
|
|
@@ -81,6 +140,13 @@ interface RoomStats {
|
|
|
81
140
|
bytesOutByClient: Map<string, number>;
|
|
82
141
|
handlerErrors: number;
|
|
83
142
|
encodesLastFlush: number;
|
|
143
|
+
aoiEncodesLastFlush: number;
|
|
144
|
+
gridBuildMs: number;
|
|
145
|
+
gridQueryMs: number;
|
|
146
|
+
aoiEncodeMs: number;
|
|
147
|
+
visibleIdsTotal: number;
|
|
148
|
+
membershipEnters: number;
|
|
149
|
+
membershipLeaves: number;
|
|
84
150
|
corrections: number;
|
|
85
151
|
}
|
|
86
152
|
/** The surface the worker host and the harness drive. Implemented by `RoomCore`. */
|
|
@@ -113,8 +179,26 @@ interface RoomCoreApi<S extends AnySchema = AnySchema> {
|
|
|
113
179
|
receive(clientId: string, frame: Uint8Array): void;
|
|
114
180
|
/** Full state + tick + rng for hibernation. Runs `onSleep`. Clears timers. */
|
|
115
181
|
serialize(): Uint8Array;
|
|
182
|
+
/**
|
|
183
|
+
* D24: the same bytes `serialize()` produces, with none of its side effects — the room carries
|
|
184
|
+
* on exactly as it was. This is what a save generation is written from; `serialize()` is what
|
|
185
|
+
* a room going to sleep is written from.
|
|
186
|
+
*/
|
|
187
|
+
snapshot(): Uint8Array;
|
|
116
188
|
/** Live JSON view of the room (dev page / supervisor admin API). */
|
|
117
189
|
inspect(): RoomInspection;
|
|
190
|
+
/**
|
|
191
|
+
* Week 12: settles the promise `hostCall(reqId, …)` returned. The host calls this from its own
|
|
192
|
+
* turn; the runtime runs the continuation as a discrete event and flushes afterwards, so state
|
|
193
|
+
* a continuation mutated goes out exactly like state a handler mutated.
|
|
194
|
+
*/
|
|
195
|
+
completeHostCall(reqId: number, result: HostCallResult): void;
|
|
196
|
+
/**
|
|
197
|
+
* D26: runs the `alarms[name]` handler as its own event between ticks, then flushes. Unknown
|
|
198
|
+
* names are logged and ignored — a room that dropped a handler in a redeploy must not crash on
|
|
199
|
+
* an alarm armed by the version before it.
|
|
200
|
+
*/
|
|
201
|
+
fireAlarm(name: string): void;
|
|
118
202
|
}
|
|
119
203
|
|
|
120
|
-
export { EVENT_RING_SIZE as E, type JoinOptions as J, type LogLevel as L, type RoomCoreApi as R, type
|
|
204
|
+
export { EVENT_RING_SIZE as E, HOST_CALL_TIMEOUT_MS as H, type JoinOptions as J, type LogLevel as L, type RoomCoreApi as R, type HostCall as a, type HostCallResult as b, type JoinResult as c, type RoomCoreOptions as d, type RoomEvent as e, type RoomEventKind as f, RoomFullError as g, type RoomHost as h, type RoomInspection as i, type RoomStats as j, inspectState as k };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { E as EVENT_RING_SIZE, J as JoinOptions,
|
|
2
|
-
export { C as CRASH_AFTER_THROWS, M as MAX_CATCHUP, a as Mulberry32, R as RoomCore } from './room-
|
|
3
|
-
import { AnySchema, PlainState, DirtySet
|
|
1
|
+
export { E as EVENT_RING_SIZE, H as HOST_CALL_TIMEOUT_MS, a as HostCall, b as HostCallResult, J as JoinOptions, c as JoinResult, L as LogLevel, R as RoomCoreApi, d as RoomCoreOptions, e as RoomEvent, f as RoomEventKind, g as RoomFullError, h as RoomHost, i as RoomInspection, j as RoomStats, k as inspectState } from './contract-B8QSO0MH.js';
|
|
2
|
+
export { C as CRASH_AFTER_THROWS, M as MAX_CATCHUP, a as Mulberry32, P as PhysicsSection, R as RoomCore, d as decodePhysicsSection, e as encodePhysicsSection, i as initPhysics, l as loadedPhysics, r as resetPhysicsForTests } from './room-BfALTh7M.js';
|
|
3
|
+
import { CollectionDesc, AnySchema, PlainState, DirtySet } from '@irtio/schema';
|
|
4
4
|
import '@irtio/protocol';
|
|
5
5
|
import '@irtio/server';
|
|
6
6
|
|
|
@@ -40,7 +40,16 @@ declare function visibleNames(ext: AnySchema, role: string): ReadonlySet<string>
|
|
|
40
40
|
*/
|
|
41
41
|
declare function viewKeyFor(ext: AnySchema, role: string): string;
|
|
42
42
|
/** The `join` snapshot: full state restricted to the client's view. */
|
|
43
|
-
declare function encodeViewSnapshot(ext: AnySchema, plain: PlainState, role: string, tick: number): Uint8Array;
|
|
43
|
+
declare function encodeViewSnapshot(ext: AnySchema, plain: PlainState, role: string, tick: number, memberships?: ReadonlyMap<string, ReadonlySet<string>>): Uint8Array;
|
|
44
|
+
interface VisibilityPolicy {
|
|
45
|
+
readonly memberships: ReadonlyMap<string, ReadonlySet<string>>;
|
|
46
|
+
maySeeCollection(desc: CollectionDesc): boolean;
|
|
47
|
+
maySeeEntity(desc: CollectionDesc, id: string): boolean;
|
|
48
|
+
/** Viewer cell, offending cells, and the radius — the diagnostics a leak report needs. */
|
|
49
|
+
describeSpatial(desc: CollectionDesc, ids: readonly string[]): string | undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Reusable authority-based policy for runtime, harness, and bot leak checks. */
|
|
52
|
+
declare function createVisibilityPolicy(ext: AnySchema, plain: PlainState, clientId: string, role: string): VisibilityPolicy;
|
|
44
53
|
/** One view's `DELTA` payload, or `null` when nothing visible to `role` changed. */
|
|
45
54
|
declare function encodeViewDelta(ext: AnySchema, plain: PlainState, dirty: DirtySet, role: string, tick: number): Uint8Array | null;
|
|
46
55
|
/**
|
|
@@ -61,14 +70,28 @@ declare function catchUpDirty(ext: AnySchema, plain: PlainState, fromRole: strin
|
|
|
61
70
|
* u32 rng state
|
|
62
71
|
* u32 tick
|
|
63
72
|
* u8 mode (1 = event, 0 = tick)
|
|
73
|
+
* [v2] blob physics section (varint length + bytes; length 0 = no world)
|
|
64
74
|
* ... encodeSnapshot(withBuiltins(schema), state)
|
|
65
75
|
*
|
|
76
|
+
* **v2 (week 9, D22)** adds the physics section: the Rapier world snapshot plus the entity↔handle
|
|
77
|
+
* map (`core/physics.ts` encodes it). It rides *inside* this blob rather than beside it so that
|
|
78
|
+
* wake is atomic — state and world always come back from the same bytes, and every store, cache
|
|
79
|
+
* and transfer path that already moves one array keeps working untouched.
|
|
80
|
+
*
|
|
81
|
+
* A **v1 blob still reads**: it simply has no physics section. For a room that has since gained
|
|
82
|
+
* physics that is the pre-physics-deploy case — the world is rebuilt from schema state and the
|
|
83
|
+
* room's `setup` runs again, which is logged. Writers emit v1 when there is no world, so a room
|
|
84
|
+
* without physics produces byte-identical blobs to the ones week 8 wrote.
|
|
85
|
+
*
|
|
66
86
|
* Note: the *deployment* version is deliberately **not** in here. It lives in the store
|
|
67
87
|
* key (`<project>/<room>@v<deployment>`), which keeps the blob format frozen — an old snapshot
|
|
68
88
|
* stays valid across deployments — and lets a wake path discover the version by listing keys
|
|
69
89
|
* instead of parsing bytes it may not yet know how to read.
|
|
70
90
|
*/
|
|
71
|
-
|
|
91
|
+
/** Written when the blob carries a physics world; v1 otherwise (and v1 is still read). */
|
|
92
|
+
declare const SNAPSHOT_FORMAT_VERSION = 2;
|
|
93
|
+
/** Versions this build can parse. */
|
|
94
|
+
declare const READABLE_SNAPSHOT_VERSIONS: readonly number[];
|
|
72
95
|
type SnapshotMode = 'tick' | 'event';
|
|
73
96
|
interface SnapshotHeader {
|
|
74
97
|
readonly seed: number;
|
|
@@ -77,11 +100,15 @@ interface SnapshotHeader {
|
|
|
77
100
|
readonly mode: SnapshotMode;
|
|
78
101
|
}
|
|
79
102
|
interface ParsedSnapshot extends SnapshotHeader {
|
|
103
|
+
/** The blob's own format version (1 or 2). */
|
|
104
|
+
readonly version: number;
|
|
105
|
+
/** The encoded physics section, or `undefined` for a v1 blob / a room with no world. */
|
|
106
|
+
readonly physics: Uint8Array | undefined;
|
|
80
107
|
/** The codec snapshot, encoded under `withBuiltins(schema)`. */
|
|
81
108
|
readonly snapshot: Uint8Array;
|
|
82
109
|
}
|
|
83
110
|
declare function parseHibernationBlob(bytes: Uint8Array): ParsedSnapshot;
|
|
84
|
-
declare function writeHibernationBlob(header: SnapshotHeader, snapshot: Uint8Array): Uint8Array;
|
|
111
|
+
declare function writeHibernationBlob(header: SnapshotHeader, snapshot: Uint8Array, physics?: Uint8Array): Uint8Array;
|
|
85
112
|
|
|
86
113
|
/**
|
|
87
114
|
* Wake-time schema migration.
|
|
@@ -123,7 +150,11 @@ interface MigrationHelpers {
|
|
|
123
150
|
}
|
|
124
151
|
interface MigrationModule {
|
|
125
152
|
up(state: MigrationState, s: MigrationHelpers): MigrationState | void;
|
|
126
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* Scaffolded by `irtio migrate create` and stored, but never called. `irtio rollback` restores
|
|
155
|
+
* the pre-migration save generation the `migrate` deploy wrote rather than running an inverse
|
|
156
|
+
* transform, which is how it undoes migrations that have no `down` at all.
|
|
157
|
+
*/
|
|
127
158
|
down?(state: MigrationState, s: MigrationHelpers): MigrationState | void;
|
|
128
159
|
}
|
|
129
160
|
/**
|
|
@@ -158,4 +189,4 @@ declare function migrateSnapshot(blob: Uint8Array, chain: readonly MigrationStep
|
|
|
158
189
|
declare function toMigrationState(schema: AnySchema, plain: PlainState): MigrationState;
|
|
159
190
|
declare function fromMigrationState(schema: AnySchema, state: MigrationState, version: number): PlainState;
|
|
160
191
|
|
|
161
|
-
export { type MigrateOptions, type MigrationEntity, type MigrationHelpers, type MigrationModule, type MigrationOutcome, type MigrationRecord, type MigrationState, type MigrationStep, type ParsedSnapshot, RPC_TIMEOUT_MS, SNAPSHOT_FORMAT_VERSION, type SnapshotHeader, type SnapshotMode, catchUpDirty, encodeViewDelta, encodeViewSnapshot, fromMigrationState, isVisible, migrateSnapshot, parseHibernationBlob, toMigrationState, viewKeyFor, visibleNames, visibleTo, writeHibernationBlob };
|
|
192
|
+
export { type MigrateOptions, type MigrationEntity, type MigrationHelpers, type MigrationModule, type MigrationOutcome, type MigrationRecord, type MigrationState, type MigrationStep, type ParsedSnapshot, READABLE_SNAPSHOT_VERSIONS, RPC_TIMEOUT_MS, SNAPSHOT_FORMAT_VERSION, type SnapshotHeader, type SnapshotMode, type VisibilityPolicy, catchUpDirty, createVisibilityPolicy, encodeViewDelta, encodeViewSnapshot, fromMigrationState, isVisible, migrateSnapshot, parseHibernationBlob, toMigrationState, viewKeyFor, visibleNames, visibleTo, writeHibernationBlob };
|
package/dist/index.js
CHANGED
|
@@ -2,44 +2,60 @@ import {
|
|
|
2
2
|
fromMigrationState,
|
|
3
3
|
migrateSnapshot,
|
|
4
4
|
toMigrationState
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FA4IOC2Z.js";
|
|
6
6
|
import {
|
|
7
7
|
CRASH_AFTER_THROWS,
|
|
8
8
|
EVENT_RING_SIZE,
|
|
9
|
+
HOST_CALL_TIMEOUT_MS,
|
|
9
10
|
MAX_CATCHUP,
|
|
10
11
|
Mulberry32,
|
|
12
|
+
READABLE_SNAPSHOT_VERSIONS,
|
|
11
13
|
RPC_TIMEOUT_MS,
|
|
12
14
|
RoomCore,
|
|
13
15
|
RoomFullError,
|
|
14
16
|
SNAPSHOT_FORMAT_VERSION,
|
|
15
17
|
catchUpDirty,
|
|
18
|
+
createVisibilityPolicy,
|
|
19
|
+
decodePhysicsSection,
|
|
20
|
+
encodePhysicsSection,
|
|
16
21
|
encodeViewDelta,
|
|
17
22
|
encodeViewSnapshot,
|
|
23
|
+
initPhysics,
|
|
18
24
|
inspectState,
|
|
19
25
|
isVisible,
|
|
26
|
+
loadedPhysics,
|
|
20
27
|
parseHibernationBlob,
|
|
28
|
+
resetPhysicsForTests,
|
|
21
29
|
viewKeyFor,
|
|
22
30
|
visibleNames,
|
|
23
31
|
visibleTo,
|
|
24
32
|
writeHibernationBlob
|
|
25
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-GKMD3ICD.js";
|
|
26
34
|
export {
|
|
27
35
|
CRASH_AFTER_THROWS,
|
|
28
36
|
EVENT_RING_SIZE,
|
|
37
|
+
HOST_CALL_TIMEOUT_MS,
|
|
29
38
|
MAX_CATCHUP,
|
|
30
39
|
Mulberry32,
|
|
40
|
+
READABLE_SNAPSHOT_VERSIONS,
|
|
31
41
|
RPC_TIMEOUT_MS,
|
|
32
42
|
RoomCore,
|
|
33
43
|
RoomFullError,
|
|
34
44
|
SNAPSHOT_FORMAT_VERSION,
|
|
35
45
|
catchUpDirty,
|
|
46
|
+
createVisibilityPolicy,
|
|
47
|
+
decodePhysicsSection,
|
|
48
|
+
encodePhysicsSection,
|
|
36
49
|
encodeViewDelta,
|
|
37
50
|
encodeViewSnapshot,
|
|
38
51
|
fromMigrationState,
|
|
52
|
+
initPhysics,
|
|
39
53
|
inspectState,
|
|
40
54
|
isVisible,
|
|
55
|
+
loadedPhysics,
|
|
41
56
|
migrateSnapshot,
|
|
42
57
|
parseHibernationBlob,
|
|
58
|
+
resetPhysicsForTests,
|
|
43
59
|
toMigrationState,
|
|
44
60
|
viewKeyFor,
|
|
45
61
|
visibleNames,
|