@antha/multiplayer-server 0.0.8 → 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/dist/cli/bin.script.d.ts +2 -0
- package/dist/cli/bin.script.js +19 -0
- package/dist/cli/cli.d.ts +6 -0
- package/dist/cli/cli.js +14 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/multiplayer-api-implementation.d.ts +103 -0
- package/dist/{implemented-multiplayer-api.js → multiplayer-api-implementation.js} +63 -7
- package/dist/start-server.d.ts +57 -8
- package/dist/start-server.js +19 -1
- package/package.json +24 -17
- package/dist/implemented-multiplayer-api.d.ts +0 -84
|
@@ -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);
|
package/dist/cli/cli.js
ADDED
|
@@ -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
package/dist/index.js
CHANGED
|
@@ -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 (
|
|
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, {
|
package/dist/start-server.d.ts
CHANGED
|
@@ -1,17 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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<
|
|
10
|
-
|
|
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
|
}>;
|
package/dist/start-server.js
CHANGED
|
@@ -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 {
|
|
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
|
|
3
|
+
"version": "0.1.0",
|
|
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-
|
|
39
|
-
"@
|
|
40
|
-
"@augment-vir/
|
|
41
|
-
"@
|
|
42
|
-
"@
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
41
|
+
"@antha/multiplayer-core": "^0.1.0",
|
|
42
|
+
"@antha/multiplayer-p2p-lock-step": "^0.1.0",
|
|
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": "^
|
|
49
|
-
"@types/node": "^
|
|
50
|
-
"@web/dev-server-esbuild": "^
|
|
51
|
-
"@web/test-runner": "^0.
|
|
52
|
-
"@web/test-runner-playwright": "^0.
|
|
53
|
-
"c8": "^
|
|
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
|
|
64
|
+
"@antha/engine": "^0.1.0"
|
|
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
|
-
};
|