@diffenderfer-games/hub-contract 2.0.0-next.0 → 2.0.0-next.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/CHANGELOG.md +24 -0
- package/LICENSE +21 -21
- package/README.md +26 -26
- package/dist/index.d.ts +2683 -39
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +862 -18
- package/dist/index.js.map +1 -1
- package/package.json +53 -53
- package/src/api/analytics.ts +81 -81
- package/src/api/auth.ts +77 -77
- package/src/api/catalog-activity.ts +66 -0
- package/src/api/catalog.ts +177 -171
- package/src/api/daily.ts +122 -122
- package/src/api/economy/bundle.ts +69 -69
- package/src/api/index.ts +92 -85
- package/src/api/leaderboards.ts +151 -151
- package/src/api/messages.ts +142 -142
- package/src/api/mp/chat.ts +36 -36
- package/src/api/mp/invite-links.ts +42 -0
- package/src/api/mp/parties.ts +5 -0
- package/src/api/mp/races.ts +211 -211
- package/src/api/mp/rooms.ts +122 -90
- package/src/api/mp/snapshot.ts +17 -17
- package/src/api/mp.ts +135 -110
- package/src/api/notify.ts +114 -111
- package/src/api/offline.ts +45 -0
- package/src/api/progress/game-data.ts +189 -189
- package/src/api/progress.ts +59 -59
- package/src/api/race.ts +47 -47
- package/src/api/reports.ts +208 -208
- package/src/api/social/config.ts +47 -47
- package/src/api/social/endpoints.ts +179 -179
- package/src/api/social/people.ts +118 -118
- package/src/api/social/presence.ts +95 -95
- package/src/api/social.ts +9 -9
- package/src/api/tournaments/endpoints.ts +102 -0
- package/src/api/tournaments/play-online.ts +71 -0
- package/src/api/tournaments/shapes.ts +202 -0
- package/src/api/tournaments.ts +7 -0
- package/src/api/version.ts +40 -40
- package/src/coerce.ts +50 -50
- package/src/common.ts +42 -42
- package/src/entities.ts +62 -62
- package/src/errors/codes/core.ts +10 -10
- package/src/errors/codes/multiplayer.ts +56 -43
- package/src/errors/codes/play.ts +5 -5
- package/src/errors/codes/social.ts +31 -31
- package/src/errors/index.ts +88 -88
- package/src/index.ts +16 -16
- package/src/limits.ts +125 -100
- package/src/logic/daily.ts +54 -54
- package/src/logic/index.ts +8 -8
- package/src/logic/presence.ts +62 -62
- package/src/logic/time.ts +81 -81
- package/src/manifest/changes.ts +55 -55
- package/src/manifest/controls.ts +42 -42
- package/src/manifest/fields.ts +89 -89
- package/src/manifest/game.ts +139 -132
- package/src/manifest/index.ts +13 -12
- package/src/manifest/inject.ts +31 -31
- package/src/manifest/labels.ts +99 -0
- package/src/manifest/leaderboards.ts +29 -29
- package/src/manifest/multiplayer.ts +79 -71
- package/src/manifest/race.ts +93 -93
- package/src/middleware.ts +47 -47
- package/src/realtime/define.ts +52 -52
- package/src/realtime/envelope.ts +67 -67
- package/src/realtime/events/multiplayer.ts +9 -8
- package/src/realtime/events/parties.ts +31 -31
- package/src/realtime/events/races.ts +27 -27
- package/src/realtime/events/rooms.ts +52 -48
- package/src/realtime/events/social.ts +81 -81
- package/src/realtime/events/tournaments.ts +12 -0
- package/src/realtime/index.ts +24 -24
- package/src/realtime/ops/empty.ts +8 -8
- package/src/realtime/ops/hello.ts +40 -40
- package/src/realtime/ops/multiplayer.ts +8 -8
- package/src/realtime/ops/parties.ts +13 -13
- package/src/realtime/ops/races.ts +99 -99
- package/src/realtime/ops/rooms.ts +22 -8
- package/src/realtime/ops/social.ts +58 -58
package/src/api/version.ts
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `GET /version`: which client versions this hub serves (plan §4.3.3). Games'
|
|
3
|
-
* clients read it once per page, and `hub-doctor` reads it in a game's CI.
|
|
4
|
-
* The old hub has no such route and answers 404 "No such API endpoint.", which
|
|
5
|
-
* clients read as "a hub from before versioning".
|
|
6
|
-
*/
|
|
7
|
-
import { z } from 'zod';
|
|
8
|
-
import { session } from '../middleware';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* A semver range in the npm form: comparators (`>=2.0.0-0`, `<3.0.0`)
|
|
12
|
-
* separated by spaces are all required; `||` separates alternatives.
|
|
13
|
-
*/
|
|
14
|
-
export const VersionRange = z.string().min(1);
|
|
15
|
-
|
|
16
|
-
/** What `GET /version` answers. */
|
|
17
|
-
export const HubVersion = z.object({
|
|
18
|
-
/** The hub release this server was built from: the version of the client it serves at `/_hub/hub.js`. */
|
|
19
|
-
server: z.string(),
|
|
20
|
-
/** The version of `@diffenderfer-games/hub-contract` the server implements. */
|
|
21
|
-
contract: z.string(),
|
|
22
|
-
/** Client versions the server supports (`x-hub-client`); a client outside it should be updated. */
|
|
23
|
-
supported: VersionRange,
|
|
24
|
-
/** Supported client versions that are deprecated: they still work, and `hub-doctor` warns. */
|
|
25
|
-
deprecated: VersionRange,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
/** The hub's version and the client versions it supports. */
|
|
29
|
-
export type HubVersion = z.infer<typeof HubVersion>;
|
|
30
|
-
|
|
31
|
-
/** The version endpoints. */
|
|
32
|
-
export const versionEndpoints = {
|
|
33
|
-
...session.group({
|
|
34
|
-
getHubVersion: {
|
|
35
|
-
method: 'GET', path: '/version',
|
|
36
|
-
response: HubVersion,
|
|
37
|
-
doc: { summary: 'The hub version and the client versions it supports', tags: ['catalog'] },
|
|
38
|
-
},
|
|
39
|
-
}),
|
|
40
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* `GET /version`: which client versions this hub serves (plan §4.3.3). Games'
|
|
3
|
+
* clients read it once per page, and `hub-doctor` reads it in a game's CI.
|
|
4
|
+
* The old hub has no such route and answers 404 "No such API endpoint.", which
|
|
5
|
+
* clients read as "a hub from before versioning".
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { session } from '../middleware';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A semver range in the npm form: comparators (`>=2.0.0-0`, `<3.0.0`)
|
|
12
|
+
* separated by spaces are all required; `||` separates alternatives.
|
|
13
|
+
*/
|
|
14
|
+
export const VersionRange = z.string().min(1);
|
|
15
|
+
|
|
16
|
+
/** What `GET /version` answers. */
|
|
17
|
+
export const HubVersion = z.object({
|
|
18
|
+
/** The hub release this server was built from: the version of the client it serves at `/_hub/hub.js`. */
|
|
19
|
+
server: z.string(),
|
|
20
|
+
/** The version of `@diffenderfer-games/hub-contract` the server implements. */
|
|
21
|
+
contract: z.string(),
|
|
22
|
+
/** Client versions the server supports (`x-hub-client`); a client outside it should be updated. */
|
|
23
|
+
supported: VersionRange,
|
|
24
|
+
/** Supported client versions that are deprecated: they still work, and `hub-doctor` warns. */
|
|
25
|
+
deprecated: VersionRange,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/** The hub's version and the client versions it supports. */
|
|
29
|
+
export type HubVersion = z.infer<typeof HubVersion>;
|
|
30
|
+
|
|
31
|
+
/** The version endpoints. */
|
|
32
|
+
export const versionEndpoints = {
|
|
33
|
+
...session.group({
|
|
34
|
+
getHubVersion: {
|
|
35
|
+
method: 'GET', path: '/version',
|
|
36
|
+
response: HubVersion,
|
|
37
|
+
doc: { summary: 'The hub version and the client versions it supports', tags: ['catalog'] },
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
};
|
package/src/coerce.ts
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request coercions the single-player handlers apply today. The old hub reads
|
|
3
|
-
* many request fields loosely (`Number(x)`, `String(x)`, truthiness), and the
|
|
4
|
-
* contract must accept every request the hub accepts, so these schemas
|
|
5
|
-
* coerce the same way while keeping the input type clients should send.
|
|
6
|
-
*/
|
|
7
|
-
import { z } from 'zod';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* A finite number, read like the hub's `Number(x)`: numeric strings (and
|
|
11
|
-
* query-string values) pass. Clients should send a JSON number.
|
|
12
|
-
*/
|
|
13
|
-
export const LooseNumber = z.coerce.number<number>();
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* A flag read by truthiness, like the hub's `if (body.on)`: any value is
|
|
17
|
-
* accepted and becomes `true` or `false`. Clients should send a boolean.
|
|
18
|
-
*/
|
|
19
|
-
export const Truthy = z.coerce.boolean<boolean>();
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Free text read with `String(x)`; the hub trims or clips it to its own limit
|
|
23
|
-
* rather than rejecting it. Clients should send a string.
|
|
24
|
-
*/
|
|
25
|
-
export const LooseText = z.coerce.string<string>();
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* A row count from the query string (`?limit=`, `?top=`). The hub clamps it to
|
|
29
|
-
* its own range and falls back to a default for `0` or a missing value.
|
|
30
|
-
*/
|
|
31
|
-
export const RowCount = LooseNumber.int();
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Required text read like the hub's `String(x || '')`, with the old hub's
|
|
35
|
-
* message for a missing or invalid value. Numbers are accepted and become
|
|
36
|
-
* strings; anything else fails with `message`. Refine the result with
|
|
37
|
-
* `.pipe(...)` (e.g. a pattern carrying the same message).
|
|
38
|
-
*/
|
|
39
|
-
export function requiredText(message: string) {
|
|
40
|
-
return z.union([z.string(), z.number()], { error: message }).transform(String);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* A positive integer id read like the hub's `Number(x)` (numeric strings
|
|
45
|
-
* pass), with the old hub's message for any bad value (`"id must be a user
|
|
46
|
-
* id."`). Clients should send a JSON number.
|
|
47
|
-
*/
|
|
48
|
-
export function requiredId(message: string) {
|
|
49
|
-
return z.coerce.number<number>({ error: message }).int({ error: message }).positive({ error: message });
|
|
50
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Request coercions the single-player handlers apply today. The old hub reads
|
|
3
|
+
* many request fields loosely (`Number(x)`, `String(x)`, truthiness), and the
|
|
4
|
+
* contract must accept every request the hub accepts, so these schemas
|
|
5
|
+
* coerce the same way while keeping the input type clients should send.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A finite number, read like the hub's `Number(x)`: numeric strings (and
|
|
11
|
+
* query-string values) pass. Clients should send a JSON number.
|
|
12
|
+
*/
|
|
13
|
+
export const LooseNumber = z.coerce.number<number>();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A flag read by truthiness, like the hub's `if (body.on)`: any value is
|
|
17
|
+
* accepted and becomes `true` or `false`. Clients should send a boolean.
|
|
18
|
+
*/
|
|
19
|
+
export const Truthy = z.coerce.boolean<boolean>();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Free text read with `String(x)`; the hub trims or clips it to its own limit
|
|
23
|
+
* rather than rejecting it. Clients should send a string.
|
|
24
|
+
*/
|
|
25
|
+
export const LooseText = z.coerce.string<string>();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A row count from the query string (`?limit=`, `?top=`). The hub clamps it to
|
|
29
|
+
* its own range and falls back to a default for `0` or a missing value.
|
|
30
|
+
*/
|
|
31
|
+
export const RowCount = LooseNumber.int();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Required text read like the hub's `String(x || '')`, with the old hub's
|
|
35
|
+
* message for a missing or invalid value. Numbers are accepted and become
|
|
36
|
+
* strings; anything else fails with `message`. Refine the result with
|
|
37
|
+
* `.pipe(...)` (e.g. a pattern carrying the same message).
|
|
38
|
+
*/
|
|
39
|
+
export function requiredText(message: string) {
|
|
40
|
+
return z.union([z.string(), z.number()], { error: message }).transform(String);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A positive integer id read like the hub's `Number(x)` (numeric strings
|
|
45
|
+
* pass), with the old hub's message for any bad value (`"id must be a user
|
|
46
|
+
* id."`). Clients should send a JSON number.
|
|
47
|
+
*/
|
|
48
|
+
export function requiredId(message: string) {
|
|
49
|
+
return z.coerce.number<number>({ error: message }).int({ error: message }).positive({ error: message });
|
|
50
|
+
}
|
package/src/common.ts
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Primitives shared by every part of the contract. Each one is the single
|
|
3
|
-
* definition of its rule: the server validates with it, the client's types
|
|
4
|
-
* come from it, and the docs are generated from it.
|
|
5
|
-
*/
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
|
|
8
|
-
/** A user id: a positive integer. In paths it arrives as a string and is coerced. */
|
|
9
|
-
export const UserId = z.number().int().positive();
|
|
10
|
-
|
|
11
|
-
/** A user id taken from a URL path segment (`/players/:userId`). */
|
|
12
|
-
export const UserIdParam = z.coerce.number().int().positive();
|
|
13
|
-
|
|
14
|
-
/** A numeric row id taken from a URL path segment (`/trades/:id`, `/reports/:id`). */
|
|
15
|
-
export const IdParam = z.coerce.number().int().positive();
|
|
16
|
-
|
|
17
|
-
/** Milliseconds since the Unix epoch. */
|
|
18
|
-
export const Millis = z.number().int().nonnegative();
|
|
19
|
-
|
|
20
|
-
/** A game's slug: its folder name under `apps/`, as used in `/<slug>/` URLs. */
|
|
21
|
-
export const Slug = z.string().min(1).max(64);
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* An app-chosen identifier: a save slot, leaderboard key or stat name.
|
|
25
|
-
* Letters, digits and `_ . : -`, 1 to 64 characters.
|
|
26
|
-
*/
|
|
27
|
-
export const Key = z.string().regex(/^[A-Za-z0-9_.:-]{1,64}$/);
|
|
28
|
-
|
|
29
|
-
/** Any JSON value (saves, metadata, room state). */
|
|
30
|
-
export const Json = z.json();
|
|
31
|
-
|
|
32
|
-
/** A JSON value as stored and returned by the hub: never `undefined`. */
|
|
33
|
-
export type Json = z.infer<typeof Json>;
|
|
34
|
-
|
|
35
|
-
/** The `{ ok: true }` body many write endpoints answer with. */
|
|
36
|
-
export const Ok = z.object({ ok: z.literal(true) });
|
|
37
|
-
|
|
38
|
-
/** A UTC day key, `YYYY-MM-DD`. */
|
|
39
|
-
export const DayKey = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
40
|
-
|
|
41
|
-
/** A `#rrggbb` colour. */
|
|
42
|
-
export const HexColor = z.string().regex(/^#[0-9a-fA-F]{6}$/);
|
|
1
|
+
/**
|
|
2
|
+
* Primitives shared by every part of the contract. Each one is the single
|
|
3
|
+
* definition of its rule: the server validates with it, the client's types
|
|
4
|
+
* come from it, and the docs are generated from it.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
/** A user id: a positive integer. In paths it arrives as a string and is coerced. */
|
|
9
|
+
export const UserId = z.number().int().positive();
|
|
10
|
+
|
|
11
|
+
/** A user id taken from a URL path segment (`/players/:userId`). */
|
|
12
|
+
export const UserIdParam = z.coerce.number().int().positive();
|
|
13
|
+
|
|
14
|
+
/** A numeric row id taken from a URL path segment (`/trades/:id`, `/reports/:id`). */
|
|
15
|
+
export const IdParam = z.coerce.number().int().positive();
|
|
16
|
+
|
|
17
|
+
/** Milliseconds since the Unix epoch. */
|
|
18
|
+
export const Millis = z.number().int().nonnegative();
|
|
19
|
+
|
|
20
|
+
/** A game's slug: its folder name under `apps/`, as used in `/<slug>/` URLs. */
|
|
21
|
+
export const Slug = z.string().min(1).max(64);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* An app-chosen identifier: a save slot, leaderboard key or stat name.
|
|
25
|
+
* Letters, digits and `_ . : -`, 1 to 64 characters.
|
|
26
|
+
*/
|
|
27
|
+
export const Key = z.string().regex(/^[A-Za-z0-9_.:-]{1,64}$/);
|
|
28
|
+
|
|
29
|
+
/** Any JSON value (saves, metadata, room state). */
|
|
30
|
+
export const Json = z.json();
|
|
31
|
+
|
|
32
|
+
/** A JSON value as stored and returned by the hub: never `undefined`. */
|
|
33
|
+
export type Json = z.infer<typeof Json>;
|
|
34
|
+
|
|
35
|
+
/** The `{ ok: true }` body many write endpoints answer with. */
|
|
36
|
+
export const Ok = z.object({ ok: z.literal(true) });
|
|
37
|
+
|
|
38
|
+
/** A UTC day key, `YYYY-MM-DD`. */
|
|
39
|
+
export const DayKey = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
40
|
+
|
|
41
|
+
/** A `#rrggbb` colour. */
|
|
42
|
+
export const HexColor = z.string().regex(/^#[0-9a-fA-F]{6}$/);
|
package/src/entities.ts
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entity shapes that several areas of the API share. Shapes used by only one
|
|
3
|
-
* area live in that area's `api/` file.
|
|
4
|
-
*/
|
|
5
|
-
import { z } from 'zod';
|
|
6
|
-
import { Millis, UserId } from './common';
|
|
7
|
-
|
|
8
|
-
/** Account roles. An empty string is a normal player. */
|
|
9
|
-
export const Role = z.enum(['', 'admin']);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The signed-in user as the hub sees it (`GET /me`, socket `hello`).
|
|
13
|
-
* `id`, `username` and `guest` are the long-standing fields; the rest drive
|
|
14
|
-
* social permissions and are only ever sent to the user themself.
|
|
15
|
-
*/
|
|
16
|
-
export const SessionUser = z.object({
|
|
17
|
-
id: UserId,
|
|
18
|
-
username: z.string(),
|
|
19
|
-
/** A temporary account with no password yet; it can be claimed. */
|
|
20
|
-
guest: z.boolean(),
|
|
21
|
-
role: Role,
|
|
22
|
-
/** Avatar token, `''` for the default. */
|
|
23
|
-
avatar: z.string(),
|
|
24
|
-
/** A parent locked chat for this account. */
|
|
25
|
-
chatLock: z.boolean(),
|
|
26
|
-
/** Muted until this time (epoch ms), `0` when not muted. */
|
|
27
|
-
mutedUntil: Millis,
|
|
28
|
-
/** Suspended until this time (epoch ms), `0` when not suspended. */
|
|
29
|
-
suspendedUntil: Millis,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
/** The signed-in user. */
|
|
33
|
-
export type SessionUser = z.infer<typeof SessionUser>;
|
|
34
|
-
|
|
35
|
-
/** The short account shape the auth endpoints return for a new session. */
|
|
36
|
-
export const AuthUser = SessionUser.pick({ id: true, username: true, guest: true });
|
|
37
|
-
|
|
38
|
-
/** The short account shape. */
|
|
39
|
-
export type AuthUser = z.infer<typeof AuthUser>;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The effective chat mode of a conversation, room or the whole site: free
|
|
43
|
-
* text (still filtered), quick-chat phrases only, or no messaging at all.
|
|
44
|
-
* The strictest of the operator setting, the admin switch and every
|
|
45
|
-
* participant (guests and parent-locked accounts are `quick`) applies.
|
|
46
|
-
*/
|
|
47
|
-
export const ChatMode = z.enum(['on', 'quick', 'off']);
|
|
48
|
-
|
|
49
|
-
/** A chat mode. */
|
|
50
|
-
export type ChatMode = z.infer<typeof ChatMode>;
|
|
51
|
-
|
|
52
|
-
/** Another player as lists and cards show them. */
|
|
53
|
-
export const PlayerLite = z.object({
|
|
54
|
-
id: UserId,
|
|
55
|
-
username: z.string(),
|
|
56
|
-
/** Avatar token; never empty (a default is derived from the id). */
|
|
57
|
-
avatar: z.string(),
|
|
58
|
-
guest: z.boolean(),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
/** Another player. */
|
|
62
|
-
export type PlayerLite = z.infer<typeof PlayerLite>;
|
|
1
|
+
/**
|
|
2
|
+
* Entity shapes that several areas of the API share. Shapes used by only one
|
|
3
|
+
* area live in that area's `api/` file.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { Millis, UserId } from './common';
|
|
7
|
+
|
|
8
|
+
/** Account roles. An empty string is a normal player. */
|
|
9
|
+
export const Role = z.enum(['', 'admin']);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The signed-in user as the hub sees it (`GET /me`, socket `hello`).
|
|
13
|
+
* `id`, `username` and `guest` are the long-standing fields; the rest drive
|
|
14
|
+
* social permissions and are only ever sent to the user themself.
|
|
15
|
+
*/
|
|
16
|
+
export const SessionUser = z.object({
|
|
17
|
+
id: UserId,
|
|
18
|
+
username: z.string(),
|
|
19
|
+
/** A temporary account with no password yet; it can be claimed. */
|
|
20
|
+
guest: z.boolean(),
|
|
21
|
+
role: Role,
|
|
22
|
+
/** Avatar token, `''` for the default. */
|
|
23
|
+
avatar: z.string(),
|
|
24
|
+
/** A parent locked chat for this account. */
|
|
25
|
+
chatLock: z.boolean(),
|
|
26
|
+
/** Muted until this time (epoch ms), `0` when not muted. */
|
|
27
|
+
mutedUntil: Millis,
|
|
28
|
+
/** Suspended until this time (epoch ms), `0` when not suspended. */
|
|
29
|
+
suspendedUntil: Millis,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** The signed-in user. */
|
|
33
|
+
export type SessionUser = z.infer<typeof SessionUser>;
|
|
34
|
+
|
|
35
|
+
/** The short account shape the auth endpoints return for a new session. */
|
|
36
|
+
export const AuthUser = SessionUser.pick({ id: true, username: true, guest: true });
|
|
37
|
+
|
|
38
|
+
/** The short account shape. */
|
|
39
|
+
export type AuthUser = z.infer<typeof AuthUser>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The effective chat mode of a conversation, room or the whole site: free
|
|
43
|
+
* text (still filtered), quick-chat phrases only, or no messaging at all.
|
|
44
|
+
* The strictest of the operator setting, the admin switch and every
|
|
45
|
+
* participant (guests and parent-locked accounts are `quick`) applies.
|
|
46
|
+
*/
|
|
47
|
+
export const ChatMode = z.enum(['on', 'quick', 'off']);
|
|
48
|
+
|
|
49
|
+
/** A chat mode. */
|
|
50
|
+
export type ChatMode = z.infer<typeof ChatMode>;
|
|
51
|
+
|
|
52
|
+
/** Another player as lists and cards show them. */
|
|
53
|
+
export const PlayerLite = z.object({
|
|
54
|
+
id: UserId,
|
|
55
|
+
username: z.string(),
|
|
56
|
+
/** Avatar token; never empty (a default is derived from the id). */
|
|
57
|
+
avatar: z.string(),
|
|
58
|
+
guest: z.boolean(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** Another player. */
|
|
62
|
+
export type PlayerLite = z.infer<typeof PlayerLite>;
|
package/src/errors/codes/core.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Error codes any endpoint or socket op can return. */
|
|
2
|
-
export const CORE_CODES = [
|
|
3
|
-
'bad_request',
|
|
4
|
-
'signed_out',
|
|
5
|
-
'suspended',
|
|
6
|
-
'claim_required',
|
|
7
|
-
'rate_limited',
|
|
8
|
-
'content_rejected',
|
|
9
|
-
'too_large',
|
|
10
|
-
] as const;
|
|
1
|
+
/** Error codes any endpoint or socket op can return. */
|
|
2
|
+
export const CORE_CODES = [
|
|
3
|
+
'bad_request',
|
|
4
|
+
'signed_out',
|
|
5
|
+
'suspended',
|
|
6
|
+
'claim_required',
|
|
7
|
+
'rate_limited',
|
|
8
|
+
'content_rejected',
|
|
9
|
+
'too_large',
|
|
10
|
+
] as const;
|
|
@@ -1,43 +1,56 @@
|
|
|
1
|
-
/** Error codes from invites, parties, hub rooms, races and the socket envelope. */
|
|
2
|
-
export const MULTIPLAYER_CODES = [
|
|
3
|
-
// Socket envelope.
|
|
4
|
-
'unknown_op',
|
|
5
|
-
'hello_required',
|
|
6
|
-
// Games and modes.
|
|
7
|
-
'not_multiplayer',
|
|
8
|
-
'not_supported',
|
|
9
|
-
'bad_mode',
|
|
10
|
-
// Invites, parties, launches, joins.
|
|
11
|
-
'bad_target',
|
|
12
|
-
'cannot_invite',
|
|
13
|
-
'already_member',
|
|
14
|
-
'party_full',
|
|
15
|
-
'invite_gone',
|
|
16
|
-
'party_gone',
|
|
17
|
-
'not_leader',
|
|
18
|
-
'bad_info',
|
|
19
|
-
'launch_invalid',
|
|
20
|
-
'not_joinable',
|
|
21
|
-
//
|
|
22
|
-
'
|
|
23
|
-
|
|
24
|
-
'
|
|
25
|
-
|
|
26
|
-
'
|
|
27
|
-
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
|
|
40
|
-
'
|
|
41
|
-
'
|
|
42
|
-
'
|
|
43
|
-
|
|
1
|
+
/** Error codes from invites, invite links, parties, hub rooms, races, tournaments and the socket envelope. */
|
|
2
|
+
export const MULTIPLAYER_CODES = [
|
|
3
|
+
// Socket envelope.
|
|
4
|
+
'unknown_op',
|
|
5
|
+
'hello_required',
|
|
6
|
+
// Games and modes.
|
|
7
|
+
'not_multiplayer',
|
|
8
|
+
'not_supported',
|
|
9
|
+
'bad_mode',
|
|
10
|
+
// Invites, parties, launches, joins.
|
|
11
|
+
'bad_target',
|
|
12
|
+
'cannot_invite',
|
|
13
|
+
'already_member',
|
|
14
|
+
'party_full',
|
|
15
|
+
'invite_gone',
|
|
16
|
+
'party_gone',
|
|
17
|
+
'not_leader',
|
|
18
|
+
'bad_info',
|
|
19
|
+
'launch_invalid',
|
|
20
|
+
'not_joinable',
|
|
21
|
+
// Invite links.
|
|
22
|
+
'link_invalid',
|
|
23
|
+
'link_room_gone',
|
|
24
|
+
'too_many_links',
|
|
25
|
+
// Group chat.
|
|
26
|
+
'bad_quick',
|
|
27
|
+
// Hub rooms.
|
|
28
|
+
'room_not_found',
|
|
29
|
+
'not_in_room',
|
|
30
|
+
'not_host',
|
|
31
|
+
'too_many_rooms',
|
|
32
|
+
'banned',
|
|
33
|
+
'in_progress',
|
|
34
|
+
'room_full',
|
|
35
|
+
'not_ready',
|
|
36
|
+
'ended',
|
|
37
|
+
'bad_patch',
|
|
38
|
+
'race_room',
|
|
39
|
+
// Races.
|
|
40
|
+
'not_race',
|
|
41
|
+
'not_in_race',
|
|
42
|
+
'not_started',
|
|
43
|
+
'race_over',
|
|
44
|
+
'too_fast',
|
|
45
|
+
'bad_stats',
|
|
46
|
+
'bad_param',
|
|
47
|
+
// Tournaments.
|
|
48
|
+
'tournament_not_found',
|
|
49
|
+
'tournament_closed',
|
|
50
|
+
'tournament_full',
|
|
51
|
+
'tournament_over',
|
|
52
|
+
'not_creator',
|
|
53
|
+
'not_entered',
|
|
54
|
+
'cannot_join',
|
|
55
|
+
'match_not_ready',
|
|
56
|
+
] as const;
|
package/src/errors/codes/play.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Error codes from accounts and the single-player API (saves, stats, boards, daily, economy, trades). */
|
|
2
|
-
export const PLAY_CODES = [
|
|
3
|
-
/** A score was sent to a board only the game's own server may update (`source: "server"`). */
|
|
4
|
-
'server_board',
|
|
5
|
-
] as const;
|
|
1
|
+
/** Error codes from accounts and the single-player API (saves, stats, boards, daily, economy, trades). */
|
|
2
|
+
export const PLAY_CODES = [
|
|
3
|
+
/** A score was sent to a board only the game's own server may update (`source: "server"`). */
|
|
4
|
+
'server_board',
|
|
5
|
+
] as const;
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
/** Error codes from friends, messages, notifications, reports and suggestions. */
|
|
2
|
-
export const SOCIAL_CODES = [
|
|
3
|
-
/** No such player, or one who blocked you or is suspended (they look the same). */
|
|
4
|
-
'no_player',
|
|
5
|
-
/** Not one of the preset avatars. */
|
|
6
|
-
'bad_avatar',
|
|
7
|
-
/** The chat-lock password was wrong. */
|
|
8
|
-
'bad_password',
|
|
9
|
-
/** An admin turned new friend requests off. */
|
|
10
|
-
'friend_requests_off',
|
|
11
|
-
/** You can't do that to yourself (friend, block; also invites, joins and room targets). */
|
|
12
|
-
'bad_target',
|
|
13
|
-
/** The other player is a guest and must create an account first. */
|
|
14
|
-
'guest_target',
|
|
15
|
-
/** You blocked them: unblock first. */
|
|
16
|
-
'blocked',
|
|
17
|
-
/** You or they have the most friends allowed. */
|
|
18
|
-
'friends_limit',
|
|
19
|
-
/** Too many outgoing friend requests waiting. */
|
|
20
|
-
'pending_limit',
|
|
21
|
-
/** The friend request is gone. */
|
|
22
|
-
'no_request',
|
|
23
|
-
/** You're not friends (messages, friend bells). */
|
|
24
|
-
'not_friends',
|
|
25
|
-
/** You've blocked the most players allowed. */
|
|
26
|
-
'blocks_limit',
|
|
27
|
-
/** The player isn't taking messages. */
|
|
28
|
-
'dms_closed',
|
|
29
|
-
/** Too many of your suggestions are waiting for review. */
|
|
30
|
-
'too_many_pending',
|
|
31
|
-
] as const;
|
|
1
|
+
/** Error codes from friends, messages, notifications, reports and suggestions. */
|
|
2
|
+
export const SOCIAL_CODES = [
|
|
3
|
+
/** No such player, or one who blocked you or is suspended (they look the same). */
|
|
4
|
+
'no_player',
|
|
5
|
+
/** Not one of the preset avatars. */
|
|
6
|
+
'bad_avatar',
|
|
7
|
+
/** The chat-lock password was wrong. */
|
|
8
|
+
'bad_password',
|
|
9
|
+
/** An admin turned new friend requests off. */
|
|
10
|
+
'friend_requests_off',
|
|
11
|
+
/** You can't do that to yourself (friend, block; also invites, joins and room targets). */
|
|
12
|
+
'bad_target',
|
|
13
|
+
/** The other player is a guest and must create an account first. */
|
|
14
|
+
'guest_target',
|
|
15
|
+
/** You blocked them: unblock first. */
|
|
16
|
+
'blocked',
|
|
17
|
+
/** You or they have the most friends allowed. */
|
|
18
|
+
'friends_limit',
|
|
19
|
+
/** Too many outgoing friend requests waiting. */
|
|
20
|
+
'pending_limit',
|
|
21
|
+
/** The friend request is gone. */
|
|
22
|
+
'no_request',
|
|
23
|
+
/** You're not friends (messages, friend bells). */
|
|
24
|
+
'not_friends',
|
|
25
|
+
/** You've blocked the most players allowed. */
|
|
26
|
+
'blocks_limit',
|
|
27
|
+
/** The player isn't taking messages. */
|
|
28
|
+
'dms_closed',
|
|
29
|
+
/** Too many of your suggestions are waiting for review. */
|
|
30
|
+
'too_many_pending',
|
|
31
|
+
] as const;
|