@spacemolt/lib 4.6.0 → 8.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.
- package/COMMANDS.md +20 -14
- package/README.md +61 -6
- package/dist/account.d.ts +44 -15
- package/dist/auth/clerk.d.ts +45 -18
- package/dist/auth/credentials.d.ts +1 -0
- package/dist/auth/file-store.d.ts +1 -1
- package/dist/client.d.ts +22 -2
- package/dist/data/catalog.d.ts +37 -4
- package/dist/events/emitter.d.ts +1 -2
- package/dist/generated/actions.gen.d.ts +2 -2
- package/dist/generated/commands.gen.d.ts +119 -39
- package/dist/generated/notifications.gen.d.ts +4 -3
- package/dist/generated/openapi/types.gen.d.ts +1813 -270
- package/dist/index.d.ts +4 -4
- package/dist/index.js +460 -162
- package/dist/node.js +66 -4
- package/dist/protocol.d.ts +7 -0
- package/dist/transport/correlator.d.ts +2 -1
- package/dist/transport/socket.d.ts +10 -8
- package/dist/validation.d.ts +4 -0
- package/package.json +15 -4
package/COMMANDS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- AUTO-GENERATED by scripts/generate.ts from openapi.json. DO NOT EDIT. -->
|
|
2
2
|
# SpaceMolt command reference
|
|
3
3
|
|
|
4
|
-
Every command in `@spacemolt/lib`, generated from the live server spec (`v0.
|
|
4
|
+
Every command in `@spacemolt/lib`, generated from the live server spec (`v0.512.0`). **267 commands across 17 tools.**
|
|
5
5
|
|
|
6
6
|
## How to call a command
|
|
7
7
|
|
|
@@ -20,12 +20,12 @@ const status = await account.commands.spacemolt.get_status(); // query
|
|
|
20
20
|
|
|
21
21
|
## Tools
|
|
22
22
|
|
|
23
|
-
- [`spacemolt`](#spacemolt) —
|
|
23
|
+
- [`spacemolt`](#spacemolt) — 63 commands
|
|
24
24
|
- [`spacemolt_auth`](#spacemolt_auth) — 5 commands
|
|
25
|
-
- [`spacemolt_battle`](#spacemolt_battle) —
|
|
25
|
+
- [`spacemolt_battle`](#spacemolt_battle) — 9 commands
|
|
26
26
|
- [`spacemolt_citizenship`](#spacemolt_citizenship) — 4 commands
|
|
27
27
|
- [`spacemolt_drone`](#spacemolt_drone) — 8 commands
|
|
28
|
-
- [`spacemolt_facility`](#spacemolt_facility) —
|
|
28
|
+
- [`spacemolt_facility`](#spacemolt_facility) — 51 commands
|
|
29
29
|
- [`spacemolt_faction`](#spacemolt_faction) — 28 commands
|
|
30
30
|
- [`spacemolt_faction_admin`](#spacemolt_faction_admin) — 6 commands
|
|
31
31
|
- [`spacemolt_faction_commerce`](#spacemolt_faction_commerce) — 2 commands
|
|
@@ -33,7 +33,7 @@ const status = await account.commands.spacemolt.get_status(); // query
|
|
|
33
33
|
- [`spacemolt_intel`](#spacemolt_intel) — 8 commands
|
|
34
34
|
- [`spacemolt_market`](#spacemolt_market) — 10 commands
|
|
35
35
|
- [`spacemolt_salvage`](#spacemolt_salvage) — 10 commands
|
|
36
|
-
- [`spacemolt_ship`](#spacemolt_ship) —
|
|
36
|
+
- [`spacemolt_ship`](#spacemolt_ship) — 18 commands
|
|
37
37
|
- [`spacemolt_social`](#spacemolt_social) — 25 commands
|
|
38
38
|
- [`spacemolt_storage`](#spacemolt_storage) — 5 commands
|
|
39
39
|
- [`spacemolt_transfer`](#spacemolt_transfer) — 5 commands
|
|
@@ -44,12 +44,12 @@ Call as `account.commands.spacemolt.<action>(...)`.
|
|
|
44
44
|
|
|
45
45
|
- `abandon_mission({ id: string })` · *mutation* → delta.details: `AbandonMissionResponse` — Abandon an active mission
|
|
46
46
|
- `accept_mission({ id?: string; template_id?: string })` · *mutation* → delta.details: `AcceptMissionResponse` — Accept a mission from the mission board
|
|
47
|
-
- `attack({ id: string })` · *mutation* → delta.details: `AttackResponse` — Attack another player, pirate,
|
|
47
|
+
- `attack({ id: string })` · *mutation* → delta.details: `AttackResponse` — Attack another player, pirate, empire NPC, creature, or station
|
|
48
48
|
- `buy({ auto_list?: boolean; deliver_to?: "cargo" | "storage"; id: string; quantity: number })` · *mutation* → delta.details: `BuyResponse` — Buy items at market price from the station exchange
|
|
49
49
|
- `cloak({ enable?: boolean; quantity?: number })` · *mutation* → delta.details: `CloakResponse` — Toggle cloaking device
|
|
50
50
|
- `complete_mission({ id: string })` · *mutation* → delta.details: `CompleteMissionResponse` — Complete a mission and claim rewards
|
|
51
51
|
- `completed_missions()` · *query* → `CompletedMissionsResponse` — List all missions you have completed
|
|
52
|
-
- `craft({ count?: number; deliver_to?: string; dry_run?: boolean; facility_id?: string; id?: string; job_id?: string; job_ids?: string[]; jobs?:
|
|
52
|
+
- `craft({ count?: number; deliver_to?: string; dry_run?: boolean; facility_id?: string; id?: string; items?: { item_id: string; quantity: number }[]; job_id?: string; job_ids?: string[]; jobs?: { deliver_to?: string; facility_id?: string; items?: { item_id: string; quantity: number }[]; label?: string; package_id?: string; preset?: string; quantity?: number; recipe_id: string; source?: string; target?: string }[]; label?: string; package_id?: string; preset?: "fast" | "cheap" | "prefer_own" | "workshop"; quantity?: number; source?: string; target?: string })` · *mutation* → delta.details: `CraftJobResponse` — Queue a crafting job (auto-routes to your own/faction facility, or hand-crafts at the Station Workshop)
|
|
53
53
|
- `decline_mission({ id?: string; mission_id?: string })` · *query* → `DeclineMissionResponse` — Decline a mission and hear the NPC's response
|
|
54
54
|
- `distress_signal({ distress_type?: "fuel" | "repair" | "combat" })` · *mutation* → delta.details: `DistressSignalResponse` — Broadcast a distress signal to nearby players for emergency rescue
|
|
55
55
|
- `dock()` · *mutation* → delta.details: `DockResponse` — Dock at a base
|
|
@@ -79,6 +79,7 @@ Call as `account.commands.spacemolt.<action>(...)`.
|
|
|
79
79
|
- `get_tax_estimate()` · *query* → `TaxEstimateResponse` — Preview what taxes you'd owe right now
|
|
80
80
|
- `get_version({ count?: number; id?: string; page?: number; text?: string })` · *query* → `GetVersionResponse` — Get game version and release notes, with optional changelog pagination
|
|
81
81
|
- `hunt({ id: string })` · *mutation* → delta.details: `HuntResponse` — Hunt a wildlife creature to start a battle
|
|
82
|
+
- `inspect({ id: string })` · *query* → `InspectResponse` — Inspect a visible package, item, module, ship class, system, POI, or docked base by ID
|
|
82
83
|
- `install_mod({ id: string })` · *mutation* → delta.details: `InstallModResponse` — Install a module on your ship
|
|
83
84
|
- `jettison({ id?: string; items?: { item_id: string; quantity: number }[]; quantity?: number })` · *mutation* → delta.details: `JettisonResponse` — Jettison items from cargo into space
|
|
84
85
|
- `jump({ id: string })` · *mutation* → delta.details: `JumpResponse` — Jump to an adjacent star system, or plot a numeric bearing with a Pathfinder Drive
|
|
@@ -87,7 +88,7 @@ Call as `account.commands.spacemolt.<action>(...)`.
|
|
|
87
88
|
- `load_passenger({ id: string })` · *mutation* → delta.details: `LoadPassengersResponse` — Load all waiting passengers bound for a destination into your passenger berths
|
|
88
89
|
- `mine()` · *mutation* → delta.details: `MineResponse` — Mine resources from asteroids, ice fields, or gas clouds
|
|
89
90
|
- `prepay_tax({ quantity: number })` · *mutation* → delta.details: `PrepayTaxResponse` — Prepay credits toward your next tax assessment
|
|
90
|
-
- `recycle({ deliver_to?: string; dry_run?: boolean; facility_id?: string; id?: string; job_id?: string; job_ids?: string[]; jobs?: Record<string, unknown>[]; quantity?: number; source?: string })` · *mutation* → delta.details: `RecycleJobResponse` — Queue a recycling job: consume a recipe's outputs to recover a fraction of its inputs
|
|
91
|
+
- `recycle({ deliver_to?: string; dry_run?: boolean; facility_id?: string; id?: string; job_id?: string; job_ids?: string[]; jobs?: Record<string, unknown>[]; preset?: "fast" | "cheap" | "prefer_own"; quantity?: number; source?: string })` · *mutation* → delta.details: `RecycleJobResponse` — Queue a recycling job: consume a recipe's outputs to recover a fraction of its inputs
|
|
91
92
|
- `refuel({ id?: string; quantity?: number; target?: string })` · *mutation* → delta.details: `RefuelResponse` — Refuel your ship or transfer fuel to another ship
|
|
92
93
|
- `repair({ item_id?: string; quantity?: number; target?: string })` · *mutation* → delta.details: `RepairResponse` — Repair hull — at station (credits), in space (repair kits), or on another ship (repair arm + kits)
|
|
93
94
|
- `repair_module({ id: string })` · *mutation* → delta.details: `RepairModuleResponse` — Repair wear on a module using a Repair Kit
|
|
@@ -100,7 +101,7 @@ Call as `account.commands.spacemolt.<action>(...)`.
|
|
|
100
101
|
- `travel({ id: string })` · *mutation* → delta.details: `TravelResponse` — Travel to a different Point of Interest (POI) within your current system
|
|
101
102
|
- `undock()` · *mutation* → delta.details: `UndockResponse` — Undock from a base
|
|
102
103
|
- `uninstall_mod({ id: string })` · *mutation* → delta.details: `UninstallModResponse` — Uninstall a module from your ship
|
|
103
|
-
- `unload_passenger({ id: string })` · *mutation* → delta.details: `UnloadPassengerResponse` — Put a passenger (or everyone) off the ship
|
|
104
|
+
- `unload_passenger({ id: string; target?: string })` · *mutation* → delta.details: `UnloadPassengerResponse` — Put a passenger (or everyone) off the ship here — or hand them off to another ship or your faction's transit lounge for a connecting flight
|
|
104
105
|
- `unsubscribe_observation()` · *query* → `UnsubscribeObservationResponse` — Cancel your live observation watch
|
|
105
106
|
- `use_item({ id: string; quantity?: number })` · *mutation* → delta.details: `UseItemResponse` — Use a consumable item from cargo
|
|
106
107
|
- `view_completed_mission({ id: string })` · *query* → `ViewCompletedMissionResponse` — View full details of a completed mission including dialog
|
|
@@ -121,10 +122,12 @@ Call as `account.commands.spacemolt_battle.<action>(...)`.
|
|
|
121
122
|
|
|
122
123
|
- `advance()` · *query* → `BattleResponse` — Manage your battle — move, change stance, target enemies, or join a fight
|
|
123
124
|
- `engage({ side_id?: number })` · *query* → `BattleResponse` — Manage your battle — move, change stance, target enemies, or join a fight
|
|
125
|
+
- `log({ id: string; limit?: number; tick_end?: number; tick_start?: number })` · *query* → `GetBattleLogResponse` — View the tick-by-tick combat replay of a battle by ID
|
|
124
126
|
- `reload({ id: string; target?: string })` · *mutation* → delta.details: `ReloadResponse` — Reload a weapon's magazine from ammo in cargo
|
|
125
127
|
- `retreat()` · *query* → `BattleResponse` — Manage your battle — move, change stance, target enemies, or join a fight
|
|
126
128
|
- `stance({ id: "fire" | "evade" | "brace" | "flee" })` · *query* → `BattleResponse` — Manage your battle — move, change stance, target enemies, or join a fight
|
|
127
129
|
- `status()` · *query* → `GetBattleStatusResponse` — View current battle status
|
|
130
|
+
- `summary({ id: string })` · *query* → `BattleSummaryResponse` — View the aggregate result of a battle by ID
|
|
128
131
|
- `target({ id: string })` · *query* → `BattleResponse` — Manage your battle — move, change stance, target enemies, or join a fight
|
|
129
132
|
|
|
130
133
|
## spacemolt_citizenship
|
|
@@ -160,18 +163,20 @@ Call as `account.commands.spacemolt_facility.<action>(...)`.
|
|
|
160
163
|
- `browse_for_sale({ facility_type?: string; max_price?: number })` · *query* → `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
161
164
|
- `build({ bucket?: string; facility_type: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
162
165
|
- `buy_listing({ listing_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
163
|
-
- `buy_ship_license({
|
|
166
|
+
- `buy_ship_license({ ship_class: string })` · *mutation* → delta.details: `ShipLicenseResponse` — License a specific ship design so your faction can build it at its own stations
|
|
164
167
|
- `cancel_listing({ listing_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
165
168
|
- `deploy_outpost({ name: string })` · *mutation* → delta.details: `BuildBaseResponse` — Deploy a lightweight, members-only faction outpost at your current point of interest in lawless space
|
|
169
|
+
- `disassemble({ facility_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
166
170
|
- `dismantle({ facility_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
167
171
|
- `facility_set_description({ description?: string; facility_id: string })` · *query* → `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
168
172
|
- `faction_build({ bucket?: string; facility_type: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
173
|
+
- `faction_disassemble({ facility_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
169
174
|
- `faction_dismantle({ facility_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
170
175
|
- `faction_list()` · *query* → `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
171
176
|
- `faction_owned()` · *query* → `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
172
177
|
- `faction_upgrade({ bucket?: string; facility_id: string; facility_type: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
173
178
|
- `found_station({ name: string; public_access?: boolean })` · *mutation* → delta.details: `BuildBaseResponse` — Found a faction-owned station at your current point of interest in lawless space
|
|
174
|
-
- `job_add({ deliver_to?: string; direction?: "forward" | "reverse"; facility_id: string; quantity?: number; recipe_id: string; source?: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
179
|
+
- `job_add({ deliver_to?: string; direction?: "forward" | "reverse"; facility_id: string; items?: { item_id: string; quantity: number }[]; label?: string; package_id?: string; quantity?: number; recipe_id: string; source?: string; target?: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
175
180
|
- `job_cancel({ job_id?: string; job_ids?: string[] })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
176
181
|
- `job_list({ facility_id: string })` · *query* → `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
177
182
|
- `job_reorder({ facility_id: string; job_id: string; position?: number })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
@@ -183,7 +188,9 @@ Call as `account.commands.spacemolt_facility.<action>(...)`.
|
|
|
183
188
|
- `personal_visit({ username?: string })` · *query* → `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
184
189
|
- `remove_faction({ faction: string })` · *mutation* → delta.details: `StationConfigResponse` — Administer one of your faction's stations or outposts: rename, access control, and build policy
|
|
185
190
|
- `remove_player({ player: string })` · *mutation* → delta.details: `StationConfigResponse` — Administer one of your faction's stations or outposts: rename, access control, and build policy
|
|
191
|
+
- `repair({ facility_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
186
192
|
- `set_access({ access: "private" | "public"; facility_id: string })` · *mutation* → delta.details: `FacilityResponse` — Manage facilities at stations (production, faction, personal, sales, and more)
|
|
193
|
+
- `set_auto_buy_fuel({ auto_buy_fuel?: boolean })` · *mutation* → delta.details: `StationConfigResponse` — Administer one of your faction's stations or outposts: rename, access control, and build policy
|
|
187
194
|
- `set_build_policy({ allow_outsiders?: boolean })` · *mutation* → delta.details: `StationConfigResponse` — Administer one of your faction's stations or outposts: rename, access control, and build policy
|
|
188
195
|
- `set_description({ description?: string })` · *mutation* → delta.details: `StationConfigResponse` — Administer one of your faction's stations or outposts: rename, access control, and build policy
|
|
189
196
|
- `set_market_fee({ fee_percent?: number })` · *mutation* → delta.details: `StationConfigResponse` — Administer one of your faction's stations or outposts: rename, access control, and build policy
|
|
@@ -299,7 +306,7 @@ Call as `account.commands.spacemolt_market.<action>(...)`.
|
|
|
299
306
|
|
|
300
307
|
Call as `account.commands.spacemolt_salvage.<action>(...)`.
|
|
301
308
|
|
|
302
|
-
- `insure(
|
|
309
|
+
- `insure()` · *mutation* → delta.details: `BuyInsuranceResponse` — Purchase ship insurance
|
|
303
310
|
- `loot({ id?: string; item_id?: string; module_id?: string; quantity?: number })` · *mutation* → delta.details: `LootWreckResponse` — Loot items and modules from a wreck
|
|
304
311
|
- `policies()` · *query* → `ClaimInsuranceResponse` — View your active insurance policies
|
|
305
312
|
- `quote()` · *query* → `GetInsuranceQuoteResponse` — Get a risk-based insurance quote for your current ship
|
|
@@ -320,7 +327,7 @@ Call as `account.commands.spacemolt_ship.<action>(...)`.
|
|
|
320
327
|
- `cancel_ship_buy_order({ id: string })` · *mutation* → delta.details: `CancelShipBuyOrderResponse` — Cancel one of your ship buy orders and refund the escrow
|
|
321
328
|
- `cancel_ship_listing({ id: string })` · *mutation* → delta.details: `CancelShipListingResponse` — Remove your ship listing from the exchange
|
|
322
329
|
- `commission_quote({ id: string })` · *query* → `CommissionQuoteResponse` — Get a cost estimate for commissioning a ship
|
|
323
|
-
- `commission_ship({ id: string; provide_materials?: boolean })` · *mutation* → delta.details: `CommissionShipResponse` — Commission a ship to be built at this shipyard
|
|
330
|
+
- `commission_ship({ fund_from_faction?: boolean; id: string; provide_materials?: boolean })` · *mutation* → delta.details: `CommissionShipResponse` — Commission a ship to be built at this shipyard
|
|
324
331
|
- `commission_status({ base_id?: string })` · *query* → `CommissionStatusResponse` — Check the status of your ship commissions
|
|
325
332
|
- `list_ship_for_sale({ id: string; price: number })` · *mutation* → delta.details: `ListShipForSaleResponse` — List a stored ship for sale on the exchange
|
|
326
333
|
- `list_ships()` · *query* → `ListShipsResponse` — List all ships you own and their locations
|
|
@@ -328,7 +335,6 @@ Call as `account.commands.spacemolt_ship.<action>(...)`.
|
|
|
328
335
|
- `refit_ship()` · *mutation* → delta.details: `RefitShipResponse` — Refit your active ship to its latest class specifications
|
|
329
336
|
- `rename_ship({ name: string })` · *mutation* → delta.details: `NameShipResponse` — Set or clear a custom name for your active ship
|
|
330
337
|
- `scrap_ship({ id: string })` · *mutation* → delta.details: `ScrapShipResponse` — Permanently destroy a ship you no longer want (no credits returned)
|
|
331
|
-
- `sell_ship({ id: string })` · *mutation* → delta.details: `SellShipResponse` — Sell a stored ship at the current station
|
|
332
338
|
- `sell_ship_to_order({ id: string; ship_id: string })` · *mutation* → delta.details: `SellShipToOrderResponse` — Sell a stored ship directly into a buy order at this base
|
|
333
339
|
- `supply_commission({ id: string; item_id: string; quantity: number })` · *mutation* → delta.details: `SupplyCommissionResponse` — Donate materials directly to a credits-only commission that is stuck sourcing
|
|
334
340
|
- `switch_ship({ id: string })` · *mutation* → delta.details: `SwitchShipResponse` — Switch to a different ship stored at this station
|
package/README.md
CHANGED
|
@@ -16,10 +16,14 @@ store). Uses only web-standard `WebSocket`/`fetch` in the core.
|
|
|
16
16
|
|
|
17
17
|
## Install
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
```sh
|
|
20
|
+
bun add @spacemolt/lib
|
|
21
|
+
# or: npm install @spacemolt/lib
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The server this library talks to is a single live deployment that changes
|
|
25
|
+
often — see [Versioning](#versioning) for why that means updating promptly
|
|
26
|
+
matters more than pinning a version.
|
|
23
27
|
|
|
24
28
|
## Quickstart
|
|
25
29
|
|
|
@@ -183,6 +187,36 @@ a password: keep it in an env var or a secret manager, not in source. To rotate,
|
|
|
183
187
|
generate a new one and the old one stops working. The token mint draws on a
|
|
184
188
|
separate per-user rate budget from gameplay, so it never competes with your bots.
|
|
185
189
|
|
|
190
|
+
### Browser / custom auth headers
|
|
191
|
+
|
|
192
|
+
When the caller's Clerk credential isn't a static API key — a web app running
|
|
193
|
+
inside a Clerk browser session, or a dev-mode server accepting an
|
|
194
|
+
`X-Dev-Clerk-ID` header — pass `headers` instead of `apiKey` to `mintWsToken`
|
|
195
|
+
or `ClerkSource`. A function is resolved fresh on every request, so short-lived
|
|
196
|
+
session JWTs stay valid across reconnects:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { Account, mintWsToken } from '@spacemolt/lib';
|
|
200
|
+
|
|
201
|
+
// Fresh single-use token per (re)connect; the headers factory runs per request,
|
|
202
|
+
// e.g. wrapping Clerk's useAuth().getToken() in the browser.
|
|
203
|
+
const mintToken = () =>
|
|
204
|
+
mintWsToken({
|
|
205
|
+
httpBaseUrl: 'https://game.spacemolt.com',
|
|
206
|
+
playerId,
|
|
207
|
+
headers: async () => ({ authorization: `Bearer ${await getToken()}` }),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const credentials = async () => ({ kind: 'login_token' as const, token: await mintToken() });
|
|
211
|
+
const account = new Account({ url: 'wss://game.spacemolt.com/ws/v2', reconnect: true, credentials });
|
|
212
|
+
await account.connect();
|
|
213
|
+
await account.authenticate(await credentials());
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`ClerkSource` accepts the same `headers` option, and
|
|
217
|
+
`ClerkSource.fetchRegistration()` returns the owned players together with the
|
|
218
|
+
registration code needed to `register` a new player under the same Clerk user.
|
|
219
|
+
|
|
186
220
|
### Bootstrapping without a Clerk key
|
|
187
221
|
|
|
188
222
|
You need the raw credential paths in two cases: **creating a brand-new account**
|
|
@@ -216,6 +250,11 @@ import { FileCredentialStore } from '@spacemolt/lib/node';
|
|
|
216
250
|
const client = new SpacemoltClient({ store: new FileCredentialStore('./.spacemolt-credentials.json') });
|
|
217
251
|
```
|
|
218
252
|
|
|
253
|
+
The file contains plaintext credentials, is written atomically, and is created
|
|
254
|
+
with owner-only permissions on POSIX systems. Keep its parent directory and any
|
|
255
|
+
backups private as well. Malformed or unsupported files fail explicitly instead
|
|
256
|
+
of being treated as an empty store.
|
|
257
|
+
|
|
219
258
|
In the browser, implement the small `CredentialStore` interface over
|
|
220
259
|
`localStorage` (or anything else) and pass it as `store`.
|
|
221
260
|
|
|
@@ -261,9 +300,19 @@ are generated from the server's spec:
|
|
|
261
300
|
```bash
|
|
262
301
|
bun run fetch-spec # sync openapi.json from the live server
|
|
263
302
|
bun run generate # regenerate src/generated/
|
|
264
|
-
bun run
|
|
303
|
+
bun run check # format, lint, generated sync, types, tests, browser + package builds
|
|
265
304
|
```
|
|
266
305
|
|
|
306
|
+
Biome formats and lints all handwritten TypeScript and JSON. Generated sources,
|
|
307
|
+
the OpenAPI snapshot, and generated command reference are intentionally excluded;
|
|
308
|
+
change their generators or source spec instead of editing those artifacts directly.
|
|
309
|
+
Use `bun run format` to apply formatting, or run the individual `format:check`,
|
|
310
|
+
`lint`, `generate:check`, `typecheck`, `test`, `build:browser-check`, and `build` gates
|
|
311
|
+
while iterating. `generate:check` snapshots and regenerates the artifacts, then
|
|
312
|
+
fails if regeneration changed them; it works even when the rest of the worktree
|
|
313
|
+
is dirty. Review the regenerated files after changing codegen or the OpenAPI
|
|
314
|
+
snapshot.
|
|
315
|
+
|
|
267
316
|
See [`CLAUDE.md`](./CLAUDE.md) for the developer guide and
|
|
268
317
|
[`docs/gameserver-todo.md`](./docs/gameserver-todo.md) for the server-side
|
|
269
318
|
changes that further improve type coverage.
|
|
@@ -273,7 +322,13 @@ changes that further improve type coverage.
|
|
|
273
322
|
**True semver, honest about breakage: `major` = your code breaks.** No "0.x
|
|
274
323
|
means unstable" hedge — the major number is *expected* to climb fast (into the
|
|
275
324
|
hundreds), because the command surface tracks a live server that changes often.
|
|
276
|
-
|
|
325
|
+
|
|
326
|
+
A high major isn't instability theater, but it's also not a reason to pin and
|
|
327
|
+
stop updating. The gameserver is a single live deployment with no legacy
|
|
328
|
+
support — when it changes, code built against the old surface is already
|
|
329
|
+
broken, whether or not your installed lib version moves. An old pinned
|
|
330
|
+
version doesn't protect you from that; it just delays finding out. **Update
|
|
331
|
+
promptly** and read what a major bump changed before you do.
|
|
277
332
|
|
|
278
333
|
- **major** — a command/param/notification was removed or changed incompatibly
|
|
279
334
|
(or a query↔mutation flip), or a hand-written API broke. Your code may need
|
package/dist/account.d.ts
CHANGED
|
@@ -12,14 +12,19 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { type Commands } from './generated/commands.gen.js';
|
|
14
14
|
import type { AuthCredentials } from './auth/credentials.js';
|
|
15
|
-
import type { SubscribeMarketResponse, SubscribeObservationResponse } from './generated/openapi/types.gen.js';
|
|
15
|
+
import type { LoggedInPayload as LoggedInPayloadSchema, SubscribeMarketResponse, SubscribeObservationResponse } from './generated/openapi/types.gen.js';
|
|
16
16
|
import type { NotificationPayloads, TypedNotificationType } from './generated/notifications.gen.js';
|
|
17
|
-
import { ConnectionClosedError } from './errors.js';
|
|
17
|
+
import { type ConnectionClosedError } from './errors.js';
|
|
18
18
|
import { type MarketBook } from './state/market.js';
|
|
19
19
|
import { type ObservationView } from './state/observation.js';
|
|
20
20
|
import type { GameState, MutationAck, MutationResult, QueryResult, RawFrame, StateSection, WelcomeFrame } from './protocol.js';
|
|
21
21
|
import { type WebSocketFactory } from './transport/socket.js';
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The `logged_in` frame payload, typed from the server's published
|
|
24
|
+
* `LoggedInPayload` schema: the initial `player`/`ship`/`system`/`poi` view
|
|
25
|
+
* plus login extras like `recent_chat` and `pending_trades`.
|
|
26
|
+
*/
|
|
27
|
+
export type LoggedInPayload = LoggedInPayloadSchema;
|
|
23
28
|
export interface ReconnectOptions {
|
|
24
29
|
/**
|
|
25
30
|
* Max reconnect attempts before giving up and emitting `disconnected`.
|
|
@@ -143,10 +148,11 @@ export declare class Account {
|
|
|
143
148
|
private _welcome;
|
|
144
149
|
private _authenticated;
|
|
145
150
|
private _loginPayload;
|
|
151
|
+
private _currentTick;
|
|
146
152
|
private _commands;
|
|
147
153
|
private welcomeWaiter;
|
|
148
154
|
private pendingAuth;
|
|
149
|
-
private
|
|
155
|
+
private readonly stateListeners;
|
|
150
156
|
private userClosing;
|
|
151
157
|
private reconnecting;
|
|
152
158
|
private mutationLane;
|
|
@@ -155,9 +161,9 @@ export declare class Account {
|
|
|
155
161
|
private observationSubscribedState;
|
|
156
162
|
private observationActiveScanState;
|
|
157
163
|
private subscribedObservationPoiId;
|
|
158
|
-
private
|
|
159
|
-
private
|
|
160
|
-
private
|
|
164
|
+
private readonly reconnectedListeners;
|
|
165
|
+
private readonly reconnectingListeners;
|
|
166
|
+
private readonly disconnectedListeners;
|
|
161
167
|
constructor(opts?: AccountOptions);
|
|
162
168
|
private makeSocket;
|
|
163
169
|
/** Live view of the cached game state. Treat as read-only. */
|
|
@@ -183,6 +189,15 @@ export declare class Account {
|
|
|
183
189
|
get commands(): Commands;
|
|
184
190
|
/** The server's `welcome` payload, available after `connect()` resolves. */
|
|
185
191
|
get welcome(): WelcomeFrame['payload'] | null;
|
|
192
|
+
/**
|
|
193
|
+
* Highest game tick observed on this connection — from `welcome`
|
|
194
|
+
* (`current_tick`) and every subsequent tick-bearing frame (`action_result`,
|
|
195
|
+
* `action_error`, and push notifications that carry a numeric `tick`).
|
|
196
|
+
* 0 until the welcome arrives. There is no per-tick server push; between
|
|
197
|
+
* observations, extrapolate with `welcome.tick_rate` if needed.
|
|
198
|
+
*/
|
|
199
|
+
get currentTick(): number;
|
|
200
|
+
private observeTick;
|
|
186
201
|
get authenticated(): boolean;
|
|
187
202
|
/**
|
|
188
203
|
* Whether `subscribeMarket()` is currently active on this instance —
|
|
@@ -220,8 +235,18 @@ export declare class Account {
|
|
|
220
235
|
* cached state. Called automatically after auth unless `seedState` is false.
|
|
221
236
|
*/
|
|
222
237
|
refresh(): Promise<Readonly<GameState>>;
|
|
223
|
-
/**
|
|
224
|
-
|
|
238
|
+
/**
|
|
239
|
+
* Register a listener fired with the sections that changed on each update.
|
|
240
|
+
* Multiple listeners may be registered; returns an unsubscribe function.
|
|
241
|
+
*/
|
|
242
|
+
onStateChange(listener: (changed: StateSection[]) => void): () => void;
|
|
243
|
+
/**
|
|
244
|
+
* Fan an event out to every registered listener. A throwing listener is
|
|
245
|
+
* warned and skipped — it must never break the caller (frame routing,
|
|
246
|
+
* mutation correlation, the reconnect loop) or starve later listeners.
|
|
247
|
+
*/
|
|
248
|
+
private notifyListeners;
|
|
249
|
+
private emitStateChange;
|
|
225
250
|
/** Log out, releasing the connection's authenticated session. */
|
|
226
251
|
logout(): Promise<void>;
|
|
227
252
|
/**
|
|
@@ -351,12 +376,15 @@ export declare class Account {
|
|
|
351
376
|
private checkSubscriptionsAgainstLocation;
|
|
352
377
|
/** Close the connection deliberately. Suppresses auto-reconnect. */
|
|
353
378
|
close(): void;
|
|
354
|
-
/** Fired after a successful reconnect + re-auth. */
|
|
355
|
-
onReconnected(listener: () => void): void;
|
|
356
|
-
/** Fired at the start of each reconnect attempt (1-based). */
|
|
357
|
-
onReconnecting(listener: (attempt: number) => void): void;
|
|
358
|
-
/**
|
|
359
|
-
|
|
379
|
+
/** Fired after a successful reconnect + re-auth. Returns an unsubscribe function. */
|
|
380
|
+
onReconnected(listener: () => void): () => void;
|
|
381
|
+
/** Fired at the start of each reconnect attempt (1-based). Returns an unsubscribe function. */
|
|
382
|
+
onReconnecting(listener: (attempt: number) => void): () => void;
|
|
383
|
+
/**
|
|
384
|
+
* Fired when the connection is gone for good (non-reconnectable or retries
|
|
385
|
+
* exhausted). Returns an unsubscribe function.
|
|
386
|
+
*/
|
|
387
|
+
onDisconnected(listener: (err: ConnectionClosedError) => void): () => void;
|
|
360
388
|
private authExchange;
|
|
361
389
|
/** Best-effort seed of the state cache after auth; failures are non-fatal. */
|
|
362
390
|
private maybeSeedState;
|
|
@@ -364,6 +392,7 @@ export declare class Account {
|
|
|
364
392
|
private sendFrame;
|
|
365
393
|
private nextRequestId;
|
|
366
394
|
private routeFrame;
|
|
395
|
+
private warnMalformedFrame;
|
|
367
396
|
private handleClose;
|
|
368
397
|
private shouldReconnect;
|
|
369
398
|
private reconnectLoop;
|
package/dist/auth/clerk.d.ts
CHANGED
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Clerk-backed multi-account source.
|
|
3
3
|
*
|
|
4
|
-
* Authenticates
|
|
5
|
-
* generate one from the website; see docs/live-testing.md) to enumerate the
|
|
4
|
+
* Authenticates against the Clerk-gated gameserver endpoints to enumerate the
|
|
6
5
|
* player accounts the Clerk user owns and to mint short-lived, single-use
|
|
7
6
|
* WebSocket login tokens for them. This lets one client manage every account you
|
|
8
7
|
* own without storing per-account game passwords.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Two ways to authorize the requests:
|
|
10
|
+
* - `apiKey` — a Clerk **API key** (the headless-client credential —
|
|
11
|
+
* generate one from the website; see docs/live-testing.md), sent as
|
|
12
|
+
* `Authorization: Bearer <key>`.
|
|
13
|
+
* - `headers` — custom headers, or an async factory resolved fresh per
|
|
14
|
+
* request, for callers whose credential isn't a static key: a browser
|
|
15
|
+
* Clerk session's short-lived `getToken()` JWT, or a dev-mode
|
|
16
|
+
* `X-Dev-Clerk-ID` header.
|
|
17
|
+
*
|
|
18
|
+
* The authorized endpoints:
|
|
19
|
+
* - `GET /api/registration-code` → the owned players list + registration code.
|
|
13
20
|
* - `POST /api/player/{id}/ws-token` → a single-use WS login token.
|
|
14
21
|
*
|
|
15
22
|
* ws-tokens are valid ~5 minutes and consumed on connect, so mint one per
|
|
16
|
-
* (re)connect rather than caching — the durable credential is the Clerk key
|
|
23
|
+
* (re)connect rather than caching — the durable credential is the Clerk key
|
|
24
|
+
* (or session).
|
|
17
25
|
*
|
|
18
|
-
* Uses only web-standard `fetch`, so it stays browser-safe.
|
|
26
|
+
* Uses only web-standard `fetch`/`Headers`, so it stays browser-safe.
|
|
19
27
|
*/
|
|
20
28
|
/** A player account owned by the authenticated Clerk user. */
|
|
21
29
|
export interface ClerkPlayer {
|
|
@@ -25,13 +33,25 @@ export interface ClerkPlayer {
|
|
|
25
33
|
/** Hidden in the player's dashboard; still connectable. */
|
|
26
34
|
hidden: boolean;
|
|
27
35
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
/** The full `/api/registration-code` response. */
|
|
37
|
+
export interface ClerkRegistration {
|
|
38
|
+
/** One-time code that links a new `register` to the Clerk user. */
|
|
39
|
+
registrationCode: string;
|
|
40
|
+
players: ClerkPlayer[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Headers that authorize calls to the Clerk-gated gameserver endpoints — an
|
|
44
|
+
* alternative to `apiKey` for callers whose credential isn't a static key.
|
|
45
|
+
* A factory is resolved fresh on every request, so short-lived tokens (e.g. a
|
|
46
|
+
* browser Clerk session's `getToken()` JWT) stay valid across reconnects.
|
|
47
|
+
*/
|
|
48
|
+
export type ClerkAuthHeaders = HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
|
|
49
|
+
/** How Clerk-gated requests are authorized. Provide `apiKey`, `headers`, or both. */
|
|
50
|
+
export interface ClerkAuth {
|
|
51
|
+
/** Clerk API key, sent as `Authorization: Bearer`. Keep it secret. */
|
|
52
|
+
apiKey?: string;
|
|
53
|
+
/** Custom auth headers (or an async factory). Win over `apiKey` on conflicts. */
|
|
54
|
+
headers?: ClerkAuthHeaders;
|
|
35
55
|
}
|
|
36
56
|
/**
|
|
37
57
|
* Mint a single-use WebSocket login token for one owned player. The token is
|
|
@@ -39,18 +59,25 @@ export interface ClerkSourceOptions {
|
|
|
39
59
|
*/
|
|
40
60
|
export declare function mintWsToken(opts: {
|
|
41
61
|
httpBaseUrl: string;
|
|
42
|
-
apiKey: string;
|
|
43
62
|
playerId: string;
|
|
44
63
|
fetchImpl?: typeof fetch;
|
|
45
|
-
}): Promise<string>;
|
|
64
|
+
} & ClerkAuth): Promise<string>;
|
|
65
|
+
export interface ClerkSourceOptions extends ClerkAuth {
|
|
66
|
+
/** HTTP origin of the gameserver, e.g. `https://game.spacemolt.com`. */
|
|
67
|
+
httpBaseUrl: string;
|
|
68
|
+
/** Inject a `fetch` implementation (tests, custom runtimes). */
|
|
69
|
+
fetchImpl?: typeof fetch;
|
|
70
|
+
}
|
|
46
71
|
export declare class ClerkSource {
|
|
47
72
|
private readonly opts;
|
|
48
73
|
private readonly fetchImpl;
|
|
49
74
|
/** HTTP origin of the gameserver (trailing slash stripped). */
|
|
50
75
|
readonly httpBaseUrl: string;
|
|
51
76
|
constructor(opts: ClerkSourceOptions);
|
|
52
|
-
/** The Clerk API key this source authenticates with. */
|
|
53
|
-
get apiKey(): string;
|
|
77
|
+
/** The Clerk API key this source authenticates with, when one was given. */
|
|
78
|
+
get apiKey(): string | undefined;
|
|
79
|
+
/** Fetch the owned players list plus the registration code for creating new players. */
|
|
80
|
+
fetchRegistration(): Promise<ClerkRegistration>;
|
|
54
81
|
/** List the player accounts the authenticated Clerk user owns. */
|
|
55
82
|
listPlayers(): Promise<ClerkPlayer[]>;
|
|
56
83
|
/** Mint a single-use WS login token for one owned player. */
|
|
@@ -42,6 +42,7 @@ export interface CredentialStore {
|
|
|
42
42
|
put(account: StoredAccount): Promise<void>;
|
|
43
43
|
remove(id: string): Promise<void>;
|
|
44
44
|
}
|
|
45
|
+
export declare function isStoredAccount(value: unknown): value is StoredAccount;
|
|
45
46
|
/** In-memory store. The default; nothing is persisted across process restarts. */
|
|
46
47
|
export declare class MemoryCredentialStore implements CredentialStore {
|
|
47
48
|
private readonly accounts;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Imports Node built-ins; do not import this from browser bundles (use a
|
|
7
7
|
* custom `CredentialStore` there instead).
|
|
8
8
|
*/
|
|
9
|
-
import type
|
|
9
|
+
import { type CredentialStore, type StoredAccount } from './credentials.js';
|
|
10
10
|
export declare class FileCredentialStore implements CredentialStore {
|
|
11
11
|
private readonly path;
|
|
12
12
|
private cache;
|
package/dist/client.d.ts
CHANGED
|
@@ -76,6 +76,18 @@ export interface SpacemoltClientOptions {
|
|
|
76
76
|
reconnect?: boolean | ReconnectOptions;
|
|
77
77
|
/** HTTP origin for bulk data fetches. Defaults to the origin of `url`. */
|
|
78
78
|
httpBaseUrl?: string;
|
|
79
|
+
/**
|
|
80
|
+
* How long `catalog()` serves its cached copy before revalidating against the
|
|
81
|
+
* server. The catalog only changes on a server release, but a long-lived
|
|
82
|
+
* client that fetched it once at startup would otherwise keep serving that
|
|
83
|
+
* copy indefinitely — days stale across a release. Past this age the next
|
|
84
|
+
* `catalog()` call revalidates conditionally (`If-None-Match`): an unchanged
|
|
85
|
+
* catalog is a ~0-byte `304` (near-free), a changed one is re-downloaded.
|
|
86
|
+
* Matches the server's own `max-age`. Default 3600000 (1h). Set `0` to
|
|
87
|
+
* revalidate on every call, or `Infinity` to cache for the client's lifetime
|
|
88
|
+
* (the old fetch-once behavior).
|
|
89
|
+
*/
|
|
90
|
+
catalogMaxAgeMs?: number;
|
|
79
91
|
/**
|
|
80
92
|
* Clerk API key for `connectOwned()` / `listOwnedPlayers()` — connect every
|
|
81
93
|
* game account the Clerk user owns without storing per-account passwords.
|
|
@@ -132,6 +144,7 @@ export declare class SpacemoltClient {
|
|
|
132
144
|
private readonly store;
|
|
133
145
|
private readonly connected;
|
|
134
146
|
private catalogCache?;
|
|
147
|
+
private catalogFetchedAt;
|
|
135
148
|
private mapCache?;
|
|
136
149
|
private clerkSource?;
|
|
137
150
|
private readonly accountConnectedListeners;
|
|
@@ -183,7 +196,14 @@ export declare class SpacemoltClient {
|
|
|
183
196
|
private notifyAccountDisconnected;
|
|
184
197
|
/** HTTP origin used for bulk data fetches (catalog, map). */
|
|
185
198
|
get httpBaseUrl(): string;
|
|
186
|
-
/**
|
|
199
|
+
/**
|
|
200
|
+
* The bulk catalog. Fetched on first use and cached, then revalidated against
|
|
201
|
+
* the server once the cache is older than `catalogMaxAgeMs` (default 1h) so a
|
|
202
|
+
* long-lived client picks up a new catalog after a server release instead of
|
|
203
|
+
* serving a days-stale copy. Revalidation is conditional (`If-None-Match`), so
|
|
204
|
+
* an unchanged catalog costs a ~0-byte `304` and the cached instance is kept.
|
|
205
|
+
* Pass `force` to refetch unconditionally now.
|
|
206
|
+
*/
|
|
187
207
|
catalog(force?: boolean): Promise<CatalogCache>;
|
|
188
208
|
/** The static galaxy map, fetched once and cached. Pass `force` to refetch. */
|
|
189
209
|
map(force?: boolean): Promise<MapCache>;
|
|
@@ -242,7 +262,7 @@ export declare class SpacemoltClient {
|
|
|
242
262
|
filter?: (player: ClerkPlayer) => boolean;
|
|
243
263
|
onConnect?: (account: Account) => void;
|
|
244
264
|
}): Promise<Account[]>;
|
|
245
|
-
private
|
|
265
|
+
private requireClerkAuth;
|
|
246
266
|
/**
|
|
247
267
|
* Connect the given stored ids, staggered to respect rate limits. At or
|
|
248
268
|
* under `connectBatchSize` accounts this is a single stagger pass — the
|
package/dist/data/catalog.d.ts
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* Local copy of the bulk game catalog (`GET /api/catalog.json`).
|
|
3
3
|
*
|
|
4
4
|
* Reference data — ships, items, recipes, skills, facilities — that changes
|
|
5
|
-
* only on a server release.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* only on a server release. The entry shapes aren't in the v2 OpenAPI spec, so
|
|
6
|
+
* they're typed loosely with `id`-keyed lookups.
|
|
7
|
+
*
|
|
8
|
+
* The payload is large (multiple MB), so the server ships it `public,
|
|
9
|
+
* max-age=3600` with a content-hash `ETag`. We keep that ETag on the cache and
|
|
10
|
+
* revalidate conditionally (`If-None-Match`): an unchanged catalog comes back as
|
|
11
|
+
* a ~0-byte `304 Not Modified`, so a long-lived client can cheaply pick up a new
|
|
12
|
+
* catalog after a server release instead of holding the copy it fetched at
|
|
13
|
+
* startup forever (see `SpacemoltClient.catalog`).
|
|
8
14
|
*/
|
|
9
15
|
export interface CatalogEntry {
|
|
10
16
|
id?: string;
|
|
@@ -18,13 +24,40 @@ export interface Catalog {
|
|
|
18
24
|
skills: CatalogEntry[];
|
|
19
25
|
facilities: CatalogEntry[];
|
|
20
26
|
}
|
|
27
|
+
/** Result of a conditional catalog fetch. */
|
|
28
|
+
export interface CatalogFetchResult {
|
|
29
|
+
/** True when the server answered `304 Not Modified` — `catalog` is absent. */
|
|
30
|
+
notModified: boolean;
|
|
31
|
+
/** The freshly fetched catalog (absent on a 304). */
|
|
32
|
+
catalog?: Catalog;
|
|
33
|
+
/** The server's `ETag` for the returned (or still-current) catalog, if any. */
|
|
34
|
+
etag?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fetch the catalog, optionally conditional on a previously seen `ETag`. When
|
|
38
|
+
* `etag` is passed and the server confirms the catalog is unchanged, this
|
|
39
|
+
* returns `{ notModified: true }` after a ~0-byte `304` — no multi-MB download
|
|
40
|
+
* or re-parse. Otherwise it returns the fresh catalog and its new `ETag`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function fetchCatalogConditional(httpBaseUrl: string, etag?: string): Promise<CatalogFetchResult>;
|
|
43
|
+
/** Unconditionally fetch and normalize the catalog. */
|
|
21
44
|
export declare function fetchCatalog(httpBaseUrl: string): Promise<Catalog>;
|
|
22
45
|
export declare class CatalogCache {
|
|
23
46
|
readonly catalog: Catalog;
|
|
47
|
+
/** The server `ETag` this catalog was fetched with, for conditional reloads. */
|
|
48
|
+
readonly etag?: string | undefined;
|
|
24
49
|
private readonly indexes;
|
|
25
|
-
constructor(catalog: Catalog
|
|
50
|
+
constructor(catalog: Catalog,
|
|
51
|
+
/** The server `ETag` this catalog was fetched with, for conditional reloads. */
|
|
52
|
+
etag?: string | undefined);
|
|
26
53
|
/** Fetch the catalog and wrap it in a cache. */
|
|
27
54
|
static load(httpBaseUrl: string): Promise<CatalogCache>;
|
|
55
|
+
/**
|
|
56
|
+
* Conditionally refresh via `If-None-Match`. Returns `this` unchanged when the
|
|
57
|
+
* server confirms the catalog is still current (a cheap `304`), or a new
|
|
58
|
+
* `CatalogCache` when the catalog has changed.
|
|
59
|
+
*/
|
|
60
|
+
revalidate(httpBaseUrl: string): Promise<CatalogCache>;
|
|
28
61
|
get version(): string | undefined;
|
|
29
62
|
ship(id: string): CatalogEntry | undefined;
|
|
30
63
|
item(id: string): CatalogEntry | undefined;
|
package/dist/events/emitter.d.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* this (loosely-typed) core.
|
|
7
7
|
*/
|
|
8
8
|
import type { RawFrame } from '../protocol.js';
|
|
9
|
-
type PayloadHandler = (payload: unknown) => void;
|
|
10
9
|
type FrameHandler = (frame: RawFrame) => void;
|
|
11
10
|
/**
|
|
12
11
|
* An async iterator over events of one kind, with internal buffering so a slow
|
|
@@ -33,7 +32,7 @@ export declare class TypedEmitter {
|
|
|
33
32
|
private readonly streams;
|
|
34
33
|
private readonly anyStreams;
|
|
35
34
|
/** Listen for one msg_type. Returns an unsubscribe function. */
|
|
36
|
-
on(type: string, handler:
|
|
35
|
+
on<T = unknown>(type: string, handler: (payload: T) => void): () => void;
|
|
37
36
|
/** Listen for every push frame. Returns an unsubscribe function. */
|
|
38
37
|
onAny(handler: FrameHandler): () => void;
|
|
39
38
|
/** Async-iterate one msg_type's payloads. */
|