@antha/multiplayer-server 0.1.1 → 0.1.2

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
@@ -29,7 +29,7 @@ await startMultiplayerServer({
29
29
 
30
30
  ## CLI
31
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`.
32
+ The `start-mp-server` command accepts a required path to a JavaScript, TypeScript, JSON, YAML, or TOML configuration file.
33
33
 
34
34
  Create a configuration file:
35
35
 
@@ -53,3 +53,5 @@ Start the server with the configuration file path:
53
53
  ```sh
54
54
  npx start-mp-server ./multiplayer-server.config.mjs
55
55
  ```
56
+
57
+ [The `ensure-service` package](https://www.npmjs.com/package/ensure-service) is recommended for making sure the server stays up.
package/dist/cli/cli.d.ts CHANGED
@@ -1,6 +1,207 @@
1
+ /**
2
+ * Shape definition for {@link MultiplayerServerCliConfig}.
3
+ *
4
+ * @category Internal
5
+ */
6
+ declare const multiplayerServerCliConfigShape: 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
+ configReloadInterval?: (Required<Pick<{
50
+ years: number;
51
+ months: number;
52
+ weeks: number;
53
+ days: number;
54
+ hours: number;
55
+ minutes: number;
56
+ seconds: number;
57
+ milliseconds: number;
58
+ }, import("date-vir").DurationUnit.Years>> & Partial<Pick<{
59
+ years: number;
60
+ months: number;
61
+ weeks: number;
62
+ days: number;
63
+ hours: number;
64
+ minutes: number;
65
+ seconds: number;
66
+ milliseconds: number;
67
+ }, import("date-vir").DurationUnit.Months | import("date-vir").DurationUnit.Weeks | import("date-vir").DurationUnit.Days | import("date-vir").DurationUnit.Hours | import("date-vir").DurationUnit.Minutes | import("date-vir").DurationUnit.Seconds | import("date-vir").DurationUnit.Milliseconds>>) | (Required<Pick<{
68
+ years: number;
69
+ months: number;
70
+ weeks: number;
71
+ days: number;
72
+ hours: number;
73
+ minutes: number;
74
+ seconds: number;
75
+ milliseconds: number;
76
+ }, import("date-vir").DurationUnit.Months>> & Partial<Pick<{
77
+ years: number;
78
+ months: number;
79
+ weeks: number;
80
+ days: number;
81
+ hours: number;
82
+ minutes: number;
83
+ seconds: number;
84
+ milliseconds: number;
85
+ }, import("date-vir").DurationUnit.Years | import("date-vir").DurationUnit.Weeks | import("date-vir").DurationUnit.Days | import("date-vir").DurationUnit.Hours | import("date-vir").DurationUnit.Minutes | import("date-vir").DurationUnit.Seconds | import("date-vir").DurationUnit.Milliseconds>>) | (Required<Pick<{
86
+ years: number;
87
+ months: number;
88
+ weeks: number;
89
+ days: number;
90
+ hours: number;
91
+ minutes: number;
92
+ seconds: number;
93
+ milliseconds: number;
94
+ }, import("date-vir").DurationUnit.Weeks>> & Partial<Pick<{
95
+ years: number;
96
+ months: number;
97
+ weeks: number;
98
+ days: number;
99
+ hours: number;
100
+ minutes: number;
101
+ seconds: number;
102
+ milliseconds: number;
103
+ }, import("date-vir").DurationUnit.Years | import("date-vir").DurationUnit.Months | import("date-vir").DurationUnit.Days | import("date-vir").DurationUnit.Hours | import("date-vir").DurationUnit.Minutes | import("date-vir").DurationUnit.Seconds | import("date-vir").DurationUnit.Milliseconds>>) | (Required<Pick<{
104
+ years: number;
105
+ months: number;
106
+ weeks: number;
107
+ days: number;
108
+ hours: number;
109
+ minutes: number;
110
+ seconds: number;
111
+ milliseconds: number;
112
+ }, import("date-vir").DurationUnit.Days>> & Partial<Pick<{
113
+ years: number;
114
+ months: number;
115
+ weeks: number;
116
+ days: number;
117
+ hours: number;
118
+ minutes: number;
119
+ seconds: number;
120
+ milliseconds: number;
121
+ }, import("date-vir").DurationUnit.Years | import("date-vir").DurationUnit.Months | import("date-vir").DurationUnit.Weeks | import("date-vir").DurationUnit.Hours | import("date-vir").DurationUnit.Minutes | import("date-vir").DurationUnit.Seconds | import("date-vir").DurationUnit.Milliseconds>>) | (Required<Pick<{
122
+ years: number;
123
+ months: number;
124
+ weeks: number;
125
+ days: number;
126
+ hours: number;
127
+ minutes: number;
128
+ seconds: number;
129
+ milliseconds: number;
130
+ }, import("date-vir").DurationUnit.Hours>> & Partial<Pick<{
131
+ years: number;
132
+ months: number;
133
+ weeks: number;
134
+ days: number;
135
+ hours: number;
136
+ minutes: number;
137
+ seconds: number;
138
+ milliseconds: number;
139
+ }, import("date-vir").DurationUnit.Years | import("date-vir").DurationUnit.Months | import("date-vir").DurationUnit.Weeks | import("date-vir").DurationUnit.Days | import("date-vir").DurationUnit.Minutes | import("date-vir").DurationUnit.Seconds | import("date-vir").DurationUnit.Milliseconds>>) | (Required<Pick<{
140
+ years: number;
141
+ months: number;
142
+ weeks: number;
143
+ days: number;
144
+ hours: number;
145
+ minutes: number;
146
+ seconds: number;
147
+ milliseconds: number;
148
+ }, import("date-vir").DurationUnit.Minutes>> & Partial<Pick<{
149
+ years: number;
150
+ months: number;
151
+ weeks: number;
152
+ days: number;
153
+ hours: number;
154
+ minutes: number;
155
+ seconds: number;
156
+ milliseconds: number;
157
+ }, import("date-vir").DurationUnit.Years | import("date-vir").DurationUnit.Months | import("date-vir").DurationUnit.Weeks | import("date-vir").DurationUnit.Days | import("date-vir").DurationUnit.Hours | import("date-vir").DurationUnit.Seconds | import("date-vir").DurationUnit.Milliseconds>>) | (Required<Pick<{
158
+ years: number;
159
+ months: number;
160
+ weeks: number;
161
+ days: number;
162
+ hours: number;
163
+ minutes: number;
164
+ seconds: number;
165
+ milliseconds: number;
166
+ }, import("date-vir").DurationUnit.Seconds>> & Partial<Pick<{
167
+ years: number;
168
+ months: number;
169
+ weeks: number;
170
+ days: number;
171
+ hours: number;
172
+ minutes: number;
173
+ seconds: number;
174
+ milliseconds: number;
175
+ }, import("date-vir").DurationUnit.Years | import("date-vir").DurationUnit.Months | import("date-vir").DurationUnit.Weeks | import("date-vir").DurationUnit.Days | import("date-vir").DurationUnit.Hours | import("date-vir").DurationUnit.Minutes | import("date-vir").DurationUnit.Milliseconds>>) | (Required<Pick<{
176
+ years: number;
177
+ months: number;
178
+ weeks: number;
179
+ days: number;
180
+ hours: number;
181
+ minutes: number;
182
+ seconds: number;
183
+ milliseconds: number;
184
+ }, import("date-vir").DurationUnit.Milliseconds>> & Partial<Pick<{
185
+ years: number;
186
+ months: number;
187
+ weeks: number;
188
+ days: number;
189
+ hours: number;
190
+ minutes: number;
191
+ seconds: number;
192
+ milliseconds: number;
193
+ }, import("date-vir").DurationUnit.Years | import("date-vir").DurationUnit.Months | import("date-vir").DurationUnit.Weeks | import("date-vir").DurationUnit.Days | import("date-vir").DurationUnit.Hours | import("date-vir").DurationUnit.Minutes | import("date-vir").DurationUnit.Seconds>>) | null | undefined;
194
+ }>>;
195
+ /**
196
+ * Config for the CLI.
197
+ *
198
+ * @category CLI
199
+ */
200
+ export type MultiplayerServerCliConfig = typeof multiplayerServerCliConfigShape.runtimeType;
1
201
  /**
2
202
  * Load a config file and start the multiplayer server from its options.
3
203
  *
4
204
  * @category Internal
5
205
  */
6
206
  export declare function runMultiplayerServerCli(configFilePath: string): Promise<void>;
207
+ export {};
package/dist/cli/cli.js CHANGED
@@ -1,14 +1,51 @@
1
+ import { assert } from '@augment-vir/assert';
2
+ import { ensureErrorAndPrependMessage, log } from '@augment-vir/common';
1
3
  import { loadConfig } from 'config-vir';
4
+ import { atLeastOneDurationShape, convertDuration } from 'date-vir';
5
+ import { intersectShape, nullableShape } from 'object-shape-tester';
2
6
  import { startMultiplayerServer, startMultiplayerServerOptionsShape } from '../start-server.js';
7
+ /**
8
+ * Shape definition for {@link MultiplayerServerCliConfig}.
9
+ *
10
+ * @category Internal
11
+ */
12
+ const multiplayerServerCliConfigShape = intersectShape(startMultiplayerServerOptionsShape, {
13
+ /**
14
+ * How often to reload the config file.
15
+ *
16
+ * @default `{minutes: 5}`
17
+ */
18
+ configReloadInterval: nullableShape(atLeastOneDurationShape()),
19
+ });
3
20
  /**
4
21
  * Load a config file and start the multiplayer server from its options.
5
22
  *
6
23
  * @category Internal
7
24
  */
8
25
  export async function runMultiplayerServerCli(configFilePath) {
9
- const config = await loadConfig({
10
- configPath: configFilePath,
11
- configShape: startMultiplayerServerOptionsShape,
12
- });
26
+ const config = await loadServerCliConfig(configFilePath, {});
27
+ assert.isDefined(config, 'No config loaded.');
13
28
  await startMultiplayerServer(config);
14
29
  }
30
+ async function loadServerCliConfig(configFilePath, existingConfig) {
31
+ try {
32
+ Object.assign(existingConfig, await loadConfig({
33
+ configPath: configFilePath,
34
+ configShape: multiplayerServerCliConfigShape,
35
+ }));
36
+ return existingConfig;
37
+ }
38
+ catch (error) {
39
+ log.error(ensureErrorAndPrependMessage(error, 'Failed to reload multiplayer config.'));
40
+ return undefined;
41
+ }
42
+ finally {
43
+ globalThis.setTimeout(async () => {
44
+ await loadServerCliConfig(configFilePath, existingConfig);
45
+ }, convertDuration(existingConfig.configReloadInterval || {
46
+ minutes: 5,
47
+ }, {
48
+ milliseconds: true,
49
+ }).milliseconds);
50
+ }
51
+ }
@@ -20,6 +20,7 @@ export declare const multiplayerServerOptionsShape: import("object-shape-tester"
20
20
  info: import("@sinclair/typebox").TUnsafe<(...args: ReadonlyArray<unknown>) => void>;
21
21
  }>)[]>>>;
22
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
+ /** The server's supported list of games. */
23
24
  games: import("object-shape-tester").Shape<import("@sinclair/typebox").TUnion<(import("@sinclair/typebox").TObject<{
24
25
  byId: import("@sinclair/typebox").TUnsafe<Record<string, string | RegExp | import("@rest-vir/api").OriginCheckCallback | {
25
26
  anyOriginWithCredentials?: undefined;
@@ -93,7 +94,9 @@ export type ImplementedMultiplayerApi = ReturnType<typeof implementMultiplayerAp
93
94
  *
94
95
  * @category Internal
95
96
  */
96
- export declare function implementMultiplayerApi(options: MultiplayerServerOptions): {
97
+ export declare function implementMultiplayerApi(
98
+ /** Server options. Any external mutations made to this object will be picked up by the server. */
99
+ options: Readonly<MultiplayerServerOptions>): {
97
100
  serverState: MultiplayerServerState;
98
101
  api: Readonly<import("@rest-vir/host").ApiImplementation<{
99
102
  apiName: string;
@@ -28,6 +28,7 @@ export const multiplayerServerOptionsShape = defineShape({
28
28
  info: (...args) => { },
29
29
  }),
30
30
  backendOrigin: nullableShape(''),
31
+ /** The server's supported list of games. */
31
32
  games: unionShape({
32
33
  /**
33
34
  * Allow specific games by id. If a game id is not matched, the below `default`
@@ -71,7 +72,9 @@ export const defaultMultiplayerApiLogger = {
71
72
  *
72
73
  * @category Internal
73
74
  */
74
- export function implementMultiplayerApi(options) {
75
+ export function implementMultiplayerApi(
76
+ /** Server options. Any external mutations made to this object will be picked up by the server. */
77
+ options) {
75
78
  const logger = options.logger || defaultMultiplayerApiLogger;
76
79
  const roomHandler = createMultiplayerRoomHandler({
77
80
  logger,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antha/multiplayer-server",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "An multiplayer server that can be used with the Antha multiplayer mod.",
5
5
  "keywords": [
6
6
  "vir",
@@ -38,17 +38,17 @@
38
38
  "test:docs": "virmator docs check"
39
39
  },
40
40
  "dependencies": {
41
- "@antha/multiplayer-core": "^0.1.1",
42
- "@antha/multiplayer-p2p-lock-step": "^0.1.1",
41
+ "@antha/multiplayer-core": "^0.1.2",
42
+ "@antha/multiplayer-p2p-lock-step": "^0.1.2",
43
43
  "@augment-vir/assert": "^32.2.2",
44
44
  "@augment-vir/common": "^32.2.2",
45
45
  "@augment-vir/node": "^32.2.2",
46
46
  "@rest-vir/api": "^2.3.1",
47
47
  "@rest-vir/host": "^2.3.1",
48
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"
49
+ "config-vir": "^1.0.5",
50
+ "date-vir": "^9.1.0",
51
+ "object-shape-tester": "^6.15.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@augment-vir/test": "^32.2.2",
@@ -58,10 +58,10 @@
58
58
  "@web/test-runner-playwright": "^1.0.0",
59
59
  "c8": "^12.0.0",
60
60
  "istanbul-smart-text-reporter": "^1.1.5",
61
- "tsx": "^4.23.11"
61
+ "tsx": "^4.23.12"
62
62
  },
63
63
  "peerDependencies": {
64
- "@antha/engine": "^0.1.1"
64
+ "@antha/engine": "^0.1.2"
65
65
  },
66
66
  "engines": {
67
67
  "node": ">=22"