@flitt/api 1.0.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +277 -0
  4. package/SECURITY.md +15 -0
  5. package/dist/cjs/client.d.ts +243 -0
  6. package/dist/cjs/client.d.ts.map +1 -0
  7. package/dist/cjs/client.js +470 -0
  8. package/dist/cjs/client.js.map +1 -0
  9. package/dist/cjs/errors.d.ts +71 -0
  10. package/dist/cjs/errors.d.ts.map +1 -0
  11. package/dist/cjs/errors.js +107 -0
  12. package/dist/cjs/errors.js.map +1 -0
  13. package/dist/cjs/http.d.ts +53 -0
  14. package/dist/cjs/http.d.ts.map +1 -0
  15. package/dist/cjs/http.js +322 -0
  16. package/dist/cjs/http.js.map +1 -0
  17. package/dist/cjs/index.d.ts +13 -0
  18. package/dist/cjs/index.d.ts.map +1 -0
  19. package/dist/cjs/index.js +31 -0
  20. package/dist/cjs/index.js.map +1 -0
  21. package/dist/cjs/package.json +3 -0
  22. package/dist/cjs/types.d.ts +406 -0
  23. package/dist/cjs/types.d.ts.map +1 -0
  24. package/dist/cjs/types.js +7 -0
  25. package/dist/cjs/types.js.map +1 -0
  26. package/dist/cjs/version.d.ts +3 -0
  27. package/dist/cjs/version.d.ts.map +1 -0
  28. package/dist/cjs/version.js +6 -0
  29. package/dist/cjs/version.js.map +1 -0
  30. package/dist/cjs/webhooks.d.ts +40 -0
  31. package/dist/cjs/webhooks.d.ts.map +1 -0
  32. package/dist/cjs/webhooks.js +98 -0
  33. package/dist/cjs/webhooks.js.map +1 -0
  34. package/dist/esm/client.d.ts +243 -0
  35. package/dist/esm/client.d.ts.map +1 -0
  36. package/dist/esm/client.js +465 -0
  37. package/dist/esm/client.js.map +1 -0
  38. package/dist/esm/errors.d.ts +71 -0
  39. package/dist/esm/errors.d.ts.map +1 -0
  40. package/dist/esm/errors.js +90 -0
  41. package/dist/esm/errors.js.map +1 -0
  42. package/dist/esm/http.d.ts +53 -0
  43. package/dist/esm/http.d.ts.map +1 -0
  44. package/dist/esm/http.js +310 -0
  45. package/dist/esm/http.js.map +1 -0
  46. package/dist/esm/index.d.ts +13 -0
  47. package/dist/esm/index.d.ts.map +1 -0
  48. package/dist/esm/index.js +9 -0
  49. package/dist/esm/index.js.map +1 -0
  50. package/dist/esm/types.d.ts +406 -0
  51. package/dist/esm/types.d.ts.map +1 -0
  52. package/dist/esm/types.js +6 -0
  53. package/dist/esm/types.js.map +1 -0
  54. package/dist/esm/version.d.ts +3 -0
  55. package/dist/esm/version.d.ts.map +1 -0
  56. package/dist/esm/version.js +3 -0
  57. package/dist/esm/version.js.map +1 -0
  58. package/dist/esm/webhooks.d.ts +40 -0
  59. package/dist/esm/webhooks.d.ts.map +1 -0
  60. package/dist/esm/webhooks.js +93 -0
  61. package/dist/esm/webhooks.js.map +1 -0
  62. package/package.json +67 -0
  63. package/src/client.ts +576 -0
  64. package/src/errors.ts +92 -0
  65. package/src/http.ts +353 -0
  66. package/src/index.ts +26 -0
  67. package/src/types.ts +390 -0
  68. package/src/version.ts +2 -0
  69. package/src/webhooks.ts +115 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 — 2026-09-28
4
+
5
+ First release.
6
+
7
+ - `Flitt` client for the Public API v1: usage, servers, players, firewall (settings, rules, blocks), in-game commands, Discord account linking.
8
+ - `FlittVotes` client for the Vote API: check, claim (idempotent), list, top voters, server info, stats, reviews.
9
+ - `verifyWebhook()` for signed Flitt webhooks (HMAC-SHA256, timestamp tolerance, replay hook).
10
+ - Async iterators for paginated endpoints (`listAll`).
11
+ - Timeouts, retries with exponential backoff and `Retry-After`, typed errors, rate-limit state.
12
+ - ESM + CommonJS builds, TypeScript types, zero dependencies, Node.js 20+.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Flitt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # @flitt/api
2
+
3
+ Official TypeScript / JavaScript client for the [Flitt](https://flitt.me) **Public API** and **Vote API**: servers, players, anti-VPN firewall, Discord account linking, in-game commands, votes and webhooks for FiveM, Garry's Mod and Minecraft servers.
4
+
5
+ - **Zero dependencies**, ESM + CommonJS, full TypeScript types.
6
+ - Runs on **Node.js 20+**, Deno, Bun, Cloudflare Workers and any runtime with `fetch`.
7
+ - **Safe by default**: HTTPS only, key never logged, no redirect follow, browser guard, typed errors.
8
+ - **Resilient**: per-request timeout, automatic retries with exponential backoff, `Retry-After` honoured, idempotent vote claims.
9
+
10
+ ```bash
11
+ npm install @flitt/api
12
+ # or: pnpm add @flitt/api · yarn add @flitt/api · bun add @flitt/api
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { Flitt } from "@flitt/api";
19
+
20
+ const flitt = new Flitt({ apiKey: process.env.FLITT_API_KEY });
21
+
22
+ const { data: servers } = await flitt.servers.list();
23
+ for (const server of servers) {
24
+ console.log(`${server.name}: ${server.playersOnline} players (${server.status})`);
25
+ }
26
+ ```
27
+
28
+ CommonJS works too:
29
+
30
+ ```js
31
+ const { Flitt } = require("@flitt/api");
32
+ ```
33
+
34
+ Create your API key in **Dashboard → Profile → API** on [flitt.me](https://flitt.me). It starts with `flt_` and is shown once. If `apiKey` is omitted, the client reads the `FLITT_API_KEY` environment variable.
35
+
36
+ > **Keep your key on a server.** Anyone who reads it can act on your servers (bans, firewall, commands). The client refuses to run in a web page unless you pass `dangerouslyAllowBrowser: true`.
37
+
38
+ ## Quotas
39
+
40
+ | Plan | Public API | Vote API |
41
+ |---|---|---|
42
+ | Freemium | 1,000 requests / month | 120 requests / minute per token |
43
+ | Premium | 20,000 requests / month | 120 requests / minute per token |
44
+ | Enterprise | Unlimited | 120 requests / minute per token |
45
+
46
+ The quota state of the last response is available on `flitt.rateLimit` (`{ limit, remaining, reset }`, `null` values meaning unlimited), or through the `onRateLimit` callback.
47
+
48
+ ## Public API
49
+
50
+ Every method returns a Promise and throws a typed error on failure (see [Errors](#errors)).
51
+
52
+ ### Account
53
+
54
+ ```ts
55
+ const usage = await flitt.usage.get();
56
+ // { enabled, plan, limitPerMonth, usedLast30d, remaining, resetAt }
57
+ ```
58
+
59
+ ### Servers
60
+
61
+ ```ts
62
+ const page = await flitt.servers.list({ page: 1, limit: 25 }); // { data, pagination }
63
+ const server = await flitt.servers.get("srv_123"); // ip/port hidden for the VIEWER role
64
+
65
+ for await (const s of flitt.servers.listAll()) {
66
+ // every server you own or are a member of, page after page
67
+ }
68
+ ```
69
+
70
+ ### Players
71
+
72
+ ```ts
73
+ const { players } = await flitt.players.list("srv_123", { status: "online", limit: 50 });
74
+ const player = await flitt.players.get("srv_123", "76561198000000000"); // Flitt id or external id
75
+
76
+ for await (const p of flitt.players.listAll("srv_123", { status: "all" })) {
77
+ console.log(p.name, p.totalPlaySeconds);
78
+ }
79
+ ```
80
+
81
+ ### Firewall (anti-VPN)
82
+
83
+ Changes need the **OWNER** or **ADMIN** role on the server.
84
+
85
+ ```ts
86
+ await flitt.firewall.update("srv_123", { enabled: true, blockVpn: true, kickMessage: "VPN not allowed" });
87
+
88
+ // One rule, or up to 100 in one call. Partial success is possible:
89
+ const result = await flitt.firewall.rules.create("srv_123", [
90
+ { action: "DENY", kind: "IDENTIFIER", value: "76561198000000000", note: "Cheater" },
91
+ { action: "DENY", kind: "COUNTRY", value: "XX" },
92
+ ]);
93
+ for (const e of result.errors) console.warn(`rule ${e.index}: ${e.code} ${e.message}`);
94
+
95
+ const { rules } = await flitt.firewall.rules.list("srv_123", { action: "DENY", q: "7656" });
96
+ await flitt.firewall.rules.delete("srv_123", rules[0].id);
97
+ await flitt.firewall.rules.deleteMany("srv_123", { kind: "COUNTRY" }); // refuses an empty filter
98
+ const blocked = await flitt.firewall.blocks("srv_123", { limit: 20 });
99
+ ```
100
+
101
+ ### In-game commands
102
+
103
+ Queued for the Flitt addon of the server. `chat` and `notify` need the **EDITOR** role, the others **ADMIN**. Pass `waitMs` (max 15000) to wait for the addon's answer.
104
+
105
+ ```ts
106
+ await flitt.commands.chat("srv_123", "Restart in 5 minutes!");
107
+ await flitt.commands.notify("srv_123", "76561198000000000", "Your VIP is active");
108
+ await flitt.commands.kick("srv_123", "76561198000000000", "AFK");
109
+ const res = await flitt.commands.ban("srv_123", "76561198000000000", { reason: "RDM", durationSeconds: 86_400 }, { waitMs: 5000 });
110
+ console.log(res.result?.ok, res.result?.output);
111
+ await flitt.commands.unban("srv_123", "76561198000000000");
112
+ await flitt.commands.setGroup("srv_123", "76561198000000000", "vip"); // ULX, SAM, CAMI, ace groups, LuckPerms…
113
+ await flitt.commands.setGroup("srv_123", "76561198000000000", "vip", { add: false });
114
+ const { players } = await flitt.commands.groups("srv_123"); // current groups of online players
115
+ ```
116
+
117
+ Commands are **not retried automatically**: a retry could run a ban twice.
118
+
119
+ ### Discord account linking
120
+
121
+ The same flow as the Flitt bot's `/link`, for your own bot.
122
+
123
+ ```ts
124
+ const { code } = await flitt.discord.createLinkCode("123456789012345678");
125
+ // the player types `!flitt CODE` in game (GMod / FiveM) or `/flitt link CODE` (Minecraft)
126
+
127
+ const links = await flitt.discord.findLinks({ discordId: "123456789012345678" });
128
+ await flitt.discord.link("srv_123", { discordId: "123456789012345678", externalId: "76561198000000000" });
129
+ await flitt.discord.unlink("srv_123", "76561198000000000");
130
+ await flitt.discord.setModule("srv_123", true); // API-only setups, without the Flitt bot
131
+ ```
132
+
133
+ ## Vote API
134
+
135
+ For servers **without the Flitt addon**: your own script checks that a player voted, claims the vote exactly once, then gives the reward. One token per server, created in **Dashboard → your server → Votes → Vote API** (starts with `flv_`, shown once). Default env variable: `FLITT_VOTE_TOKEN`.
136
+
137
+ ```ts
138
+ import { FlittVotes } from "@flitt/api";
139
+
140
+ const votes = new FlittVotes({ token: process.env.FLITT_VOTE_TOKEN });
141
+
142
+ const claim = await votes.claim({ player: "Alex_RP" });
143
+ if (claim.status === "CLAIMED_NOW") {
144
+ giveReward("Alex_RP");
145
+ // Premium / Enterprise servers: bonus rewards won in the draw
146
+ for (const bonus of claim.rewards ?? []) giveBonus("Alex_RP", bonus.id);
147
+ }
148
+ ```
149
+
150
+ Identify the player with **exactly one** of `player`, `steamId`, `discordId`, `license`, `uuid`, `ip` or `voteId`.
151
+
152
+ | Method | Description |
153
+ |---|---|
154
+ | `check(identity)` | `CLAIMABLE`, `CLAIMED` or `NOT_FOUND`, plus `nextVoteInMinutes` |
155
+ | `claim(identity, { idempotencyKey? })` | Claims the oldest unclaimed vote (24 h window) |
156
+ | `list({ since?, limit?, cursor? })` / `listAll()` | Recent votes, cursor pagination (30 days max) |
157
+ | `top({ period?, limit? })` | Top voters: `current_month`, `last_month`, `all_time` or `YYYY-MM` |
158
+ | `server({ includeStats? })` | Status, vote counters, ranking, reviews |
159
+ | `stats()` | Daily / weekly / monthly votes, views and join clicks |
160
+ | `reviews({ limit?, cursor?, sort? })` | Published reviews |
161
+
162
+ `claim()` always sends an `Idempotency-Key`, so an automatic retry after a network error can never claim two votes. Pass your own key (for example `${player}:${hour}`) to make your own retries safe as well.
163
+
164
+ ## Webhooks
165
+
166
+ Verify that a webhook really comes from Flitt before trusting it. Pass the **raw** body (not re-serialised JSON) and the secret shown when you created the webhook.
167
+
168
+ ```ts
169
+ import express from "express";
170
+ import { verifyWebhook, FlittWebhookError } from "@flitt/api";
171
+
172
+ const app = express();
173
+ const seen = new Map<string, number>(); // use Redis or your database in production
174
+
175
+ app.post("/flitt-webhook", express.raw({ type: "application/json" }), async (req, res) => {
176
+ try {
177
+ const event = await verifyWebhook({
178
+ payload: req.body, // Buffer
179
+ headers: req.headers,
180
+ secret: process.env.FLITT_WEBHOOK_SECRET!,
181
+ isReplay: (nonce) => { // optional replay protection
182
+ if (seen.has(nonce)) return true;
183
+ seen.set(nonce, Date.now());
184
+ return false;
185
+ },
186
+ });
187
+ if (event.event === "server_down") console.log(`${event.server.name} is down`);
188
+ res.sendStatus(204);
189
+ } catch (err) {
190
+ res.sendStatus(err instanceof FlittWebhookError ? 400 : 500);
191
+ }
192
+ });
193
+ ```
194
+
195
+ With the Fetch API (Next.js route handlers, Workers, Deno, Bun):
196
+
197
+ ```ts
198
+ export async function POST(request: Request) {
199
+ const event = await verifyWebhook({ payload: await request.text(), headers: request.headers, secret: process.env.FLITT_WEBHOOK_SECRET! });
200
+ return new Response(null, { status: 204 });
201
+ }
202
+ ```
203
+
204
+ The signature is HMAC-SHA256 of `timestamp.nonce.body`, compared in constant time; deliveries older than 5 minutes are refused (`toleranceSec`).
205
+
206
+ ## Errors
207
+
208
+ All errors extend `FlittError`. API errors extend `FlittAPIError` and carry `status`, `code`, `message`, `details`, `method`, `path`, `rateLimit` and `retryAfterMs`. **They never contain your key.**
209
+
210
+ | Class | When |
211
+ |---|---|
212
+ | `FlittConfigError` | Bad option or argument, detected before any request |
213
+ | `FlittValidationError` | 400 invalid parameter |
214
+ | `FlittAuthenticationError` | 401 missing, invalid or revoked key / token |
215
+ | `FlittPermissionError` | 403 plan or role does not allow it |
216
+ | `FlittNotFoundError` | 404 not found, or not yours |
217
+ | `FlittConflictError` | 409 conflict (duplicate rule, inactive server…) |
218
+ | `FlittRateLimitError` | 429 quota reached: see `retryAfterMs` / `rateLimit.reset` |
219
+ | `FlittServerError` | 5xx temporary error on Flitt's side |
220
+ | `FlittTimeoutError` | No response within `timeoutMs` |
221
+ | `FlittConnectionError` | Network failure (DNS, TLS, reset…) |
222
+ | `FlittAbortError` | Aborted through your `AbortSignal` |
223
+
224
+ ```ts
225
+ import { FlittNotFoundError, FlittRateLimitError } from "@flitt/api";
226
+
227
+ try {
228
+ await flitt.servers.get("srv_123");
229
+ } catch (err) {
230
+ if (err instanceof FlittNotFoundError) console.log("Unknown server");
231
+ else if (err instanceof FlittRateLimitError) console.log(`Quota reached, retry in ${err.retryAfterMs} ms`);
232
+ else throw err;
233
+ }
234
+ ```
235
+
236
+ ## Options
237
+
238
+ ```ts
239
+ new Flitt({
240
+ apiKey: "flt_…", // default: process.env.FLITT_API_KEY
241
+ baseUrl: "https://api.flitt.me",
242
+ timeoutMs: 15_000, // per attempt
243
+ maxRetries: 2, // idempotent requests: network errors, 408, 425, 5xx, short 429
244
+ maxRetryDelayMs: 30_000, // longest single wait; a longer Retry-After is not waited for
245
+ fetch: customFetch, // tests, proxies, instrumentation
246
+ userAgent: "my-bot/1.0", // server-side only
247
+ onRateLimit: (rl) => metrics.gauge("flitt.remaining", rl.remaining ?? Infinity),
248
+ dangerouslyAllowBrowser: false,
249
+ });
250
+ ```
251
+
252
+ Every method also takes a last `options` argument: `{ signal?: AbortSignal, timeoutMs?: number, maxRetries?: number }`.
253
+
254
+ ```ts
255
+ const controller = new AbortController();
256
+ setTimeout(() => controller.abort(), 2000);
257
+ await flitt.servers.list({}, { signal: controller.signal });
258
+ ```
259
+
260
+ ## Security
261
+
262
+ - HTTPS only (HTTP is accepted for `localhost` during development); credentials, query strings and fragments in `baseUrl` are rejected.
263
+ - Redirects are never followed, so the `Authorization` header cannot leak to another host.
264
+ - Path segments are URL-encoded and dot segments are refused.
265
+ - The key lives in a private class field: `console.log`, `util.inspect`, `JSON.stringify` and error objects never show it.
266
+ - Keys are format-checked locally, so a vote token passed as an API key (or the reverse) fails before any request.
267
+ - Responses larger than 32 MB are refused.
268
+
269
+ Report a vulnerability: see [SECURITY.md](./SECURITY.md).
270
+
271
+ ## Links
272
+
273
+ - API reference: https://flitt.me/docs/public-api
274
+ - Support: https://flitt.me/dashboard/support · contact@flitt.me
275
+ - Discord: https://discord.gg/DujRDRsrWD
276
+
277
+ MIT © Flitt
package/SECURITY.md ADDED
@@ -0,0 +1,15 @@
1
+ # Security policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Please do not open a public issue. Write to **contact@flitt.me** (subject "Security") or open a ticket from https://flitt.me/dashboard/support with the steps to reproduce. We acknowledge within 48 hours and do not pursue good-faith researchers.
6
+
7
+ ## Supported versions
8
+
9
+ Security fixes are released for the latest major version of `@flitt/api`.
10
+
11
+ ## Handling your credentials
12
+
13
+ - Public API keys (`flt_…`) and Vote API tokens (`flv_…`) are secrets. Keep them in environment variables or a secret manager, never in client-side code or a public repository.
14
+ - If a key leaks, rotate it at once from the dashboard (Profile → API, or your server → Votes → Vote API).
15
+ - This package never logs, prints or serialises your key, only sends it over HTTPS in the `Authorization` header, and never follows redirects.
@@ -0,0 +1,243 @@
1
+ import { Transport, type FetchLike, type RequestOptions } from "./http.js";
2
+ import type { AccountLink, CommandInput, CommandResult, DiscordModule, FirewallBlock, FirewallRuleBulkDelete, FirewallRuleCreateResult, FirewallRuleInput, FirewallRuleList, FirewallRuleQuery, FirewallSettings, FirewallSettingsUpdate, GroupList, LinkCode, PageParams, Player, PlayerList, PlayerStatusFilter, RateLimit, ReviewList, ReviewListParams, Server, ServerList, ServerSummary, TopVoters, TopVotersPeriod, Usage, VoteCheck, VoteClaim, VoteIdentity, VoteList, VoteListItem, VoteListParams, VoteServer, VoteStats } from "./types.js";
3
+ export declare const DEFAULT_BASE_URL = "https://api.flitt.me";
4
+ export type ClientOptions = {
5
+ /** API root, default `https://api.flitt.me`. HTTPS only (HTTP allowed for localhost). */
6
+ baseUrl?: string;
7
+ /** Per-attempt timeout in ms, default 15000. */
8
+ timeoutMs?: number;
9
+ /** Retries of idempotent requests on network errors, 5xx and short 429s. Default 2. */
10
+ maxRetries?: number;
11
+ /** Upper bound of a single wait between retries, in ms. Default 30000. */
12
+ maxRetryDelayMs?: number;
13
+ /** Custom fetch (tests, proxies, older runtimes). Default: global fetch. */
14
+ fetch?: FetchLike;
15
+ /** Replaces the default `flitt-api-js/<version>` User-Agent (server-side only). */
16
+ userAgent?: string;
17
+ /** Called with the quota state after every response that carries X-RateLimit-* headers. */
18
+ onRateLimit?: (rateLimit: RateLimit) => void;
19
+ /**
20
+ * Your key is a secret: anyone who reads it can act on your servers. The
21
+ * client refuses to run in a browser unless you set this to true (e.g. an
22
+ * internal tool where only you use the page).
23
+ */
24
+ dangerouslyAllowBrowser?: boolean;
25
+ };
26
+ export type FlittOptions = ClientOptions & {
27
+ /** Public API key (`flt_…`, Profile → API). Default: `process.env.FLITT_API_KEY`. */
28
+ apiKey?: string;
29
+ };
30
+ export type FlittVotesOptions = ClientOptions & {
31
+ /** Vote API token of one server (`flv_…`, Dashboard → server → Votes). Default: `process.env.FLITT_VOTE_TOKEN`. */
32
+ token?: string;
33
+ };
34
+ declare const INSPECT: unique symbol;
35
+ /**
36
+ * Client of the Flitt Public API v1.
37
+ *
38
+ * ```ts
39
+ * import { Flitt } from "@flitt/api";
40
+ * const flitt = new Flitt({ apiKey: process.env.FLITT_API_KEY });
41
+ * const { data } = await flitt.servers.list();
42
+ * ```
43
+ */
44
+ export declare class Flitt {
45
+ #private;
46
+ /** Your account's monthly quota. */
47
+ readonly usage: {
48
+ get(options?: RequestOptions): Promise<Usage>;
49
+ };
50
+ readonly servers: ServersResource;
51
+ readonly players: PlayersResource;
52
+ readonly firewall: FirewallResource;
53
+ readonly discord: DiscordResource;
54
+ readonly commands: CommandsResource;
55
+ constructor(options?: FlittOptions);
56
+ /** Quota state from the last response (`null` before the first request). */
57
+ get rateLimit(): RateLimit | null;
58
+ /** Never prints the key. */
59
+ toJSON(): {
60
+ client: string;
61
+ apiKey: string;
62
+ };
63
+ [INSPECT](): string;
64
+ }
65
+ declare class ServersResource {
66
+ private readonly http;
67
+ private readonly base;
68
+ constructor(http: Transport, base: string);
69
+ /** Servers you own or are a member of, newest first. `limit`: 1 to 100 (default 25). */
70
+ list(params?: PageParams, options?: RequestOptions): Promise<ServerList>;
71
+ /** Iterates over every server, page after page. */
72
+ listAll(params?: Omit<PageParams, "page">, options?: RequestOptions): AsyncGenerator<ServerSummary>;
73
+ /** One server. IP, port and addon details are hidden for the VIEWER role. */
74
+ get(serverId: string, options?: RequestOptions): Promise<Server>;
75
+ }
76
+ declare class PlayersResource {
77
+ private readonly http;
78
+ private readonly base;
79
+ constructor(http: Transport, base: string);
80
+ /** Players of a server, last joined first. `limit`: 1 to 50 (default 15). */
81
+ list(serverId: string, params?: PageParams & {
82
+ status?: PlayerStatusFilter;
83
+ }, options?: RequestOptions): Promise<PlayerList>;
84
+ /** Iterates over every player of a server. */
85
+ listAll(serverId: string, params?: {
86
+ status?: PlayerStatusFilter;
87
+ limit?: number;
88
+ }, options?: RequestOptions): AsyncGenerator<Player>;
89
+ /** One player, by Flitt player id or by external id (SteamID64, license, UUID…). */
90
+ get(serverId: string, playerId: string, options?: RequestOptions): Promise<Player>;
91
+ }
92
+ declare class FirewallResource {
93
+ private readonly http;
94
+ private readonly base;
95
+ readonly rules: FirewallRulesResource;
96
+ constructor(http: Transport, base: string);
97
+ /** Firewall settings and rule counts. */
98
+ get(serverId: string, options?: RequestOptions): Promise<FirewallSettings>;
99
+ /** Turns the firewall / VPN blocking on or off, changes the kick message. OWNER or ADMIN. */
100
+ update(serverId: string, changes: FirewallSettingsUpdate, options?: RequestOptions): Promise<void>;
101
+ /** Latest blocked connections (1 to 200, default 50). */
102
+ blocks(serverId: string, params?: {
103
+ limit?: number;
104
+ }, options?: RequestOptions): Promise<FirewallBlock[]>;
105
+ }
106
+ declare class FirewallRulesResource {
107
+ private readonly http;
108
+ private readonly base;
109
+ constructor(http: Transport, base: string);
110
+ list(serverId: string, query?: FirewallRuleQuery, options?: RequestOptions): Promise<FirewallRuleList>;
111
+ /**
112
+ * Adds one rule, or up to 100 in one call (e.g. to sync a ban list). OWNER
113
+ * or ADMIN. Partial success is possible: check `errors` in the result.
114
+ */
115
+ create(serverId: string, rules: FirewallRuleInput | FirewallRuleInput[], options?: RequestOptions): Promise<FirewallRuleCreateResult>;
116
+ /** Removes one rule. */
117
+ delete(serverId: string, ruleId: string, options?: RequestOptions): Promise<void>;
118
+ /** Removes rules by ids (up to 500) and / or by action / kind. Returns the number deleted. */
119
+ deleteMany(serverId: string, filter: FirewallRuleBulkDelete, options?: RequestOptions): Promise<number>;
120
+ }
121
+ declare class DiscordResource {
122
+ private readonly http;
123
+ private readonly base;
124
+ constructor(http: Transport, base: string);
125
+ /** Discord module state of a server (for API-only setups, without the Flitt bot). */
126
+ getModule(serverId: string, options?: RequestOptions): Promise<DiscordModule>;
127
+ /** Turns the addon's Discord module on or off. ADMIN. */
128
+ setModule(serverId: string, enabled: boolean, options?: RequestOptions): Promise<{
129
+ serverId: string;
130
+ moduleEnabled: boolean;
131
+ }>;
132
+ /** Code a player types in game to link their Discord account (same flow as the bot's /link). */
133
+ createLinkCode(discordId: string, options?: RequestOptions): Promise<LinkCode>;
134
+ /** Links of a Discord user or of a game identity, limited to players seen on your servers. */
135
+ findLinks(query: {
136
+ discordId: string;
137
+ } | {
138
+ externalId: string;
139
+ }, options?: RequestOptions): Promise<AccountLink[]>;
140
+ /** Links a player you verified yourself. The player must have joined the server. ADMIN. */
141
+ link(serverId: string, input: {
142
+ discordId: string;
143
+ externalId: string;
144
+ name?: string;
145
+ }, options?: RequestOptions): Promise<AccountLink>;
146
+ /** Removes the Discord link of a player. ADMIN. */
147
+ unlink(serverId: string, externalId: string, options?: RequestOptions): Promise<number>;
148
+ }
149
+ declare class CommandsResource {
150
+ private readonly http;
151
+ private readonly base;
152
+ constructor(http: Transport, base: string);
153
+ /**
154
+ * Queues a command for the game server's addon. `chat` and `notify` need the
155
+ * EDITOR role, everything else ADMIN. Set `waitMs` (max 15000) to wait for
156
+ * the addon's answer. Not retried automatically: a retry could run it twice.
157
+ */
158
+ send(serverId: string, input: CommandInput, options?: RequestOptions): Promise<CommandResult>;
159
+ /** Message in the game chat. */
160
+ chat(serverId: string, text: string, options?: RequestOptions & {
161
+ waitMs?: number;
162
+ }): Promise<CommandResult>;
163
+ /** Private message to one online player. */
164
+ notify(serverId: string, externalId: string, message: string, options?: RequestOptions & {
165
+ waitMs?: number;
166
+ }): Promise<CommandResult>;
167
+ kick(serverId: string, externalId: string, reason?: string, options?: RequestOptions & {
168
+ waitMs?: number;
169
+ }): Promise<CommandResult>;
170
+ /** `durationSeconds`: 0 or omitted = permanent. */
171
+ ban(serverId: string, externalId: string, params?: {
172
+ reason?: string;
173
+ durationSeconds?: number;
174
+ }, options?: RequestOptions & {
175
+ waitMs?: number;
176
+ }): Promise<CommandResult>;
177
+ unban(serverId: string, externalId: string, options?: RequestOptions & {
178
+ waitMs?: number;
179
+ }): Promise<CommandResult>;
180
+ /** Adds (default) or removes an in-game group (ULX, SAM, CAMI, ace groups, LuckPerms or your hooks). */
181
+ setGroup(serverId: string, externalId: string, group: string, params?: {
182
+ add?: boolean;
183
+ }, options?: RequestOptions & {
184
+ waitMs?: number;
185
+ }): Promise<CommandResult>;
186
+ setName(serverId: string, externalId: string, name: string, options?: RequestOptions & {
187
+ waitMs?: number;
188
+ }): Promise<CommandResult>;
189
+ /** Current in-game groups of the online players, as reported by the addon. */
190
+ groups(serverId: string, options?: RequestOptions): Promise<GroupList>;
191
+ }
192
+ /**
193
+ * Client of the Flitt Vote API: reward voters from your own scripts when the
194
+ * Flitt addon is not installed. One token = one server.
195
+ *
196
+ * ```ts
197
+ * import { FlittVotes } from "@flitt/api";
198
+ * const votes = new FlittVotes({ token: process.env.FLITT_VOTE_TOKEN });
199
+ * const claim = await votes.claim({ player: "Alex_RP" });
200
+ * if (claim.status === "CLAIMED_NOW") giveReward("Alex_RP");
201
+ * ```
202
+ */
203
+ export declare class FlittVotes {
204
+ #private;
205
+ constructor(options?: FlittVotesOptions);
206
+ /** Quota state from the last response (120 requests / minute per token). */
207
+ get rateLimit(): RateLimit | null;
208
+ /** Whether the player has a vote waiting to be claimed (last 24 h). */
209
+ check(identity: VoteIdentity, options?: RequestOptions): Promise<VoteCheck>;
210
+ /**
211
+ * Claims the player's oldest unclaimed vote, exactly once across every
212
+ * channel (addon, API, NuVotifier). Give the reward only when `status` is
213
+ * `CLAIMED_NOW`. An idempotency key is generated so automatic retries can
214
+ * never claim twice; pass your own to make your retries safe too.
215
+ */
216
+ claim(identity: VoteIdentity, options?: RequestOptions & {
217
+ idempotencyKey?: string;
218
+ }): Promise<VoteClaim>;
219
+ /** Recent votes, oldest first (up to 30 days back), cursor pagination. */
220
+ list(params?: VoteListParams, options?: RequestOptions): Promise<VoteList>;
221
+ /** Iterates over every vote since `since`. */
222
+ listAll(params?: Omit<VoteListParams, "cursor">, options?: RequestOptions): AsyncGenerator<VoteListItem>;
223
+ /** Top voters of a month (`current_month`, `last_month`, `all_time` or `YYYY-MM`). */
224
+ top(params?: {
225
+ period?: TopVotersPeriod;
226
+ limit?: number;
227
+ }, options?: RequestOptions): Promise<TopVoters>;
228
+ /** Server info: status, votes, ranking, reviews (and stats with `includeStats`). */
229
+ server(params?: {
230
+ includeStats?: boolean;
231
+ }, options?: RequestOptions): Promise<VoteServer>;
232
+ /** Daily, weekly and monthly votes, page views and join clicks. */
233
+ stats(options?: RequestOptions): Promise<VoteStats>;
234
+ /** Published reviews of the server. */
235
+ reviews(params?: ReviewListParams, options?: RequestOptions): Promise<ReviewList>;
236
+ toJSON(): {
237
+ client: string;
238
+ token: string;
239
+ };
240
+ [INSPECT](): string;
241
+ }
242
+ export {};
243
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}