@notidotbot/noti-api-client 1.6.13 → 1.7.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/classes/adminFishing.d.ts +489 -0
- package/dist/classes/adminFishing.js +226 -0
- package/dist/classes/guildFishing.d.ts +188 -0
- package/dist/classes/guildFishing.js +115 -0
- package/dist/classes/guildRolePanel.d.ts +6 -0
- package/dist/classes/minigamesFishing.d.ts +168 -0
- package/dist/classes/minigamesFishing.js +84 -0
- package/dist/core/manager.d.ts +6 -0
- package/dist/core/manager.js +6 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/other/templates.d.ts +19 -0
- package/dist/other/templates.js +19 -0
- package/dist/other/zod/rolePanels.zod.d.ts +6 -0
- package/dist/other/zod/rolePanels.zod.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/prisma/schema/models/rolePanels.prisma +4 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import { CancelOutWebResponses } from '../types';
|
|
2
|
+
import { WebDataManager } from '../core/manager';
|
|
3
|
+
/**
|
|
4
|
+
* Dev-only backend for the Fishing minigame admin dashboard.
|
|
5
|
+
*
|
|
6
|
+
* Every method here requires a developer account — the routes check the caller against the developer
|
|
7
|
+
* list and return 403 otherwise, so these are not merely "admin" in the guild-owner sense.
|
|
8
|
+
*
|
|
9
|
+
* Endpoints live under `/admin/minigames/fishing/*`. The `minigames` segment is deliberate: Fishing is
|
|
10
|
+
* the first minigame, not the only one, so a second game slots in beside it rather than replacing it.
|
|
11
|
+
*/
|
|
12
|
+
export declare class APIAdminFishing {
|
|
13
|
+
private web;
|
|
14
|
+
constructor(web: WebDataManager);
|
|
15
|
+
/** Rollout state, active kill switches, pending flush backlog and Redis memory. */
|
|
16
|
+
getHealth({ auth }: AdminFishingFunctionsInput['getHealth']): Promise<import("../types").WebResponse<FishingHealth>>;
|
|
17
|
+
getRollout({ auth }: AdminFishingFunctionsInput['getRollout']): Promise<import("../types").WebResponse<FishingRollout>>;
|
|
18
|
+
/** Add or remove guilds from the beta allowlist. This is what starts a beta cohort. */
|
|
19
|
+
setRolloutAllowlist({ auth, action, guildIds }: AdminFishingFunctionsInput['setRolloutAllowlist']): Promise<import("../types").WebResponse<FishingRolloutChange>>;
|
|
20
|
+
/**
|
|
21
|
+
* Set the percentage dial.
|
|
22
|
+
*
|
|
23
|
+
* **0 is the fleet-wide kill switch** — the fastest way to stop fishing everywhere without a
|
|
24
|
+
* deploy. It stops ingestion only; the flush keeps draining so nobody's unflushed progress is lost.
|
|
25
|
+
*/
|
|
26
|
+
setRolloutPercent({ auth, percent }: AdminFishingFunctionsInput['setRolloutPercent']): Promise<import("../types").WebResponse<FishingRollout>>;
|
|
27
|
+
getKills({ auth }: AdminFishingFunctionsInput['getKills']): Promise<import("../types").WebResponse<FishingKills>>;
|
|
28
|
+
/**
|
|
29
|
+
* Throw or clear a kill switch.
|
|
30
|
+
*
|
|
31
|
+
* `scope` is either a subsystem (`cast`, `sell`, `boss`, …) or a single target (`guild:<id>` /
|
|
32
|
+
* `user:<id>`). A kill stops INGESTION only — the flush keeps draining, so throwing a switch mid
|
|
33
|
+
* incident does not destroy a window of every active player's progress.
|
|
34
|
+
*/
|
|
35
|
+
setKill({ auth, scope, on, reason }: AdminFishingFunctionsInput['setKill']): Promise<import("../types").WebResponse<FishingKillResult>>;
|
|
36
|
+
/** Every dial with its current value and its permitted bounds. */
|
|
37
|
+
getDials({ auth }: AdminFishingFunctionsInput['getDials']): Promise<import("../types").WebResponse<FishingDial[]>>;
|
|
38
|
+
/**
|
|
39
|
+
* Set a dial, or pass `value: null` to reset it to its seeded default.
|
|
40
|
+
*
|
|
41
|
+
* Out-of-range values are **rejected with a 400, not clamped** — an operator who typed 500 should
|
|
42
|
+
* learn it did not take rather than quietly getting 3.
|
|
43
|
+
*/
|
|
44
|
+
setDial({ auth, dial, value, reason }: AdminFishingFunctionsInput['setDial']): Promise<import("../types").WebResponse<FishingDialResult>>;
|
|
45
|
+
/** The editable content tables, plus the currently effective content version. */
|
|
46
|
+
getContentTables({ auth }: AdminFishingFunctionsInput['getContentTables']): Promise<import("../types").WebResponse<FishingContentIndex>>;
|
|
47
|
+
listContent<T = Record<string, unknown>>({ auth, table, limit }: AdminFishingFunctionsInput['listContent']): Promise<import("../types").WebResponse<T[]>>;
|
|
48
|
+
/**
|
|
49
|
+
* Create or update one content row (upsert — one verb, not two).
|
|
50
|
+
*
|
|
51
|
+
* For `dateDerived` tables the change does **not** apply today: `effectiveFrom` in the response is
|
|
52
|
+
* the next 00:00 UTC. Daily demand, the shop rotation and the quest board are a date-seeded shuffle
|
|
53
|
+
* over the content list, so editing it mid-day would reshuffle a day players already acted on.
|
|
54
|
+
*/
|
|
55
|
+
upsertContent<T = Record<string, unknown>>({ auth, table, id, data, reason }: AdminFishingFunctionsInput['upsertContent']): Promise<import("../types").WebResponse<FishingContentWrite<T>>>;
|
|
56
|
+
/**
|
|
57
|
+
* Disable a content row. **Nothing is hard-deleted** — player rows store content ids (claimed sets,
|
|
58
|
+
* caught species, owned items), so removing a row would orphan them.
|
|
59
|
+
*/
|
|
60
|
+
disableContent<T = Record<string, unknown>>({ auth, table, id }: AdminFishingFunctionsInput['disableContent']): Promise<import("../types").WebResponse<FishingContentDisable<T>>>;
|
|
61
|
+
/** Global progression, plus per-guild wallet/inventory/ledger when `guildId` is supplied. */
|
|
62
|
+
getPlayer({ auth, userId, guildId }: AdminFishingFunctionsInput['getPlayer']): Promise<import("../types").WebResponse<FishingPlayerInspect>>;
|
|
63
|
+
getGuild({ auth, guildId }: AdminFishingFunctionsInput['getGuild']): Promise<import("../types").WebResponse<FishingGuildInspect>>;
|
|
64
|
+
/**
|
|
65
|
+
* Grant (positive delta) or revoke (negative delta) coins.
|
|
66
|
+
*
|
|
67
|
+
* A revoke **clamps at zero**. A negative balance silently blocks every future purchase with no
|
|
68
|
+
* explanation the player can act on, and support would have to undo it by hand.
|
|
69
|
+
*/
|
|
70
|
+
adjustPlayerCoins({ auth, userId, guildId, delta, reason }: AdminFishingFunctionsInput['adjustPlayerCoins']): Promise<import("../types").WebResponse<FishingCoinAdjustment>>;
|
|
71
|
+
/**
|
|
72
|
+
* Reset a player's server stats, their global progression, a guild's dock, or a guild's economy.
|
|
73
|
+
*
|
|
74
|
+
* `claimedSets` and `claimedMilestones` are **preserved unless `alsoClearClaims` is set**. They
|
|
75
|
+
* record what a player was already *paid* for — clearing them makes every milestone and collection
|
|
76
|
+
* pay out a second time as the counters climb back, so "please reset me" becomes a faucet. Setting
|
|
77
|
+
* the flag is audited as its own action. A dock reset likewise preserves `prestige`.
|
|
78
|
+
*/
|
|
79
|
+
resetTarget({ auth, scope, userId, guildId, alsoClearClaims, reason }: AdminFishingFunctionsInput['resetTarget']): Promise<import("../types").WebResponse<FishingResetResult>>;
|
|
80
|
+
/**
|
|
81
|
+
* Subtract what a range of flush batches awarded, clamped at zero.
|
|
82
|
+
*
|
|
83
|
+
* This is **not** an undo — deltas are not invertible once superseded (earn 500, buy a 500-coin
|
|
84
|
+
* rod, undo, and the balance goes negative while they keep the rod). It reads what those batches
|
|
85
|
+
* actually applied and reverses that much.
|
|
86
|
+
*
|
|
87
|
+
* **Dry-run unless `apply` is true.** Each subtraction is idempotent per player per range, so a
|
|
88
|
+
* retried apply cannot double-charge.
|
|
89
|
+
*/
|
|
90
|
+
compensateBatches({ auth, fromBatchId, toBatchId, apply, reason }: AdminFishingFunctionsInput['compensateBatches']): Promise<import("../types").WebResponse<FishingCompensation>>;
|
|
91
|
+
/** Who ran what, with before → after. Distinct from the coin ledger, which is where coins came from. */
|
|
92
|
+
getAudit({ auth, limit }: AdminFishingFunctionsInput['getAudit']): Promise<import("../types").WebResponse<FishingAuditEntry[]>>;
|
|
93
|
+
/**
|
|
94
|
+
* Abuse review queue.
|
|
95
|
+
*
|
|
96
|
+
* A queue of things for a HUMAN to look at, never a list of confirmed cheats. Detection runs
|
|
97
|
+
* against an economy with no live data, so its false positives are disproportionately legitimate
|
|
98
|
+
* heavy players — the most engaged users in the feature. Nothing here bans, and there is
|
|
99
|
+
* deliberately no bulk action: confirmed abuse is actioned through `resetTarget`,
|
|
100
|
+
* `adjustPlayerCoins` or `setKill`, each of which writes an audit row.
|
|
101
|
+
*
|
|
102
|
+
* Defaults to PENDING flags, ordered most-severe-first.
|
|
103
|
+
*/
|
|
104
|
+
getAbuseQueue({ auth, status, severity, kind, userId, guildId, limit, offset }: AdminFishingFunctionsInput['getAbuseQueue']): Promise<import("../types").WebResponse<FishingAbuseQueue>>;
|
|
105
|
+
/**
|
|
106
|
+
* Mark a flag reviewed, or reopen one.
|
|
107
|
+
*
|
|
108
|
+
* Pass `reviewed: false` to reopen — a reviewer who dismisses the wrong row otherwise has no way
|
|
109
|
+
* back, because the queue's day-grained dedupe key stops the same condition re-raising it.
|
|
110
|
+
*
|
|
111
|
+
* Reviewing is also what makes retention work: reviewed flags age out after 30 days, unreviewed
|
|
112
|
+
* ones after 90.
|
|
113
|
+
*/
|
|
114
|
+
updateAbuseFlag({ auth, flagId, reviewed, reason }: AdminFishingFunctionsInput['updateAbuseFlag']): Promise<import("../types").WebResponse<FishingAbuseFlag>>;
|
|
115
|
+
}
|
|
116
|
+
export type AdminFishingFunctionsInput = {
|
|
117
|
+
'getHealth': {
|
|
118
|
+
auth: string;
|
|
119
|
+
};
|
|
120
|
+
'getRollout': {
|
|
121
|
+
auth: string;
|
|
122
|
+
};
|
|
123
|
+
'setRolloutAllowlist': {
|
|
124
|
+
auth: string;
|
|
125
|
+
action: 'add' | 'remove';
|
|
126
|
+
guildIds: string[];
|
|
127
|
+
};
|
|
128
|
+
'setRolloutPercent': {
|
|
129
|
+
auth: string;
|
|
130
|
+
percent: number;
|
|
131
|
+
};
|
|
132
|
+
'getKills': {
|
|
133
|
+
auth: string;
|
|
134
|
+
};
|
|
135
|
+
'setKill': {
|
|
136
|
+
auth: string;
|
|
137
|
+
scope: FishingKillScope | (string & {});
|
|
138
|
+
on: boolean;
|
|
139
|
+
reason?: string;
|
|
140
|
+
};
|
|
141
|
+
'getDials': {
|
|
142
|
+
auth: string;
|
|
143
|
+
};
|
|
144
|
+
'setDial': {
|
|
145
|
+
auth: string;
|
|
146
|
+
dial: FishingDialName;
|
|
147
|
+
value: number | null;
|
|
148
|
+
reason?: string;
|
|
149
|
+
};
|
|
150
|
+
'getContentTables': {
|
|
151
|
+
auth: string;
|
|
152
|
+
};
|
|
153
|
+
'listContent': {
|
|
154
|
+
auth: string;
|
|
155
|
+
table: FishingContentTable;
|
|
156
|
+
limit?: number;
|
|
157
|
+
};
|
|
158
|
+
'upsertContent': {
|
|
159
|
+
auth: string;
|
|
160
|
+
table: FishingContentTable;
|
|
161
|
+
id: string | number;
|
|
162
|
+
data: Record<string, unknown>;
|
|
163
|
+
reason?: string;
|
|
164
|
+
};
|
|
165
|
+
'disableContent': {
|
|
166
|
+
auth: string;
|
|
167
|
+
table: FishingContentTable;
|
|
168
|
+
id: string | number;
|
|
169
|
+
};
|
|
170
|
+
'getPlayer': {
|
|
171
|
+
auth: string;
|
|
172
|
+
userId: string;
|
|
173
|
+
guildId?: string;
|
|
174
|
+
};
|
|
175
|
+
'getGuild': {
|
|
176
|
+
auth: string;
|
|
177
|
+
guildId: string;
|
|
178
|
+
};
|
|
179
|
+
'adjustPlayerCoins': {
|
|
180
|
+
auth: string;
|
|
181
|
+
userId: string;
|
|
182
|
+
guildId: string;
|
|
183
|
+
delta: number;
|
|
184
|
+
reason?: string;
|
|
185
|
+
};
|
|
186
|
+
'resetTarget': {
|
|
187
|
+
auth: string;
|
|
188
|
+
scope: FishingResetScope;
|
|
189
|
+
userId?: string;
|
|
190
|
+
guildId?: string;
|
|
191
|
+
alsoClearClaims?: boolean;
|
|
192
|
+
reason?: string;
|
|
193
|
+
};
|
|
194
|
+
'compensateBatches': {
|
|
195
|
+
auth: string;
|
|
196
|
+
fromBatchId: string;
|
|
197
|
+
toBatchId: string;
|
|
198
|
+
apply?: boolean;
|
|
199
|
+
reason?: string;
|
|
200
|
+
};
|
|
201
|
+
'getAudit': {
|
|
202
|
+
auth: string;
|
|
203
|
+
limit?: number;
|
|
204
|
+
};
|
|
205
|
+
'getAbuseQueue': {
|
|
206
|
+
auth: string;
|
|
207
|
+
status?: FishingAbuseStatus;
|
|
208
|
+
severity?: FishingAbuseSeverity;
|
|
209
|
+
kind?: FishingAbuseKind;
|
|
210
|
+
userId?: string;
|
|
211
|
+
guildId?: string;
|
|
212
|
+
limit?: number;
|
|
213
|
+
offset?: number;
|
|
214
|
+
};
|
|
215
|
+
'updateAbuseFlag': {
|
|
216
|
+
auth: string;
|
|
217
|
+
flagId: string;
|
|
218
|
+
reviewed?: boolean;
|
|
219
|
+
reason?: string;
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
export type AdminFishingGetReturnTypes = {
|
|
223
|
+
'getHealthRaw': Awaited<ReturnType<APIAdminFishing['getHealth']>>;
|
|
224
|
+
'getHealthSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getHealth']>>>;
|
|
225
|
+
'getRolloutRaw': Awaited<ReturnType<APIAdminFishing['getRollout']>>;
|
|
226
|
+
'getRolloutSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getRollout']>>>;
|
|
227
|
+
'setRolloutAllowlistRaw': Awaited<ReturnType<APIAdminFishing['setRolloutAllowlist']>>;
|
|
228
|
+
'setRolloutAllowlistSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['setRolloutAllowlist']>>>;
|
|
229
|
+
'setRolloutPercentRaw': Awaited<ReturnType<APIAdminFishing['setRolloutPercent']>>;
|
|
230
|
+
'setRolloutPercentSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['setRolloutPercent']>>>;
|
|
231
|
+
'getKillsRaw': Awaited<ReturnType<APIAdminFishing['getKills']>>;
|
|
232
|
+
'getKillsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getKills']>>>;
|
|
233
|
+
'setKillRaw': Awaited<ReturnType<APIAdminFishing['setKill']>>;
|
|
234
|
+
'setKillSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['setKill']>>>;
|
|
235
|
+
'getDialsRaw': Awaited<ReturnType<APIAdminFishing['getDials']>>;
|
|
236
|
+
'getDialsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getDials']>>>;
|
|
237
|
+
'setDialRaw': Awaited<ReturnType<APIAdminFishing['setDial']>>;
|
|
238
|
+
'setDialSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['setDial']>>>;
|
|
239
|
+
'getContentTablesRaw': Awaited<ReturnType<APIAdminFishing['getContentTables']>>;
|
|
240
|
+
'getContentTablesSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getContentTables']>>>;
|
|
241
|
+
'listContentRaw': Awaited<ReturnType<APIAdminFishing['listContent']>>;
|
|
242
|
+
'listContentSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['listContent']>>>;
|
|
243
|
+
'upsertContentRaw': Awaited<ReturnType<APIAdminFishing['upsertContent']>>;
|
|
244
|
+
'upsertContentSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['upsertContent']>>>;
|
|
245
|
+
'disableContentRaw': Awaited<ReturnType<APIAdminFishing['disableContent']>>;
|
|
246
|
+
'disableContentSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['disableContent']>>>;
|
|
247
|
+
'getPlayerRaw': Awaited<ReturnType<APIAdminFishing['getPlayer']>>;
|
|
248
|
+
'getPlayerSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getPlayer']>>>;
|
|
249
|
+
'getGuildRaw': Awaited<ReturnType<APIAdminFishing['getGuild']>>;
|
|
250
|
+
'getGuildSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getGuild']>>>;
|
|
251
|
+
'adjustPlayerCoinsRaw': Awaited<ReturnType<APIAdminFishing['adjustPlayerCoins']>>;
|
|
252
|
+
'adjustPlayerCoinsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['adjustPlayerCoins']>>>;
|
|
253
|
+
'resetTargetRaw': Awaited<ReturnType<APIAdminFishing['resetTarget']>>;
|
|
254
|
+
'resetTargetSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['resetTarget']>>>;
|
|
255
|
+
'compensateBatchesRaw': Awaited<ReturnType<APIAdminFishing['compensateBatches']>>;
|
|
256
|
+
'compensateBatchesSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['compensateBatches']>>>;
|
|
257
|
+
'getAuditRaw': Awaited<ReturnType<APIAdminFishing['getAudit']>>;
|
|
258
|
+
'getAuditSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getAudit']>>>;
|
|
259
|
+
'getAbuseQueueRaw': Awaited<ReturnType<APIAdminFishing['getAbuseQueue']>>;
|
|
260
|
+
'getAbuseQueueSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['getAbuseQueue']>>>;
|
|
261
|
+
'updateAbuseFlagRaw': Awaited<ReturnType<APIAdminFishing['updateAbuseFlag']>>;
|
|
262
|
+
'updateAbuseFlagSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFishing['updateAbuseFlag']>>>;
|
|
263
|
+
};
|
|
264
|
+
export type FishingRollout = {
|
|
265
|
+
allowlist: string[];
|
|
266
|
+
percent: number;
|
|
267
|
+
};
|
|
268
|
+
export type FishingRolloutChange = FishingRollout & {
|
|
269
|
+
changed: number;
|
|
270
|
+
};
|
|
271
|
+
/** Subsystems that can be switched off independently, alongside `guild:<id>` / `user:<id>` targets. */
|
|
272
|
+
export type FishingKillScope = 'cast' | 'sell' | 'shop' | 'stock' | 'dock' | 'boss' | 'quests' | 'boosters';
|
|
273
|
+
export type FishingKills = {
|
|
274
|
+
/** Scopes currently switched off. */
|
|
275
|
+
active: string[];
|
|
276
|
+
scopes: readonly FishingKillScope[];
|
|
277
|
+
};
|
|
278
|
+
export type FishingKillResult = {
|
|
279
|
+
scope: string;
|
|
280
|
+
on: boolean;
|
|
281
|
+
};
|
|
282
|
+
export type FishingDialName = 'catchRateMultiplier' | 'coinRateMultiplier' | 'xpRateMultiplier' | 'scrapRateMultiplier' | 'cooldownBaseMs' | 'cooldownFloorMs' | 'demandMultiplierMax' | 'demandSpeciesPerDay' | 'demandPremiumSaleCap' | 'rarityCeiling' | 'bossConcurrentCap' | 'bossEditThrottleMs' | 'flushIntervalMs';
|
|
283
|
+
export type FishingDial = {
|
|
284
|
+
name: FishingDialName;
|
|
285
|
+
value: number;
|
|
286
|
+
min: number;
|
|
287
|
+
max: number;
|
|
288
|
+
default: number;
|
|
289
|
+
};
|
|
290
|
+
export type FishingDialResult = {
|
|
291
|
+
dial: FishingDialName;
|
|
292
|
+
value: number;
|
|
293
|
+
reset?: boolean;
|
|
294
|
+
};
|
|
295
|
+
export type FishingHealth = {
|
|
296
|
+
rollout: FishingRollout;
|
|
297
|
+
kills: string[];
|
|
298
|
+
/** Players with unflushed deltas waiting in Redis. */
|
|
299
|
+
pendingPlayers: number;
|
|
300
|
+
redis: {
|
|
301
|
+
usedMemoryBytes: number | null;
|
|
302
|
+
maxMemoryBytes: number | null;
|
|
303
|
+
/** `null` when CONFIG GET is disabled on the instance. */
|
|
304
|
+
policy: string | null;
|
|
305
|
+
dbSize: number | null;
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
export type FishingContentTable = 'species' | 'components' | 'dockTiers' | 'shop' | 'bosses' | 'quests' | 'milestones' | 'collections' | 'badges' | 'rarityTables';
|
|
309
|
+
export type FishingContentTableInfo = {
|
|
310
|
+
name: FishingContentTable;
|
|
311
|
+
key: string;
|
|
312
|
+
/**
|
|
313
|
+
* True when the table feeds a date-seeded shuffle (demand, shop rotation, quest board). Edits to
|
|
314
|
+
* these take effect at the next 00:00 UTC rather than immediately.
|
|
315
|
+
*/
|
|
316
|
+
dateDerived: boolean;
|
|
317
|
+
};
|
|
318
|
+
export type FishingContentIndex = {
|
|
319
|
+
tables: FishingContentTableInfo[];
|
|
320
|
+
contentVersion: string;
|
|
321
|
+
};
|
|
322
|
+
/** `effectiveFrom` is a `YYYY-MM-DD` date for date-derived tables, or `'immediately'`. */
|
|
323
|
+
export type FishingContentWrite<T = Record<string, unknown>> = {
|
|
324
|
+
row: T;
|
|
325
|
+
effectiveFrom: string;
|
|
326
|
+
};
|
|
327
|
+
export type FishingContentDisable<T = Record<string, unknown>> = {
|
|
328
|
+
row: T;
|
|
329
|
+
disabled: true;
|
|
330
|
+
note: string;
|
|
331
|
+
effectiveFrom: string;
|
|
332
|
+
};
|
|
333
|
+
export type FishingPlayerGlobal = {
|
|
334
|
+
level: number;
|
|
335
|
+
xp: bigint;
|
|
336
|
+
voteStreak: number;
|
|
337
|
+
caughtSpecies: string[];
|
|
338
|
+
personalBests: unknown;
|
|
339
|
+
claimedSets: string[];
|
|
340
|
+
claimedMilestones: string[];
|
|
341
|
+
lifetimeCasts: number;
|
|
342
|
+
lifetimeCatches: number;
|
|
343
|
+
lifetimeLegendary: number;
|
|
344
|
+
lifetimeVotes: number;
|
|
345
|
+
};
|
|
346
|
+
export type FishingPlayerMember = {
|
|
347
|
+
coins: bigint;
|
|
348
|
+
lifetimeCoins: bigint;
|
|
349
|
+
lifetimeCatches: number;
|
|
350
|
+
biggestCatchG: number;
|
|
351
|
+
lastActiveAt: Date;
|
|
352
|
+
};
|
|
353
|
+
export type FishingInventoryStack = {
|
|
354
|
+
speciesId: string;
|
|
355
|
+
count: number;
|
|
356
|
+
totalValue: bigint;
|
|
357
|
+
bestWeightG: number;
|
|
358
|
+
};
|
|
359
|
+
export type FishingLedgerEntry = {
|
|
360
|
+
type: string;
|
|
361
|
+
currency: string;
|
|
362
|
+
delta: bigint;
|
|
363
|
+
reason: string | null;
|
|
364
|
+
createdAt: Date;
|
|
365
|
+
};
|
|
366
|
+
export type FishingPlayerInspect = {
|
|
367
|
+
global: FishingPlayerGlobal | null;
|
|
368
|
+
/** `null` unless a `guildId` was supplied. */
|
|
369
|
+
member: FishingPlayerMember | null;
|
|
370
|
+
inventory: FishingInventoryStack[] | null;
|
|
371
|
+
recentLedger: FishingLedgerEntry[];
|
|
372
|
+
};
|
|
373
|
+
export type FishingGuildConfig = {
|
|
374
|
+
enabled: boolean;
|
|
375
|
+
allowedChannelIds: string[];
|
|
376
|
+
cooldownOverrideMs: number | null;
|
|
377
|
+
dockChannelId: string | null;
|
|
378
|
+
logChannelId: string | null;
|
|
379
|
+
};
|
|
380
|
+
export type FishingGuildDock = {
|
|
381
|
+
tier: number;
|
|
382
|
+
prestige: number;
|
|
383
|
+
scrapContributed: bigint;
|
|
384
|
+
buildCompletesAt: Date | null;
|
|
385
|
+
};
|
|
386
|
+
export type FishingGuildInspect = {
|
|
387
|
+
config: FishingGuildConfig | null;
|
|
388
|
+
dock: FishingGuildDock | null;
|
|
389
|
+
components: {
|
|
390
|
+
componentId: string;
|
|
391
|
+
quantity: number;
|
|
392
|
+
}[];
|
|
393
|
+
topMembers: {
|
|
394
|
+
userId: string;
|
|
395
|
+
coins: bigint;
|
|
396
|
+
lifetimeCatches: number;
|
|
397
|
+
lastActiveAt: Date;
|
|
398
|
+
}[];
|
|
399
|
+
};
|
|
400
|
+
export type FishingCoinAdjustment = {
|
|
401
|
+
userId: string;
|
|
402
|
+
guildId: string;
|
|
403
|
+
balanceAfter: number;
|
|
404
|
+
};
|
|
405
|
+
export type FishingResetScope =
|
|
406
|
+
/** Per-guild wallet, inventory and seasonal stats for one member. */
|
|
407
|
+
'serverStats'
|
|
408
|
+
/** Global XP, level, codex, records and lifetime counters for one user. */
|
|
409
|
+
| 'globalProgression'
|
|
410
|
+
/** One guild's dock tier, components and contributors. Preserves `prestige`. */
|
|
411
|
+
| 'guildDock'
|
|
412
|
+
/** Every member's coins and inventory in one guild. */
|
|
413
|
+
| 'guildEconomy';
|
|
414
|
+
export type FishingResetResult = {
|
|
415
|
+
scope: FishingResetScope;
|
|
416
|
+
cleared: string[];
|
|
417
|
+
claimsCleared: boolean;
|
|
418
|
+
note: string;
|
|
419
|
+
};
|
|
420
|
+
export type FishingCompensation = {
|
|
421
|
+
batches: number;
|
|
422
|
+
players: number;
|
|
423
|
+
totalCoins: number;
|
|
424
|
+
/** Capped at the first 100 players; `players` is the true count. */
|
|
425
|
+
perPlayer: {
|
|
426
|
+
userId: string;
|
|
427
|
+
guildId: string;
|
|
428
|
+
coins: number;
|
|
429
|
+
}[];
|
|
430
|
+
applied: boolean;
|
|
431
|
+
note: string;
|
|
432
|
+
};
|
|
433
|
+
export type FishingAuditEntry = {
|
|
434
|
+
actorId: string;
|
|
435
|
+
action: string;
|
|
436
|
+
target: string | null;
|
|
437
|
+
before: unknown;
|
|
438
|
+
after: unknown;
|
|
439
|
+
reason: string | null;
|
|
440
|
+
createdAt: Date;
|
|
441
|
+
};
|
|
442
|
+
/**
|
|
443
|
+
* What a heuristic detected.
|
|
444
|
+
*
|
|
445
|
+
* Hand-copied from `FlagKind` in the server's `modules/fishing/integrity.ts`. Nothing links the two,
|
|
446
|
+
* so adding a detector server-side leaves this quietly incomplete — diff both when either changes.
|
|
447
|
+
*/
|
|
448
|
+
export type FishingAbuseKind = 'burst' | 'earnRate' | 'impossibleState' | 'replay';
|
|
449
|
+
export type FishingAbuseSeverity = 'low' | 'medium' | 'high';
|
|
450
|
+
/**
|
|
451
|
+
* The response to a flag. Note what is absent: there is no `ban`, at any layer.
|
|
452
|
+
*
|
|
453
|
+
* Enforcement is SOFT and self-expiring — a throttled player waits longer, a silenced one sees an
|
|
454
|
+
* ordinary miss. Neither is ever told they were flagged, because a message saying so is a feedback
|
|
455
|
+
* signal that lets someone A/B test their way around the detection.
|
|
456
|
+
*/
|
|
457
|
+
export type FishingAbuseEnforcement = 'allow' | 'throttle' | 'silentNoop';
|
|
458
|
+
/** Which slice of the queue to read. `pending` is the default — the archive is not the work. */
|
|
459
|
+
export type FishingAbuseStatus = 'pending' | 'reviewed' | 'all';
|
|
460
|
+
export type FishingAbuseFlag = {
|
|
461
|
+
dbId: string;
|
|
462
|
+
userId: string;
|
|
463
|
+
guildId: string | null;
|
|
464
|
+
kind: FishingAbuseKind;
|
|
465
|
+
severity: FishingAbuseSeverity;
|
|
466
|
+
/** Human-readable, for the reviewer. Never shown to the flagged player. */
|
|
467
|
+
detail: string;
|
|
468
|
+
/** The observed value and what was expected, so a reviewer can judge without re-querying. */
|
|
469
|
+
observed: number;
|
|
470
|
+
expected: number;
|
|
471
|
+
enforcement: FishingAbuseEnforcement;
|
|
472
|
+
/** How many times this same condition re-raised. One row per (player, kind, day). */
|
|
473
|
+
hits: number;
|
|
474
|
+
reviewedAt: string | null;
|
|
475
|
+
reviewedBy: string | null;
|
|
476
|
+
createdAt: string;
|
|
477
|
+
updatedAt: string;
|
|
478
|
+
};
|
|
479
|
+
export type FishingAbuseQueue = {
|
|
480
|
+
/** Ordered most-severe-first, then most recently updated. */
|
|
481
|
+
flags: FishingAbuseFlag[];
|
|
482
|
+
/** Rows matching the current filters, for paging. */
|
|
483
|
+
matching: number;
|
|
484
|
+
/** Unreviewed rows overall — the badge count, independent of the filters applied. */
|
|
485
|
+
pending: number;
|
|
486
|
+
limit: number;
|
|
487
|
+
offset: number;
|
|
488
|
+
note: string;
|
|
489
|
+
};
|