xpt-shared-types 1.12.1 → 1.15.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 +12 -4
- package/dist/generated/enums.d.ts +2 -0
- package/dist/generated/inputs.d.ts +17 -1
- package/dist/generated/models.d.ts +17 -1
- package/dist/manual/index.d.ts +1 -0
- package/dist/manual/index.js +1 -0
- package/dist/manual/notification.d.ts +40 -0
- package/dist/manual/notification.js +96 -0
- package/package.json +1 -1
- package/scripts/overlay-local.mjs +32 -0
- package/src/generated/enums.ts +7 -0
- package/src/generated/inputs.ts +18 -0
- package/src/generated/models.ts +18 -0
- package/src/index.ts +23 -23
- package/src/manual/country.ts +6 -6
- package/src/manual/index.ts +1 -0
- package/src/manual/notification.ts +120 -0
- package/scripts/sync-from-strapi.js +0 -281
package/README.md
CHANGED
|
@@ -110,11 +110,19 @@ edits are picked up after `yarn build` with no publish step.
|
|
|
110
110
|
|
|
111
111
|
`prepublishOnly` runs `yarn build`, so `dist/` cannot go stale.
|
|
112
112
|
|
|
113
|
+
Publishing runs in GitHub Actions ([`.github/workflows/publish.yml`](.github/workflows/publish.yml))
|
|
114
|
+
using npm trusted publishing, so no npm token or 2FA prompt is involved.
|
|
115
|
+
|
|
113
116
|
1. `yarn sync` and commit, if schemas changed
|
|
114
|
-
2. `
|
|
115
|
-
3. `
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
2. `yarn version --patch` (or `--minor`), which commits and tags `vX.Y.Z`
|
|
118
|
+
3. `git push --follow-tags`
|
|
119
|
+
|
|
120
|
+
The workflow fires on the `v*` tag, refuses to run if the tag and
|
|
121
|
+
`package.json` version disagree, then builds and publishes.
|
|
122
|
+
|
|
123
|
+
The trusted publisher on npmjs.com is linked to user `otemu`, repository
|
|
124
|
+
`xpt-shared-types`, workflow `publish.yml`, no environment. Renaming the
|
|
125
|
+
workflow file breaks publishing until that link is recreated.
|
|
118
126
|
|
|
119
127
|
## License
|
|
120
128
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** `AdminAction.targetType` */
|
|
2
|
+
export type AdminActionTargetType = "user" | "tournament" | "match" | "transaction";
|
|
1
3
|
/** `Faq.category` */
|
|
2
4
|
export type FaqCategory = "gettingStarted" | "tournamentsMatches" | "hosting" | "walletCoins" | "account";
|
|
3
5
|
/** `Friendship.status` */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BlocksContent, MediaInput, RelationInput } from '../contracts';
|
|
2
|
-
import type { FaqCategory, FriendshipStatus, GameGenre, GameRequestCustomLobbies, GameRequestGenre, GameRequestTeamPlay, GameVisibility, MatchDisputeReason, MatchLobbyStatus, MatchResultType, MatchRound, MatchStreamPlatform, MatchWinnerSlot, PlatformCode, ReferralStatus, TeamCurrentStatus, TeamInviteStatus, TeamInviteTeamRole, TeamPlayerTeamRole, TournamentAccess, TournamentCurrentStatus, TournamentInviteStatus, TournamentJoinRequestEntryType, TournamentJoinRequestStatus, TournamentParticipantEntryType, TournamentParticipantStatus, TournamentRoleRole, TournamentTeamSize, TournamentType, TournamentVisibility, UserTransactionStripeStatus, UserTransactionType } from './enums';
|
|
2
|
+
import type { AdminActionTargetType, FaqCategory, FriendshipStatus, GameGenre, GameRequestCustomLobbies, GameRequestGenre, GameRequestTeamPlay, GameVisibility, MatchDisputeReason, MatchLobbyStatus, MatchResultType, MatchRound, MatchStreamPlatform, MatchWinnerSlot, PlatformCode, ReferralStatus, TeamCurrentStatus, TeamInviteStatus, TeamInviteTeamRole, TeamPlayerTeamRole, TournamentAccess, TournamentCurrentStatus, TournamentInviteStatus, TournamentJoinRequestEntryType, TournamentJoinRequestStatus, TournamentParticipantEntryType, TournamentParticipantStatus, TournamentRoleRole, TournamentTeamSize, TournamentType, TournamentVisibility, UserTransactionStripeStatus, UserTransactionType } from './enums';
|
|
3
3
|
/** Write payload for `about`. */
|
|
4
4
|
export interface AboutInput {
|
|
5
5
|
heroTitle?: string;
|
|
@@ -7,6 +7,20 @@ export interface AboutInput {
|
|
|
7
7
|
aboutInfo?: unknown;
|
|
8
8
|
gameIcons?: MediaInput[];
|
|
9
9
|
}
|
|
10
|
+
/** Write payload for `admin-action`. */
|
|
11
|
+
export interface AdminActionInput {
|
|
12
|
+
action?: string;
|
|
13
|
+
adminId?: number;
|
|
14
|
+
adminUsername?: string;
|
|
15
|
+
targetType?: AdminActionTargetType;
|
|
16
|
+
targetId?: string;
|
|
17
|
+
targetLabel?: string;
|
|
18
|
+
contextId?: string;
|
|
19
|
+
reason?: string;
|
|
20
|
+
before?: unknown;
|
|
21
|
+
after?: unknown;
|
|
22
|
+
metadata?: unknown;
|
|
23
|
+
}
|
|
10
24
|
/** Write payload for `dm-message`. */
|
|
11
25
|
export interface DmMessageInput {
|
|
12
26
|
conversationId?: string;
|
|
@@ -383,6 +397,8 @@ export interface UserInput {
|
|
|
383
397
|
countryCode?: string;
|
|
384
398
|
dob?: string;
|
|
385
399
|
notifyUpdates?: boolean;
|
|
400
|
+
blockedReason?: string;
|
|
401
|
+
blockedAt?: string;
|
|
386
402
|
xptCoins?: number;
|
|
387
403
|
user_transactions?: RelationInput | RelationInput[];
|
|
388
404
|
dailyRewardStreak?: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BlocksContent, StrapiDocument, StrapiMedia, UserRole } from '../contracts';
|
|
2
|
-
import type { FaqCategory, FriendshipStatus, GameGenre, GameRequestCustomLobbies, GameRequestGenre, GameRequestTeamPlay, GameVisibility, MatchDisputeReason, MatchLobbyStatus, MatchResultType, MatchRound, MatchStreamPlatform, MatchWinnerSlot, PlatformCode, ReferralStatus, TeamCurrentStatus, TeamInviteStatus, TeamInviteTeamRole, TeamPlayerTeamRole, TournamentAccess, TournamentCurrentStatus, TournamentInviteStatus, TournamentJoinRequestEntryType, TournamentJoinRequestStatus, TournamentParticipantEntryType, TournamentParticipantStatus, TournamentRoleRole, TournamentTeamSize, TournamentType, TournamentVisibility, UserTransactionStripeStatus, UserTransactionType } from './enums';
|
|
2
|
+
import type { AdminActionTargetType, FaqCategory, FriendshipStatus, GameGenre, GameRequestCustomLobbies, GameRequestGenre, GameRequestTeamPlay, GameVisibility, MatchDisputeReason, MatchLobbyStatus, MatchResultType, MatchRound, MatchStreamPlatform, MatchWinnerSlot, PlatformCode, ReferralStatus, TeamCurrentStatus, TeamInviteStatus, TeamInviteTeamRole, TeamPlayerTeamRole, TournamentAccess, TournamentCurrentStatus, TournamentInviteStatus, TournamentJoinRequestEntryType, TournamentJoinRequestStatus, TournamentParticipantEntryType, TournamentParticipantStatus, TournamentRoleRole, TournamentTeamSize, TournamentType, TournamentVisibility, UserTransactionStripeStatus, UserTransactionType } from './enums';
|
|
3
3
|
/** `about` */
|
|
4
4
|
export interface About extends StrapiDocument {
|
|
5
5
|
heroTitle?: string | null;
|
|
@@ -7,6 +7,20 @@ export interface About extends StrapiDocument {
|
|
|
7
7
|
aboutInfo?: unknown | null;
|
|
8
8
|
gameIcons?: StrapiMedia[];
|
|
9
9
|
}
|
|
10
|
+
/** `admin-action` */
|
|
11
|
+
export interface AdminAction extends StrapiDocument {
|
|
12
|
+
action?: string | null;
|
|
13
|
+
adminId?: number | null;
|
|
14
|
+
adminUsername?: string | null;
|
|
15
|
+
targetType?: AdminActionTargetType | null;
|
|
16
|
+
targetId?: string | null;
|
|
17
|
+
targetLabel?: string | null;
|
|
18
|
+
contextId?: string | null;
|
|
19
|
+
reason?: string | null;
|
|
20
|
+
before?: unknown | null;
|
|
21
|
+
after?: unknown | null;
|
|
22
|
+
metadata?: unknown | null;
|
|
23
|
+
}
|
|
10
24
|
/** `dm-message` */
|
|
11
25
|
export interface DmMessage extends StrapiDocument {
|
|
12
26
|
conversationId?: string | null;
|
|
@@ -383,6 +397,8 @@ export interface User extends StrapiDocument {
|
|
|
383
397
|
countryCode?: string | null;
|
|
384
398
|
dob?: string | null;
|
|
385
399
|
notifyUpdates?: boolean | null;
|
|
400
|
+
blockedReason?: string | null;
|
|
401
|
+
blockedAt?: string | null;
|
|
386
402
|
xptCoins?: number | null;
|
|
387
403
|
user_transactions?: UserTransaction[];
|
|
388
404
|
dailyRewardStreak?: number | null;
|
package/dist/manual/index.d.ts
CHANGED
package/dist/manual/index.js
CHANGED
|
@@ -19,6 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
*/
|
|
20
20
|
__exportStar(require("./country"), exports);
|
|
21
21
|
__exportStar(require("./lobby"), exports);
|
|
22
|
+
__exportStar(require("./notification"), exports);
|
|
22
23
|
__exportStar(require("./tournamentEntry"), exports);
|
|
23
24
|
__exportStar(require("./tournamentInvite"), exports);
|
|
24
25
|
__exportStar(require("./tournamentJoinRequest"), exports);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification types — the contract between the server's writers and the
|
|
3
|
+
* client's bell.
|
|
4
|
+
*
|
|
5
|
+
* The `notification` content type stores `type` as a plain string (there is no
|
|
6
|
+
* enum on the schema), so the generated `Notification.type` is `string`. This
|
|
7
|
+
* is the closed list both sides agree on: the server refuses to write a type
|
|
8
|
+
* that is not here, the client switches on it for icons, actions and routes,
|
|
9
|
+
* and the preference page groups toggles by `NOTIFICATION_TYPE_GROUP`.
|
|
10
|
+
*
|
|
11
|
+
* Adding a type means adding it here, giving it a group, and then a writer
|
|
12
|
+
* on the server and a glyph on the client — the `Record`s below fail to
|
|
13
|
+
* compile until the group is chosen.
|
|
14
|
+
*/
|
|
15
|
+
export declare const NOTIFICATION_TYPES: readonly ["match_ready", "match_result", "match_dispute", "tournament_registered", "tournament_status", "tournament_eliminated", "tournament_placement", "tournament_withdrawn", "tournament_roster", "tournament_join_request", "tournament_join_approved", "tournament_join_declined", "tournament_join_expired", "tournament_announcement", "team_invite", "team_kicked", "team_captaincy", "team_joined", "friend_request", "friend_request_accepted", "xp_earned", "wallet_credit", "wallet_debit"];
|
|
16
|
+
export type NotificationType = (typeof NOTIFICATION_TYPES)[number];
|
|
17
|
+
/** The in-app toggles on the notification settings page, one per group. */
|
|
18
|
+
export declare const NOTIFICATION_GROUPS: readonly ["matchAlerts", "tournamentUpdates", "teamSocial", "accountRewards"];
|
|
19
|
+
export type NotificationGroup = (typeof NOTIFICATION_GROUPS)[number];
|
|
20
|
+
/**
|
|
21
|
+
* Which toggle gates each type. Exhaustive: a new type must pick a group, or
|
|
22
|
+
* say `null` to mean it is always delivered.
|
|
23
|
+
*/
|
|
24
|
+
export declare const NOTIFICATION_TYPE_GROUP: Record<NotificationType, NotificationGroup | null>;
|
|
25
|
+
/**
|
|
26
|
+
* The stored preference blob on a user. The four groups gate in-app delivery;
|
|
27
|
+
* `emailNotifications` is the single email opt-out; `marketing` is stored for
|
|
28
|
+
* a future channel and read by nothing yet.
|
|
29
|
+
*/
|
|
30
|
+
export interface NotificationPreferences {
|
|
31
|
+
matchAlerts: boolean;
|
|
32
|
+
tournamentUpdates: boolean;
|
|
33
|
+
teamSocial: boolean;
|
|
34
|
+
accountRewards: boolean;
|
|
35
|
+
marketing: boolean;
|
|
36
|
+
emailNotifications: boolean;
|
|
37
|
+
}
|
|
38
|
+
/** Applied when a user has never saved preferences. */
|
|
39
|
+
export declare const DEFAULT_NOTIFICATION_PREFERENCES: NotificationPreferences;
|
|
40
|
+
export declare const isNotificationType: (value: unknown) => value is NotificationType;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Notification types — the contract between the server's writers and the
|
|
4
|
+
* client's bell.
|
|
5
|
+
*
|
|
6
|
+
* The `notification` content type stores `type` as a plain string (there is no
|
|
7
|
+
* enum on the schema), so the generated `Notification.type` is `string`. This
|
|
8
|
+
* is the closed list both sides agree on: the server refuses to write a type
|
|
9
|
+
* that is not here, the client switches on it for icons, actions and routes,
|
|
10
|
+
* and the preference page groups toggles by `NOTIFICATION_TYPE_GROUP`.
|
|
11
|
+
*
|
|
12
|
+
* Adding a type means adding it here, giving it a group, and then a writer
|
|
13
|
+
* on the server and a glyph on the client — the `Record`s below fail to
|
|
14
|
+
* compile until the group is chosen.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.isNotificationType = exports.DEFAULT_NOTIFICATION_PREFERENCES = exports.NOTIFICATION_TYPE_GROUP = exports.NOTIFICATION_GROUPS = exports.NOTIFICATION_TYPES = void 0;
|
|
18
|
+
exports.NOTIFICATION_TYPES = [
|
|
19
|
+
// matchAlerts
|
|
20
|
+
'match_ready',
|
|
21
|
+
'match_result',
|
|
22
|
+
'match_dispute',
|
|
23
|
+
// tournamentUpdates
|
|
24
|
+
'tournament_registered',
|
|
25
|
+
'tournament_status',
|
|
26
|
+
'tournament_eliminated',
|
|
27
|
+
'tournament_placement',
|
|
28
|
+
'tournament_withdrawn',
|
|
29
|
+
'tournament_roster',
|
|
30
|
+
'tournament_join_request',
|
|
31
|
+
'tournament_join_approved',
|
|
32
|
+
'tournament_join_declined',
|
|
33
|
+
'tournament_join_expired',
|
|
34
|
+
// a free-text message from the XPT team to every entrant of a tournament
|
|
35
|
+
'tournament_announcement',
|
|
36
|
+
// teamSocial
|
|
37
|
+
'team_invite',
|
|
38
|
+
'team_kicked',
|
|
39
|
+
'team_captaincy',
|
|
40
|
+
'team_joined',
|
|
41
|
+
'friend_request',
|
|
42
|
+
'friend_request_accepted',
|
|
43
|
+
// accountRewards
|
|
44
|
+
'xp_earned',
|
|
45
|
+
'wallet_credit',
|
|
46
|
+
// ungated — coins leaving an account cannot be muted
|
|
47
|
+
'wallet_debit',
|
|
48
|
+
];
|
|
49
|
+
/** The in-app toggles on the notification settings page, one per group. */
|
|
50
|
+
exports.NOTIFICATION_GROUPS = [
|
|
51
|
+
'matchAlerts',
|
|
52
|
+
'tournamentUpdates',
|
|
53
|
+
'teamSocial',
|
|
54
|
+
'accountRewards',
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Which toggle gates each type. Exhaustive: a new type must pick a group, or
|
|
58
|
+
* say `null` to mean it is always delivered.
|
|
59
|
+
*/
|
|
60
|
+
exports.NOTIFICATION_TYPE_GROUP = {
|
|
61
|
+
match_ready: 'matchAlerts',
|
|
62
|
+
match_result: 'matchAlerts',
|
|
63
|
+
match_dispute: 'matchAlerts',
|
|
64
|
+
tournament_registered: 'tournamentUpdates',
|
|
65
|
+
tournament_status: 'tournamentUpdates',
|
|
66
|
+
tournament_eliminated: 'tournamentUpdates',
|
|
67
|
+
tournament_placement: 'tournamentUpdates',
|
|
68
|
+
tournament_withdrawn: 'tournamentUpdates',
|
|
69
|
+
tournament_roster: 'tournamentUpdates',
|
|
70
|
+
tournament_join_request: 'tournamentUpdates',
|
|
71
|
+
tournament_join_approved: 'tournamentUpdates',
|
|
72
|
+
tournament_join_declined: 'tournamentUpdates',
|
|
73
|
+
tournament_join_expired: 'tournamentUpdates',
|
|
74
|
+
tournament_announcement: 'tournamentUpdates',
|
|
75
|
+
team_invite: 'teamSocial',
|
|
76
|
+
team_kicked: 'teamSocial',
|
|
77
|
+
team_captaincy: 'teamSocial',
|
|
78
|
+
team_joined: 'teamSocial',
|
|
79
|
+
friend_request: 'teamSocial',
|
|
80
|
+
friend_request_accepted: 'teamSocial',
|
|
81
|
+
xp_earned: 'accountRewards',
|
|
82
|
+
wallet_credit: 'accountRewards',
|
|
83
|
+
wallet_debit: null,
|
|
84
|
+
};
|
|
85
|
+
/** Applied when a user has never saved preferences. */
|
|
86
|
+
exports.DEFAULT_NOTIFICATION_PREFERENCES = {
|
|
87
|
+
matchAlerts: true,
|
|
88
|
+
tournamentUpdates: true,
|
|
89
|
+
teamSocial: true,
|
|
90
|
+
accountRewards: true,
|
|
91
|
+
marketing: false,
|
|
92
|
+
emailNotifications: true,
|
|
93
|
+
};
|
|
94
|
+
const isNotificationType = (value) => typeof value === 'string' &&
|
|
95
|
+
exports.NOTIFICATION_TYPES.includes(value);
|
|
96
|
+
exports.isNotificationType = isNotificationType;
|
package/package.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copies this package (package.json + dist) over the consumers' installed copy,
|
|
3
|
+
* so both apps see an unpublished build. This is what has been done by hand
|
|
4
|
+
* for every local iteration; a plain `yarn install` in either app reverts it.
|
|
5
|
+
*
|
|
6
|
+
* yarn build && node scripts/overlay-local.mjs
|
|
7
|
+
*/
|
|
8
|
+
import { cpSync, existsSync, rmSync } from 'node:fs';
|
|
9
|
+
import { dirname, join, resolve } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const root = resolve(here, '..');
|
|
14
|
+
const consumers = ['xpt-strapi', 'xpt-client'].map((name) =>
|
|
15
|
+
resolve(root, '..', name, 'node_modules', 'xpt-shared-types')
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
if (!existsSync(join(root, 'dist', 'index.js'))) {
|
|
19
|
+
console.error('dist/ is missing - run `yarn build` first');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const target of consumers) {
|
|
24
|
+
if (!existsSync(dirname(target))) {
|
|
25
|
+
console.warn(`skip ${target} (no node_modules)`);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
rmSync(join(target, 'dist'), { recursive: true, force: true });
|
|
29
|
+
cpSync(join(root, 'dist'), join(target, 'dist'), { recursive: true });
|
|
30
|
+
cpSync(join(root, 'package.json'), join(target, 'package.json'));
|
|
31
|
+
console.log(`overlaid ${target}`);
|
|
32
|
+
}
|
package/src/generated/enums.ts
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
// Source: xpt-strapi/src/**/content-types/**/schema.json
|
|
3
3
|
// Regenerate with: yarn sync
|
|
4
4
|
|
|
5
|
+
/** `AdminAction.targetType` */
|
|
6
|
+
export type AdminActionTargetType =
|
|
7
|
+
| "user"
|
|
8
|
+
| "tournament"
|
|
9
|
+
| "match"
|
|
10
|
+
| "transaction";
|
|
11
|
+
|
|
5
12
|
/** `Faq.category` */
|
|
6
13
|
export type FaqCategory =
|
|
7
14
|
| "gettingStarted"
|
package/src/generated/inputs.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
RelationInput,
|
|
9
9
|
} from '../contracts';
|
|
10
10
|
import type {
|
|
11
|
+
AdminActionTargetType,
|
|
11
12
|
FaqCategory,
|
|
12
13
|
FriendshipStatus,
|
|
13
14
|
GameGenre,
|
|
@@ -50,6 +51,21 @@ export interface AboutInput {
|
|
|
50
51
|
gameIcons?: MediaInput[];
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
/** Write payload for `admin-action`. */
|
|
55
|
+
export interface AdminActionInput {
|
|
56
|
+
action?: string;
|
|
57
|
+
adminId?: number;
|
|
58
|
+
adminUsername?: string;
|
|
59
|
+
targetType?: AdminActionTargetType;
|
|
60
|
+
targetId?: string;
|
|
61
|
+
targetLabel?: string;
|
|
62
|
+
contextId?: string;
|
|
63
|
+
reason?: string;
|
|
64
|
+
before?: unknown;
|
|
65
|
+
after?: unknown;
|
|
66
|
+
metadata?: unknown;
|
|
67
|
+
}
|
|
68
|
+
|
|
53
69
|
/** Write payload for `dm-message`. */
|
|
54
70
|
export interface DmMessageInput {
|
|
55
71
|
conversationId?: string;
|
|
@@ -461,6 +477,8 @@ export interface UserInput {
|
|
|
461
477
|
countryCode?: string;
|
|
462
478
|
dob?: string;
|
|
463
479
|
notifyUpdates?: boolean;
|
|
480
|
+
blockedReason?: string;
|
|
481
|
+
blockedAt?: string;
|
|
464
482
|
xptCoins?: number;
|
|
465
483
|
user_transactions?: RelationInput | RelationInput[];
|
|
466
484
|
dailyRewardStreak?: number;
|
package/src/generated/models.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
UserRole,
|
|
10
10
|
} from '../contracts';
|
|
11
11
|
import type {
|
|
12
|
+
AdminActionTargetType,
|
|
12
13
|
FaqCategory,
|
|
13
14
|
FriendshipStatus,
|
|
14
15
|
GameGenre,
|
|
@@ -51,6 +52,21 @@ export interface About extends StrapiDocument {
|
|
|
51
52
|
gameIcons?: StrapiMedia[];
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/** `admin-action` */
|
|
56
|
+
export interface AdminAction extends StrapiDocument {
|
|
57
|
+
action?: string | null;
|
|
58
|
+
adminId?: number | null;
|
|
59
|
+
adminUsername?: string | null;
|
|
60
|
+
targetType?: AdminActionTargetType | null;
|
|
61
|
+
targetId?: string | null;
|
|
62
|
+
targetLabel?: string | null;
|
|
63
|
+
contextId?: string | null;
|
|
64
|
+
reason?: string | null;
|
|
65
|
+
before?: unknown | null;
|
|
66
|
+
after?: unknown | null;
|
|
67
|
+
metadata?: unknown | null;
|
|
68
|
+
}
|
|
69
|
+
|
|
54
70
|
/** `dm-message` */
|
|
55
71
|
export interface DmMessage extends StrapiDocument {
|
|
56
72
|
conversationId?: string | null;
|
|
@@ -462,6 +478,8 @@ export interface User extends StrapiDocument {
|
|
|
462
478
|
countryCode?: string | null;
|
|
463
479
|
dob?: string | null;
|
|
464
480
|
notifyUpdates?: boolean | null;
|
|
481
|
+
blockedReason?: string | null;
|
|
482
|
+
blockedAt?: string | null;
|
|
465
483
|
xptCoins?: number | null;
|
|
466
484
|
user_transactions?: UserTransaction[];
|
|
467
485
|
dailyRewardStreak?: number | null;
|
package/src/index.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
// Generated from the Strapi schemas — see scripts/sync-from-strapi.js
|
|
2
|
-
export * from './generated';
|
|
3
|
-
|
|
4
|
-
// Hand-written contract primitives (response envelopes, Populated, media)
|
|
5
|
-
export * from './contracts';
|
|
6
|
-
|
|
7
|
-
// Hand-written types with no Strapi content type behind them
|
|
8
|
-
export * from './manual';
|
|
9
|
-
|
|
10
|
-
// Bracket shape — shared by the backend generator and Storybook fixtures
|
|
11
|
-
export * from './bracket';
|
|
12
|
-
|
|
13
|
-
// Game/platform/account catalogue — the game -> platform -> account chain,
|
|
14
|
-
// applied identically by the backend resolver and the client's pickers
|
|
15
|
-
export * from './gameCatalogue';
|
|
16
|
-
|
|
17
|
-
// Stream links — one pasted URL parsed the same way by the backend that stores
|
|
18
|
-
// the derived columns and the client that embeds the player
|
|
19
|
-
export * from './stream';
|
|
20
|
-
|
|
21
|
-
// Data
|
|
22
|
-
export * from './data/countriesList';
|
|
23
|
-
export * from './data/gameGenres';
|
|
1
|
+
// Generated from the Strapi schemas — see scripts/sync-from-strapi.js
|
|
2
|
+
export * from './generated';
|
|
3
|
+
|
|
4
|
+
// Hand-written contract primitives (response envelopes, Populated, media)
|
|
5
|
+
export * from './contracts';
|
|
6
|
+
|
|
7
|
+
// Hand-written types with no Strapi content type behind them
|
|
8
|
+
export * from './manual';
|
|
9
|
+
|
|
10
|
+
// Bracket shape — shared by the backend generator and Storybook fixtures
|
|
11
|
+
export * from './bracket';
|
|
12
|
+
|
|
13
|
+
// Game/platform/account catalogue — the game -> platform -> account chain,
|
|
14
|
+
// applied identically by the backend resolver and the client's pickers
|
|
15
|
+
export * from './gameCatalogue';
|
|
16
|
+
|
|
17
|
+
// Stream links — one pasted URL parsed the same way by the backend that stores
|
|
18
|
+
// the derived columns and the client that embeds the player
|
|
19
|
+
export * from './stream';
|
|
20
|
+
|
|
21
|
+
// Data
|
|
22
|
+
export * from './data/countriesList';
|
|
23
|
+
export * from './data/gameGenres';
|
package/src/manual/country.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export interface Country {
|
|
2
|
-
countryName: string;
|
|
3
|
-
alpha2: string;
|
|
4
|
-
alpha3: string;
|
|
5
|
-
numeric: string;
|
|
6
|
-
}
|
|
1
|
+
export interface Country {
|
|
2
|
+
countryName: string;
|
|
3
|
+
alpha2: string;
|
|
4
|
+
alpha3: string;
|
|
5
|
+
numeric: string;
|
|
6
|
+
}
|
package/src/manual/index.ts
CHANGED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification types — the contract between the server's writers and the
|
|
3
|
+
* client's bell.
|
|
4
|
+
*
|
|
5
|
+
* The `notification` content type stores `type` as a plain string (there is no
|
|
6
|
+
* enum on the schema), so the generated `Notification.type` is `string`. This
|
|
7
|
+
* is the closed list both sides agree on: the server refuses to write a type
|
|
8
|
+
* that is not here, the client switches on it for icons, actions and routes,
|
|
9
|
+
* and the preference page groups toggles by `NOTIFICATION_TYPE_GROUP`.
|
|
10
|
+
*
|
|
11
|
+
* Adding a type means adding it here, giving it a group, and then a writer
|
|
12
|
+
* on the server and a glyph on the client — the `Record`s below fail to
|
|
13
|
+
* compile until the group is chosen.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const NOTIFICATION_TYPES = [
|
|
17
|
+
// matchAlerts
|
|
18
|
+
'match_ready',
|
|
19
|
+
'match_result',
|
|
20
|
+
'match_dispute',
|
|
21
|
+
// tournamentUpdates
|
|
22
|
+
'tournament_registered',
|
|
23
|
+
'tournament_status',
|
|
24
|
+
'tournament_eliminated',
|
|
25
|
+
'tournament_placement',
|
|
26
|
+
'tournament_withdrawn',
|
|
27
|
+
'tournament_roster',
|
|
28
|
+
'tournament_join_request',
|
|
29
|
+
'tournament_join_approved',
|
|
30
|
+
'tournament_join_declined',
|
|
31
|
+
'tournament_join_expired',
|
|
32
|
+
// a free-text message from the XPT team to every entrant of a tournament
|
|
33
|
+
'tournament_announcement',
|
|
34
|
+
// teamSocial
|
|
35
|
+
'team_invite',
|
|
36
|
+
'team_kicked',
|
|
37
|
+
'team_captaincy',
|
|
38
|
+
'team_joined',
|
|
39
|
+
'friend_request',
|
|
40
|
+
'friend_request_accepted',
|
|
41
|
+
// accountRewards
|
|
42
|
+
'xp_earned',
|
|
43
|
+
'wallet_credit',
|
|
44
|
+
// ungated — coins leaving an account cannot be muted
|
|
45
|
+
'wallet_debit',
|
|
46
|
+
] as const;
|
|
47
|
+
|
|
48
|
+
export type NotificationType = (typeof NOTIFICATION_TYPES)[number];
|
|
49
|
+
|
|
50
|
+
/** The in-app toggles on the notification settings page, one per group. */
|
|
51
|
+
export const NOTIFICATION_GROUPS = [
|
|
52
|
+
'matchAlerts',
|
|
53
|
+
'tournamentUpdates',
|
|
54
|
+
'teamSocial',
|
|
55
|
+
'accountRewards',
|
|
56
|
+
] as const;
|
|
57
|
+
|
|
58
|
+
export type NotificationGroup = (typeof NOTIFICATION_GROUPS)[number];
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Which toggle gates each type. Exhaustive: a new type must pick a group, or
|
|
62
|
+
* say `null` to mean it is always delivered.
|
|
63
|
+
*/
|
|
64
|
+
export const NOTIFICATION_TYPE_GROUP: Record<
|
|
65
|
+
NotificationType,
|
|
66
|
+
NotificationGroup | null
|
|
67
|
+
> =
|
|
68
|
+
{
|
|
69
|
+
match_ready: 'matchAlerts',
|
|
70
|
+
match_result: 'matchAlerts',
|
|
71
|
+
match_dispute: 'matchAlerts',
|
|
72
|
+
tournament_registered: 'tournamentUpdates',
|
|
73
|
+
tournament_status: 'tournamentUpdates',
|
|
74
|
+
tournament_eliminated: 'tournamentUpdates',
|
|
75
|
+
tournament_placement: 'tournamentUpdates',
|
|
76
|
+
tournament_withdrawn: 'tournamentUpdates',
|
|
77
|
+
tournament_roster: 'tournamentUpdates',
|
|
78
|
+
tournament_join_request: 'tournamentUpdates',
|
|
79
|
+
tournament_join_approved: 'tournamentUpdates',
|
|
80
|
+
tournament_join_declined: 'tournamentUpdates',
|
|
81
|
+
tournament_join_expired: 'tournamentUpdates',
|
|
82
|
+
tournament_announcement: 'tournamentUpdates',
|
|
83
|
+
team_invite: 'teamSocial',
|
|
84
|
+
team_kicked: 'teamSocial',
|
|
85
|
+
team_captaincy: 'teamSocial',
|
|
86
|
+
team_joined: 'teamSocial',
|
|
87
|
+
friend_request: 'teamSocial',
|
|
88
|
+
friend_request_accepted: 'teamSocial',
|
|
89
|
+
xp_earned: 'accountRewards',
|
|
90
|
+
wallet_credit: 'accountRewards',
|
|
91
|
+
wallet_debit: null,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The stored preference blob on a user. The four groups gate in-app delivery;
|
|
96
|
+
* `emailNotifications` is the single email opt-out; `marketing` is stored for
|
|
97
|
+
* a future channel and read by nothing yet.
|
|
98
|
+
*/
|
|
99
|
+
export interface NotificationPreferences {
|
|
100
|
+
matchAlerts: boolean;
|
|
101
|
+
tournamentUpdates: boolean;
|
|
102
|
+
teamSocial: boolean;
|
|
103
|
+
accountRewards: boolean;
|
|
104
|
+
marketing: boolean;
|
|
105
|
+
emailNotifications: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Applied when a user has never saved preferences. */
|
|
109
|
+
export const DEFAULT_NOTIFICATION_PREFERENCES: NotificationPreferences = {
|
|
110
|
+
matchAlerts: true,
|
|
111
|
+
tournamentUpdates: true,
|
|
112
|
+
teamSocial: true,
|
|
113
|
+
accountRewards: true,
|
|
114
|
+
marketing: false,
|
|
115
|
+
emailNotifications: true,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const isNotificationType = (value: unknown): value is NotificationType =>
|
|
119
|
+
typeof value === 'string' &&
|
|
120
|
+
(NOTIFICATION_TYPES as readonly string[]).includes(value);
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
/**
|
|
3
|
-
* Generates the shared API contract from the Strapi content-type schemas.
|
|
4
|
-
*
|
|
5
|
-
* `schema.json` is the source of truth — not `types/generated/contentTypes.d.ts`,
|
|
6
|
-
* which is gitignored in xpt-strapi and only exists after `strapi develop` has run.
|
|
7
|
-
*
|
|
8
|
-
* node scripts/sync-from-strapi.js [pathToStrapiRepo]
|
|
9
|
-
*
|
|
10
|
-
* Output is committed to this repo; run this whenever a content type changes.
|
|
11
|
-
*/
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
const STRAPI_ROOT =
|
|
16
|
-
process.argv[2] ||
|
|
17
|
-
process.env.XPT_STRAPI_PATH ||
|
|
18
|
-
path.resolve(__dirname, '../../xpt-strapi');
|
|
19
|
-
const OUT = path.resolve(__dirname, '../src/generated');
|
|
20
|
-
|
|
21
|
-
const BANNER = [
|
|
22
|
-
'// AUTO-GENERATED by scripts/sync-from-strapi.js — DO NOT EDIT MANUALLY.',
|
|
23
|
-
'// Source: xpt-strapi/src/**/content-types/**/schema.json',
|
|
24
|
-
'// Regenerate with: yarn sync',
|
|
25
|
-
'',
|
|
26
|
-
].join('\n');
|
|
27
|
-
|
|
28
|
-
// ── helpers ────────────────────────────────────────────────────────────────
|
|
29
|
-
/** Quote a property name only when it is not a bare identifier. */
|
|
30
|
-
const prop = (name) =>
|
|
31
|
-
/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
|
|
32
|
-
|
|
33
|
-
const pascal = (s) =>
|
|
34
|
-
String(s)
|
|
35
|
-
.replace(/[_-]+([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())
|
|
36
|
-
.replace(/^([a-z])/, (_, c) => c.toUpperCase())
|
|
37
|
-
.replace(/[^A-Za-z0-9]/g, '');
|
|
38
|
-
|
|
39
|
-
/** api::tournament-participant.tournament-participant -> TournamentParticipant */
|
|
40
|
-
function modelNameFromUid(uid) {
|
|
41
|
-
if (uid === 'plugin::users-permissions.user') return 'User';
|
|
42
|
-
if (uid === 'plugin::users-permissions.role') return 'UserRole';
|
|
43
|
-
if (uid === 'plugin::upload.file') return 'StrapiMedia';
|
|
44
|
-
const m = /^api::[^.]+\.(.+)$/.exec(uid);
|
|
45
|
-
return m ? pascal(m[1]) : null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const SCALARS = {
|
|
49
|
-
string: 'string',
|
|
50
|
-
text: 'string',
|
|
51
|
-
richtext: 'string',
|
|
52
|
-
uid: 'string',
|
|
53
|
-
email: 'string',
|
|
54
|
-
password: 'string',
|
|
55
|
-
datetime: 'string',
|
|
56
|
-
date: 'string',
|
|
57
|
-
time: 'string',
|
|
58
|
-
biginteger: 'string', // Strapi serialises bigint as string
|
|
59
|
-
integer: 'number',
|
|
60
|
-
float: 'number',
|
|
61
|
-
decimal: 'number',
|
|
62
|
-
boolean: 'boolean',
|
|
63
|
-
json: 'unknown',
|
|
64
|
-
blocks: 'BlocksContent',
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// ── collect schemas ────────────────────────────────────────────────────────
|
|
68
|
-
function findSchemas(root) {
|
|
69
|
-
const out = [];
|
|
70
|
-
const roots = [
|
|
71
|
-
path.join(root, 'src', 'api'),
|
|
72
|
-
path.join(root, 'src', 'extensions'),
|
|
73
|
-
];
|
|
74
|
-
for (const base of roots) {
|
|
75
|
-
if (!fs.existsSync(base)) continue;
|
|
76
|
-
for (const dir of fs.readdirSync(base)) {
|
|
77
|
-
const ctDir = path.join(base, dir, 'content-types');
|
|
78
|
-
if (!fs.existsSync(ctDir)) continue;
|
|
79
|
-
for (const ct of fs.readdirSync(ctDir)) {
|
|
80
|
-
const file = path.join(ctDir, ct, 'schema.json');
|
|
81
|
-
if (fs.existsSync(file)) out.push(file);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return out.sort();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const files = findSchemas(STRAPI_ROOT);
|
|
89
|
-
if (!files.length) {
|
|
90
|
-
console.error(
|
|
91
|
-
'No schema.json found under ' +
|
|
92
|
-
STRAPI_ROOT +
|
|
93
|
-
'. Pass the xpt-strapi path as an argument.'
|
|
94
|
-
);
|
|
95
|
-
process.exit(1);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const collected = [];
|
|
99
|
-
for (const file of files) {
|
|
100
|
-
const raw = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
101
|
-
const info = raw.info || {};
|
|
102
|
-
const singular = info.singularName || path.basename(path.dirname(file));
|
|
103
|
-
// The users-permissions extension augments the plugin's own user model.
|
|
104
|
-
const isUserExt = file.split(path.sep).includes('users-permissions');
|
|
105
|
-
collected.push({
|
|
106
|
-
name: isUserExt ? 'User' : pascal(singular),
|
|
107
|
-
singular: isUserExt ? 'user' : singular,
|
|
108
|
-
attributes: raw.attributes || {},
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Merge any model declared more than once (e.g. the user extension).
|
|
113
|
-
const byName = new Map();
|
|
114
|
-
for (const m of collected) {
|
|
115
|
-
if (byName.has(m.name)) {
|
|
116
|
-
Object.assign(byName.get(m.name).attributes, m.attributes);
|
|
117
|
-
} else {
|
|
118
|
-
byName.set(m.name, m);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
const allModels = [...byName.values()].sort((a, b) =>
|
|
122
|
-
a.name.localeCompare(b.name)
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
// ── enums ──────────────────────────────────────────────────────────────────
|
|
126
|
-
const enums = [];
|
|
127
|
-
for (const m of allModels) {
|
|
128
|
-
for (const [field, def] of Object.entries(m.attributes)) {
|
|
129
|
-
if (def.type !== 'enumeration' || !Array.isArray(def.enum)) continue;
|
|
130
|
-
enums.push({
|
|
131
|
-
name: m.name + pascal(field),
|
|
132
|
-
values: def.enum,
|
|
133
|
-
model: m.name,
|
|
134
|
-
field,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
enums.sort((a, b) => a.name.localeCompare(b.name));
|
|
139
|
-
|
|
140
|
-
let enumsOut = BANNER + '\n';
|
|
141
|
-
for (const e of enums) {
|
|
142
|
-
enumsOut +=
|
|
143
|
-
'/** `' +
|
|
144
|
-
e.model +
|
|
145
|
-
'.' +
|
|
146
|
-
e.field +
|
|
147
|
-
'` */\nexport type ' +
|
|
148
|
-
e.name +
|
|
149
|
-
' =\n' +
|
|
150
|
-
e.values.map((v) => ' | ' + JSON.stringify(v)).join('\n') +
|
|
151
|
-
';\n\n';
|
|
152
|
-
}
|
|
153
|
-
enumsOut +=
|
|
154
|
-
'/** Readability alias for `tournament.currentStatus`. */\n' +
|
|
155
|
-
'export type TournamentStatus = TournamentCurrentStatus;\n';
|
|
156
|
-
|
|
157
|
-
// ── models (read shapes) ───────────────────────────────────────────────────
|
|
158
|
-
const enumLookup = new Map(enums.map((e) => [e.model + '.' + e.field, e.name]));
|
|
159
|
-
const usedEnums = new Set();
|
|
160
|
-
|
|
161
|
-
function readTypeFor(model, field, def) {
|
|
162
|
-
if (def.type === 'enumeration') {
|
|
163
|
-
return enumLookup.get(model.name + '.' + field) || 'string';
|
|
164
|
-
}
|
|
165
|
-
if (def.type === 'media') {
|
|
166
|
-
return def.multiple ? 'StrapiMedia[]' : 'StrapiMedia';
|
|
167
|
-
}
|
|
168
|
-
if (def.type === 'relation') {
|
|
169
|
-
const target = modelNameFromUid(def.target);
|
|
170
|
-
if (!target) return 'unknown';
|
|
171
|
-
const many =
|
|
172
|
-
def.relation === 'oneToMany' || def.relation === 'manyToMany';
|
|
173
|
-
return many ? target + '[]' : target;
|
|
174
|
-
}
|
|
175
|
-
return SCALARS[def.type] || 'unknown';
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
let modelsBody = '';
|
|
179
|
-
for (const m of allModels) {
|
|
180
|
-
const lines = [];
|
|
181
|
-
for (const [field, def] of Object.entries(m.attributes)) {
|
|
182
|
-
// `private` attributes are never returned by the content API.
|
|
183
|
-
if (def.private) continue;
|
|
184
|
-
const t = readTypeFor(m, field, def);
|
|
185
|
-
if (def.type === 'enumeration') usedEnums.add(t);
|
|
186
|
-
// Everything except id/documentId is optional, because nothing else is
|
|
187
|
-
// guaranteed on the wire:
|
|
188
|
-
// - relations and media appear only when the query populates them;
|
|
189
|
-
// - any scalar disappears when the query uses `fields`, which this
|
|
190
|
-
// codebase does pervasively — so even a schema-`required` field like
|
|
191
|
-
// user.email is absent from most responses.
|
|
192
|
-
// The base model is therefore the minimum guarantee; use `Populated<T, K>`
|
|
193
|
-
// at a call site to record what that particular query actually returned.
|
|
194
|
-
// Strapi also sends `null` rather than omitting an unset nullable value,
|
|
195
|
-
// so single-valued optionals are `?: T | null`. Lists come back as `[]`.
|
|
196
|
-
const isList = t.endsWith('[]');
|
|
197
|
-
const rendered = isList ? t : t + ' | null';
|
|
198
|
-
lines.push(' ' + prop(field) + '?: ' + rendered + ';');
|
|
199
|
-
}
|
|
200
|
-
modelsBody +=
|
|
201
|
-
'/** `' +
|
|
202
|
-
m.singular +
|
|
203
|
-
'` */\nexport interface ' +
|
|
204
|
-
m.name +
|
|
205
|
-
' extends StrapiDocument {\n' +
|
|
206
|
-
lines.join('\n') +
|
|
207
|
-
'\n}\n\n';
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const enumImportList = [...usedEnums]
|
|
211
|
-
.filter((e) => !e.endsWith('[]'))
|
|
212
|
-
.sort()
|
|
213
|
-
.map((e) => ' ' + e + ',')
|
|
214
|
-
.join('\n');
|
|
215
|
-
|
|
216
|
-
const modelsOut =
|
|
217
|
-
BANNER +
|
|
218
|
-
"\nimport type {\n BlocksContent,\n StrapiDocument,\n StrapiMedia,\n UserRole,\n} from '../contracts';\n" +
|
|
219
|
-
(enumImportList ? 'import type {\n' + enumImportList + "\n} from './enums';\n" : '') +
|
|
220
|
-
'\n' +
|
|
221
|
-
modelsBody;
|
|
222
|
-
|
|
223
|
-
// ── inputs (write shapes) ──────────────────────────────────────────────────
|
|
224
|
-
// Write payloads differ structurally from read shapes: relations are sent as
|
|
225
|
-
// documentIds or connect/set/disconnect, media as numeric file ids.
|
|
226
|
-
let inputsBody = '';
|
|
227
|
-
for (const m of allModels) {
|
|
228
|
-
const lines = [];
|
|
229
|
-
for (const [field, def] of Object.entries(m.attributes)) {
|
|
230
|
-
if (def.private) continue;
|
|
231
|
-
let t;
|
|
232
|
-
if (def.type === 'relation') {
|
|
233
|
-
const many =
|
|
234
|
-
def.relation === 'oneToMany' || def.relation === 'manyToMany';
|
|
235
|
-
t = many ? 'RelationInput | RelationInput[]' : 'RelationInput';
|
|
236
|
-
} else if (def.type === 'media') {
|
|
237
|
-
t = def.multiple ? 'MediaInput[]' : 'MediaInput';
|
|
238
|
-
} else if (def.type === 'enumeration') {
|
|
239
|
-
t = enumLookup.get(m.name + '.' + field) || 'string';
|
|
240
|
-
} else {
|
|
241
|
-
t = SCALARS[def.type] || 'unknown';
|
|
242
|
-
}
|
|
243
|
-
lines.push(' ' + prop(field) + '?: ' + t + ';');
|
|
244
|
-
}
|
|
245
|
-
inputsBody +=
|
|
246
|
-
'/** Write payload for `' +
|
|
247
|
-
m.singular +
|
|
248
|
-
'`. */\nexport interface ' +
|
|
249
|
-
m.name +
|
|
250
|
-
'Input {\n' +
|
|
251
|
-
lines.join('\n') +
|
|
252
|
-
'\n}\n\n';
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const inputsOut =
|
|
256
|
-
BANNER +
|
|
257
|
-
"\nimport type {\n BlocksContent,\n MediaInput,\n RelationInput,\n} from '../contracts';\n" +
|
|
258
|
-
(enumImportList ? 'import type {\n' + enumImportList + "\n} from './enums';\n" : '') +
|
|
259
|
-
'\n' +
|
|
260
|
-
inputsBody;
|
|
261
|
-
|
|
262
|
-
// ── write ──────────────────────────────────────────────────────────────────
|
|
263
|
-
fs.mkdirSync(OUT, { recursive: true });
|
|
264
|
-
fs.writeFileSync(path.join(OUT, 'enums.ts'), enumsOut);
|
|
265
|
-
fs.writeFileSync(path.join(OUT, 'models.ts'), modelsOut);
|
|
266
|
-
fs.writeFileSync(path.join(OUT, 'inputs.ts'), inputsOut);
|
|
267
|
-
fs.writeFileSync(
|
|
268
|
-
path.join(OUT, 'index.ts'),
|
|
269
|
-
BANNER +
|
|
270
|
-
"\nexport * from './enums';\nexport * from './models';\nexport * from './inputs';\n"
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
console.log(
|
|
274
|
-
'Generated ' +
|
|
275
|
-
allModels.length +
|
|
276
|
-
' models and ' +
|
|
277
|
-
enums.length +
|
|
278
|
-
' enums from ' +
|
|
279
|
-
files.length +
|
|
280
|
-
' schemas.'
|
|
281
|
-
);
|