@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.
Files changed (81) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -21
  3. package/README.md +26 -26
  4. package/dist/index.d.ts +2683 -39
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +862 -18
  7. package/dist/index.js.map +1 -1
  8. package/package.json +53 -53
  9. package/src/api/analytics.ts +81 -81
  10. package/src/api/auth.ts +77 -77
  11. package/src/api/catalog-activity.ts +66 -0
  12. package/src/api/catalog.ts +177 -171
  13. package/src/api/daily.ts +122 -122
  14. package/src/api/economy/bundle.ts +69 -69
  15. package/src/api/index.ts +92 -85
  16. package/src/api/leaderboards.ts +151 -151
  17. package/src/api/messages.ts +142 -142
  18. package/src/api/mp/chat.ts +36 -36
  19. package/src/api/mp/invite-links.ts +42 -0
  20. package/src/api/mp/parties.ts +5 -0
  21. package/src/api/mp/races.ts +211 -211
  22. package/src/api/mp/rooms.ts +122 -90
  23. package/src/api/mp/snapshot.ts +17 -17
  24. package/src/api/mp.ts +135 -110
  25. package/src/api/notify.ts +114 -111
  26. package/src/api/offline.ts +45 -0
  27. package/src/api/progress/game-data.ts +189 -189
  28. package/src/api/progress.ts +59 -59
  29. package/src/api/race.ts +47 -47
  30. package/src/api/reports.ts +208 -208
  31. package/src/api/social/config.ts +47 -47
  32. package/src/api/social/endpoints.ts +179 -179
  33. package/src/api/social/people.ts +118 -118
  34. package/src/api/social/presence.ts +95 -95
  35. package/src/api/social.ts +9 -9
  36. package/src/api/tournaments/endpoints.ts +102 -0
  37. package/src/api/tournaments/play-online.ts +71 -0
  38. package/src/api/tournaments/shapes.ts +202 -0
  39. package/src/api/tournaments.ts +7 -0
  40. package/src/api/version.ts +40 -40
  41. package/src/coerce.ts +50 -50
  42. package/src/common.ts +42 -42
  43. package/src/entities.ts +62 -62
  44. package/src/errors/codes/core.ts +10 -10
  45. package/src/errors/codes/multiplayer.ts +56 -43
  46. package/src/errors/codes/play.ts +5 -5
  47. package/src/errors/codes/social.ts +31 -31
  48. package/src/errors/index.ts +88 -88
  49. package/src/index.ts +16 -16
  50. package/src/limits.ts +125 -100
  51. package/src/logic/daily.ts +54 -54
  52. package/src/logic/index.ts +8 -8
  53. package/src/logic/presence.ts +62 -62
  54. package/src/logic/time.ts +81 -81
  55. package/src/manifest/changes.ts +55 -55
  56. package/src/manifest/controls.ts +42 -42
  57. package/src/manifest/fields.ts +89 -89
  58. package/src/manifest/game.ts +139 -132
  59. package/src/manifest/index.ts +13 -12
  60. package/src/manifest/inject.ts +31 -31
  61. package/src/manifest/labels.ts +99 -0
  62. package/src/manifest/leaderboards.ts +29 -29
  63. package/src/manifest/multiplayer.ts +79 -71
  64. package/src/manifest/race.ts +93 -93
  65. package/src/middleware.ts +47 -47
  66. package/src/realtime/define.ts +52 -52
  67. package/src/realtime/envelope.ts +67 -67
  68. package/src/realtime/events/multiplayer.ts +9 -8
  69. package/src/realtime/events/parties.ts +31 -31
  70. package/src/realtime/events/races.ts +27 -27
  71. package/src/realtime/events/rooms.ts +52 -48
  72. package/src/realtime/events/social.ts +81 -81
  73. package/src/realtime/events/tournaments.ts +12 -0
  74. package/src/realtime/index.ts +24 -24
  75. package/src/realtime/ops/empty.ts +8 -8
  76. package/src/realtime/ops/hello.ts +40 -40
  77. package/src/realtime/ops/multiplayer.ts +8 -8
  78. package/src/realtime/ops/parties.ts +13 -13
  79. package/src/realtime/ops/races.ts +99 -99
  80. package/src/realtime/ops/rooms.ts +22 -8
  81. package/src/realtime/ops/social.ts +58 -58
package/src/api/daily.ts CHANGED
@@ -1,122 +1,122 @@
1
- /**
2
- * Daily challenges: one deterministic challenge per UTC day for games with
3
- * `game.dailyChallenges: true`. Starting a day mints a signed token; the game
4
- * presents it on completion. Completions are counted on the game's `daily`
5
- * leaderboard. The client owns the calendar (its local date); the hub only
6
- * reports which days are done.
7
- */
8
- import { use } from '@ayepi/core';
9
- import { z } from 'zod';
10
- import { DayKey, Json, Millis, Slug, UserId } from '../common';
11
- import { ErrorBody } from '../errors';
12
- import { game, requireUser, session } from '../middleware';
13
- import { Rank } from './leaderboards';
14
-
15
- /** One completed day. */
16
- export const DailyCompletion = z.object({
17
- /** Epoch ms (server clock). */
18
- completedAt: Millis,
19
- /** The JSON the game sent on completion, or `null`. */
20
- meta: Json,
21
- });
22
-
23
- /** One completed day. */
24
- export type DailyCompletion = z.infer<typeof DailyCompletion>;
25
-
26
- /** A player's completions in one game, keyed by `YYYY-MM-DD`. */
27
- export const DailyCompletions = z.record(DayKey, DailyCompletion);
28
-
29
- /** A player's completions in one game. */
30
- export type DailyCompletions = z.infer<typeof DailyCompletions>;
31
-
32
- /** `:day` of a challenge: within 30 days back and 1 day ahead of UTC today. */
33
- const DayParams = z.object({ day: z.string().refine((day) => DayKey.safeParse(day).success, { error: 'Invalid day (expected YYYY-MM-DD).' }) });
34
-
35
- /** The daily endpoints. */
36
- export const dailyEndpoints = {
37
- ...session.group({
38
- /**
39
- * Every daily game with the caller's completions (empty maps when signed
40
- * out), plus the top 10 players by completions across all games.
41
- */
42
- listDailyChallengesForAllGames: {
43
- method: 'GET', path: '/daily',
44
- response: z.object({
45
- /** UTC today, a hint: clients use their local date. */
46
- today: DayKey,
47
- games: z.array(z.object({ slug: Slug, title: z.string(), completions: DailyCompletions })),
48
- global: z.array(z.object({
49
- rank: Rank,
50
- userId: UserId,
51
- username: z.string(),
52
- /** Daily challenges completed, across all games. */
53
- score: z.number().int().nonnegative(),
54
- })),
55
- }),
56
- doc: { summary: 'Daily challenges across every game, plus global standings', tags: ['daily'] },
57
- },
58
- }),
59
- ...use(session, game).path('/games/:slug').group({
60
- getGameDailyChallenges: {
61
- method: 'GET', path: '/daily',
62
- response: z.object({
63
- enabled: z.literal(true),
64
- /** UTC today, a hint: clients use their local date. */
65
- today: DayKey,
66
- /** Empty when signed out. */
67
- completions: DailyCompletions,
68
- }),
69
- errors: { 404: ErrorBody },
70
- doc: { summary: "The caller's completions in this game (404 if it has no dailies)", tags: ['daily'] },
71
- },
72
- }),
73
- ...use(requireUser, game).path('/games/:slug').group({
74
- /**
75
- * Start (or replay) a day: returns its seed and a signed token to present
76
- * on completion. 400 when the day is outside the window.
77
- */
78
- startDailyChallenge: {
79
- method: 'POST', path: '/daily/:day/start', params: DayParams,
80
- response: z.object({
81
- /** Present it to `dailyComplete` for the same day. */
82
- token: z.string(),
83
- day: DayKey,
84
- /** Deterministic per (game, day), an unsigned 32-bit integer. */
85
- seed: z.number().int().min(0).max(0xffff_ffff),
86
- /** When the token stops working (epoch ms), about 26 hours out. */
87
- expiresAt: Millis,
88
- alreadyCompleted: z.boolean(),
89
- /** Epoch ms, or `null` when not completed yet. */
90
- completedAt: Millis.nullable(),
91
- /** The earlier completion's JSON, or `null`. */
92
- meta: Json,
93
- }),
94
- errors: { 400: ErrorBody, 401: ErrorBody, 404: ErrorBody },
95
- doc: { summary: "Start a day's challenge and get its token", tags: ['daily'] },
96
- },
97
- /**
98
- * Record a completion with the token from `dailyStart`. Idempotent: a
99
- * replay of a done day changes nothing. 401 on a bad, expired or
100
- * mismatched token.
101
- */
102
- completeDailyChallenge: {
103
- method: 'POST', path: '/daily/:day/complete', params: DayParams,
104
- body: z.object({
105
- /** The token from `dailyStart`; a missing or non-text token is refused like a bad one (401). */
106
- token: z.string().optional().catch(undefined),
107
- /** Any JSON; a numeric `meta.score` is kept with the completion. */
108
- meta: Json.optional(),
109
- }),
110
- response: z.object({
111
- ok: z.literal(true),
112
- day: DayKey,
113
- /** The caller's completions in this game. */
114
- count: z.number().int().positive(),
115
- /** The caller's rank on the game's `daily` board. */
116
- rank: Rank.nullable(),
117
- }),
118
- errors: { 400: ErrorBody, 401: ErrorBody, 404: ErrorBody },
119
- doc: { summary: 'Complete a day with its token', tags: ['daily'] },
120
- },
121
- }),
122
- };
1
+ /**
2
+ * Daily challenges: one deterministic challenge per UTC day for games with
3
+ * `game.dailyChallenges: true`. Starting a day mints a signed token; the game
4
+ * presents it on completion. Completions are counted on the game's `daily`
5
+ * leaderboard. The client owns the calendar (its local date); the hub only
6
+ * reports which days are done.
7
+ */
8
+ import { use } from '@ayepi/core';
9
+ import { z } from 'zod';
10
+ import { DayKey, Json, Millis, Slug, UserId } from '../common';
11
+ import { ErrorBody } from '../errors';
12
+ import { game, requireUser, session } from '../middleware';
13
+ import { Rank } from './leaderboards';
14
+
15
+ /** One completed day. */
16
+ export const DailyCompletion = z.object({
17
+ /** Epoch ms (server clock). */
18
+ completedAt: Millis,
19
+ /** The JSON the game sent on completion, or `null`. */
20
+ meta: Json,
21
+ });
22
+
23
+ /** One completed day. */
24
+ export type DailyCompletion = z.infer<typeof DailyCompletion>;
25
+
26
+ /** A player's completions in one game, keyed by `YYYY-MM-DD`. */
27
+ export const DailyCompletions = z.record(DayKey, DailyCompletion);
28
+
29
+ /** A player's completions in one game. */
30
+ export type DailyCompletions = z.infer<typeof DailyCompletions>;
31
+
32
+ /** `:day` of a challenge: within 30 days back and 1 day ahead of UTC today. */
33
+ const DayParams = z.object({ day: z.string().refine((day) => DayKey.safeParse(day).success, { error: 'Invalid day (expected YYYY-MM-DD).' }) });
34
+
35
+ /** The daily endpoints. */
36
+ export const dailyEndpoints = {
37
+ ...session.group({
38
+ /**
39
+ * Every daily game with the caller's completions (empty maps when signed
40
+ * out), plus the top 10 players by completions across all games.
41
+ */
42
+ listDailyChallengesForAllGames: {
43
+ method: 'GET', path: '/daily',
44
+ response: z.object({
45
+ /** UTC today, a hint: clients use their local date. */
46
+ today: DayKey,
47
+ games: z.array(z.object({ slug: Slug, title: z.string(), completions: DailyCompletions })),
48
+ global: z.array(z.object({
49
+ rank: Rank,
50
+ userId: UserId,
51
+ username: z.string(),
52
+ /** Daily challenges completed, across all games. */
53
+ score: z.number().int().nonnegative(),
54
+ })),
55
+ }),
56
+ doc: { summary: 'Daily challenges across every game, plus global standings', tags: ['daily'] },
57
+ },
58
+ }),
59
+ ...use(session, game).path('/games/:slug').group({
60
+ getGameDailyChallenges: {
61
+ method: 'GET', path: '/daily',
62
+ response: z.object({
63
+ enabled: z.literal(true),
64
+ /** UTC today, a hint: clients use their local date. */
65
+ today: DayKey,
66
+ /** Empty when signed out. */
67
+ completions: DailyCompletions,
68
+ }),
69
+ errors: { 404: ErrorBody },
70
+ doc: { summary: "The caller's completions in this game (404 if it has no dailies)", tags: ['daily'] },
71
+ },
72
+ }),
73
+ ...use(requireUser, game).path('/games/:slug').group({
74
+ /**
75
+ * Start (or replay) a day: returns its seed and a signed token to present
76
+ * on completion. 400 when the day is outside the window.
77
+ */
78
+ startDailyChallenge: {
79
+ method: 'POST', path: '/daily/:day/start', params: DayParams,
80
+ response: z.object({
81
+ /** Present it to `dailyComplete` for the same day. */
82
+ token: z.string(),
83
+ day: DayKey,
84
+ /** Deterministic per (game, day), an unsigned 32-bit integer. */
85
+ seed: z.number().int().min(0).max(0xffff_ffff),
86
+ /** When the token stops working (epoch ms), about 26 hours out. */
87
+ expiresAt: Millis,
88
+ alreadyCompleted: z.boolean(),
89
+ /** Epoch ms, or `null` when not completed yet. */
90
+ completedAt: Millis.nullable(),
91
+ /** The earlier completion's JSON, or `null`. */
92
+ meta: Json,
93
+ }),
94
+ errors: { 400: ErrorBody, 401: ErrorBody, 404: ErrorBody },
95
+ doc: { summary: "Start a day's challenge and get its token", tags: ['daily'] },
96
+ },
97
+ /**
98
+ * Record a completion with the token from `dailyStart`. Idempotent: a
99
+ * replay of a done day changes nothing. 401 on a bad, expired or
100
+ * mismatched token.
101
+ */
102
+ completeDailyChallenge: {
103
+ method: 'POST', path: '/daily/:day/complete', params: DayParams,
104
+ body: z.object({
105
+ /** The token from `dailyStart`; a missing or non-text token is refused like a bad one (401). */
106
+ token: z.string().optional().catch(undefined),
107
+ /** Any JSON; a numeric `meta.score` is kept with the completion. */
108
+ meta: Json.optional(),
109
+ }),
110
+ response: z.object({
111
+ ok: z.literal(true),
112
+ day: DayKey,
113
+ /** The caller's completions in this game. */
114
+ count: z.number().int().positive(),
115
+ /** The caller's rank on the game's `daily` board. */
116
+ rank: Rank.nullable(),
117
+ }),
118
+ errors: { 400: ErrorBody, 401: ErrorBody, 404: ErrorBody },
119
+ doc: { summary: 'Complete a day with its token', tags: ['daily'] },
120
+ },
121
+ }),
122
+ };
@@ -1,69 +1,69 @@
1
- /**
2
- * Economy shapes: a player's per-game holdings and the bundles that move
3
- * goods. Items are opaque, app-defined {@link Key}s; the hub only counts them.
4
- */
5
- import { z } from 'zod';
6
- import { Key } from '../../common';
7
-
8
- /**
9
- * The default largest quantity (or coin amount) one bundle entry may carry.
10
- * The hub's limit is `HUB_MAX_ITEM_QTY`, which defaults to this.
11
- */
12
- export const MAX_ITEM_QTY = 1_000_000;
13
-
14
- /**
15
- * The default most distinct item keys one bundle may name. The hub's limit
16
- * is `HUB_MAX_BUNDLE_ITEMS`, which defaults to this.
17
- */
18
- export const MAX_BUNDLE_ITEMS = 50;
19
-
20
- /** A player's holdings in one game: items with a positive count, and coins. */
21
- export const Inventory = z.object({
22
- /** Sorted by key. */
23
- items: z.array(z.object({ key: Key, qty: z.number().int().positive() })),
24
- coins: z.number().int().nonnegative(),
25
- });
26
-
27
- /** A player's holdings in one game. */
28
- export type Inventory = z.infer<typeof Inventory>;
29
-
30
- /**
31
- * A bundle quantity, read like the hub's `Number(x)` (numeric strings pass).
32
- * A value that is not a number reads as `NaN` here rather than failing, so
33
- * the hub's own range check, which knows its configured limits, answers with
34
- * its message (e.g. `grant.coins must be an integer in [0, 1000000].`).
35
- * Clients should send a JSON integer.
36
- */
37
- const BundleQuantity = z.coerce.number<number>().catch(Number.NaN);
38
-
39
- /**
40
- * Goods to grant, spend or trade, as a request sends them, for the request
41
- * field named `label` (`grant`, `take`, `give`, `want`), which the error
42
- * messages name. Both parts are optional (`null` or missing means none).
43
- * Item keys must be {@link Key}s, at most `HUB_MAX_BUNDLE_ITEMS` of them,
44
- * each with a quantity from 1 to `HUB_MAX_ITEM_QTY`; coins run from 0 to
45
- * `HUB_MAX_ITEM_QTY`. The hub checks those limits and the keys itself.
46
- */
47
- export function bundleInput(label: string) {
48
- return z.object({
49
- /** 0 to `HUB_MAX_ITEM_QTY`. */
50
- coins: BundleQuantity.nullish(),
51
- /** Item key to quantity (1 to `HUB_MAX_ITEM_QTY`). */
52
- items: z.record(z.string(), BundleQuantity, { error: `${label}.items must be an object of key→quantity.` }).nullish(),
53
- }, { error: `${label} must be an object.` });
54
- }
55
-
56
- /** A request bundle, for documentation and clients. */
57
- export const BundleInput = bundleInput('bundle');
58
-
59
- /** A request bundle. */
60
- export type BundleInput = z.infer<typeof BundleInput>;
61
-
62
- /** A bundle as the hub stores and returns it on a trade offer: both parts always present. */
63
- export const Bundle = z.object({
64
- items: z.record(Key, z.number().int().positive()),
65
- coins: z.number().int().nonnegative(),
66
- });
67
-
68
- /** A stored bundle. */
69
- export type Bundle = z.infer<typeof Bundle>;
1
+ /**
2
+ * Economy shapes: a player's per-game holdings and the bundles that move
3
+ * goods. Items are opaque, app-defined {@link Key}s; the hub only counts them.
4
+ */
5
+ import { z } from 'zod';
6
+ import { Key } from '../../common';
7
+
8
+ /**
9
+ * The default largest quantity (or coin amount) one bundle entry may carry.
10
+ * The hub's limit is `HUB_MAX_ITEM_QTY`, which defaults to this.
11
+ */
12
+ export const MAX_ITEM_QTY = 1_000_000;
13
+
14
+ /**
15
+ * The default most distinct item keys one bundle may name. The hub's limit
16
+ * is `HUB_MAX_BUNDLE_ITEMS`, which defaults to this.
17
+ */
18
+ export const MAX_BUNDLE_ITEMS = 50;
19
+
20
+ /** A player's holdings in one game: items with a positive count, and coins. */
21
+ export const Inventory = z.object({
22
+ /** Sorted by key. */
23
+ items: z.array(z.object({ key: Key, qty: z.number().int().positive() })),
24
+ coins: z.number().int().nonnegative(),
25
+ });
26
+
27
+ /** A player's holdings in one game. */
28
+ export type Inventory = z.infer<typeof Inventory>;
29
+
30
+ /**
31
+ * A bundle quantity, read like the hub's `Number(x)` (numeric strings pass).
32
+ * A value that is not a number reads as `NaN` here rather than failing, so
33
+ * the hub's own range check, which knows its configured limits, answers with
34
+ * its message (e.g. `grant.coins must be an integer in [0, 1000000].`).
35
+ * Clients should send a JSON integer.
36
+ */
37
+ const BundleQuantity = z.coerce.number<number>().catch(Number.NaN);
38
+
39
+ /**
40
+ * Goods to grant, spend or trade, as a request sends them, for the request
41
+ * field named `label` (`grant`, `take`, `give`, `want`), which the error
42
+ * messages name. Both parts are optional (`null` or missing means none).
43
+ * Item keys must be {@link Key}s, at most `HUB_MAX_BUNDLE_ITEMS` of them,
44
+ * each with a quantity from 1 to `HUB_MAX_ITEM_QTY`; coins run from 0 to
45
+ * `HUB_MAX_ITEM_QTY`. The hub checks those limits and the keys itself.
46
+ */
47
+ export function bundleInput(label: string) {
48
+ return z.object({
49
+ /** 0 to `HUB_MAX_ITEM_QTY`. */
50
+ coins: BundleQuantity.nullish(),
51
+ /** Item key to quantity (1 to `HUB_MAX_ITEM_QTY`). */
52
+ items: z.record(z.string(), BundleQuantity, { error: `${label}.items must be an object of key→quantity.` }).nullish(),
53
+ }, { error: `${label} must be an object.` });
54
+ }
55
+
56
+ /** A request bundle, for documentation and clients. */
57
+ export const BundleInput = bundleInput('bundle');
58
+
59
+ /** A request bundle. */
60
+ export type BundleInput = z.infer<typeof BundleInput>;
61
+
62
+ /** A bundle as the hub stores and returns it on a trade offer: both parts always present. */
63
+ export const Bundle = z.object({
64
+ items: z.record(Key, z.number().int().positive()),
65
+ coins: z.number().int().nonnegative(),
66
+ });
67
+
68
+ /** A stored bundle. */
69
+ export type Bundle = z.infer<typeof Bundle>;
package/src/api/index.ts CHANGED
@@ -1,85 +1,92 @@
1
- /**
2
- * The public REST API: every endpoint a game, the menu or the social runtime
3
- * calls, as one ayepi spec. Paths are relative to `/_api`. One file per area.
4
- */
5
- import { spec } from '@ayepi/core';
6
- import { analyticsEndpoints } from './analytics';
7
- import { authEndpoints } from './auth';
8
- import { catalogEndpoints } from './catalog';
9
- import { dailyEndpoints } from './daily';
10
- import { economyEndpoints } from './economy';
11
- import { leaderboardsEndpoints } from './leaderboards';
12
- import { messagesEndpoints } from './messages';
13
- import { mpEndpoints } from './mp';
14
- import { notifyEndpoints } from './notify';
15
- import { progressEndpoints } from './progress';
16
- import { raceEndpoints } from './race';
17
- import { reportsEndpoints } from './reports';
18
- import { socialEndpoints } from './social';
19
- import { versionEndpoints } from './version';
20
-
21
- // Every area's shapes (request, response and entity schemas), for clients and tests.
22
- export * from './analytics';
23
- export * from './auth';
24
- export * from './catalog';
25
- export * from './daily';
26
- export * from './economy';
27
- export * from './leaderboards';
28
- export * from './messages';
29
- export * from './mp';
30
- export * from './notify';
31
- export * from './progress';
32
- export * from './race';
33
- export * from './reports';
34
- export * from './social';
35
- export * from './version';
36
-
37
- /**
38
- * Every public endpoint, by name. Typed as an intersection of the areas so the
39
- * published .d.ts refers to each area instead of repeating every endpoint.
40
- */
41
- export type PublicEndpoints =
42
- typeof authEndpoints
43
- & typeof catalogEndpoints
44
- & typeof progressEndpoints
45
- & typeof leaderboardsEndpoints
46
- & typeof dailyEndpoints
47
- & typeof economyEndpoints
48
- & typeof analyticsEndpoints
49
- & typeof socialEndpoints
50
- & typeof messagesEndpoints
51
- & typeof notifyEndpoints
52
- & typeof reportsEndpoints
53
- & typeof mpEndpoints
54
- & typeof raceEndpoints
55
- & typeof versionEndpoints;
56
-
57
- /** Every public endpoint, by name. */
58
- export const publicEndpoints: PublicEndpoints = {
59
- ...authEndpoints,
60
- ...catalogEndpoints,
61
- ...progressEndpoints,
62
- ...leaderboardsEndpoints,
63
- ...dailyEndpoints,
64
- ...economyEndpoints,
65
- ...analyticsEndpoints,
66
- ...socialEndpoints,
67
- ...messagesEndpoints,
68
- ...notifyEndpoints,
69
- ...reportsEndpoints,
70
- ...mpEndpoints,
71
- ...raceEndpoints,
72
- ...versionEndpoints,
73
- };
74
-
75
- /**
76
- * The public API spec's type. Declared (not inferred) so the published
77
- * `.d.ts` refers to `publicEndpoints` instead of repeating every endpoint.
78
- */
79
- export interface PublicApi {
80
- /** Every public endpoint, by name. */
81
- readonly endpoints: PublicEndpoints;
82
- }
83
-
84
- /** The public API spec (paths relative to `/_api`). */
85
- export const publicApi: PublicApi = spec({ endpoints: publicEndpoints });
1
+ /**
2
+ * The public REST API: every endpoint a game, the menu or the social runtime
3
+ * calls, as one ayepi spec. Paths are relative to `/_api`. One file per area.
4
+ */
5
+ import { spec } from '@ayepi/core';
6
+ import { analyticsEndpoints } from './analytics';
7
+ import { authEndpoints } from './auth';
8
+ import { catalogEndpoints } from './catalog';
9
+ import { dailyEndpoints } from './daily';
10
+ import { economyEndpoints } from './economy';
11
+ import { leaderboardsEndpoints } from './leaderboards';
12
+ import { messagesEndpoints } from './messages';
13
+ import { mpEndpoints } from './mp';
14
+ import { notifyEndpoints } from './notify';
15
+ import { progressEndpoints } from './progress';
16
+ import { raceEndpoints } from './race';
17
+ import { reportsEndpoints } from './reports';
18
+ import { socialEndpoints } from './social';
19
+ import { playOnlineEndpoints, tournamentEndpoints } from './tournaments';
20
+ import { versionEndpoints } from './version';
21
+
22
+ // Every area's shapes (request, response and entity schemas), for clients and tests.
23
+ export * from './analytics';
24
+ export * from './auth';
25
+ export * from './catalog';
26
+ export * from './daily';
27
+ export * from './economy';
28
+ export * from './leaderboards';
29
+ export * from './messages';
30
+ export * from './mp';
31
+ export * from './notify';
32
+ export * from './offline';
33
+ export * from './progress';
34
+ export * from './race';
35
+ export * from './reports';
36
+ export * from './social';
37
+ export * from './tournaments';
38
+ export * from './version';
39
+
40
+ /**
41
+ * Every public endpoint, by name. Typed as an intersection of the areas so the
42
+ * published .d.ts refers to each area instead of repeating every endpoint.
43
+ */
44
+ export type PublicEndpoints =
45
+ typeof authEndpoints
46
+ & typeof catalogEndpoints
47
+ & typeof progressEndpoints
48
+ & typeof leaderboardsEndpoints
49
+ & typeof dailyEndpoints
50
+ & typeof economyEndpoints
51
+ & typeof analyticsEndpoints
52
+ & typeof socialEndpoints
53
+ & typeof messagesEndpoints
54
+ & typeof notifyEndpoints
55
+ & typeof reportsEndpoints
56
+ & typeof mpEndpoints
57
+ & typeof raceEndpoints
58
+ & typeof tournamentEndpoints
59
+ & typeof playOnlineEndpoints
60
+ & typeof versionEndpoints;
61
+
62
+ /** Every public endpoint, by name. */
63
+ export const publicEndpoints: PublicEndpoints = {
64
+ ...authEndpoints,
65
+ ...catalogEndpoints,
66
+ ...progressEndpoints,
67
+ ...leaderboardsEndpoints,
68
+ ...dailyEndpoints,
69
+ ...economyEndpoints,
70
+ ...analyticsEndpoints,
71
+ ...socialEndpoints,
72
+ ...messagesEndpoints,
73
+ ...notifyEndpoints,
74
+ ...reportsEndpoints,
75
+ ...mpEndpoints,
76
+ ...raceEndpoints,
77
+ ...tournamentEndpoints,
78
+ ...playOnlineEndpoints,
79
+ ...versionEndpoints,
80
+ };
81
+
82
+ /**
83
+ * The public API spec's type. Declared (not inferred) so the published
84
+ * `.d.ts` refers to `publicEndpoints` instead of repeating every endpoint.
85
+ */
86
+ export interface PublicApi {
87
+ /** Every public endpoint, by name. */
88
+ readonly endpoints: PublicEndpoints;
89
+ }
90
+
91
+ /** The public API spec (paths relative to `/_api`). */
92
+ export const publicApi: PublicApi = spec({ endpoints: publicEndpoints });