@irtio/runtime 0.1.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/LICENSE +21 -0
- package/dist/chunk-3DQHT4CM.js +129 -0
- package/dist/chunk-X5S364FY.js +1573 -0
- package/dist/contract-BhD88PGb.d.ts +120 -0
- package/dist/index.d.ts +161 -0
- package/dist/index.js +48 -0
- package/dist/room-CBsSCueH.d.ts +246 -0
- package/dist/test/index.d.ts +283 -0
- package/dist/test/index.js +774 -0
- package/dist/worker/index.d.ts +173 -0
- package/dist/worker/index.js +280 -0
- package/package.json +39 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { L as LogLevel, h as RoomStats, R as RoomCoreApi, f as RoomHost } from '../contract-BhD88PGb.js';
|
|
2
|
+
import { ErrorCodeName } from '@irtio/protocol';
|
|
3
|
+
import { LeaveReason } from '@irtio/server';
|
|
4
|
+
import '@irtio/schema';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Supervisor ↔ room-worker `postMessage` protocol. Every `Uint8Array` is transferred.
|
|
8
|
+
* Keep it additive: deployed supervisors speak exactly this.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* One deployment in a wake-time migration chain. The worker imports each
|
|
13
|
+
* `migrationUrl` and runs `up` inside its own sandbox — migrations are tenant code and never run
|
|
14
|
+
* in the supervisor process. The first step is the version the snapshot was written under and
|
|
15
|
+
* carries no migration; it is there to supply the decoding schema.
|
|
16
|
+
*/
|
|
17
|
+
interface MigrationChainStep {
|
|
18
|
+
version: number;
|
|
19
|
+
/** `schema.canonical` of that deployment. */
|
|
20
|
+
schemaJson: string;
|
|
21
|
+
/** `file://` URL of a bundled module exporting `{ up }` (default or named). */
|
|
22
|
+
migrationUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
type ToWorker = {
|
|
25
|
+
t: 'init';
|
|
26
|
+
roomId: string;
|
|
27
|
+
/** `file://` URL of the bundled room (default export = RoomDefinition). */
|
|
28
|
+
bundleUrl: string;
|
|
29
|
+
seed?: number;
|
|
30
|
+
publicUrl?: string;
|
|
31
|
+
/** Restore from a hibernation snapshot. */
|
|
32
|
+
snapshot?: Uint8Array;
|
|
33
|
+
/**
|
|
34
|
+
* Bring `snapshot` forward before restoring it. Ascending; the last version must be
|
|
35
|
+
* the one `bundleUrl` implements.
|
|
36
|
+
*/
|
|
37
|
+
migrate?: MigrationChainStep[];
|
|
38
|
+
} | {
|
|
39
|
+
t: 'join';
|
|
40
|
+
clientId: string;
|
|
41
|
+
role?: string;
|
|
42
|
+
name?: string;
|
|
43
|
+
reconnecting?: boolean;
|
|
44
|
+
} | {
|
|
45
|
+
t: 'leave';
|
|
46
|
+
clientId: string;
|
|
47
|
+
reason: LeaveReason;
|
|
48
|
+
} | {
|
|
49
|
+
t: 'disconnected';
|
|
50
|
+
clientId: string;
|
|
51
|
+
} | {
|
|
52
|
+
t: 'frame';
|
|
53
|
+
clientId: string;
|
|
54
|
+
bytes: Uint8Array;
|
|
55
|
+
} | {
|
|
56
|
+
t: 'serialize';
|
|
57
|
+
reqId: number;
|
|
58
|
+
} | {
|
|
59
|
+
t: 'inspect';
|
|
60
|
+
reqId: number;
|
|
61
|
+
} | {
|
|
62
|
+
t: 'stats';
|
|
63
|
+
} | {
|
|
64
|
+
t: 'stop';
|
|
65
|
+
};
|
|
66
|
+
type FromWorker = {
|
|
67
|
+
t: 'ready';
|
|
68
|
+
roomId: string;
|
|
69
|
+
schemaHash: string;
|
|
70
|
+
extHash: string;
|
|
71
|
+
/** The room definition's resolved config: the supervisor needs
|
|
72
|
+
* idleMs/reconnectGraceMs/maxClients/mode without importing the bundle twice. */
|
|
73
|
+
config: {
|
|
74
|
+
mode: 'tick' | 'event';
|
|
75
|
+
tickRate: number;
|
|
76
|
+
idleMs: number;
|
|
77
|
+
reconnectGraceMs: number;
|
|
78
|
+
maxClients: number;
|
|
79
|
+
};
|
|
80
|
+
/** Present when `init.migrate` ran; the supervisor re-snapshots on the strength of it. */
|
|
81
|
+
migrated?: {
|
|
82
|
+
fromVersion: number;
|
|
83
|
+
toVersion: number;
|
|
84
|
+
applied: number[];
|
|
85
|
+
ms: number;
|
|
86
|
+
};
|
|
87
|
+
} | {
|
|
88
|
+
t: 'initFailed';
|
|
89
|
+
reason: string;
|
|
90
|
+
} | {
|
|
91
|
+
t: 'joined';
|
|
92
|
+
clientId: string;
|
|
93
|
+
role: string;
|
|
94
|
+
tick: number;
|
|
95
|
+
snapshot: Uint8Array;
|
|
96
|
+
} | {
|
|
97
|
+
t: 'joinRejected';
|
|
98
|
+
clientId: string;
|
|
99
|
+
code: ErrorCodeName;
|
|
100
|
+
reason?: string;
|
|
101
|
+
} | {
|
|
102
|
+
t: 'send';
|
|
103
|
+
clientId: string;
|
|
104
|
+
bytes: Uint8Array;
|
|
105
|
+
} | {
|
|
106
|
+
t: 'kick';
|
|
107
|
+
clientId: string;
|
|
108
|
+
code: ErrorCodeName;
|
|
109
|
+
reason?: string;
|
|
110
|
+
} | {
|
|
111
|
+
t: 'close';
|
|
112
|
+
reason?: string;
|
|
113
|
+
} | {
|
|
114
|
+
t: 'sleep';
|
|
115
|
+
} | {
|
|
116
|
+
t: 'log';
|
|
117
|
+
level: LogLevel;
|
|
118
|
+
args: unknown[];
|
|
119
|
+
} | {
|
|
120
|
+
t: 'crashed';
|
|
121
|
+
reason: string;
|
|
122
|
+
} | {
|
|
123
|
+
t: 'serialized';
|
|
124
|
+
reqId: number;
|
|
125
|
+
bytes: Uint8Array;
|
|
126
|
+
} | {
|
|
127
|
+
t: 'inspected';
|
|
128
|
+
reqId: number;
|
|
129
|
+
tick: number;
|
|
130
|
+
stateJson: Record<string, unknown>;
|
|
131
|
+
recent: readonly {
|
|
132
|
+
tick: number;
|
|
133
|
+
kind: string;
|
|
134
|
+
clientId?: string;
|
|
135
|
+
detail?: string;
|
|
136
|
+
}[];
|
|
137
|
+
/** Worker process RSS in bytes. */
|
|
138
|
+
rss: number;
|
|
139
|
+
} | {
|
|
140
|
+
t: 'stats';
|
|
141
|
+
stats: Omit<RoomStats, 'bytesOutByClient'> & {
|
|
142
|
+
bytesOutByClient: [string, number][];
|
|
143
|
+
};
|
|
144
|
+
} | {
|
|
145
|
+
t: 'stopped';
|
|
146
|
+
};
|
|
147
|
+
/** Collects transferable buffers from a message (for `postMessage(msg, transfer)`). */
|
|
148
|
+
declare function transferList(msg: ToWorker | FromWorker): ArrayBuffer[];
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The `worker_threads` room host. Imported as a worker, this file drives one
|
|
152
|
+
* `RoomCore` over the typed `ToWorker`/`FromWorker` `postMessage` protocol. It is also safe to
|
|
153
|
+
* import from the main thread — nothing runs unless `!isMainThread && parentPort`, so tests and
|
|
154
|
+
* future hosts can import `createWorkerHost`/`handleMessage` directly.
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Builds a `RoomHost` that posts `FromWorker` messages via `post`. Uses real timers
|
|
159
|
+
* (`setTimeout`/`clearTimeout`) and a monotonic clock (`performance.now()`).
|
|
160
|
+
*/
|
|
161
|
+
declare function createWorkerHost(post: (msg: FromWorker, transfer?: ArrayBuffer[]) => void): RoomHost;
|
|
162
|
+
/** Mutable state the message handler drives. Exported for tests that want to inspect it. */
|
|
163
|
+
interface WorkerState {
|
|
164
|
+
core: RoomCoreApi | undefined;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Handles one `ToWorker` message against `state`, using `host` (already wired to `post`) to
|
|
168
|
+
* construct/drive the `RoomCore`. Never throws — handler bugs are logged via `post` instead of
|
|
169
|
+
* killing the worker.
|
|
170
|
+
*/
|
|
171
|
+
declare function handleMessage(state: WorkerState, host: RoomHost, post: (msg: FromWorker, transfer?: ArrayBuffer[]) => void, msg: ToWorker): Promise<void>;
|
|
172
|
+
|
|
173
|
+
export { type FromWorker, type MigrationChainStep, type ToWorker, type WorkerState, createWorkerHost, handleMessage, transferList };
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
migrateSnapshot
|
|
3
|
+
} from "../chunk-3DQHT4CM.js";
|
|
4
|
+
import {
|
|
5
|
+
RoomCore,
|
|
6
|
+
RoomFullError
|
|
7
|
+
} from "../chunk-X5S364FY.js";
|
|
8
|
+
|
|
9
|
+
// src/worker/index.ts
|
|
10
|
+
import { isMainThread, parentPort } from "worker_threads";
|
|
11
|
+
import { isRoomDefinition } from "@irtio/server";
|
|
12
|
+
|
|
13
|
+
// src/worker/protocol.ts
|
|
14
|
+
function transferList(msg) {
|
|
15
|
+
const out = [];
|
|
16
|
+
for (const v of Object.values(msg)) {
|
|
17
|
+
if (v instanceof Uint8Array && v.buffer instanceof ArrayBuffer) out.push(v.buffer);
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/worker/index.ts
|
|
23
|
+
function ownBuffer(bytes) {
|
|
24
|
+
if (bytes.byteOffset !== 0 || bytes.byteLength !== bytes.buffer.byteLength) {
|
|
25
|
+
return bytes.slice();
|
|
26
|
+
}
|
|
27
|
+
return bytes;
|
|
28
|
+
}
|
|
29
|
+
function createWorkerHost(post) {
|
|
30
|
+
return {
|
|
31
|
+
now() {
|
|
32
|
+
return performance.now();
|
|
33
|
+
},
|
|
34
|
+
setTimeout(fn, ms) {
|
|
35
|
+
return setTimeout(fn, ms);
|
|
36
|
+
},
|
|
37
|
+
clearTimeout(handle) {
|
|
38
|
+
clearTimeout(handle);
|
|
39
|
+
},
|
|
40
|
+
send(clientId, frame) {
|
|
41
|
+
const bytes = ownBuffer(frame);
|
|
42
|
+
post({ t: "send", clientId, bytes }, [bytes.buffer]);
|
|
43
|
+
},
|
|
44
|
+
kick(clientId, code, reason) {
|
|
45
|
+
post({ t: "kick", clientId, code, ...reason !== void 0 ? { reason } : {} });
|
|
46
|
+
},
|
|
47
|
+
close(reason) {
|
|
48
|
+
post({ t: "close", ...reason !== void 0 ? { reason } : {} });
|
|
49
|
+
},
|
|
50
|
+
sleep() {
|
|
51
|
+
post({ t: "sleep" });
|
|
52
|
+
},
|
|
53
|
+
log(level, args) {
|
|
54
|
+
post({ t: "log", level, args });
|
|
55
|
+
},
|
|
56
|
+
crashed(reason) {
|
|
57
|
+
post({ t: "crashed", reason });
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function loadChain(steps) {
|
|
62
|
+
const out = [];
|
|
63
|
+
for (const step of steps) {
|
|
64
|
+
let migration;
|
|
65
|
+
if (step.migrationUrl !== void 0) {
|
|
66
|
+
const mod = await import(step.migrationUrl);
|
|
67
|
+
const candidate = typeof mod.up === "function" ? mod : mod.default;
|
|
68
|
+
if (!candidate || typeof candidate.up !== "function") {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`migration for v${step.version} at ${step.migrationUrl} does not export an \`up\` function`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
migration = candidate;
|
|
74
|
+
}
|
|
75
|
+
out.push({
|
|
76
|
+
version: step.version,
|
|
77
|
+
schemaJson: step.schemaJson,
|
|
78
|
+
...migration !== void 0 ? { migration } : {}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
function statsPayload(stats) {
|
|
84
|
+
const { bytesOutByClient, ...rest } = stats;
|
|
85
|
+
return { t: "stats", stats: { ...rest, bytesOutByClient: [...bytesOutByClient.entries()] } };
|
|
86
|
+
}
|
|
87
|
+
async function handleMessage(state, host, post, msg) {
|
|
88
|
+
try {
|
|
89
|
+
switch (msg.t) {
|
|
90
|
+
case "init": {
|
|
91
|
+
let def;
|
|
92
|
+
try {
|
|
93
|
+
const mod = await import(msg.bundleUrl);
|
|
94
|
+
if (!isRoomDefinition(mod.default)) {
|
|
95
|
+
post({ t: "initFailed", reason: "bundle default export is not a RoomDefinition" });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
def = mod.default;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
post({ t: "initFailed", reason: String(err instanceof Error ? err.stack : err) });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
let snapshot = msg.snapshot;
|
|
104
|
+
let migrated;
|
|
105
|
+
if (snapshot && msg.migrate && msg.migrate.length > 0) {
|
|
106
|
+
try {
|
|
107
|
+
const chain = await loadChain(msg.migrate);
|
|
108
|
+
migrated = migrateSnapshot(snapshot, chain, {
|
|
109
|
+
roomId: msg.roomId,
|
|
110
|
+
log: (level, args) => post({ t: "log", level, args })
|
|
111
|
+
});
|
|
112
|
+
snapshot = migrated.bytes;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
post({
|
|
115
|
+
t: "initFailed",
|
|
116
|
+
reason: `migration failed: ${String(err instanceof Error ? err.stack ?? err.message : err)}`
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const options = {
|
|
123
|
+
roomId: msg.roomId,
|
|
124
|
+
...msg.seed !== void 0 ? { seed: msg.seed } : {},
|
|
125
|
+
...msg.publicUrl !== void 0 ? { publicUrl: msg.publicUrl } : {}
|
|
126
|
+
};
|
|
127
|
+
const core = snapshot ? RoomCore.restore(def, snapshot, host, options) : new RoomCore(def, host, options);
|
|
128
|
+
state.core = core;
|
|
129
|
+
core.start();
|
|
130
|
+
const c = def.config;
|
|
131
|
+
post({
|
|
132
|
+
t: "ready",
|
|
133
|
+
roomId: msg.roomId,
|
|
134
|
+
schemaHash: def.schema.hash,
|
|
135
|
+
extHash: core.ext.hash,
|
|
136
|
+
config: {
|
|
137
|
+
mode: c.mode,
|
|
138
|
+
tickRate: c.tickRate,
|
|
139
|
+
idleMs: c.idleMs,
|
|
140
|
+
reconnectGraceMs: c.reconnectGraceMs,
|
|
141
|
+
maxClients: c.maxClients
|
|
142
|
+
},
|
|
143
|
+
...migrated ? {
|
|
144
|
+
migrated: {
|
|
145
|
+
fromVersion: migrated.fromVersion,
|
|
146
|
+
toVersion: migrated.toVersion,
|
|
147
|
+
applied: [...migrated.applied],
|
|
148
|
+
ms: migrated.ms
|
|
149
|
+
}
|
|
150
|
+
} : {}
|
|
151
|
+
});
|
|
152
|
+
} catch (err) {
|
|
153
|
+
post({ t: "initFailed", reason: String(err instanceof Error ? err.stack : err) });
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
case "join": {
|
|
158
|
+
const core = state.core;
|
|
159
|
+
if (!core) {
|
|
160
|
+
post({
|
|
161
|
+
t: "joinRejected",
|
|
162
|
+
clientId: msg.clientId,
|
|
163
|
+
code: "E_INTERNAL",
|
|
164
|
+
reason: "not initialized"
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const joinOptions = {
|
|
170
|
+
...msg.role !== void 0 ? { role: msg.role } : {},
|
|
171
|
+
...msg.name !== void 0 ? { name: msg.name } : {},
|
|
172
|
+
...msg.reconnecting !== void 0 ? { reconnecting: msg.reconnecting } : {}
|
|
173
|
+
};
|
|
174
|
+
const result = core.join(msg.clientId, joinOptions);
|
|
175
|
+
const snapshot = ownBuffer(result.snapshot);
|
|
176
|
+
post(
|
|
177
|
+
{
|
|
178
|
+
t: "joined",
|
|
179
|
+
clientId: msg.clientId,
|
|
180
|
+
role: result.role,
|
|
181
|
+
tick: result.tick,
|
|
182
|
+
snapshot
|
|
183
|
+
},
|
|
184
|
+
[snapshot.buffer]
|
|
185
|
+
);
|
|
186
|
+
} catch (err) {
|
|
187
|
+
if (err instanceof RoomFullError) {
|
|
188
|
+
post({ t: "joinRejected", clientId: msg.clientId, code: "E_ROOM_FULL" });
|
|
189
|
+
} else {
|
|
190
|
+
post({
|
|
191
|
+
t: "joinRejected",
|
|
192
|
+
clientId: msg.clientId,
|
|
193
|
+
code: "E_INTERNAL",
|
|
194
|
+
reason: String(err instanceof Error ? err.message : err)
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
case "leave": {
|
|
201
|
+
state.core?.leave(msg.clientId, msg.reason);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
case "disconnected": {
|
|
205
|
+
state.core?.markDisconnected(msg.clientId);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
case "frame": {
|
|
209
|
+
state.core?.receive(msg.clientId, msg.bytes);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
case "serialize": {
|
|
213
|
+
const core = state.core;
|
|
214
|
+
if (!core) return;
|
|
215
|
+
const bytes = ownBuffer(core.serialize());
|
|
216
|
+
post({ t: "serialized", reqId: msg.reqId, bytes }, [bytes.buffer]);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
case "inspect": {
|
|
220
|
+
const core = state.core;
|
|
221
|
+
if (!core) return;
|
|
222
|
+
const ins = core.inspect();
|
|
223
|
+
post({
|
|
224
|
+
t: "inspected",
|
|
225
|
+
reqId: msg.reqId,
|
|
226
|
+
tick: ins.tick,
|
|
227
|
+
stateJson: ins.state,
|
|
228
|
+
recent: ins.recent,
|
|
229
|
+
rss: typeof process !== "undefined" ? process.memoryUsage().rss : 0
|
|
230
|
+
});
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
case "stats": {
|
|
234
|
+
const core = state.core;
|
|
235
|
+
if (!core) return;
|
|
236
|
+
post(statsPayload(core.stats));
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
case "stop": {
|
|
240
|
+
state.core?.stop();
|
|
241
|
+
post({ t: "stopped" });
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
default: {
|
|
245
|
+
const unknown = msg;
|
|
246
|
+
post({
|
|
247
|
+
t: "log",
|
|
248
|
+
level: "warn",
|
|
249
|
+
args: [`worker: unknown message type ${String(unknown.t)}`]
|
|
250
|
+
});
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} catch (err) {
|
|
255
|
+
post({
|
|
256
|
+
t: "log",
|
|
257
|
+
level: "error",
|
|
258
|
+
args: [
|
|
259
|
+
`worker: handling '${msg.t}' threw`,
|
|
260
|
+
err instanceof Error ? err.stack ?? err.message : err
|
|
261
|
+
]
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (!isMainThread && parentPort) {
|
|
266
|
+
const port = parentPort;
|
|
267
|
+
const post = (msg, transfer) => {
|
|
268
|
+
port.postMessage(msg, transfer ?? transferList(msg));
|
|
269
|
+
};
|
|
270
|
+
const host = createWorkerHost(post);
|
|
271
|
+
const state = { core: void 0 };
|
|
272
|
+
port.on("message", (msg) => {
|
|
273
|
+
void handleMessage(state, host, post, msg);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
export {
|
|
277
|
+
createWorkerHost,
|
|
278
|
+
handleMessage,
|
|
279
|
+
transferList
|
|
280
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@irtio/runtime",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "irtio room runtime: RoomCore, worker_threads host, in-process test harness",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./worker": {
|
|
19
|
+
"types": "./dist/worker/index.d.ts",
|
|
20
|
+
"import": "./dist/worker/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./test": {
|
|
23
|
+
"types": "./dist/test/index.d.ts",
|
|
24
|
+
"import": "./dist/test/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@irtio/protocol": "0.1.0",
|
|
32
|
+
"@irtio/schema": "0.1.0",
|
|
33
|
+
"@irtio/server": "0.1.0"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsup",
|
|
37
|
+
"test": "vitest run"
|
|
38
|
+
}
|
|
39
|
+
}
|