xpt-shared-types 1.0.3 → 1.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/README.md +121 -30
- package/dist/contracts/index.d.ts +139 -0
- package/dist/contracts/index.js +8 -0
- package/dist/data/countriesList.d.ts +1 -1
- package/dist/data/countriesList.js +2 -2
- package/dist/generated/enums.d.ts +48 -0
- package/dist/generated/enums.js +5 -0
- package/dist/generated/index.d.ts +3 -0
- package/dist/generated/index.js +22 -0
- package/dist/generated/inputs.d.ts +420 -0
- package/dist/generated/inputs.js +5 -0
- package/dist/generated/models.d.ts +420 -0
- package/dist/generated/models.js +5 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -5
- package/dist/manual/index.d.ts +4 -0
- package/dist/manual/index.js +20 -0
- package/package.json +26 -23
- package/scripts/sync-from-strapi.js +281 -0
- package/src/contracts/index.ts +158 -0
- package/src/data/countriesList.ts +1156 -1156
- package/src/generated/enums.ts +171 -0
- package/src/generated/index.ts +7 -0
- package/src/generated/inputs.ts +496 -0
- package/src/generated/models.ts +497 -0
- package/src/index.ts +11 -7
- package/src/manual/index.ts +4 -0
- package/dist/types/match.d.ts +0 -1
- package/dist/types/match.js +0 -2
- package/dist/types/tournament.d.ts +0 -1
- package/dist/types/tournament.js +0 -2
- package/src/types/match.ts +0 -8
- package/src/types/tournament.ts +0 -4
- /package/dist/{types → manual}/country.d.ts +0 -0
- /package/dist/{types → manual}/country.js +0 -0
- /package/src/{types → manual}/country.ts +0 -0
package/README.md
CHANGED
|
@@ -1,30 +1,121 @@
|
|
|
1
|
-
# xpt-shared-types
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1
|
+
# xpt-shared-types
|
|
2
|
+
|
|
3
|
+
The API contract shared by `xpt-strapi` and `xpt-client`.
|
|
4
|
+
|
|
5
|
+
Strapi's content-type schemas are the single source of truth. This package
|
|
6
|
+
turns them into plain TypeScript so both projects describe the same API, and a
|
|
7
|
+
schema change breaks compilation at every stale usage instead of drifting
|
|
8
|
+
silently.
|
|
9
|
+
|
|
10
|
+
## Layout
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
src/
|
|
14
|
+
├── generated/ # DO NOT EDIT — produced by scripts/sync-from-strapi.js
|
|
15
|
+
│ ├── enums.ts # one union per `enumeration` attribute
|
|
16
|
+
│ ├── models.ts # one interface per content type (read shapes)
|
|
17
|
+
│ └── inputs.ts # one interface per content type (write shapes)
|
|
18
|
+
├── contracts/ # hand-written primitives the generated code builds on
|
|
19
|
+
├── manual/ # types with no Strapi content type behind them
|
|
20
|
+
└── data/ # shared runtime data (COUNTRIES_LIST)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Everything is re-exported from the package root:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import type { Tournament, TournamentStatus, Populated } from 'xpt-shared-types';
|
|
27
|
+
import { COUNTRIES_LIST } from 'xpt-shared-types';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Regenerating after a schema change
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
yarn sync # reads ../xpt-strapi/src/**/content-types/**/schema.json
|
|
34
|
+
yarn build # tsc only
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`sync` is deliberately **not** part of `build`, so publishing does not require a
|
|
38
|
+
sibling `xpt-strapi` checkout. The generated output is committed — treat
|
|
39
|
+
`yarn sync` as something you run and commit, like a lockfile.
|
|
40
|
+
|
|
41
|
+
Point it elsewhere with an argument or `XPT_STRAPI_PATH`:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
node scripts/sync-from-strapi.js ../some/other/xpt-strapi
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
It reads `schema.json`, **not** `xpt-strapi/types/generated/contentTypes.d.ts`.
|
|
48
|
+
The latter is Strapi's own output for its server-side types; it is regenerated
|
|
49
|
+
by `strapi develop` and expressed in `Schema.Attribute.*` wrappers that the
|
|
50
|
+
frontend cannot consume.
|
|
51
|
+
|
|
52
|
+
## The rules the generator follows
|
|
53
|
+
|
|
54
|
+
**Everything except `id` and `documentId` is optional.** Not just relations.
|
|
55
|
+
This codebase uses Strapi's `fields` selection pervasively, so even a
|
|
56
|
+
schema-`required` attribute like `user.email` is absent from most responses.
|
|
57
|
+
The base model is the *minimum guarantee*, not the full row.
|
|
58
|
+
|
|
59
|
+
**Single values are `?: T | null`.** Strapi sends `null` for an unset value
|
|
60
|
+
rather than omitting the key. Lists come back as `[]`, so they are not nullable.
|
|
61
|
+
|
|
62
|
+
**Relations and media are optional regardless of the schema**, because whether
|
|
63
|
+
they come back depends entirely on the query's `populate`.
|
|
64
|
+
|
|
65
|
+
**`private` attributes are omitted**, because the content API never returns
|
|
66
|
+
them (for example `user.password`).
|
|
67
|
+
|
|
68
|
+
**Read and write shapes differ**, so both are generated. On read a relation is
|
|
69
|
+
a nested object; on write it is a documentId or a `connect`/`set` form, and
|
|
70
|
+
media is a numeric file id. Use `models.ts` for responses and `inputs.ts` for
|
|
71
|
+
request payloads — typing a mutation with a read model is a common mistake that
|
|
72
|
+
produces confusing optionality errors.
|
|
73
|
+
|
|
74
|
+
**Enums are named `<Model><PascalField>`** — `tournament.currentStatus` becomes
|
|
75
|
+
`TournamentCurrentStatus`. `TournamentStatus` is exported as a readability
|
|
76
|
+
alias.
|
|
77
|
+
|
|
78
|
+
## Narrowing with `Populated<T, K>`
|
|
79
|
+
|
|
80
|
+
Because relations are always optional, record what a specific query actually
|
|
81
|
+
asked for:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const tournament = await getTournament(slug); // Populated<Tournament, 'game' | 'prizes'>
|
|
85
|
+
|
|
86
|
+
tournament.game.title; // ok — the annotation says it was populated
|
|
87
|
+
tournament.region?.name; // still optional — this query did not populate it
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If the annotation and the query disagree, that is a bug a reader can see. Do
|
|
91
|
+
not reach for a cast: a cast on a schema-backed field is always avoidable, and
|
|
92
|
+
silently disables exactly the checking this package exists to provide.
|
|
93
|
+
|
|
94
|
+
## Local development
|
|
95
|
+
|
|
96
|
+
The two apps are on different Yarn majors, so they link differently:
|
|
97
|
+
|
|
98
|
+
| Repo | Yarn | Dependency |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `xpt-strapi` | 1.22.5 (classic) | `"xpt-shared-types": "link:../xpt-shared-types"` |
|
|
101
|
+
| `xpt-client` | 4.1.1 (Berry) | `"xpt-shared-types": "portal:../xpt-shared-types"` |
|
|
102
|
+
|
|
103
|
+
`portal:` is Berry-only and fails on Yarn 1. Both symlink to this directory, so
|
|
104
|
+
edits are picked up after `yarn build` with no publish step.
|
|
105
|
+
|
|
106
|
+
> **Before deploying, revert both to the published range (`^1.x`) and publish
|
|
107
|
+
> this package.** The link/portal wiring is for local development only.
|
|
108
|
+
|
|
109
|
+
## Publishing
|
|
110
|
+
|
|
111
|
+
`prepublishOnly` runs `yarn build`, so `dist/` cannot go stale.
|
|
112
|
+
|
|
113
|
+
1. `yarn sync` and commit, if schemas changed
|
|
114
|
+
2. `npm login`
|
|
115
|
+
3. `yarn version --patch`
|
|
116
|
+
4. `npm publish`
|
|
117
|
+
5. `git push --follow-tags`
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand-written contract primitives.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is maintained by hand — the generated models in
|
|
5
|
+
* `src/generated` import from this module, so keep the names stable.
|
|
6
|
+
*/
|
|
7
|
+
/** Strapi 5 returns flat documents: no `attributes` envelope. */
|
|
8
|
+
export interface StrapiDocument {
|
|
9
|
+
id: number;
|
|
10
|
+
documentId: string;
|
|
11
|
+
createdAt?: string | null;
|
|
12
|
+
updatedAt?: string | null;
|
|
13
|
+
publishedAt?: string | null;
|
|
14
|
+
locale?: string | null;
|
|
15
|
+
}
|
|
16
|
+
/** A single size variant produced by the upload plugin. */
|
|
17
|
+
export interface StrapiMediaFormat {
|
|
18
|
+
name: string;
|
|
19
|
+
hash: string;
|
|
20
|
+
ext: string;
|
|
21
|
+
mime: string;
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
size: number;
|
|
25
|
+
url: string;
|
|
26
|
+
path?: string | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Size variants the upload plugin generates. The four named breakpoints are
|
|
30
|
+
* Strapi's defaults; the index signature covers custom ones.
|
|
31
|
+
*/
|
|
32
|
+
export interface StrapiMediaFormats {
|
|
33
|
+
thumbnail?: StrapiMediaFormat;
|
|
34
|
+
small?: StrapiMediaFormat;
|
|
35
|
+
medium?: StrapiMediaFormat;
|
|
36
|
+
large?: StrapiMediaFormat;
|
|
37
|
+
[breakpoint: string]: StrapiMediaFormat | undefined;
|
|
38
|
+
}
|
|
39
|
+
/** `plugin::upload.file` */
|
|
40
|
+
export interface StrapiMedia {
|
|
41
|
+
id: number;
|
|
42
|
+
documentId?: string;
|
|
43
|
+
name: string;
|
|
44
|
+
alternativeText?: string | null;
|
|
45
|
+
caption?: string | null;
|
|
46
|
+
width?: number | null;
|
|
47
|
+
height?: number | null;
|
|
48
|
+
formats?: StrapiMediaFormats | null;
|
|
49
|
+
hash: string;
|
|
50
|
+
ext?: string | null;
|
|
51
|
+
mime: string;
|
|
52
|
+
size: number;
|
|
53
|
+
url: string;
|
|
54
|
+
previewUrl?: string | null;
|
|
55
|
+
provider?: string;
|
|
56
|
+
provider_metadata?: unknown;
|
|
57
|
+
folderPath?: string;
|
|
58
|
+
createdAt?: string;
|
|
59
|
+
updatedAt?: string;
|
|
60
|
+
publishedAt?: string;
|
|
61
|
+
locale?: string | null;
|
|
62
|
+
}
|
|
63
|
+
/** Rich-text `blocks` payload; shape is defined by the blocks renderer. */
|
|
64
|
+
export type BlocksContent = unknown[];
|
|
65
|
+
/**
|
|
66
|
+
* How a relation is sent on create/update. Strapi accepts a bare documentId,
|
|
67
|
+
* a numeric id, or the connect/set/disconnect long form.
|
|
68
|
+
*/
|
|
69
|
+
export type RelationInput = string | number | {
|
|
70
|
+
id: number;
|
|
71
|
+
} | {
|
|
72
|
+
documentId: string;
|
|
73
|
+
} | {
|
|
74
|
+
connect?: Array<string | number>;
|
|
75
|
+
disconnect?: Array<string | number>;
|
|
76
|
+
} | {
|
|
77
|
+
set: Array<string | number>;
|
|
78
|
+
};
|
|
79
|
+
/** Media is written as the uploaded file's numeric id. */
|
|
80
|
+
export type MediaInput = number | number[] | null;
|
|
81
|
+
export interface Pagination {
|
|
82
|
+
page: number;
|
|
83
|
+
pageSize: number;
|
|
84
|
+
pageCount: number;
|
|
85
|
+
total: number;
|
|
86
|
+
}
|
|
87
|
+
export interface Meta {
|
|
88
|
+
pagination?: Pagination;
|
|
89
|
+
[key: string]: unknown;
|
|
90
|
+
}
|
|
91
|
+
/** Single-entity response. Strapi still sends `meta`, usually `{}`. */
|
|
92
|
+
export interface StrapiResponse<T> {
|
|
93
|
+
data: T;
|
|
94
|
+
meta?: Meta;
|
|
95
|
+
}
|
|
96
|
+
/** Collection response. */
|
|
97
|
+
export interface StrapiCollectionResponse<T> {
|
|
98
|
+
data: T[];
|
|
99
|
+
meta?: Meta;
|
|
100
|
+
}
|
|
101
|
+
export interface StrapiError {
|
|
102
|
+
status: number;
|
|
103
|
+
name: string;
|
|
104
|
+
message: string;
|
|
105
|
+
details?: unknown;
|
|
106
|
+
}
|
|
107
|
+
export interface StrapiErrorResponse {
|
|
108
|
+
data: null;
|
|
109
|
+
error: StrapiError;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Marks relations as present.
|
|
113
|
+
*
|
|
114
|
+
* Generated models leave every relation optional, because whether one comes
|
|
115
|
+
* back depends entirely on the query's `populate`. Use this at a call site to
|
|
116
|
+
* record what that particular query actually asked for:
|
|
117
|
+
*
|
|
118
|
+
* ```ts
|
|
119
|
+
* type WithGame = Populated<Tournament, 'game' | 'prizes'>;
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* This is the type-level counterpart to remembering to populate — if the query
|
|
123
|
+
* and the annotation disagree, that is a bug the reader can see.
|
|
124
|
+
*/
|
|
125
|
+
export type Populated<T, K extends keyof T> = T & {
|
|
126
|
+
[P in K]-?: NonNullable<T[P]>;
|
|
127
|
+
};
|
|
128
|
+
/** Recursively marks every relation on `T` as optional (the default shape). */
|
|
129
|
+
export type Unpopulated<T> = {
|
|
130
|
+
[P in keyof T]?: T[P];
|
|
131
|
+
};
|
|
132
|
+
/** `plugin::users-permissions.role` */
|
|
133
|
+
export interface UserRole {
|
|
134
|
+
id: number;
|
|
135
|
+
documentId?: string;
|
|
136
|
+
name: string;
|
|
137
|
+
description?: string | null;
|
|
138
|
+
type?: string | null;
|
|
139
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hand-written contract primitives.
|
|
4
|
+
*
|
|
5
|
+
* Everything here is maintained by hand — the generated models in
|
|
6
|
+
* `src/generated` import from this module, so keep the names stable.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Country } from "../
|
|
1
|
+
import { Country } from "../manual/country";
|
|
2
2
|
export declare const COUNTRIES_LIST: Country[];
|
|
@@ -401,7 +401,7 @@ exports.COUNTRIES_LIST = [
|
|
|
401
401
|
{
|
|
402
402
|
countryName: "Guinea-Bissau",
|
|
403
403
|
alpha2: "GW",
|
|
404
|
-
alpha3: "
|
|
404
|
+
alpha3: "GNB",
|
|
405
405
|
numeric: "624",
|
|
406
406
|
},
|
|
407
407
|
{
|
|
@@ -1090,7 +1090,7 @@ exports.COUNTRIES_LIST = [
|
|
|
1090
1090
|
},
|
|
1091
1091
|
{
|
|
1092
1092
|
countryName: "United Kingdom",
|
|
1093
|
-
alpha2: "GB",
|
|
1093
|
+
alpha2: "GB-UKM",
|
|
1094
1094
|
alpha3: "GBR",
|
|
1095
1095
|
numeric: "826",
|
|
1096
1096
|
},
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** `Friendship.status` */
|
|
2
|
+
export type FriendshipStatus = "pending" | "accepted";
|
|
3
|
+
/** `GameRequest.customLobbies` */
|
|
4
|
+
export type GameRequestCustomLobbies = "Yes" | "No" | "Not sure";
|
|
5
|
+
/** `GameRequest.genre` */
|
|
6
|
+
export type GameRequestGenre = "FPS" | "MOBA" | "Battle Royale" | "Fighting (FGC)" | "Sports" | "Strategy/RTS" | "Sim Racing" | "Card Game" | "Other";
|
|
7
|
+
/** `GameRequest.teamPlay` */
|
|
8
|
+
export type GameRequestTeamPlay = "No (solo)" | "Yes, 2v2" | "Yes, 3v3" | "Yes, 4v4+" | "Don't know";
|
|
9
|
+
/** `Match.lobbyStatus` */
|
|
10
|
+
export type MatchLobbyStatus = "waiting" | "ready" | "disputed" | "completed";
|
|
11
|
+
/** `Match.round` */
|
|
12
|
+
export type MatchRound = "Round 32" | "Round 16" | "Quarter Final" | "Semi-Final" | "Third Round" | "Finals" | "League";
|
|
13
|
+
/** `Match.streamPlatform` */
|
|
14
|
+
export type MatchStreamPlatform = "twitch" | "youtube" | "kick" | "other";
|
|
15
|
+
/** `Match.winnerSlot` */
|
|
16
|
+
export type MatchWinnerSlot = "home" | "away";
|
|
17
|
+
/** `Prize.rank` */
|
|
18
|
+
export type PrizeRank = "one" | "two" | "three";
|
|
19
|
+
/** `Referral.status` */
|
|
20
|
+
export type ReferralStatus = "pending" | "completed";
|
|
21
|
+
/** `Team.current_status` */
|
|
22
|
+
export type TeamCurrentStatus = "active" | "disbanded";
|
|
23
|
+
/** `TeamInvite.status` */
|
|
24
|
+
export type TeamInviteStatus = "pending" | "accepted" | "declined";
|
|
25
|
+
/** `TeamInvite.team_role` */
|
|
26
|
+
export type TeamInviteTeamRole = "captain" | "co_captain" | "player" | "substitute" | "coach";
|
|
27
|
+
/** `TeamPlayer.team_role` */
|
|
28
|
+
export type TeamPlayerTeamRole = "captain" | "co_captain" | "player" | "substitute" | "coach";
|
|
29
|
+
/** `Tournament.currentStatus` */
|
|
30
|
+
export type TournamentCurrentStatus = "draft" | "open" | "checkIn" | "seeding" | "live" | "completed" | "cancelled";
|
|
31
|
+
/** `TournamentParticipant.entryType` */
|
|
32
|
+
export type TournamentParticipantEntryType = "solo" | "team";
|
|
33
|
+
/** `TournamentParticipant.status` */
|
|
34
|
+
export type TournamentParticipantStatus = "registered" | "active" | "eliminated" | "completed";
|
|
35
|
+
/** `TournamentRole.role` */
|
|
36
|
+
export type TournamentRoleRole = "moderator" | "admin";
|
|
37
|
+
/** `TournamentStage.stageName` */
|
|
38
|
+
export type TournamentStageStageName = "Round 32" | "Round 16" | "Quarter Final" | "Semi-Final" | "Third Round" | "Finals" | "League";
|
|
39
|
+
/** `Tournament.teamSize` */
|
|
40
|
+
export type TournamentTeamSize = "one" | "two" | "three" | "four" | "five";
|
|
41
|
+
/** `Tournament.type` */
|
|
42
|
+
export type TournamentType = "Single Elimination" | "League" | "Double Elimination";
|
|
43
|
+
/** `UserTransaction.stripeStatus` */
|
|
44
|
+
export type UserTransactionStripeStatus = "pending" | "completed" | "failed" | "refunded" | "internal";
|
|
45
|
+
/** `UserTransaction.type` */
|
|
46
|
+
export type UserTransactionType = "purchase" | "debit" | "credit" | "refund" | "test";
|
|
47
|
+
/** Readability alias for `tournament.currentStatus`. */
|
|
48
|
+
export type TournamentStatus = TournamentCurrentStatus;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// AUTO-GENERATED by scripts/sync-from-strapi.js — DO NOT EDIT MANUALLY.
|
|
3
|
+
// Source: xpt-strapi/src/**/content-types/**/schema.json
|
|
4
|
+
// Regenerate with: yarn sync
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
__exportStar(require("./enums"), exports);
|
|
21
|
+
__exportStar(require("./models"), exports);
|
|
22
|
+
__exportStar(require("./inputs"), exports);
|