@lootlog/sdk 0.1.0 → 0.1.1

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 (2) hide show
  1. package/README.md +261 -40
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,50 +1,271 @@
1
1
  # @lootlog/sdk
2
2
 
3
- Generated fetch-only HTTP functions for the supported Lootlog API, with a shared
4
- realtime client. No React dependency. API keys belong on trusted servers, never
5
- in distributed userscripts or browser bundles.
3
+ Read Lootlog timers, loot and battle data from your own scripts, bots and server
4
+ applications. Includes typed HTTP functions and a WebSocket client for realtime
5
+ updates. Works with Node.js and Bun; React is not required.
6
6
 
7
- ```ts
7
+ [Documentation](https://developer.lootlog.pl/docs/sdk) ·
8
+ [API reference](https://developer.lootlog.pl/reference)
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ npm install @lootlog/sdk
14
+ # or
15
+ bun add @lootlog/sdk
16
+ ```
17
+
18
+ The package uses ES modules and includes TypeScript declarations. Use a runtime
19
+ with built-in `fetch`, such as Node.js 22+ or Bun.
20
+
21
+ ## Set up your API key
22
+
23
+ Create a key at [developer.lootlog.pl/keys](https://developer.lootlog.pl/keys).
24
+ Select the Organizations you want to access and read-only permissions to follow
25
+ these examples. The key's owner must also have access to the requested data.
26
+
27
+ Keep the key on your server. Never put it in frontend code or a distributed
28
+ userscript. For in-game addons, use the
29
+ [game client API](https://developer.lootlog.pl/docs/game-client).
30
+
31
+ Set `LOOTLOG_API_KEY` in your deployment secrets or a local `.env` file excluded
32
+ from version control:
33
+
34
+ ```dotenv
35
+ LOOTLOG_API_KEY=replace-with-your-key
36
+ ```
37
+
38
+ ## Find your organization
39
+
40
+ Save this complete example as `organizations.mjs`:
41
+
42
+ ```js
8
43
  import { configureLootlogApi } from "@lootlog/sdk";
9
44
  import { usersControllerGetCurrentUserGuilds } from "@lootlog/sdk/main";
10
45
 
11
- const restore = configureLootlogApi({ apiKey: process.env.LOOTLOG_API_KEY! });
46
+ const apiKey = process.env.LOOTLOG_API_KEY;
47
+ if (!apiKey) throw new Error("Set LOOTLOG_API_KEY");
48
+
49
+ configureLootlogApi({ apiKey, environment: "production" });
50
+
51
+ const organizations = await usersControllerGetCurrentUserGuilds({
52
+ signal: AbortSignal.timeout(10_000),
53
+ });
54
+
55
+ console.table(
56
+ organizations.map((organization) => ({
57
+ id: organization.id,
58
+ name: organization.name,
59
+ accessible: organization.hasLootlogAccess,
60
+ stale: organization.isAccessDataStale,
61
+ })),
62
+ );
63
+ ```
64
+
65
+ Run it with your `.env` file:
66
+
67
+ ```sh
68
+ node --env-file=.env organizations.mjs
69
+ # or: Bun loads .env automatically
70
+ bun organizations.mjs
71
+ ```
72
+
73
+ Copy an accessible Organization's `id` into `LOOTLOG_GUILD_ID` in your `.env`:
74
+
75
+ ```dotenv
76
+ LOOTLOG_GUILD_ID=replace-with-the-organization-id
77
+ LOOTLOG_WORLD=fobos
78
+ ```
79
+
80
+ The API calls this identifier `guildId`: it is the Organization's Discord guild
81
+ ID. Replace `fobos` with your Margonem world. If `stale` is true, the returned
82
+ access information is outdated.
83
+
84
+ For the development environment, create a key at
85
+ [dev-developer.lootlog.pl/keys](https://dev-developer.lootlog.pl/keys) and use
86
+ `environment: "development"`. Keys are specific to their environment.
87
+
88
+ ## Fetch timers and the latest loot
89
+
90
+ Save this complete example as `lootlog.mjs`. It prints NPC spawn windows and the
91
+ latest 20 loot records for your chosen Organization and world.
92
+
93
+ ```js
94
+ import { configureLootlogApi } from "@lootlog/sdk";
95
+ import {
96
+ lootsControllerFetchLootsByGuildId,
97
+ timersControllerGetTimers,
98
+ } from "@lootlog/sdk/main";
99
+
100
+ const apiKey = process.env.LOOTLOG_API_KEY;
101
+ const guildId = process.env.LOOTLOG_GUILD_ID;
102
+ const world = process.env.LOOTLOG_WORLD;
103
+ if (!apiKey || !guildId || !world) {
104
+ throw new Error("Set LOOTLOG_API_KEY, LOOTLOG_GUILD_ID and LOOTLOG_WORLD");
105
+ }
106
+
107
+ configureLootlogApi({ apiKey, environment: "production" });
108
+
109
+ const timers = await timersControllerGetTimers(
110
+ { guildId },
111
+ { world },
112
+ { signal: AbortSignal.timeout(10_000) },
113
+ );
114
+
115
+ console.table(
116
+ timers.map((timer) => ({
117
+ npc: timer.npc.name,
118
+ level: timer.npc.lvl,
119
+ location: timer.npc.location,
120
+ earliestSpawn: timer.minSpawnTime,
121
+ latestSpawn: timer.maxSpawnTime,
122
+ })),
123
+ );
124
+
125
+ const loots = await lootsControllerFetchLootsByGuildId(
126
+ { guildId },
127
+ { world, limit: 20 },
128
+ { signal: AbortSignal.timeout(10_000) },
129
+ );
130
+
131
+ console.table(
132
+ loots.map((loot) => ({
133
+ id: loot.id,
134
+ date: loot.createdAt,
135
+ npcs: loot.npcs.map((npc) => npc.name).join(", "),
136
+ items: loot.items.map((item) => item.name).join(", "),
137
+ players: loot.players.map((player) => player.name).join(", "),
138
+ })),
139
+ );
140
+ ```
141
+
142
+ Run `node --env-file=.env lootlog.mjs` or `bun lootlog.mjs`.
143
+
144
+ Both functions return arrays of parsed objects. Dates are ISO strings; use
145
+ `new Date(value)` to format them in your time zone. A timer describes a spawn
146
+ window, not confirmation that an NPC is currently alive. Results reflect the
147
+ key's scope and the owner's permissions; an empty array is a successful request
148
+ with no visible results.
149
+
150
+ ## Filter loot and fetch the next page
151
+
152
+ In `lootlog.mjs`, replace the `const loots = ...` request with this block to read
153
+ legendary loot from the last seven days:
154
+
155
+ ```js
156
+ const filters = {
157
+ world,
158
+ limit: 20,
159
+ rarities: ["LEGENDARY"],
160
+ createdAtMin: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
161
+ };
162
+
163
+ const loots = await lootsControllerFetchLootsByGuildId({ guildId }, filters, {
164
+ signal: AbortSignal.timeout(10_000),
165
+ });
166
+ ```
167
+
168
+ You can also filter by `npcs`, `players`, `itemNames` and level ranges. Your
169
+ editor shows the available query fields; the
170
+ [API reference](https://developer.lootlog.pl/reference) describes their values.
171
+
172
+ To load one more page, add this after the first request:
173
+
174
+ ```js
175
+ const lastLoot = loots.at(-1);
176
+ const nextPage = lastLoot
177
+ ? await lootsControllerFetchLootsByGuildId(
178
+ { guildId },
179
+ { ...filters, cursor: lastLoot.id },
180
+ { signal: AbortSignal.timeout(10_000) },
181
+ )
182
+ : [];
183
+
184
+ console.log(`Next page: ${nextPage.length} loot records`);
185
+ ```
186
+
187
+ Loot is ordered by descending ID. Pass the last record's `id` as `cursor` and
188
+ keep the same filters to fetch older records. `limit` accepts 1–100. There is
189
+ no `nextCursor` response wrapper; an empty page means there are no more results.
190
+
191
+ ## TypeScript and imports
192
+
193
+ Import operations and response types from the service you need:
194
+
195
+ ```ts
196
+ import {
197
+ timersControllerGetTimers,
198
+ type TimerResponseDto,
199
+ } from "@lootlog/sdk/main";
200
+
201
+ // After configuring the SDK as shown above:
202
+ const timers: TimerResponseDto[] = await timersControllerGetTimers(
203
+ { guildId: "123456789012345678" },
204
+ { world: "fobos" },
205
+ );
206
+ ```
207
+
208
+ Return types are inferred, so the annotation is optional. There is no separate
209
+ `@types/lootlog` package. For Node.js TypeScript projects, use `"type": "module"`
210
+ in `package.json`, `module: "NodeNext"` and `moduleResolution: "NodeNext"` in
211
+ `tsconfig.json`, and install `@types/node`.
212
+
213
+ | Import | Contents |
214
+ | -------------------------------- | ------------------------------------------------------------------------------ |
215
+ | `@lootlog/sdk` | Authentication and environment configuration |
216
+ | `@lootlog/sdk/main` | Organizations, timers, loot and main API types |
217
+ | `@lootlog/sdk/activity` | Activity operations and types |
218
+ | `@lootlog/sdk/battlelog` | Battle records and statistics |
219
+ | `@lootlog/sdk/search` | Item, NPC and player search |
220
+ | `@lootlog/sdk/realtime` | WebSocket client and event types |
221
+ | `@lootlog/sdk/openapi/main.json` | OpenAPI specification; also available for `activity`, `battlelog` and `search` |
222
+
223
+ For the HTTP examples above, arguments are **path parameters, query parameters,
224
+ request options**. Other operations may accept a body; follow their generated
225
+ signature.
226
+
227
+ ## Handle errors
228
+
229
+ Failed HTTP requests throw an error named `ApiError` with `status` and `data`.
230
+ The constructor is not exported. Wrap your requests in `try`/`catch` and inspect
231
+ the status:
232
+
233
+ ```js
12
234
  try {
13
- const organizations = await usersControllerGetCurrentUserGuilds();
14
- } finally {
15
- restore();
235
+ const timers = await timersControllerGetTimers(
236
+ { guildId },
237
+ { world },
238
+ { signal: AbortSignal.timeout(10_000) },
239
+ );
240
+ console.log(`Loaded ${timers.length} timers`);
241
+ } catch (error) {
242
+ const status =
243
+ error instanceof Error && "status" in error ? error.status : undefined;
244
+
245
+ if (status === 401) {
246
+ console.error("Check the API key, expiration and environment");
247
+ } else if (status === 403) {
248
+ console.error("Check the key's scope and your organization permissions");
249
+ } else if (status === 429) {
250
+ console.error("Rate limit reached; wait before making another request");
251
+ } else {
252
+ console.error("Request failed", { status });
253
+ }
16
254
  }
17
255
  ```
18
256
 
19
- Use `environment: "development"` explicitly for development hosts. Configuration
20
- is process-wide; per-request `apiClient` overrides support isolated callers.
21
- HTTP failures throw `ApiError` with `status` and parsed `data`. Writes are never
22
- retried automatically. Each key remains constrained by the user's current access.
23
-
24
- Import `RealtimeClient` from `@lootlog/sdk/realtime`. On a trusted server pass
25
- `webSocketFactory: (url, protocols) => new WebSocket(url, { protocols, headers:
26
- { "X-Api-Key": apiKey } })` with a server WebSocket implementation that supports
27
- headers (for example Bun). Browser WebSocket cannot attach API key headers.
28
- Use `wss://gateway.lootlog.pl/ws` or `wss://dev-gateway.lootlog.pl/ws` explicitly.
29
- Keys support read subscriptions/queries only; presence and realtime writes remain
30
- session-only. Do not put keys in URLs or subprotocols.
31
-
32
- For local userscript integrations use the installed `lootlogGameClientApi` and
33
- `@lootlog/game-client-api` types instead of HTTP keys.
34
-
35
- `bun run client:generate` projects the reviewed operation inventory and generates
36
- these functions from service OpenAPI documents. `bun run client:check` detects
37
- drift; `bun run build` builds portable ESM and bundled declarations. Maintainers
38
- publish through the repository's **Publish SDK** workflow; see the
39
- [publication guide](https://github.com/lootlog/monorepo/blob/main/packages/sdk/PUBLISHING.md).
40
-
41
- The Organization loot count endpoint (`GET /guilds/{guildId}/loots/count`) and
42
- `lootsControllerCountLootsByGuildId` SDK function have been removed. Integrations
43
- must stop requesting a total count before the API removal is deployed. Use the
44
- paginated loot list to browse records; it does not provide a replacement total.
45
-
46
- Builds use the repository's TypeScript 7 catalog version and tsdown. The shared
47
- `packages/tsconfig.public-api.json` includes workspace source dependencies so
48
- declarations are bundled without requiring consumers to install private packages.
49
- Run `bun run test:package` to install both public packages in an isolated
50
- consumer and verify all SDK entry points with runtime checks and TypeScript.
257
+ Network errors and timeouts have no HTTP status; `cause` retains the underlying
258
+ failure. The SDK does not automatically retry HTTP requests. Keep errors distinct
259
+ from an empty result and mark previously loaded data stale after a failed refresh.
260
+
261
+ ## Next steps
262
+
263
+ `configureLootlogApi` sets process-wide HTTP configuration. Configure it once
264
+ when your application starts. Its returned function restores the previous
265
+ configuration when called. Do not change global configuration for individual requests in a server handling
266
+ multiple keys concurrently.
267
+
268
+ - [Realtime subscriptions](https://developer.lootlog.pl/docs/realtime): receive timer updates over WebSocket.
269
+ - [Keys and permissions](https://developer.lootlog.pl/docs/keys): scope access and rotate credentials.
270
+ - [Errors and limits](https://developer.lootlog.pl/docs/errors): handle failed requests and rate limits.
271
+ - [Changelog](https://developer.lootlog.pl/docs/changelog): published contract changes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lootlog/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Typed HTTP and realtime clients for the Lootlog public API",
5
5
  "homepage": "https://developer.lootlog.pl/docs/sdk",
6
6
  "bugs": {