xpt-shared-types 1.11.0 → 1.12.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/dist/manual/index.d.ts
CHANGED
package/dist/manual/index.js
CHANGED
|
@@ -22,3 +22,4 @@ __exportStar(require("./lobby"), exports);
|
|
|
22
22
|
__exportStar(require("./tournamentEntry"), exports);
|
|
23
23
|
__exportStar(require("./tournamentInvite"), exports);
|
|
24
24
|
__exportStar(require("./tournamentJoinRequest"), exports);
|
|
25
|
+
__exportStar(require("./tournamentStaff"), exports);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tournament staff — who runs a tournament and what each of them may do.
|
|
3
|
+
*
|
|
4
|
+
* Three roles. The **owner** is the tournament's `users_permissions_user`
|
|
5
|
+
* and never a row; **admin** and **moderator** are `tournament-role` rows
|
|
6
|
+
* (the `TournamentRoleRole` enum is generated from the schema). A row with
|
|
7
|
+
* no role value is read as a moderator, the least the row can mean.
|
|
8
|
+
*
|
|
9
|
+
* The capability table is the contract between the server's guards and the
|
|
10
|
+
* client's buttons: both resolve the viewer's role with
|
|
11
|
+
* `resolveTournamentStaffRole` and ask `canTournamentStaff`, so a control is
|
|
12
|
+
* never offered for a request the server would refuse. Money and the
|
|
13
|
+
* irreversible lifecycle steps stay with the owner; admins run the event;
|
|
14
|
+
* moderators run matches.
|
|
15
|
+
*/
|
|
16
|
+
import type { TournamentRoleRole } from '../generated/enums';
|
|
17
|
+
export type TournamentStaffRole = 'owner' | TournamentRoleRole;
|
|
18
|
+
/** The roles the owner can hand out — everything but their own. */
|
|
19
|
+
export type TournamentAppointedRole = TournamentRoleRole;
|
|
20
|
+
export declare const APPOINTABLE_STAFF_ROLES: readonly ["admin", "moderator"];
|
|
21
|
+
export type TournamentStaffAction =
|
|
22
|
+
/** Appoint, re-role or remove admins and moderators. */
|
|
23
|
+
'manageStaff'
|
|
24
|
+
/** `PUT /tournaments/:id` — info, rules, stages, links. */
|
|
25
|
+
| 'editTournament'
|
|
26
|
+
/** Draft → open; debits the prize pool. */
|
|
27
|
+
| 'publish'
|
|
28
|
+
/** Drafts only. */
|
|
29
|
+
| 'delete'
|
|
30
|
+
/** The forward transitions: checkIn, seeding, live, completed. */
|
|
31
|
+
| 'changeStatus'
|
|
32
|
+
/** Refunds every entrant. */
|
|
33
|
+
| 'cancel' | 'distributePrizes' | 'manageInvites' | 'reviewJoinRequests' | 'resolveDispute'
|
|
34
|
+
/** Seed, initialise the bracket, place players in slots. */
|
|
35
|
+
| 'seedBracket'
|
|
36
|
+
/** Record scores, start matches, edit match details. */
|
|
37
|
+
| 'manageMatches'
|
|
38
|
+
/** Watch any lobby and post as staff in its chat. */
|
|
39
|
+
| 'enterLobby';
|
|
40
|
+
export declare const TOURNAMENT_STAFF_CAPABILITIES: Record<TournamentStaffAction, readonly TournamentStaffRole[]>;
|
|
41
|
+
export declare const TOURNAMENT_STAFF_ROLE_LABELS: Record<TournamentStaffRole, string>;
|
|
42
|
+
export declare const tournamentStaffRoleLabel: (role: string | null | undefined) => string;
|
|
43
|
+
/** Only what the resolver reads; both apps' tournament shapes satisfy it. */
|
|
44
|
+
export interface TournamentStaffLike {
|
|
45
|
+
users_permissions_user?: {
|
|
46
|
+
id?: number | string | null;
|
|
47
|
+
} | null;
|
|
48
|
+
tournament_roles?: Array<{
|
|
49
|
+
role?: string | null;
|
|
50
|
+
users_permissions_user?: {
|
|
51
|
+
id?: number | string | null;
|
|
52
|
+
} | null;
|
|
53
|
+
}> | null;
|
|
54
|
+
}
|
|
55
|
+
/** An appointed row's role, defaulting an unset value to the least it can mean. */
|
|
56
|
+
export declare const appointedRoleOf: (role: string | null | undefined) => TournamentAppointedRole;
|
|
57
|
+
/**
|
|
58
|
+
* The viewer's staff role on a tournament, or null for everyone else. The
|
|
59
|
+
* owner wins over any row they might also hold.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveTournamentStaffRole(tournament: TournamentStaffLike | null | undefined, userId: number | string | null | undefined): TournamentStaffRole | null;
|
|
62
|
+
export declare const canTournamentStaff: (role: TournamentStaffRole | null | undefined, action: TournamentStaffAction) => boolean;
|
|
63
|
+
/** `canTournamentStaff` for a viewer, resolving their role first. */
|
|
64
|
+
export declare const tournamentStaffCan: (tournament: TournamentStaffLike | null | undefined, userId: number | string | null | undefined, action: TournamentStaffAction) => boolean;
|
|
65
|
+
/** Staff can be changed until the tournament is settled. */
|
|
66
|
+
export declare const STAFF_EDITABLE_STATUSES: readonly ["draft", "open", "checkIn", "seeding", "live"];
|
|
67
|
+
export declare const isTournamentStaffEditable: (status: string | null | undefined) => boolean;
|
|
68
|
+
/** One appointee as the owner's dialog sends it. */
|
|
69
|
+
export interface TournamentStaffMemberInput {
|
|
70
|
+
/** The user's documentId — what the search results carry. */
|
|
71
|
+
userDocumentId: string;
|
|
72
|
+
role: TournamentAppointedRole;
|
|
73
|
+
}
|
|
74
|
+
/** The whole appointed list; the server diffs it against the rows. */
|
|
75
|
+
export interface UpdateTournamentStaffBody {
|
|
76
|
+
data: {
|
|
77
|
+
staff: TournamentStaffMemberInput[];
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** `error.details.name` values the staff routes raise. */
|
|
81
|
+
export type TournamentStaffErrorName = 'NotTournamentStaff';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tournament staff — who runs a tournament and what each of them may do.
|
|
4
|
+
*
|
|
5
|
+
* Three roles. The **owner** is the tournament's `users_permissions_user`
|
|
6
|
+
* and never a row; **admin** and **moderator** are `tournament-role` rows
|
|
7
|
+
* (the `TournamentRoleRole` enum is generated from the schema). A row with
|
|
8
|
+
* no role value is read as a moderator, the least the row can mean.
|
|
9
|
+
*
|
|
10
|
+
* The capability table is the contract between the server's guards and the
|
|
11
|
+
* client's buttons: both resolve the viewer's role with
|
|
12
|
+
* `resolveTournamentStaffRole` and ask `canTournamentStaff`, so a control is
|
|
13
|
+
* never offered for a request the server would refuse. Money and the
|
|
14
|
+
* irreversible lifecycle steps stay with the owner; admins run the event;
|
|
15
|
+
* moderators run matches.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.isTournamentStaffEditable = exports.STAFF_EDITABLE_STATUSES = exports.tournamentStaffCan = exports.canTournamentStaff = exports.appointedRoleOf = exports.tournamentStaffRoleLabel = exports.TOURNAMENT_STAFF_ROLE_LABELS = exports.TOURNAMENT_STAFF_CAPABILITIES = exports.APPOINTABLE_STAFF_ROLES = void 0;
|
|
19
|
+
exports.resolveTournamentStaffRole = resolveTournamentStaffRole;
|
|
20
|
+
exports.APPOINTABLE_STAFF_ROLES = [
|
|
21
|
+
'admin',
|
|
22
|
+
'moderator',
|
|
23
|
+
];
|
|
24
|
+
const OWNER_ONLY = ['owner'];
|
|
25
|
+
const ADMIN_UP = ['owner', 'admin'];
|
|
26
|
+
const ALL_STAFF = ['owner', 'admin', 'moderator'];
|
|
27
|
+
exports.TOURNAMENT_STAFF_CAPABILITIES = {
|
|
28
|
+
manageStaff: OWNER_ONLY,
|
|
29
|
+
publish: OWNER_ONLY,
|
|
30
|
+
delete: OWNER_ONLY,
|
|
31
|
+
cancel: OWNER_ONLY,
|
|
32
|
+
distributePrizes: OWNER_ONLY,
|
|
33
|
+
editTournament: ADMIN_UP,
|
|
34
|
+
changeStatus: ADMIN_UP,
|
|
35
|
+
manageInvites: ADMIN_UP,
|
|
36
|
+
reviewJoinRequests: ADMIN_UP,
|
|
37
|
+
resolveDispute: ADMIN_UP,
|
|
38
|
+
seedBracket: ADMIN_UP,
|
|
39
|
+
manageMatches: ALL_STAFF,
|
|
40
|
+
enterLobby: ALL_STAFF,
|
|
41
|
+
};
|
|
42
|
+
exports.TOURNAMENT_STAFF_ROLE_LABELS = {
|
|
43
|
+
owner: 'Owner',
|
|
44
|
+
admin: 'Admin',
|
|
45
|
+
moderator: 'Moderator',
|
|
46
|
+
};
|
|
47
|
+
const tournamentStaffRoleLabel = (role) => {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
return (_b = exports.TOURNAMENT_STAFF_ROLE_LABELS[(_a = role) !== null && _a !== void 0 ? _a : 'moderator']) !== null && _b !== void 0 ? _b : 'Moderator';
|
|
50
|
+
};
|
|
51
|
+
exports.tournamentStaffRoleLabel = tournamentStaffRoleLabel;
|
|
52
|
+
const sameId = (a, b) => a != null && b != null && String(a) === String(b);
|
|
53
|
+
/** An appointed row's role, defaulting an unset value to the least it can mean. */
|
|
54
|
+
const appointedRoleOf = (role) => (role === 'admin' ? 'admin' : 'moderator');
|
|
55
|
+
exports.appointedRoleOf = appointedRoleOf;
|
|
56
|
+
/**
|
|
57
|
+
* The viewer's staff role on a tournament, or null for everyone else. The
|
|
58
|
+
* owner wins over any row they might also hold.
|
|
59
|
+
*/
|
|
60
|
+
function resolveTournamentStaffRole(tournament, userId) {
|
|
61
|
+
var _a, _b;
|
|
62
|
+
if (!tournament || userId == null)
|
|
63
|
+
return null;
|
|
64
|
+
if (sameId((_a = tournament.users_permissions_user) === null || _a === void 0 ? void 0 : _a.id, userId))
|
|
65
|
+
return 'owner';
|
|
66
|
+
const row = ((_b = tournament.tournament_roles) !== null && _b !== void 0 ? _b : []).find((r) => { var _a; return sameId((_a = r === null || r === void 0 ? void 0 : r.users_permissions_user) === null || _a === void 0 ? void 0 : _a.id, userId); });
|
|
67
|
+
return row ? (0, exports.appointedRoleOf)(row.role) : null;
|
|
68
|
+
}
|
|
69
|
+
const canTournamentStaff = (role, action) => role != null && exports.TOURNAMENT_STAFF_CAPABILITIES[action].includes(role);
|
|
70
|
+
exports.canTournamentStaff = canTournamentStaff;
|
|
71
|
+
/** `canTournamentStaff` for a viewer, resolving their role first. */
|
|
72
|
+
const tournamentStaffCan = (tournament, userId, action) => (0, exports.canTournamentStaff)(resolveTournamentStaffRole(tournament, userId), action);
|
|
73
|
+
exports.tournamentStaffCan = tournamentStaffCan;
|
|
74
|
+
/** Staff can be changed until the tournament is settled. */
|
|
75
|
+
exports.STAFF_EDITABLE_STATUSES = [
|
|
76
|
+
'draft',
|
|
77
|
+
'open',
|
|
78
|
+
'checkIn',
|
|
79
|
+
'seeding',
|
|
80
|
+
'live',
|
|
81
|
+
];
|
|
82
|
+
const isTournamentStaffEditable = (status) => exports.STAFF_EDITABLE_STATUSES.includes(status !== null && status !== void 0 ? status : '');
|
|
83
|
+
exports.isTournamentStaffEditable = isTournamentStaffEditable;
|
package/package.json
CHANGED
package/src/manual/index.ts
CHANGED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tournament staff — who runs a tournament and what each of them may do.
|
|
3
|
+
*
|
|
4
|
+
* Three roles. The **owner** is the tournament's `users_permissions_user`
|
|
5
|
+
* and never a row; **admin** and **moderator** are `tournament-role` rows
|
|
6
|
+
* (the `TournamentRoleRole` enum is generated from the schema). A row with
|
|
7
|
+
* no role value is read as a moderator, the least the row can mean.
|
|
8
|
+
*
|
|
9
|
+
* The capability table is the contract between the server's guards and the
|
|
10
|
+
* client's buttons: both resolve the viewer's role with
|
|
11
|
+
* `resolveTournamentStaffRole` and ask `canTournamentStaff`, so a control is
|
|
12
|
+
* never offered for a request the server would refuse. Money and the
|
|
13
|
+
* irreversible lifecycle steps stay with the owner; admins run the event;
|
|
14
|
+
* moderators run matches.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
TournamentCurrentStatus,
|
|
19
|
+
TournamentRoleRole,
|
|
20
|
+
} from '../generated/enums';
|
|
21
|
+
|
|
22
|
+
export type TournamentStaffRole = 'owner' | TournamentRoleRole;
|
|
23
|
+
|
|
24
|
+
/** The roles the owner can hand out — everything but their own. */
|
|
25
|
+
export type TournamentAppointedRole = TournamentRoleRole;
|
|
26
|
+
|
|
27
|
+
export const APPOINTABLE_STAFF_ROLES = [
|
|
28
|
+
'admin',
|
|
29
|
+
'moderator',
|
|
30
|
+
] as const satisfies readonly TournamentAppointedRole[];
|
|
31
|
+
|
|
32
|
+
export type TournamentStaffAction =
|
|
33
|
+
/** Appoint, re-role or remove admins and moderators. */
|
|
34
|
+
| 'manageStaff'
|
|
35
|
+
/** `PUT /tournaments/:id` — info, rules, stages, links. */
|
|
36
|
+
| 'editTournament'
|
|
37
|
+
/** Draft → open; debits the prize pool. */
|
|
38
|
+
| 'publish'
|
|
39
|
+
/** Drafts only. */
|
|
40
|
+
| 'delete'
|
|
41
|
+
/** The forward transitions: checkIn, seeding, live, completed. */
|
|
42
|
+
| 'changeStatus'
|
|
43
|
+
/** Refunds every entrant. */
|
|
44
|
+
| 'cancel'
|
|
45
|
+
| 'distributePrizes'
|
|
46
|
+
| 'manageInvites'
|
|
47
|
+
| 'reviewJoinRequests'
|
|
48
|
+
| 'resolveDispute'
|
|
49
|
+
/** Seed, initialise the bracket, place players in slots. */
|
|
50
|
+
| 'seedBracket'
|
|
51
|
+
/** Record scores, start matches, edit match details. */
|
|
52
|
+
| 'manageMatches'
|
|
53
|
+
/** Watch any lobby and post as staff in its chat. */
|
|
54
|
+
| 'enterLobby';
|
|
55
|
+
|
|
56
|
+
const OWNER_ONLY = ['owner'] as const;
|
|
57
|
+
const ADMIN_UP = ['owner', 'admin'] as const;
|
|
58
|
+
const ALL_STAFF = ['owner', 'admin', 'moderator'] as const;
|
|
59
|
+
|
|
60
|
+
export const TOURNAMENT_STAFF_CAPABILITIES: Record<
|
|
61
|
+
TournamentStaffAction,
|
|
62
|
+
readonly TournamentStaffRole[]
|
|
63
|
+
> = {
|
|
64
|
+
manageStaff: OWNER_ONLY,
|
|
65
|
+
publish: OWNER_ONLY,
|
|
66
|
+
delete: OWNER_ONLY,
|
|
67
|
+
cancel: OWNER_ONLY,
|
|
68
|
+
distributePrizes: OWNER_ONLY,
|
|
69
|
+
editTournament: ADMIN_UP,
|
|
70
|
+
changeStatus: ADMIN_UP,
|
|
71
|
+
manageInvites: ADMIN_UP,
|
|
72
|
+
reviewJoinRequests: ADMIN_UP,
|
|
73
|
+
resolveDispute: ADMIN_UP,
|
|
74
|
+
seedBracket: ADMIN_UP,
|
|
75
|
+
manageMatches: ALL_STAFF,
|
|
76
|
+
enterLobby: ALL_STAFF,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const TOURNAMENT_STAFF_ROLE_LABELS: Record<TournamentStaffRole, string> =
|
|
80
|
+
{
|
|
81
|
+
owner: 'Owner',
|
|
82
|
+
admin: 'Admin',
|
|
83
|
+
moderator: 'Moderator',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const tournamentStaffRoleLabel = (
|
|
87
|
+
role: string | null | undefined
|
|
88
|
+
): string =>
|
|
89
|
+
TOURNAMENT_STAFF_ROLE_LABELS[(role as TournamentStaffRole) ?? 'moderator'] ??
|
|
90
|
+
'Moderator';
|
|
91
|
+
|
|
92
|
+
/** Only what the resolver reads; both apps' tournament shapes satisfy it. */
|
|
93
|
+
export interface TournamentStaffLike {
|
|
94
|
+
users_permissions_user?: { id?: number | string | null } | null;
|
|
95
|
+
tournament_roles?: Array<{
|
|
96
|
+
role?: string | null;
|
|
97
|
+
users_permissions_user?: { id?: number | string | null } | null;
|
|
98
|
+
}> | null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const sameId = (
|
|
102
|
+
a: number | string | null | undefined,
|
|
103
|
+
b: number | string | null | undefined
|
|
104
|
+
): boolean => a != null && b != null && String(a) === String(b);
|
|
105
|
+
|
|
106
|
+
/** An appointed row's role, defaulting an unset value to the least it can mean. */
|
|
107
|
+
export const appointedRoleOf = (
|
|
108
|
+
role: string | null | undefined
|
|
109
|
+
): TournamentAppointedRole => (role === 'admin' ? 'admin' : 'moderator');
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The viewer's staff role on a tournament, or null for everyone else. The
|
|
113
|
+
* owner wins over any row they might also hold.
|
|
114
|
+
*/
|
|
115
|
+
export function resolveTournamentStaffRole(
|
|
116
|
+
tournament: TournamentStaffLike | null | undefined,
|
|
117
|
+
userId: number | string | null | undefined
|
|
118
|
+
): TournamentStaffRole | null {
|
|
119
|
+
if (!tournament || userId == null) return null;
|
|
120
|
+
if (sameId(tournament.users_permissions_user?.id, userId)) return 'owner';
|
|
121
|
+
const row = (tournament.tournament_roles ?? []).find((r) =>
|
|
122
|
+
sameId(r?.users_permissions_user?.id, userId)
|
|
123
|
+
);
|
|
124
|
+
return row ? appointedRoleOf(row.role) : null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export const canTournamentStaff = (
|
|
128
|
+
role: TournamentStaffRole | null | undefined,
|
|
129
|
+
action: TournamentStaffAction
|
|
130
|
+
): boolean =>
|
|
131
|
+
role != null && TOURNAMENT_STAFF_CAPABILITIES[action].includes(role);
|
|
132
|
+
|
|
133
|
+
/** `canTournamentStaff` for a viewer, resolving their role first. */
|
|
134
|
+
export const tournamentStaffCan = (
|
|
135
|
+
tournament: TournamentStaffLike | null | undefined,
|
|
136
|
+
userId: number | string | null | undefined,
|
|
137
|
+
action: TournamentStaffAction
|
|
138
|
+
): boolean =>
|
|
139
|
+
canTournamentStaff(resolveTournamentStaffRole(tournament, userId), action);
|
|
140
|
+
|
|
141
|
+
/** Staff can be changed until the tournament is settled. */
|
|
142
|
+
export const STAFF_EDITABLE_STATUSES = [
|
|
143
|
+
'draft',
|
|
144
|
+
'open',
|
|
145
|
+
'checkIn',
|
|
146
|
+
'seeding',
|
|
147
|
+
'live',
|
|
148
|
+
] as const satisfies readonly TournamentCurrentStatus[];
|
|
149
|
+
|
|
150
|
+
export const isTournamentStaffEditable = (
|
|
151
|
+
status: string | null | undefined
|
|
152
|
+
): boolean => (STAFF_EDITABLE_STATUSES as readonly string[]).includes(status ?? '');
|
|
153
|
+
|
|
154
|
+
// ─── `PUT /tournaments/:id/staff` ────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
/** One appointee as the owner's dialog sends it. */
|
|
157
|
+
export interface TournamentStaffMemberInput {
|
|
158
|
+
/** The user's documentId — what the search results carry. */
|
|
159
|
+
userDocumentId: string;
|
|
160
|
+
role: TournamentAppointedRole;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** The whole appointed list; the server diffs it against the rows. */
|
|
164
|
+
export interface UpdateTournamentStaffBody {
|
|
165
|
+
data: { staff: TournamentStaffMemberInput[] };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** `error.details.name` values the staff routes raise. */
|
|
169
|
+
export type TournamentStaffErrorName = 'NotTournamentStaff';
|