@spacemolt/lib 14.2.0 → 15.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/dist/index.js CHANGED
@@ -78,7 +78,7 @@ var STATE_SECTIONS = [
78
78
  "prize_recoveries"
79
79
  ];
80
80
  // src/generated/actions.gen.ts
81
- var GENERATED_SPEC_VERSION = "v0.593.0";
81
+ var GENERATED_SPEC_VERSION = "v0.609.4";
82
82
  var ACTIONS = {
83
83
  "spacemolt_arena/accept": {
84
84
  tool: "spacemolt_arena",
@@ -246,10 +246,11 @@ var ACTIONS = {
246
246
  action: "reload",
247
247
  kind: "mutation",
248
248
  summary: "Reload a weapon's magazine from ammo in cargo",
249
- detailsType: "ReloadResponse",
249
+ detailsType: "ReloadResponse | BulkReloadResponse",
250
250
  params: [
251
- { name: "id", type: "string", required: true, description: "Instance ID of the fitted weapon to reload (use get_ship to see weapon instance IDs)", positional: 0 },
252
- { name: "target", type: "string", required: false, description: "Item ID of ammo to load from cargo (must match the weapon's ammo type). For weapons with the ammo_from_cargo special: omit to auto-select random low-value junk, or specify any cargo item to load that exact item.", positional: 1 }
251
+ { name: "id", type: "string", required: false, description: "Instance ID of the fitted weapon to reload (use get_ship to see weapon instance IDs)", positional: 0 },
252
+ { name: "target", type: "string", required: false, description: "Item ID of ammo to load from cargo (must match the weapon's ammo type). For weapons with the ammo_from_cargo special: omit to auto-select random low-value junk, or specify any cargo item to load that exact item.", positional: 1 },
253
+ { name: "weapons", type: "string[]", required: false, description: "Bulk reload: array of {weapon_instance_id, ammo_item_id?} entries loaded in a single action for one tick, however many weapons. Omit weapon_instance_id/ammo_item_id when using this. Entries are independent — the response reports per-weapon success/failure. Maximum 50 entries." }
253
254
  ]
254
255
  },
255
256
  "spacemolt_battle/retreat": {
@@ -506,7 +507,7 @@ var ACTIONS = {
506
507
  summary: "License a specific ship design so your faction can build it at its own stations",
507
508
  detailsType: "ShipLicenseResponse",
508
509
  params: [
509
- { name: "ship_class", type: "string", required: true, description: "Ship class id to license (from ship_catalog), e.g. solarian_frigate" }
510
+ { name: "ship_class", type: "string", required: true, description: "Ship class id to license (from catalog type=ships), e.g. solarian_frigate" }
510
511
  ]
511
512
  },
512
513
  "spacemolt_facility/cancel_listing": {
@@ -1025,8 +1026,8 @@ var ACTIONS = {
1025
1026
  { name: "expiration_hours", type: "number", required: false, description: "Hours before mission expires (default 72, max 720)" },
1026
1027
  { name: "giver_name", type: "string", required: false, description: "Optional: NPC name who gives the mission" },
1027
1028
  { name: "giver_title", type: "string", required: false, description: "Optional: NPC title" },
1028
- { name: "objectives", type: "{ description: string; item_id?: string; quantity?: number; system_id?: string; target_base_id?: string; target_id?: string; type: string }[]", required: true, description: "List of mission objectives" },
1029
- { name: "rewards", type: "{ credits?: number; items?: Record<string, unknown>[] }", required: true, description: "Mission rewards (credits, items, reputation)" },
1029
+ { name: "objectives", type: "{ description: string; item_id?: string; pirate_tier?: string; quantity?: number; system_id?: string; target_base_id?: string; target_id?: string; type: string }[]", required: true, description: "List of mission objectives" },
1030
+ { name: "rewards", type: "{ credits?: number; items?: Record<string, unknown> }", required: true, description: "Mission rewards (credits, items, reputation)" },
1030
1031
  { name: "title", type: "string", required: true, description: "Mission title" },
1031
1032
  { name: "triggers", type: "string[]", required: false, description: "Optional: triggers like 'open_to_all' to allow non-members" },
1032
1033
  { name: "type", type: "string", required: true, description: "Mission type (delivery, combat, exploration, bounty, etc.)" }
@@ -1511,7 +1512,7 @@ var ACTIONS = {
1511
1512
  summary: "Submit system intel to your faction's shared map",
1512
1513
  detailsType: "FactionSubmitIntelResponse",
1513
1514
  params: [
1514
- { name: "systems", type: "Record<string, unknown>[]", required: true, description: "Array of system intel reports. Each entry: system_id (required), name (required), description, empire, police_level, connections (array of {system_id, name, distance} objects or bare ID strings), pois (array of {id, type, name, description, class, position:{x,y}, base_id, base_name, resources:[{resource_id, richness, remaining, max_remaining}]})" }
1515
+ { name: "systems", type: "Record<string, unknown>[]", required: true, description: "Array of system intel reports. Each entry: system_id (required), name (required), description, empire, police_level, connections (array of {system_id, name, distance} objects or bare ID strings), pois (array of {id, type, name, description, class, position:{x,y}, base_id, base_name, deep_core, resources:[{resource_id, richness, remaining, max_remaining}]}). deep_core marks a hidden deep core POI, where the mining too-sparse cutoff never applies" }
1515
1516
  ]
1516
1517
  },
1517
1518
  "spacemolt_intel/submit_trade_intel": {
@@ -1676,7 +1677,7 @@ var ACTIONS = {
1676
1677
  params: [
1677
1678
  { name: "id", type: "string", required: false, description: "UUID of the wreck to loot. Omit when towing a wreck to default to your towed wreck.", positional: 0 },
1678
1679
  { name: "item_id", type: "string", required: false, description: "Specific cargo item ID to loot. Omit to loot everything (all cargo and modules go to cargo hold)." },
1679
- { name: "module_id", type: "string", required: false, description: "Module instance ID to loot directly onto your ship (requires free slot, CPU, and power). Get module IDs from get_wrecks. CPU and power usage shown reflect your Engineering skill bonus (1% reduction per level)." },
1680
+ { name: "module_id", type: "string", required: false, description: "Module instance ID to loot into your cargo hold. Get module IDs from get_wrecks; fit it later at a station with install_mod." },
1680
1681
  { name: "quantity", type: "number", required: false, description: "Quantity of cargo item to loot (only used with item_id)" }
1681
1682
  ]
1682
1683
  },
@@ -1728,7 +1729,8 @@ var ACTIONS = {
1728
1729
  detailsType: "PrizeServiceResponse",
1729
1730
  params: [
1730
1731
  { name: "id", type: "string", required: true, description: "Claimed intact prize record ID at your current POI", positional: 0 },
1731
- { name: "quantity", type: "number", required: false, description: "Optional quantity. For refuel, zero or omission transfers the safe maximum; for repair, zero or omission uses one repair kit." },
1732
+ { name: "item_id", type: "string", required: false, description: "Optional repair item to spend on repair. Omit to use the cheapest repair item in your cargo." },
1733
+ { name: "quantity", type: "number", required: false, description: "Optional quantity. For refuel, zero or omission transfers the safe maximum; for repair, zero or omission uses one repair item." },
1732
1734
  { name: "service_action", type: '"stop" | "resume" | "redirect" | "refuel" | "repair"', required: true, description: "Physical recovery action to perform", enumValues: ["stop", "resume", "redirect", "refuel", "repair"] },
1733
1735
  { name: "target", type: "string", required: false, description: "Accessible replacement station for redirect" }
1734
1736
  ]
@@ -1834,7 +1836,7 @@ var ACTIONS = {
1834
1836
  params: [
1835
1837
  { name: "bare_hull", type: "boolean", required: false, description: "If true, commission only the hull without its default module loadout. Defaults to false so ships arrive fitted." },
1836
1838
  { name: "fund_from_faction", type: "boolean", required: false, description: "At your own faction's station: build from faction storage and treasury (requires ManageTreasury). Required there; credits-only and provide_materials are rejected." },
1837
- { name: "id", type: "string", required: true, description: "Ship class ID to commission (use ship_catalog to see options)", positional: 0 },
1839
+ { name: "id", type: "string", required: true, description: "Ship class ID to commission (use catalog type=ships to see options)", positional: 0 },
1838
1840
  { name: "provide_materials", type: "boolean", required: false, description: "At an empire/NPC shipyard: if true, supply build materials from cargo/storage (cheaper); if false, pay credits for everything (default)." },
1839
1841
  { name: "source_missing_materials", type: "boolean", required: false, description: "At an empire/NPC shipyard: take available requirements from cargo then station storage and charge only to source the deficit. Do not combine with provide_materials." }
1840
1842
  ]
@@ -2479,7 +2481,7 @@ var ACTIONS = {
2479
2481
  detailsType: "LootWreckCommandResponse",
2480
2482
  params: [
2481
2483
  { name: "item_id", type: "string", required: false, description: "Specific cargo item ID to loot. Omit to loot everything (all cargo and modules go to cargo hold).", positional: 1 },
2482
- { name: "module_id", type: "string", required: false, description: "Module instance ID to loot directly onto your ship (requires free slot, CPU, and power). Get module IDs from get_wrecks. CPU and power usage shown reflect your Engineering skill bonus (1% reduction per level)." },
2484
+ { name: "module_id", type: "string", required: false, description: "Module instance ID to loot into your cargo hold. Get module IDs from get_wrecks; fit it later at a station with install_mod." },
2483
2485
  { name: "quantity", type: "number", required: false, description: "Quantity of cargo item to loot (only used with item_id)", positional: 2 },
2484
2486
  { name: "wreck_id", type: "string", required: false, description: "UUID of the wreck to loot. Omit when towing a wreck to default to your towed wreck." }
2485
2487
  ]
@@ -2656,7 +2658,7 @@ var ACTIONS = {
2656
2658
  { name: "output_package_label", type: "string", required: false, description: "Bundle the outputs into one package: instead of depositing outputs loose per run, the job holds them and seals them into a single new package with this label in the destination on completion, consuming one cargo_container. Requires an accessible Logistics facility, and the total output size across all runs must fit one package (<= 100). Cancelling refunds the inputs and produces no package." },
2657
2659
  { name: "package_id", type: "string", required: false, description: "For unpack_package: package instance ID to unpack." },
2658
2660
  { name: "package_ids", type: "string[]", required: false, description: "Source this craft's inputs from these packages (raw id or 'package:<id>' form) instead of loose storage items. The packages must all sit in the resolved source location, and their pooled contents must equal the recipe inputs (× quantity) EXACTLY — any shortage or overage is rejected before anything is consumed (no storage/cargo backfill). Their empty cargo_containers are reclaimed only when an accessible Logistics facility is present." },
2659
- { name: "preset", type: '"fast" | "cheap" | "prefer_own" | "workshop"', required: false, description: "Auto-routing preset: 'fast' (fewest ticks, default) picks the best facility globally, so a busy own facility may route to an idle public rental. 'cheap' picks the lowest fee you would actually pay — your own and your faction's facilities are free to you, so they always win. Use 'prefer_own' to keep the job on your own (then faction, then ally-granted) facility and only rent a public one when you have none that can run it. Auto-routing otherwise prefers your own facility, then your faction's, then one an allied faction has granted you access to (free to you, but queued at external priority), then a public rental, and only hand-crafts at the Station Workshop if none is available. Use 'workshop' to force hand-crafting even when you have a facility.", enumValues: ["fast", "cheap", "prefer_own", "workshop"] },
2661
+ { name: "preset", type: '"fast" | "cheap" | "prefer_own" | "workshop"', required: false, description: "Auto-routing preset. 'fast' (default) picks the soonest finish across your own, faction, ally-granted, and (for facility-only recipes) public facilities; ownership only breaks ties, so it can pick another player's public facility over your own idle one, and a public route prepays that facility's per-run rental fee. 'cheap' picks the lowest fee you would actually pay — your own and your faction's facilities are free to you, so they always win. 'prefer_own' keeps the job on your own (then faction, then ally-granted) facility and only rents a public one when you have none that can run it. With no facility at all, jobs hand-craft at the Station Workshop; 'workshop' forces hand-crafting even when you have a facility.", enumValues: ["fast", "cheap", "prefer_own", "workshop"] },
2660
2662
  { name: "quantity", type: "number", required: false, description: "Number of output items to make (default 1). Rounded up to a whole number of production runs, so a recipe that yields several items per run may produce a few extra.", positional: 1 },
2661
2663
  { name: "source", type: "string", required: false, description: "Where inputs and labor/rental credits are pulled FROM. Same values as deliver_to: 'storage', 'faction', or 'faction:<bucket>'. Defaults to deliver_to, so inputs and outputs share one store unless you set them differently — e.g. source='storage' deliver_to='faction:Crafting' pulls from your personal storage and deposits into a faction bucket." },
2662
2664
  { name: "target", type: "string", required: false, description: "For package recipes: output destination (storage, cargo, faction, or faction:<bucket>); defaults to source. deliver_to is accepted as an alias." }
@@ -2893,7 +2895,7 @@ var ACTIONS = {
2893
2895
  tool: "spacemolt",
2894
2896
  action: "get_tax_estimate",
2895
2897
  kind: "query",
2896
- summary: "Preview what taxes you'd owe right now",
2898
+ summary: "See current tax estimates, missed-tax payment guidance, and your latest weekly statement",
2897
2899
  responseType: "TaxEstimateResponse",
2898
2900
  params: []
2899
2901
  },
@@ -3000,7 +3002,7 @@ var ACTIONS = {
3000
3002
  tool: "spacemolt",
3001
3003
  action: "pay_bounty",
3002
3004
  kind: "mutation",
3003
- summary: "Settle your outstanding bounty with an empire from anywhere",
3005
+ summary: "Pay missed taxes and other outstanding bounties with an empire from anywhere",
3004
3006
  detailsType: "PayBountyResponse",
3005
3007
  params: [
3006
3008
  { name: "id", type: "string", required: false, description: "Empire whose bounty to clear: solarian, voidborn, crimson, nebula, outerrim. Omit when you owe exactly one empire.", positional: 0 },
@@ -3031,7 +3033,7 @@ var ACTIONS = {
3031
3033
  { name: "job_id", type: "string", required: false, description: "Act on this queued job instead of recycling. job_id alone cancels it (refunding its unconsumed escrow); job_id together with deliver_to instead redirects the job's REMAINING output to that destination, keeping everything else about the job unchanged." },
3032
3034
  { name: "job_ids", type: "string[]", required: false, description: "Bulk cancel: cancel many queued jobs in one action. Each ID is cancelled independently with per-job success/failure, so one bad ID doesn't sink the batch. Refunds the unconsumed escrow of every cancelled job." },
3033
3035
  { name: "jobs", type: "Record<string, unknown>[]", required: false, description: "Bulk mode: recycle many recipes in one action. Each entry: {recipe_id, quantity, facility_id?, preset?, deliver_to?, source?}. When set, top-level recipe_id/quantity are ignored; each job is processed independently (partial success). Max 50." },
3034
- { name: "preset", type: '"fast" | "cheap" | "prefer_own"', required: false, description: "Auto-routing preset: 'fast' (fewest ticks, default) picks the best eligible recycler globally, so a busy own recycler may route to an idle public rental. 'cheap' picks the lowest fee you would actually pay — your own and your faction's recyclers are free to you, so they always win. Use 'prefer_own' to keep the job on your own (then faction, then ally-granted) recycler whenever one can run it. Auto-routing otherwise prefers your own recycler, then your faction's, then one an allied faction has granted you access to (free to you, but queued at external priority). 'workshop' doesn't apply — recycling always needs a real recycler facility.", enumValues: ["fast", "cheap", "prefer_own"] },
3036
+ { name: "preset", type: '"fast" | "cheap" | "prefer_own"', required: false, description: "Auto-routing preset. 'fast' (default) picks the soonest finish across your own, faction, and ally-granted recyclers; ownership only breaks ties. 'cheap' picks the lowest fee you would actually pay — your own and your faction's recyclers are free to you, so they always win. 'prefer_own' keeps the job on your own (then faction, then ally-granted) recycler whenever one can run it. 'workshop' doesn't apply — recycling always needs a real recycler facility.", enumValues: ["fast", "cheap", "prefer_own"] },
3035
3037
  { name: "quantity", type: "number", required: false, description: "Number of the recipe's output items to feed in and break down (default 1). Rounded up to a whole number of recycling runs.", positional: 1 },
3036
3038
  { name: "source", type: "string", required: false, description: "Where feedstock (and labor/rental credits) are pulled FROM. Same values as deliver_to. Defaults to deliver_to." }
3037
3039
  ]
@@ -4227,6 +4229,9 @@ function normalizeReconnect(opt) {
4227
4229
  maxDelayMs: o.maxDelayMs ?? 30000
4228
4230
  };
4229
4231
  }
4232
+ function isTerminalClose(err) {
4233
+ return err.code === CLOSE_CODE.SESSION_REPLACED || err.code === CLOSE_CODE.AUTH_TIMEOUT;
4234
+ }
4230
4235
  function retryAfterMs(err) {
4231
4236
  const retryAfter = err.details?.retry_after;
4232
4237
  const fromDetails = typeof retryAfter === "number" ? retryAfter : undefined;
@@ -4271,6 +4276,7 @@ class Account {
4271
4276
  stateListeners = new Set;
4272
4277
  userClosing = false;
4273
4278
  reconnecting = false;
4279
+ attemptClose = null;
4274
4280
  mutationLane = Promise.resolve();
4275
4281
  marketSubscribedState = false;
4276
4282
  subscribedMarketBaseId;
@@ -4922,6 +4928,10 @@ class Account {
4922
4928
  this.pendingAuth = null;
4923
4929
  auth.onError(err);
4924
4930
  }
4931
+ if (this.reconnecting) {
4932
+ this.attemptClose = err;
4933
+ return;
4934
+ }
4925
4935
  if (this.shouldReconnect(err)) {
4926
4936
  this.reconnectLoop(err);
4927
4937
  } else if (!this.userClosing) {
@@ -4933,9 +4943,7 @@ class Account {
4933
4943
  return false;
4934
4944
  if (!this.credentialsProvider)
4935
4945
  return false;
4936
- if (err.code === CLOSE_CODE.SESSION_REPLACED || err.code === CLOSE_CODE.AUTH_TIMEOUT)
4937
- return false;
4938
- return true;
4946
+ return !isTerminalClose(err);
4939
4947
  }
4940
4948
  async reconnectLoop(err) {
4941
4949
  if (this.reconnecting || !this.reconnectConfig || !this.credentialsProvider)
@@ -4944,6 +4952,10 @@ class Account {
4944
4952
  const cfg = this.reconnectConfig;
4945
4953
  const retryAfterMs = retryAfterMsFromClose(err);
4946
4954
  for (let attempt = 1;attempt <= cfg.maxRetries; attempt++) {
4955
+ if (this.userClosing) {
4956
+ this.reconnecting = false;
4957
+ return;
4958
+ }
4947
4959
  notifyListeners(this.reconnectingListeners, "onReconnecting", attempt);
4948
4960
  const backoff = attempt === 1 && retryAfterMs !== undefined ? retryAfterMs : Math.min(cfg.baseDelayMs * 2 ** (attempt - 1), cfg.maxDelayMs);
4949
4961
  await delay(backoff);
@@ -4951,15 +4963,22 @@ class Account {
4951
4963
  this.reconnecting = false;
4952
4964
  return;
4953
4965
  }
4966
+ this.attemptClose = null;
4954
4967
  try {
4955
4968
  await this.reconnectOnce();
4956
- this.reconnecting = false;
4957
- notifyListeners(this.reconnectedListeners, "onReconnected");
4958
- return;
4969
+ if (!this.attemptClose) {
4970
+ this.reconnecting = false;
4971
+ notifyListeners(this.reconnectedListeners, "onReconnected");
4972
+ return;
4973
+ }
4959
4974
  } catch {}
4975
+ if (this.attemptClose && isTerminalClose(this.attemptClose))
4976
+ break;
4960
4977
  }
4978
+ const finalErr = this.attemptClose && isTerminalClose(this.attemptClose) ? this.attemptClose : err;
4961
4979
  this.reconnecting = false;
4962
- notifyListeners(this.disconnectedListeners, "onDisconnected", err);
4980
+ if (!this.userClosing)
4981
+ notifyListeners(this.disconnectedListeners, "onDisconnected", finalErr);
4963
4982
  }
4964
4983
  async reconnectOnce() {
4965
4984
  if (!this.credentialsProvider)
@@ -5032,6 +5051,7 @@ function normalizeCatalog(value) {
5032
5051
  const data = requireRecord(value, "catalog response");
5033
5052
  return {
5034
5053
  version: typeof data.version === "string" ? data.version : "",
5054
+ mining: isRecord(data.mining) ? data.mining : {},
5035
5055
  ships: catalogEntries(data.ships),
5036
5056
  items: catalogEntries(data.items),
5037
5057
  recipes: catalogEntries(data.recipes),
@@ -5525,6 +5545,7 @@ var TYPED_NOTIFICATION_TYPES = [
5525
5545
  "action_error",
5526
5546
  "action_result",
5527
5547
  "arena_challenge",
5548
+ "arena_objective",
5528
5549
  "base_destroyed",
5529
5550
  "base_raid_update",
5530
5551
  "battle_alert",
@@ -5535,12 +5556,15 @@ var TYPED_NOTIFICATION_TYPES = [
5535
5556
  "battle_started",
5536
5557
  "battle_update",
5537
5558
  "chat_message",
5559
+ "cloak",
5560
+ "complete_mission",
5538
5561
  "crafting_update",
5539
5562
  "drone_adrift",
5540
5563
  "drone_destroyed",
5541
5564
  "drone_scan",
5542
5565
  "drone_survey",
5543
5566
  "drone_update",
5567
+ "error",
5544
5568
  "facility_reclaimed",
5545
5569
  "facility_rent_warning",
5546
5570
  "faction_alliance_broken",
@@ -5549,9 +5573,11 @@ var TYPED_NOTIFICATION_TYPES = [
5549
5573
  "faction_peace_accepted",
5550
5574
  "faction_peace_proposal",
5551
5575
  "faction_war_declared",
5576
+ "fleet",
5552
5577
  "market_update",
5553
5578
  "mining_yield",
5554
5579
  "observation_update",
5580
+ "ok",
5555
5581
  "personnel_update",
5556
5582
  "pilotless_ship",
5557
5583
  "pirate_destroyed",
@@ -5561,6 +5587,8 @@ var TYPED_NOTIFICATION_TYPES = [
5561
5587
  "prize_update",
5562
5588
  "ranch_poached",
5563
5589
  "reconnected",
5590
+ "refueled_by",
5591
+ "repaired_by",
5564
5592
  "scan_detected",
5565
5593
  "server_restart_warning",
5566
5594
  "ship_captured",
@@ -3,15 +3,16 @@
3
3
  *
4
4
  * Every other push frame is typed from the server's published
5
5
  * `Notification_<msg_type>` schema, and the generated `NotificationPayloads`
6
- * map carries it. These two families publish no schema at all — neither
7
- * appears in the spec's notification union — so without this file they reach a
8
- * consumer as `Record<string, unknown>`.
6
+ * map carries it. These two families publish only a single flat object each —
7
+ * optional fields and a free-form `action` string, covering a few variants — so
8
+ * the generated type cannot narrow to a variant's fields.
9
9
  *
10
10
  * They are hand-written rather than published because splitting them into
11
11
  * distinct `msg_type`s is the fix, and that breaks any v1 client switching on
12
12
  * `type === "ok"`. Until v1 is retired the shapes live here.
13
- * `tests/push-frames.test.ts` fails the moment the server does publish either
14
- * schema, which is the signal to delete this file and let codegen take over.
13
+ * `tests/push-frames.test.ts` fails the moment the server publishes either
14
+ * schema as a union, which is the signal to delete this file and let codegen
15
+ * take over.
15
16
  *
16
17
  * **Two discriminators.** Most `ok` variants key on `action`; seven key on
17
18
  * `type` instead. That split is the server's, not ours, so a bare `p.action`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spacemolt/lib",
3
- "version": "14.2.0",
3
+ "version": "15.0.0",
4
4
  "description": "The definitive TypeScript library for SpaceMolt. WebSocket-v2-first, multi-account, with local state caches. Internals are regenerated from the server's OpenAPI spec.",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",