@antha/multiplayer-server 0.0.8 → 0.1.1

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/README.md CHANGED
@@ -1 +1,55 @@
1
1
  # @antha/multiplayer-server
2
+
3
+ This package provides the server that [Antha](https://www.npmjs.com/package/@antha/engine) multiplayer clients use for room discovery and WebRTC signaling. It is only used for listing and connecting to rooms. Actual game state transfer is expected to be p2p.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm i @antha/multiplayer-server
9
+ ```
10
+
11
+ ## API
12
+
13
+ <!-- example-link: src/readme-examples/starting-server.example.ts -->
14
+
15
+ ```TypeScript
16
+ import {AnyOrigin} from '@rest-vir/api';
17
+ import {startMultiplayerServer} from '@antha/multiplayer-server';
18
+
19
+ await startMultiplayerServer({
20
+ backendOrigin: 'http://localhost:9348',
21
+ games: {
22
+ default: AnyOrigin,
23
+ },
24
+ host: 'localhost',
25
+ lockPort: true,
26
+ port: 9348,
27
+ });
28
+ ```
29
+
30
+ ## CLI
31
+
32
+ The `start-mp-server` command accepts a required path to a JavaScript, TypeScript, JSON, YAML, or TOML configuration file. The configuration uses the same options as `startMultiplayerServer`.
33
+
34
+ Create a configuration file:
35
+
36
+ <!-- example-link: src/readme-examples/multiplayer-server-config.example.ts -->
37
+
38
+ ```TypeScript
39
+ export default {
40
+ games: {
41
+ byId: {
42
+ 'example-game-id': 'https://electrovir.github.io',
43
+ },
44
+ },
45
+ host: '127.0.0.1',
46
+ lockPort: true,
47
+ port: 9348,
48
+ };
49
+ ```
50
+
51
+ Start the server with the configuration file path:
52
+
53
+ ```sh
54
+ npx start-mp-server ./multiplayer-server.config.mjs
55
+ ```
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare const packageDirPath: string;
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { assertWrap } from '@augment-vir/assert';
3
+ import { readPackageJson } from '@augment-vir/node';
4
+ import { parseArgs } from 'cli-vir';
5
+ import { resolve } from 'node:path';
6
+ import { runMultiplayerServerCli } from './cli.js';
7
+ export const packageDirPath = resolve(import.meta.dirname, '..', '..');
8
+ const binName = assertWrap.isTruthy(Object.keys(assertWrap.isObject((await readPackageJson(packageDirPath)).bin, 'Bin definition is not an object.'))[0], 'Failed to find bin name.');
9
+ const args = parseArgs(process.argv, {
10
+ configPath: {
11
+ position: 0,
12
+ required: true,
13
+ description: 'Path to a config file (can be JS, TS, JSON, YAML, or TOML) with contents matching startMultiplayerServerOptionsShape.',
14
+ },
15
+ }, {
16
+ binName,
17
+ importMeta: import.meta,
18
+ });
19
+ await runMultiplayerServerCli(args.configPath);
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Load a config file and start the multiplayer server from its options.
3
+ *
4
+ * @category Internal
5
+ */
6
+ export declare function runMultiplayerServerCli(configFilePath: string): Promise<void>;
@@ -0,0 +1,14 @@
1
+ import { loadConfig } from 'config-vir';
2
+ import { startMultiplayerServer, startMultiplayerServerOptionsShape } from '../start-server.js';
3
+ /**
4
+ * Load a config file and start the multiplayer server from its options.
5
+ *
6
+ * @category Internal
7
+ */
8
+ export async function runMultiplayerServerCli(configFilePath) {
9
+ const config = await loadConfig({
10
+ configPath: configFilePath,
11
+ configShape: startMultiplayerServerOptionsShape,
12
+ });
13
+ await startMultiplayerServer(config);
14
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export * from './implemented-multiplayer-api.js';
1
+ export * from './cli/cli.js';
2
+ export * from './multiplayer-api-implementation.js';
2
3
  export * from './start-server.js';
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- export * from './implemented-multiplayer-api.js';
1
+ export * from './cli/cli.js';
2
+ export * from './multiplayer-api-implementation.js';
2
3
  export * from './start-server.js';
@@ -0,0 +1,103 @@
1
+ import { type MultiplayerRoomHandler } from '@antha/multiplayer-core';
2
+ import { type ServerLogger } from '@rest-vir/host';
3
+ /**
4
+ * Shape definition for {@link MultiplayerServerOptions}.
5
+ *
6
+ * @category Internal
7
+ */
8
+ export declare const multiplayerServerOptionsShape: import("object-shape-tester").Shape<{
9
+ /**
10
+ * The Multiplayer server's logger.
11
+ *
12
+ * For help setting this, see any of the following from `@rest-vir/host`:
13
+ *
14
+ * - `silentServerLogger`
15
+ * - `defaultServerLogger`
16
+ * - `createServerLogger`
17
+ */
18
+ logger: import("object-shape-tester").Shape<import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<(import("@sinclair/typebox").TUndefined | import("@sinclair/typebox").TNull | import("@sinclair/typebox").TObject<{
19
+ error: import("@sinclair/typebox").TUnsafe<(error: Error) => void>;
20
+ info: import("@sinclair/typebox").TUnsafe<(...args: ReadonlyArray<unknown>) => void>;
21
+ }>)[]>>>;
22
+ backendOrigin: import("object-shape-tester").Shape<import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<(import("@sinclair/typebox").TUndefined | import("@sinclair/typebox").TNull | import("@sinclair/typebox").TString)[]>>>;
23
+ games: import("object-shape-tester").Shape<import("@sinclair/typebox").TUnion<(import("@sinclair/typebox").TObject<{
24
+ byId: import("@sinclair/typebox").TUnsafe<Record<string, string | RegExp | import("@rest-vir/api").OriginCheckCallback | {
25
+ anyOriginWithCredentials?: undefined;
26
+ anyOrigin: true;
27
+ } | {
28
+ anyOrigin?: undefined;
29
+ anyOriginWithCredentials: true;
30
+ }>>;
31
+ default: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TUndefined, import("@sinclair/typebox").TUnion<(import("@sinclair/typebox").TString | import("@sinclair/typebox").TUnsafe<RegExp> | import("@sinclair/typebox").TUnsafe<import("@rest-vir/api").OriginCheckCallback> | import("@sinclair/typebox").TObject<{
32
+ anyOrigin: import("@sinclair/typebox").TUnsafe<true>;
33
+ anyOriginWithCredentials: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUndefined>;
34
+ }> | import("@sinclair/typebox").TObject<{
35
+ anyOrigin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUndefined>;
36
+ anyOriginWithCredentials: import("@sinclair/typebox").TUnsafe<true>;
37
+ }>)[]>]>>;
38
+ }> | import("@sinclair/typebox").TObject<{
39
+ byId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TUndefined, import("@sinclair/typebox").TUnsafe<Record<string, string | RegExp | import("@rest-vir/api").OriginCheckCallback | {
40
+ anyOriginWithCredentials?: undefined;
41
+ anyOrigin: true;
42
+ } | {
43
+ anyOrigin?: undefined;
44
+ anyOriginWithCredentials: true;
45
+ }>>]>>;
46
+ default: import("@sinclair/typebox").TUnion<(import("@sinclair/typebox").TString | import("@sinclair/typebox").TUnsafe<RegExp> | import("@sinclair/typebox").TUnsafe<import("@rest-vir/api").OriginCheckCallback> | import("@sinclair/typebox").TObject<{
47
+ anyOrigin: import("@sinclair/typebox").TUnsafe<true>;
48
+ anyOriginWithCredentials: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUndefined>;
49
+ }> | import("@sinclair/typebox").TObject<{
50
+ anyOrigin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUndefined>;
51
+ anyOriginWithCredentials: import("@sinclair/typebox").TUnsafe<true>;
52
+ }>)[]>;
53
+ }>)[]>>;
54
+ }>;
55
+ /**
56
+ * Multiplayer server options.
57
+ *
58
+ * @category Internal
59
+ */
60
+ export type MultiplayerServerOptions = typeof multiplayerServerOptionsShape.runtimeType;
61
+ /**
62
+ * Internal state for the multiplayer server.
63
+ *
64
+ * @category Internal
65
+ */
66
+ export type MultiplayerServerState = {
67
+ roomHandler: MultiplayerRoomHandler;
68
+ logger: ServerLogger;
69
+ };
70
+ /**
71
+ * The default logger for {@link ImplementedMultiplayerApi}.
72
+ *
73
+ * @category Internal
74
+ */
75
+ export declare const defaultMultiplayerApiLogger: ServerLogger;
76
+ /**
77
+ * Per-request host context derived from the multiplayer API request.
78
+ *
79
+ * @category Internal
80
+ */
81
+ export type MultiplayerHostContext = {
82
+ /** Game id associated with the request or WebSocket connection. */
83
+ gameId: string;
84
+ };
85
+ /**
86
+ * The implemented API returned from {@link implementMultiplayerApi}.
87
+ *
88
+ * @category Internal
89
+ */
90
+ export type ImplementedMultiplayerApi = ReturnType<typeof implementMultiplayerApi>['api'];
91
+ /**
92
+ * Implements the multiplayer API.
93
+ *
94
+ * @category Internal
95
+ */
96
+ export declare function implementMultiplayerApi(options: MultiplayerServerOptions): {
97
+ serverState: MultiplayerServerState;
98
+ api: Readonly<import("@rest-vir/host").ApiImplementation<{
99
+ apiName: string;
100
+ endpoints: Readonly<Record<"/" | "/health" | "/rooms", Readonly<import("@rest-vir/api").EndpointDefinition>>>;
101
+ webSockets: Readonly<Record<"/connect", Readonly<import("@rest-vir/api").WebSocketDefinition>>>;
102
+ }, MultiplayerHostContext>>;
103
+ };
@@ -1,8 +1,62 @@
1
1
  import { createMultiplayerRoomHandler, multiplayerApi, multiplayerConnectWebSocket, multiplayerHealthEndpoint, multiplayerRoomsEndpoint, multiplayerRootEndpoint, } from '@antha/multiplayer-core';
2
2
  import { check } from '@augment-vir/assert';
3
3
  import { callAsynchronously, ensureArray } from '@augment-vir/common';
4
- import { AnyOrigin, checkOriginRequirement, HttpMethod, HttpStatus, } from '@rest-vir/api';
4
+ import { AnyOrigin, checkOriginRequirement, HttpMethod, HttpStatus, originRequirementShape, } from '@rest-vir/api';
5
5
  import { createApiImplementor, defaultServerLogger, implementApi, silentServerLogger, } from '@rest-vir/host';
6
+ import { defineShape, nullableShape, optionalShape, recordShape, unionShape, } from 'object-shape-tester';
7
+ /**
8
+ * Shape definition for {@link MultiplayerServerOptions}.
9
+ *
10
+ * @category Internal
11
+ */
12
+ export const multiplayerServerOptionsShape = defineShape({
13
+ /**
14
+ * The Multiplayer server's logger.
15
+ *
16
+ * For help setting this, see any of the following from `@rest-vir/host`:
17
+ *
18
+ * - `silentServerLogger`
19
+ * - `defaultServerLogger`
20
+ * - `createServerLogger`
21
+ */
22
+ logger: nullableShape({
23
+ /** Log an error reported by the multiplayer server. */
24
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
25
+ error: (error) => { },
26
+ /** Log an informational message from the multiplayer server. */
27
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28
+ info: (...args) => { },
29
+ }),
30
+ backendOrigin: nullableShape(''),
31
+ games: unionShape({
32
+ /**
33
+ * Allow specific games by id. If a game id is not matched, the below `default`
34
+ * requirement is checked. If no game id is matched and there is no specified `default`
35
+ * requirement, the request is blocked.
36
+ *
37
+ * If a game id's origin requirement is `undefined`, it is not considered a match.
38
+ */
39
+ byId: recordShape({
40
+ keys: '',
41
+ values: originRequirementShape,
42
+ }),
43
+ /**
44
+ * The default requirement for all unmatched game ids. If this is omitted or
45
+ * `undefined`, all unmatched game ids are blocked.
46
+ */
47
+ default: optionalShape(originRequirementShape, {
48
+ alsoUndefined: true,
49
+ }),
50
+ }, {
51
+ byId: optionalShape(recordShape({
52
+ keys: '',
53
+ values: originRequirementShape,
54
+ }), {
55
+ alsoUndefined: true,
56
+ }),
57
+ default: originRequirementShape,
58
+ }),
59
+ });
6
60
  /**
7
61
  * The default logger for {@link ImplementedMultiplayerApi}.
8
62
  *
@@ -59,7 +113,14 @@ export function implementMultiplayerApi(options) {
59
113
  },
60
114
  };
61
115
  }
62
- else if (!(await checkOriginRequirement(extractOrigin(requestHeaders), originRequirement))) {
116
+ else if (await checkOriginRequirement(extractOrigin(requestHeaders), originRequirement)) {
117
+ return {
118
+ context: {
119
+ gameId,
120
+ },
121
+ };
122
+ }
123
+ else {
63
124
  serverState.logger.error(new TypeError(`Origin check failed for game: '${gameId}'`));
64
125
  return {
65
126
  reject: {
@@ -67,11 +128,6 @@ export function implementMultiplayerApi(options) {
67
128
  },
68
129
  };
69
130
  }
70
- return {
71
- context: {
72
- gameId,
73
- },
74
- };
75
131
  },
76
132
  endpoints: [
77
133
  implementor.implementEndpoint(multiplayerRootEndpoint, {
@@ -1,17 +1,66 @@
1
- import { type SetRequired } from '@augment-vir/common';
2
- import { type RunApiUserOptions } from '@rest-vir/host';
3
- import { type MultiplayerServerOptions } from './implemented-multiplayer-api.js';
1
+ /**
2
+ * Shape definition for {@link StartMultiplayerServerOptions}.
3
+ *
4
+ * @category Internal
5
+ */
6
+ export declare const startMultiplayerServerOptionsShape: import("object-shape-tester").Shape<import("object-shape-tester").Shape<import("@sinclair/typebox").TUnsafe<{
7
+ logger?: {
8
+ error: (error: Error) => void;
9
+ info: (...args: ReadonlyArray<unknown>) => void;
10
+ } | null | undefined;
11
+ backendOrigin?: string | null | undefined;
12
+ games: {
13
+ default?: string | RegExp | import("@rest-vir/api").OriginCheckCallback | {
14
+ anyOriginWithCredentials?: undefined;
15
+ anyOrigin: true;
16
+ } | {
17
+ anyOrigin?: undefined;
18
+ anyOriginWithCredentials: true;
19
+ } | undefined;
20
+ byId: Record<string, string | RegExp | import("@rest-vir/api").OriginCheckCallback | {
21
+ anyOriginWithCredentials?: undefined;
22
+ anyOrigin: true;
23
+ } | {
24
+ anyOrigin?: undefined;
25
+ anyOriginWithCredentials: true;
26
+ }>;
27
+ } | {
28
+ byId?: Record<string, string | RegExp | import("@rest-vir/api").OriginCheckCallback | {
29
+ anyOriginWithCredentials?: undefined;
30
+ anyOrigin: true;
31
+ } | {
32
+ anyOrigin?: undefined;
33
+ anyOriginWithCredentials: true;
34
+ }> | undefined;
35
+ default: string | RegExp | import("@rest-vir/api").OriginCheckCallback | {
36
+ anyOriginWithCredentials?: undefined;
37
+ anyOrigin: true;
38
+ } | {
39
+ anyOrigin?: undefined;
40
+ anyOriginWithCredentials: true;
41
+ };
42
+ };
43
+ } & {
44
+ host?: string | undefined;
45
+ lockPort?: boolean | undefined;
46
+ debug?: boolean | undefined;
47
+ port: number | undefined;
48
+ }>>>;
49
+ /**
50
+ * Args for {@link startMultiplayerServer}.
51
+ *
52
+ * @category Internal
53
+ */
54
+ export type StartMultiplayerServerOptions = typeof startMultiplayerServerOptionsShape.runtimeType;
4
55
  /**
5
56
  * Starts the multiplayer server.
6
57
  *
7
58
  * @category Main
8
59
  */
9
- export declare function startMultiplayerServer(options: Readonly<MultiplayerServerOptions & SetRequired<Pick<RunApiUserOptions, 'host' | 'lockPort' | 'port'>, 'port'> & {
10
- debug?: boolean | undefined;
11
- }>): Promise<{
12
- serverState: import("./implemented-multiplayer-api.js").MultiplayerServerState;
13
- port: number;
60
+ export declare function startMultiplayerServer(options: Readonly<StartMultiplayerServerOptions>): Promise<{
61
+ serverState: import("./multiplayer-api-implementation.js").MultiplayerServerState;
14
62
  host: string;
63
+ port: number;
15
64
  server: import("fastify").FastifyInstance;
16
65
  kill: (this: void) => import("@augment-vir/common").MaybePromise<void>;
17
66
  }>;
@@ -1,7 +1,25 @@
1
1
  import { defaultMultiplayerApiOrigin } from '@antha/multiplayer-core';
2
2
  import { omitObjectKeys } from '@augment-vir/common';
3
3
  import { startApiServer } from '@rest-vir/host';
4
- import { implementMultiplayerApi, } from './implemented-multiplayer-api.js';
4
+ import { defineShape, intersectShape, optionalShape, unionShape } from 'object-shape-tester';
5
+ import { implementMultiplayerApi, multiplayerServerOptionsShape, } from './multiplayer-api-implementation.js';
6
+ /**
7
+ * Shape definition for {@link StartMultiplayerServerOptions}.
8
+ *
9
+ * @category Internal
10
+ */
11
+ export const startMultiplayerServerOptionsShape = defineShape(intersectShape(multiplayerServerOptionsShape, {
12
+ host: optionalShape('', {
13
+ alsoUndefined: true,
14
+ }),
15
+ lockPort: optionalShape(false, {
16
+ alsoUndefined: true,
17
+ }),
18
+ port: unionShape(0, undefined),
19
+ debug: optionalShape(false, {
20
+ alsoUndefined: true,
21
+ }),
22
+ }));
5
23
  /**
6
24
  * Starts the multiplayer server.
7
25
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antha/multiplayer-server",
3
- "version": "0.0.8",
3
+ "version": "0.1.1",
4
4
  "description": "An multiplayer server that can be used with the Antha multiplayer mod.",
5
5
  "keywords": [
6
6
  "vir",
@@ -27,6 +27,9 @@
27
27
  "main": "dist/index.js",
28
28
  "module": "dist/index.js",
29
29
  "types": "dist/index.d.ts",
30
+ "bin": {
31
+ "start-mp-server": "dist/cli/bin.script.js"
32
+ },
30
33
  "scripts": {
31
34
  "compile": "virmator compile",
32
35
  "docs": "virmator docs",
@@ -35,26 +38,30 @@
35
38
  "test:docs": "virmator docs check"
36
39
  },
37
40
  "dependencies": {
38
- "@antha/multiplayer-p2p-lock-step": "^0.0.8",
39
- "@augment-vir/assert": "^31.73.1",
40
- "@augment-vir/common": "^31.73.1",
41
- "@rest-vir/api": "^2.2.0",
42
- "@rest-vir/host": "^2.2.0",
43
- "date-vir": "^8.5.0",
44
- "object-shape-tester": "^6.14.0",
45
- "type-fest": "^5.7.0"
41
+ "@antha/multiplayer-core": "^0.1.1",
42
+ "@antha/multiplayer-p2p-lock-step": "^0.1.1",
43
+ "@augment-vir/assert": "^32.2.2",
44
+ "@augment-vir/common": "^32.2.2",
45
+ "@augment-vir/node": "^32.2.2",
46
+ "@rest-vir/api": "^2.3.1",
47
+ "@rest-vir/host": "^2.3.1",
48
+ "cli-vir": "^1.0.5",
49
+ "config-vir": "^1.0.1",
50
+ "date-vir": "^9.0.0",
51
+ "object-shape-tester": "^6.14.1"
46
52
  },
47
53
  "devDependencies": {
48
- "@augment-vir/test": "^31.73.1",
49
- "@types/node": "^25.9.3",
50
- "@web/dev-server-esbuild": "^1.0.5",
51
- "@web/test-runner": "^0.20.2",
52
- "@web/test-runner-playwright": "^0.11.1",
53
- "c8": "^11.0.0",
54
- "istanbul-smart-text-reporter": "^1.1.5"
54
+ "@augment-vir/test": "^32.2.2",
55
+ "@types/node": "^26.2.0",
56
+ "@web/dev-server-esbuild": "^2.0.0",
57
+ "@web/test-runner": "^1.0.0",
58
+ "@web/test-runner-playwright": "^1.0.0",
59
+ "c8": "^12.0.0",
60
+ "istanbul-smart-text-reporter": "^1.1.5",
61
+ "tsx": "^4.23.11"
55
62
  },
56
63
  "peerDependencies": {
57
- "@antha/engine": "^0.0.8"
64
+ "@antha/engine": "^0.1.1"
58
65
  },
59
66
  "engines": {
60
67
  "node": ">=22"
@@ -1,84 +0,0 @@
1
- import { type MultiplayerRoomHandler } from '@antha/multiplayer-core';
2
- import { type PartialWithUndefined } from '@augment-vir/common';
3
- import { type OriginRequirement } from '@rest-vir/api';
4
- import { type ServerLogger } from '@rest-vir/host';
5
- import { type RequireAtLeastOne } from 'type-fest';
6
- /**
7
- * Multiplayer server options.
8
- *
9
- * @category Internal
10
- */
11
- export type MultiplayerServerOptions = PartialWithUndefined<{
12
- /**
13
- * The Multiplayer server's logger.
14
- *
15
- * For help setting this, see any of the following from `@rest-vir/host`:
16
- *
17
- * - `silentServerLogger`
18
- * - `defaultServerLogger`
19
- * - `createServerLogger`
20
- */
21
- logger: ServerLogger;
22
- backendOrigin: string;
23
- }> & {
24
- games: RequireAtLeastOne<{
25
- /**
26
- * Allow specific games by id. If a game id is not matched, the below `default` requirement
27
- * is checked. If no game id is matched and there is no specified `default` requirement, the
28
- * request is blocked.
29
- *
30
- * If a game id's origin requirement is `undefined`, it is not considered a match.
31
- */
32
- byId: {
33
- [GameId in string]: OriginRequirement;
34
- };
35
- /**
36
- * The default requirement for all unmatched game ids. If this is omitted or `undefined`,
37
- * all unmatched game ids are blocked.
38
- */
39
- default: OriginRequirement;
40
- }>;
41
- };
42
- /**
43
- * Internal state for the multiplayer server.
44
- *
45
- * @category Internal
46
- */
47
- export type MultiplayerServerState = {
48
- roomHandler: MultiplayerRoomHandler;
49
- logger: ServerLogger;
50
- };
51
- /**
52
- * The default logger for {@link ImplementedMultiplayerApi}.
53
- *
54
- * @category Internal
55
- */
56
- export declare const defaultMultiplayerApiLogger: ServerLogger;
57
- /**
58
- * Per-request host context derived from the multiplayer API request.
59
- *
60
- * @category Internal
61
- */
62
- export type MultiplayerHostContext = {
63
- /** Game id associated with the request or WebSocket connection. */
64
- gameId: string;
65
- };
66
- /**
67
- * The implemented API returned from {@link implementMultiplayerApi}.
68
- *
69
- * @category Internal
70
- */
71
- export type ImplementedMultiplayerApi = ReturnType<typeof implementMultiplayerApi>['api'];
72
- /**
73
- * Implements the multiplayer API.
74
- *
75
- * @category Internal
76
- */
77
- export declare function implementMultiplayerApi(options: MultiplayerServerOptions): {
78
- serverState: MultiplayerServerState;
79
- api: Readonly<import("@rest-vir/host").ApiImplementation<{
80
- apiName: string;
81
- endpoints: Readonly<Record<"/" | "/health" | "/rooms", Readonly<import("@rest-vir/api").EndpointDefinition>>>;
82
- webSockets: Readonly<Record<"/connect", Readonly<import("@rest-vir/api").WebSocketDefinition>>>;
83
- }, MultiplayerHostContext>>;
84
- };