@spacemolt/lib 13.3.0 → 14.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 +1 -1
- package/dist/account.d.ts +0 -6
- package/dist/events/emitter.d.ts +7 -0
- package/dist/generated/actions.gen.d.ts +1 -1
- package/dist/generated/commands.gen.d.ts +1 -1
- package/dist/generated/frames.gen.d.ts +11 -0
- package/dist/generated/openapi/types.gen.d.ts +80 -8
- package/dist/index.js +72 -69
- package/dist/protocol.d.ts +15 -24
- package/dist/transport/correlator.d.ts +0 -1
- package/package.json +1 -1
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.593.0`). **296 commands across 19 tools.**
|
|
5
5
|
|
|
6
6
|
## How to call a command
|
|
7
7
|
|
package/dist/account.d.ts
CHANGED
|
@@ -251,12 +251,6 @@ export declare class Account {
|
|
|
251
251
|
* Multiple listeners may be registered; returns an unsubscribe function.
|
|
252
252
|
*/
|
|
253
253
|
onStateChange(listener: (changed: StateSection[]) => void): () => void;
|
|
254
|
-
/**
|
|
255
|
-
* Fan an event out to every registered listener. A throwing listener is
|
|
256
|
-
* warned and skipped — it must never break the caller (frame routing,
|
|
257
|
-
* mutation correlation, the reconnect loop) or starve later listeners.
|
|
258
|
-
*/
|
|
259
|
-
private notifyListeners;
|
|
260
254
|
private emitStateChange;
|
|
261
255
|
/** Log out, releasing the connection's authenticated session. */
|
|
262
256
|
logout(): Promise<void>;
|
package/dist/events/emitter.d.ts
CHANGED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
* this (loosely-typed) core.
|
|
7
7
|
*/
|
|
8
8
|
import type { RawFrame } from '../protocol.js';
|
|
9
|
+
/**
|
|
10
|
+
* Fan an event out to every registered listener. A throwing listener is warned
|
|
11
|
+
* and skipped — a listener is told what already happened, so it must never
|
|
12
|
+
* break the caller (frame routing, mutation correlation, a connect or reconnect
|
|
13
|
+
* in progress) or starve the listeners after it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function notifyListeners<A extends unknown[]>(listeners: ReadonlySet<(...args: A) => void>, label: string, ...args: A): void;
|
|
9
16
|
type FrameHandler = (frame: RawFrame) => void;
|
|
10
17
|
/**
|
|
11
18
|
* An async iterator over events of one kind, with internal buffering so a slow
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The gameserver spec version this command surface was generated from. */
|
|
2
|
-
export declare const GENERATED_SPEC_VERSION = "v0.
|
|
2
|
+
export declare const GENERATED_SPEC_VERSION = "v0.593.0";
|
|
3
3
|
export type ToolName = "spacemolt" | "spacemolt_arena" | "spacemolt_auth" | "spacemolt_battle" | "spacemolt_citizenship" | "spacemolt_drone" | "spacemolt_facility" | "spacemolt_faction" | "spacemolt_faction_admin" | "spacemolt_faction_commerce" | "spacemolt_fleet" | "spacemolt_intel" | "spacemolt_market" | "spacemolt_salvage" | "spacemolt_ship" | "spacemolt_shipping" | "spacemolt_social" | "spacemolt_storage" | "spacemolt_transfer";
|
|
4
4
|
export type ActionName = "abandon_mission" | "accept" | "accept_ally" | "accept_invite" | "accept_mission" | "accept_peace" | "active" | "advance" | "allow_faction" | "allow_player" | "analyze_market" | "apply" | "attack" | "ban" | "base_cost" | "board" | "browse_for_sale" | "browse_ships" | "build" | "buy" | "buy_listed_ship" | "buy_listing" | "buy_ship_license" | "cancel" | "cancel_commission" | "cancel_listing" | "cancel_mission" | "cancel_order" | "cancel_ship_buy_order" | "cancel_ship_listing" | "captains_log_add" | "captains_log_delete" | "captains_log_get" | "captains_log_list" | "challenge" | "challenges" | "chat" | "claim" | "claim_prize" | "cloak" | "commission_quote" | "commission_ship" | "commission_status" | "complete_mission" | "completed_missions" | "craft" | "create" | "create_buy_order" | "create_note" | "create_role" | "create_sell_order" | "declare_war" | "decline" | "decline_invite" | "decline_mission" | "delete_note" | "delete_role" | "delete_room" | "deliver" | "deploy" | "deploy_outpost" | "deposit" | "disband" | "disembark" | "dismantle" | "dismantle_outpost" | "distress_signal" | "dock" | "edit" | "edit_role" | "engage" | "espionage" | "estimate_purchase" | "facility_set_description" | "faction_build" | "faction_dismantle" | "faction_list" | "faction_owned" | "faction_personnel" | "faction_upgrade" | "fight" | "find_route" | "forum_create_thread" | "forum_delete_reply" | "forum_delete_thread" | "forum_get_thread" | "forum_list" | "forum_reply" | "forum_upvote" | "found_station" | "garages" | "get" | "get_achievements" | "get_action_log" | "get_active_missions" | "get_base" | "get_cargo" | "get_chat_history" | "get_commands" | "get_empire_info" | "get_faction_achievements" | "get_guide" | "get_invites" | "get_location" | "get_map" | "get_missions" | "get_nearby" | "get_notes" | "get_notification_settings" | "get_notifications" | "get_player" | "get_poi" | "get_queue" | "get_ship" | "get_skills" | "get_state" | "get_status" | "get_system" | "get_system_agents" | "get_tax_estimate" | "get_trades" | "get_version" | "hunt" | "info" | "inspect" | "install_mod" | "insure" | "intel_status" | "invite" | "jettison" | "job_add" | "job_cancel" | "job_list" | "job_reorder" | "join" | "jump" | "kick" | "leave" | "list" | "list_for_sale" | "list_missions" | "list_passengers" | "list_ship_for_sale" | "list_ships" | "list_station_passengers" | "load" | "load_passenger" | "log" | "login" | "login_link" | "login_link_poll" | "login_token" | "logout" | "loot" | "mine" | "modify_order" | "mute_notifications" | "name" | "owned" | "pay_bounty" | "pay_debt" | "personal_build" | "personal_decorate" | "personal_visit" | "petition" | "place_ship_buy_order" | "policies" | "post" | "post_mission" | "prepay_tax" | "profile" | "promote" | "propose_ally" | "propose_peace" | "query_intel" | "query_trade_intel" | "quote" | "ranch_set_cull" | "ranch_status" | "read_note" | "recall" | "recruit_personnel" | "recycle" | "refit_ship" | "refuel" | "register" | "release" | "reload" | "remove_ally" | "remove_enemy" | "remove_faction" | "remove_player" | "rename_ship" | "renounce" | "repair" | "retreat" | "return" | "rooms" | "scan" | "scan_poi" | "scrap" | "scrap_ship" | "search_systems" | "self_destruct" | "sell" | "sell_ship_to_order" | "service_prize" | "set_access" | "set_auto_buy_fuel" | "set_build_policy" | "set_colors" | "set_description" | "set_enemy" | "set_home" | "set_market_fee" | "set_name" | "set_output_price" | "set_public" | "set_refuel_price" | "set_repair_price" | "set_service_access" | "set_status" | "stance" | "station_info" | "station_set_name" | "status" | "submit_intel" | "submit_trade_intel" | "subscribe_market" | "subscribe_observation" | "summary" | "supply_commission" | "survey_system" | "switch_ship" | "target" | "tax_estimate" | "tow" | "track" | "trade_accept" | "trade_cancel" | "trade_decline" | "trade_intel_status" | "trade_offer" | "transfer" | "transfer_personnel" | "travel" | "treat_personnel" | "types" | "unban" | "undock" | "uninstall_mod" | "unload" | "unload_passenger" | "unmute_notifications" | "unsubscribe_market" | "unsubscribe_observation" | "upgrade" | "upgrades" | "upload" | "use_item" | "view" | "view_completed_mission" | "view_market" | "view_orders" | "view_ship_buy_orders" | "visit_room" | "withdraw" | "withdraw_invite" | "wrecks" | "write_note" | "write_room";
|
|
5
5
|
export interface ActionParam {
|
|
@@ -443,7 +443,7 @@ export interface SpacemoltFactionAdminPostMissionParams {
|
|
|
443
443
|
title: string;
|
|
444
444
|
/** Optional: triggers like 'open_to_all' to allow non-members */
|
|
445
445
|
triggers?: string[];
|
|
446
|
-
/** Mission type (delivery, combat, exploration, etc.) */
|
|
446
|
+
/** Mission type (delivery, combat, exploration, bounty, etc.) */
|
|
447
447
|
type: string;
|
|
448
448
|
}
|
|
449
449
|
export interface SpacemoltFactionAdminPromoteParams {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Runtime kind of a frame-payload field. */
|
|
2
|
+
export type FieldKind = 'string' | 'number' | 'boolean' | 'string[]' | 'number[]' | 'boolean[]';
|
|
3
|
+
/** A frame-payload field's runtime kind, and whether the server always sends it. */
|
|
4
|
+
export interface FrameField {
|
|
5
|
+
kind: FieldKind;
|
|
6
|
+
required: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Every field of the server's `WelcomePayload`, with its runtime kind and required-ness. */
|
|
9
|
+
export declare const WELCOME_PAYLOAD_FIELDS: Readonly<Record<string, FrameField>>;
|
|
10
|
+
/** Every field of the server's `RegisteredPayload`, with its runtime kind and required-ness. */
|
|
11
|
+
export declare const REGISTERED_PAYLOAD_FIELDS: Readonly<Record<string, FrameField>>;
|
|
@@ -678,15 +678,23 @@ export type AttackLogEntry = {
|
|
|
678
678
|
emergency_cloak_strength?: number;
|
|
679
679
|
final_damage: number;
|
|
680
680
|
flat_reduction_pct?: number;
|
|
681
|
+
/**
|
|
682
|
+
* Ship-level hit chance in [0.05,0.95] that every weapon starts from (separation, skills, modules, stance, speed). Each entry in weapons[] carries its own hit_chance with that weapon's ammo and mine modifiers added.
|
|
683
|
+
*/
|
|
681
684
|
hit_chance: number;
|
|
682
|
-
|
|
685
|
+
/**
|
|
686
|
+
* True when at least one weapon hit. Per-weapon outcomes are in weapons[].
|
|
687
|
+
*/
|
|
683
688
|
hit_success: boolean;
|
|
684
689
|
hull_damage: number;
|
|
685
690
|
ignored_resistance_pct?: number;
|
|
691
|
+
/**
|
|
692
|
+
* Sum of the damage of the weapons that hit, after offensive skill and buff bonuses, before the target's stance and defenses. 0 when every weapon missed. Rows recorded before per-weapon rolls report their single-roll volley damage here.
|
|
693
|
+
*/
|
|
694
|
+
landed_damage: number;
|
|
686
695
|
lifesteal_pct?: number;
|
|
687
696
|
mine_duration?: number;
|
|
688
697
|
off_buff_pct?: number;
|
|
689
|
-
pre_hit_damage: number;
|
|
690
698
|
raw_damage: number;
|
|
691
699
|
secondary_kind?: string;
|
|
692
700
|
shield_damage: number;
|
|
@@ -861,7 +869,7 @@ export type BattleCombatState = {
|
|
|
861
869
|
*/
|
|
862
870
|
disruption_ticks?: number;
|
|
863
871
|
/**
|
|
864
|
-
* Your
|
|
872
|
+
* Your derived combat speed after fitted modules, temporary buffs, pilot skills, EM disruption, and enemy webifiers. This value drives hit chance, maneuvering, escape, and boarding pursuit.
|
|
865
873
|
*/
|
|
866
874
|
effective_speed: number;
|
|
867
875
|
/**
|
|
@@ -909,11 +917,11 @@ export type BattleCombatState = {
|
|
|
909
917
|
*/
|
|
910
918
|
warp_disrupted: boolean;
|
|
911
919
|
/**
|
|
912
|
-
* Combined
|
|
920
|
+
* Combined combat-speed penalty from enemy webifiers as a percentage. Webifier penalties add and cap at 75%.
|
|
913
921
|
*/
|
|
914
922
|
web_strength_pct?: number;
|
|
915
923
|
/**
|
|
916
|
-
* An enemy stasis webifier is
|
|
924
|
+
* An enemy stasis webifier is reducing your effective combat speed.
|
|
917
925
|
*/
|
|
918
926
|
webbed: boolean;
|
|
919
927
|
};
|
|
@@ -5009,6 +5017,14 @@ export type ItemEffect = {
|
|
|
5009
5017
|
ammo?: AmmoStats;
|
|
5010
5018
|
amount?: number;
|
|
5011
5019
|
duration?: number;
|
|
5020
|
+
/**
|
|
5021
|
+
* Magnitude of the consumable's additional effect. Read together with secondary_stat.
|
|
5022
|
+
*/
|
|
5023
|
+
secondary_amount?: number;
|
|
5024
|
+
/**
|
|
5025
|
+
* Stat modified by the consumable's additional effect. Omitted when the item has only one effect.
|
|
5026
|
+
*/
|
|
5027
|
+
secondary_stat?: string;
|
|
5012
5028
|
stat?: string;
|
|
5013
5029
|
subtype?: string;
|
|
5014
5030
|
type: string;
|
|
@@ -5590,6 +5606,10 @@ export type Module = {
|
|
|
5590
5606
|
hull_bonus?: number;
|
|
5591
5607
|
hull_penalty?: number;
|
|
5592
5608
|
id: string;
|
|
5609
|
+
/**
|
|
5610
|
+
* Percentage points subtracted from each hostile ECM lock-break roll. Fitted bonuses stack up to the combat resistance cap.
|
|
5611
|
+
*/
|
|
5612
|
+
jam_resistance?: number;
|
|
5593
5613
|
jam_strength?: number;
|
|
5594
5614
|
latch_resistance?: number;
|
|
5595
5615
|
latch_strength?: number;
|
|
@@ -5615,7 +5635,14 @@ export type Module = {
|
|
|
5615
5635
|
reactive_resistance?: number;
|
|
5616
5636
|
refit_capability?: boolean;
|
|
5617
5637
|
remote_medical_treatment?: boolean;
|
|
5638
|
+
/**
|
|
5639
|
+
* Hull points repaired per tick on the most-wounded eligible ally.
|
|
5640
|
+
*/
|
|
5618
5641
|
remote_repair_power?: number;
|
|
5642
|
+
/**
|
|
5643
|
+
* Maximum remote-repair range in same-side radial-band distance to an eligible ally.
|
|
5644
|
+
*/
|
|
5645
|
+
remote_repair_range?: number;
|
|
5619
5646
|
required_skills?: {
|
|
5620
5647
|
[key: string]: number;
|
|
5621
5648
|
};
|
|
@@ -5637,6 +5664,10 @@ export type Module = {
|
|
|
5637
5664
|
speed_penalty?: number;
|
|
5638
5665
|
survey_power?: number;
|
|
5639
5666
|
targeting_reduction?: number;
|
|
5667
|
+
/**
|
|
5668
|
+
* Percentage points subtracted from hostile sensor-dampener reach reduction. Fitted bonuses stack up to the combat resistance cap.
|
|
5669
|
+
*/
|
|
5670
|
+
targeting_resistance?: number;
|
|
5640
5671
|
tow_speed_penalty?: number;
|
|
5641
5672
|
tracking_bonus?: number;
|
|
5642
5673
|
type: string;
|
|
@@ -6531,6 +6562,14 @@ export type ObjectiveInfo = {
|
|
|
6531
6562
|
system_name?: string;
|
|
6532
6563
|
target_base_id?: string;
|
|
6533
6564
|
target_base_name?: string;
|
|
6565
|
+
/**
|
|
6566
|
+
* kill_player objectives only: the username of the pilot this bounty names
|
|
6567
|
+
*/
|
|
6568
|
+
target_player?: string;
|
|
6569
|
+
/**
|
|
6570
|
+
* kill_player objectives only: the ID of the pilot this bounty names
|
|
6571
|
+
*/
|
|
6572
|
+
target_player_id?: string;
|
|
6534
6573
|
type: string;
|
|
6535
6574
|
};
|
|
6536
6575
|
export type ObjectiveProgressInfo = {
|
|
@@ -6554,6 +6593,14 @@ export type ObjectiveProgressInfo = {
|
|
|
6554
6593
|
system_name?: string;
|
|
6555
6594
|
target_base?: string;
|
|
6556
6595
|
target_base_name?: string;
|
|
6596
|
+
/**
|
|
6597
|
+
* kill_player objectives only: the username of the pilot this bounty names
|
|
6598
|
+
*/
|
|
6599
|
+
target_player?: string;
|
|
6600
|
+
/**
|
|
6601
|
+
* kill_player objectives only: the ID of the pilot this bounty names
|
|
6602
|
+
*/
|
|
6603
|
+
target_player_id?: string;
|
|
6557
6604
|
type: string;
|
|
6558
6605
|
};
|
|
6559
6606
|
export type OpenOrderSummary = {
|
|
@@ -8255,7 +8302,7 @@ export type ShipClass = {
|
|
|
8255
8302
|
[key: string]: unknown;
|
|
8256
8303
|
}>;
|
|
8257
8304
|
/**
|
|
8258
|
-
* Minimum reputation with the ship's empire to commission or buy this ship (0 = no requirement)
|
|
8305
|
+
* Minimum reputation with the ship's empire to commission or buy this ship (0 = no requirement). Not applied to a faction-funded build at the faction's own station when the faction holds a buy_ship_license for this design — the license authorizes that build instead
|
|
8259
8306
|
*/
|
|
8260
8307
|
required_reputation?: number;
|
|
8261
8308
|
/**
|
|
@@ -9655,6 +9702,16 @@ export type V2Personnel = {
|
|
|
9655
9702
|
injured_marines: number;
|
|
9656
9703
|
};
|
|
9657
9704
|
export type V2Player = {
|
|
9705
|
+
/**
|
|
9706
|
+
* NPC arena challenge win counts, keyed by challenge_id. Omitted until the first NPC-trial win; a missing challenge key means zero wins.
|
|
9707
|
+
*/
|
|
9708
|
+
arena_won?: {
|
|
9709
|
+
[key: string]: number;
|
|
9710
|
+
};
|
|
9711
|
+
/**
|
|
9712
|
+
* Combat XP earned from arena fights during the UTC date in day, keyed by skill ID in by_skill. Omitted until the first arena fight; a missing skill key means zero XP. The ledger resets when the UTC date changes.
|
|
9713
|
+
*/
|
|
9714
|
+
arena_xp?: ArenaXpLedger;
|
|
9658
9715
|
/**
|
|
9659
9716
|
* Empire IDs this player holds citizenship in (omitted when empty). Independent of the immutable origin empire.
|
|
9660
9717
|
*/
|
|
@@ -10027,6 +10084,18 @@ export type WeaponFireDetail = {
|
|
|
10027
10084
|
crit_roll: number;
|
|
10028
10085
|
damage: number;
|
|
10029
10086
|
damage_type: string;
|
|
10087
|
+
/**
|
|
10088
|
+
* This weapon's own hit chance in [0.05,0.95]: the entry's hit_chance plus this weapon's loaded ammo accuracy and mine guidance. Present on every weapon that fired; absent on rows recorded before per-weapon rolls.
|
|
10089
|
+
*/
|
|
10090
|
+
hit_chance?: number;
|
|
10091
|
+
/**
|
|
10092
|
+
* This weapon's roll in [0,1). It hit when hit_roll < hit_chance. Present on every weapon that fired; absent on rows recorded before per-weapon rolls.
|
|
10093
|
+
*/
|
|
10094
|
+
hit_roll?: number;
|
|
10095
|
+
/**
|
|
10096
|
+
* True when this weapon connected. Omitted when it missed, and on rows recorded before per-weapon rolls (use the entry's hit_success there).
|
|
10097
|
+
*/
|
|
10098
|
+
hit_success?: boolean;
|
|
10030
10099
|
instance_id: string;
|
|
10031
10100
|
name: string;
|
|
10032
10101
|
type_bonus_pct: number;
|
|
@@ -17412,9 +17481,12 @@ export type SpacemoltFactionAdminPostMissionData = {
|
|
|
17412
17481
|
* Destination for a deliver_item or dock_at_base objective, as either the station's Base ID or station POI ID. Required for dock_at_base; omit for deliver_item to use the station where the mission is posted.
|
|
17413
17482
|
*/
|
|
17414
17483
|
target_base_id?: string;
|
|
17484
|
+
/**
|
|
17485
|
+
* Bounty target for a kill_player objective: the pilot's username or player ID. Required for kill_player.
|
|
17486
|
+
*/
|
|
17415
17487
|
target_id?: string;
|
|
17416
17488
|
/**
|
|
17417
|
-
* Objective type (deliver_item, kill_player, visit_system,
|
|
17489
|
+
* Objective type (deliver_item, kill_pirate, kill_player, visit_system, dock_at_base)
|
|
17418
17490
|
*/
|
|
17419
17491
|
type: string;
|
|
17420
17492
|
}>;
|
|
@@ -17436,7 +17508,7 @@ export type SpacemoltFactionAdminPostMissionData = {
|
|
|
17436
17508
|
*/
|
|
17437
17509
|
triggers?: Array<string>;
|
|
17438
17510
|
/**
|
|
17439
|
-
* Mission type (delivery, combat, exploration, etc.)
|
|
17511
|
+
* Mission type (delivery, combat, exploration, bounty, etc.)
|
|
17440
17512
|
*/
|
|
17441
17513
|
type: string;
|
|
17442
17514
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
// src/generated/frames.gen.ts
|
|
2
|
+
var WELCOME_PAYLOAD_FIELDS = {
|
|
3
|
+
current_tick: { kind: "number", required: true },
|
|
4
|
+
game_info: { kind: "string", required: true },
|
|
5
|
+
help_text: { kind: "string", required: true },
|
|
6
|
+
motd: { kind: "string", required: false },
|
|
7
|
+
release_date: { kind: "string", required: true },
|
|
8
|
+
release_notes: { kind: "string[]", required: true },
|
|
9
|
+
server_time: { kind: "number", required: true },
|
|
10
|
+
terms: { kind: "string", required: true },
|
|
11
|
+
tick_rate: { kind: "number", required: true },
|
|
12
|
+
version: { kind: "string", required: true },
|
|
13
|
+
website: { kind: "string", required: true }
|
|
14
|
+
};
|
|
15
|
+
var REGISTERED_PAYLOAD_FIELDS = {
|
|
16
|
+
password: { kind: "string", required: true },
|
|
17
|
+
player_id: { kind: "string", required: true }
|
|
18
|
+
};
|
|
19
|
+
|
|
1
20
|
// src/validation.ts
|
|
2
21
|
function isRecord(value) {
|
|
3
22
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -24,14 +43,28 @@ function isActionErrorFrame(frame) {
|
|
|
24
43
|
function isErrorFrame(frame) {
|
|
25
44
|
return frame.type === "error" && hasPayload(frame) && typeof frame.payload.code === "string" && typeof frame.payload.message === "string" && (frame.payload.details === undefined || isRecord(frame.payload.details)) && (frame.payload.pending_command === undefined || typeof frame.payload.pending_command === "string");
|
|
26
45
|
}
|
|
46
|
+
function matchesKind(value, kind) {
|
|
47
|
+
const element = kind.endsWith("[]") ? kind.slice(0, -2) : undefined;
|
|
48
|
+
if (element)
|
|
49
|
+
return Array.isArray(value) && value.every((item) => typeof item === element);
|
|
50
|
+
return typeof value === kind;
|
|
51
|
+
}
|
|
52
|
+
function matchesFields(payload, fields) {
|
|
53
|
+
return Object.entries(fields).every(([field, { kind, required }]) => {
|
|
54
|
+
const value = payload[field];
|
|
55
|
+
if (value === undefined)
|
|
56
|
+
return !required;
|
|
57
|
+
return matchesKind(value, kind);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
27
60
|
function isWelcomeFrame(frame) {
|
|
28
|
-
return frame.type === "welcome" && hasPayload(frame) &&
|
|
61
|
+
return frame.type === "welcome" && hasPayload(frame) && matchesFields(frame.payload, WELCOME_PAYLOAD_FIELDS);
|
|
29
62
|
}
|
|
30
63
|
function isLoggedInFrame(frame) {
|
|
31
64
|
return frame.type === "logged_in" && hasPayload(frame);
|
|
32
65
|
}
|
|
33
66
|
function isRegisteredFrame(frame) {
|
|
34
|
-
return frame.type === "registered" && hasPayload(frame) &&
|
|
67
|
+
return frame.type === "registered" && hasPayload(frame) && matchesFields(frame.payload, REGISTERED_PAYLOAD_FIELDS);
|
|
35
68
|
}
|
|
36
69
|
var STATE_SECTIONS = [
|
|
37
70
|
"player",
|
|
@@ -45,7 +78,7 @@ var STATE_SECTIONS = [
|
|
|
45
78
|
"prize_recoveries"
|
|
46
79
|
];
|
|
47
80
|
// src/generated/actions.gen.ts
|
|
48
|
-
var GENERATED_SPEC_VERSION = "v0.
|
|
81
|
+
var GENERATED_SPEC_VERSION = "v0.593.0";
|
|
49
82
|
var ACTIONS = {
|
|
50
83
|
"spacemolt_arena/accept": {
|
|
51
84
|
tool: "spacemolt_arena",
|
|
@@ -996,7 +1029,7 @@ var ACTIONS = {
|
|
|
996
1029
|
{ name: "rewards", type: "{ credits?: number; items?: Record<string, unknown>[] }", required: true, description: "Mission rewards (credits, items, reputation)" },
|
|
997
1030
|
{ name: "title", type: "string", required: true, description: "Mission title" },
|
|
998
1031
|
{ name: "triggers", type: "string[]", required: false, description: "Optional: triggers like 'open_to_all' to allow non-members" },
|
|
999
|
-
{ name: "type", type: "string", required: true, description: "Mission type (delivery, combat, exploration, etc.)" }
|
|
1032
|
+
{ name: "type", type: "string", required: true, description: "Mission type (delivery, combat, exploration, bounty, etc.)" }
|
|
1000
1033
|
]
|
|
1001
1034
|
},
|
|
1002
1035
|
"spacemolt_faction_admin/promote": {
|
|
@@ -3629,6 +3662,16 @@ function retryAfterMsFromClose(err) {
|
|
|
3629
3662
|
}
|
|
3630
3663
|
|
|
3631
3664
|
// src/events/emitter.ts
|
|
3665
|
+
function notifyListeners(listeners, label, ...args) {
|
|
3666
|
+
for (const listener of listeners) {
|
|
3667
|
+
try {
|
|
3668
|
+
listener(...args);
|
|
3669
|
+
} catch (err) {
|
|
3670
|
+
console.warn(`[spacemolt] ${label} listener threw: ${err}`);
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3632
3675
|
class EventStream {
|
|
3633
3676
|
onClose;
|
|
3634
3677
|
buffer = [];
|
|
@@ -3923,14 +3966,17 @@ class StateCache {
|
|
|
3923
3966
|
function extractPendingAck(structured) {
|
|
3924
3967
|
if (!structured)
|
|
3925
3968
|
return;
|
|
3926
|
-
if (structured.pending === true) {
|
|
3927
|
-
return { command: String(structured.command ?? ""), message: String(structured.message ?? "") };
|
|
3928
|
-
}
|
|
3929
3969
|
const details = structured.details;
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
return
|
|
3970
|
+
const source = structured.pending === true ? structured : isRecord(details) && details.pending === true ? details : undefined;
|
|
3971
|
+
if (!source)
|
|
3972
|
+
return;
|
|
3973
|
+
return {
|
|
3974
|
+
pending: true,
|
|
3975
|
+
command: String(source.command ?? ""),
|
|
3976
|
+
message: String(source.message ?? ""),
|
|
3977
|
+
...typeof source.auto_docked === "boolean" && { auto_docked: source.auto_docked },
|
|
3978
|
+
...typeof source.auto_undocked === "boolean" && { auto_undocked: source.auto_undocked }
|
|
3979
|
+
};
|
|
3934
3980
|
}
|
|
3935
3981
|
|
|
3936
3982
|
class Correlator {
|
|
@@ -3964,14 +4010,14 @@ class Correlator {
|
|
|
3964
4010
|
return this.rejectInvalidResponse(requestId, pending, frame.type);
|
|
3965
4011
|
const payload = frame.payload;
|
|
3966
4012
|
if (pending.kind === "query") {
|
|
3967
|
-
this.
|
|
4013
|
+
this.pending.delete(requestId);
|
|
3968
4014
|
pending.resolve({ result: payload.result, structuredContent: payload.structuredContent });
|
|
3969
4015
|
return true;
|
|
3970
4016
|
}
|
|
3971
4017
|
const structured = payload.structuredContent;
|
|
3972
4018
|
const ack = extractPendingAck(structured);
|
|
3973
4019
|
if (!ack) {
|
|
3974
|
-
this.
|
|
4020
|
+
this.pending.delete(requestId);
|
|
3975
4021
|
pending.resolve({
|
|
3976
4022
|
command: String(structured?.command ?? ""),
|
|
3977
4023
|
tick: 0,
|
|
@@ -3989,7 +4035,7 @@ class Correlator {
|
|
|
3989
4035
|
if (!isActionResultFrame(frame))
|
|
3990
4036
|
return this.rejectInvalidResponse(requestId, pending, frame.type);
|
|
3991
4037
|
const payload = frame.payload;
|
|
3992
|
-
this.
|
|
4038
|
+
this.pending.delete(requestId);
|
|
3993
4039
|
pending.resolve({
|
|
3994
4040
|
command: payload.command,
|
|
3995
4041
|
tick: payload.tick,
|
|
@@ -4002,14 +4048,14 @@ class Correlator {
|
|
|
4002
4048
|
case "action_error": {
|
|
4003
4049
|
if (!isActionErrorFrame(frame))
|
|
4004
4050
|
return this.rejectInvalidResponse(requestId, pending, frame.type);
|
|
4005
|
-
this.
|
|
4051
|
+
this.pending.delete(requestId);
|
|
4006
4052
|
pending.reject(errorFromActionFrame(frame));
|
|
4007
4053
|
return true;
|
|
4008
4054
|
}
|
|
4009
4055
|
case "error": {
|
|
4010
4056
|
if (!isErrorFrame(frame))
|
|
4011
4057
|
return this.rejectInvalidResponse(requestId, pending, frame.type);
|
|
4012
|
-
this.
|
|
4058
|
+
this.pending.delete(requestId);
|
|
4013
4059
|
pending.reject(errorFromFrame(frame));
|
|
4014
4060
|
return true;
|
|
4015
4061
|
}
|
|
@@ -4022,46 +4068,15 @@ class Correlator {
|
|
|
4022
4068
|
pending.reject(err);
|
|
4023
4069
|
this.pending.clear();
|
|
4024
4070
|
}
|
|
4025
|
-
settle(requestId) {
|
|
4026
|
-
this.pending.delete(requestId);
|
|
4027
|
-
}
|
|
4028
4071
|
rejectInvalidResponse(requestId, pending, frameType) {
|
|
4029
|
-
this.
|
|
4072
|
+
this.pending.delete(requestId);
|
|
4030
4073
|
pending.reject(new SpacemoltError("invalid_response", `Malformed ${frameType} frame for request ${requestId}`));
|
|
4031
4074
|
return true;
|
|
4032
4075
|
}
|
|
4033
4076
|
}
|
|
4034
4077
|
|
|
4035
4078
|
// src/transport/socket.ts
|
|
4036
|
-
|
|
4037
|
-
socket;
|
|
4038
|
-
constructor(url) {
|
|
4039
|
-
this.socket = new WebSocket(url);
|
|
4040
|
-
}
|
|
4041
|
-
send(data) {
|
|
4042
|
-
this.socket.send(data);
|
|
4043
|
-
}
|
|
4044
|
-
close(code, reason) {
|
|
4045
|
-
this.socket.close(code, reason);
|
|
4046
|
-
}
|
|
4047
|
-
addEventListener(...args) {
|
|
4048
|
-
switch (args[0]) {
|
|
4049
|
-
case "open":
|
|
4050
|
-
this.socket.addEventListener("open", () => args[1]());
|
|
4051
|
-
break;
|
|
4052
|
-
case "message":
|
|
4053
|
-
this.socket.addEventListener("message", (event) => args[1]({ data: event.data }));
|
|
4054
|
-
break;
|
|
4055
|
-
case "close":
|
|
4056
|
-
this.socket.addEventListener("close", (event) => args[1]({ code: event.code, reason: event.reason }));
|
|
4057
|
-
break;
|
|
4058
|
-
case "error":
|
|
4059
|
-
this.socket.addEventListener("error", (event) => args[1](event));
|
|
4060
|
-
break;
|
|
4061
|
-
}
|
|
4062
|
-
}
|
|
4063
|
-
}
|
|
4064
|
-
var defaultFactory = (url) => new NativeWebSocketAdapter(url);
|
|
4079
|
+
var defaultFactory = (url) => new WebSocket(url);
|
|
4065
4080
|
|
|
4066
4081
|
class Socket {
|
|
4067
4082
|
opts;
|
|
@@ -4436,17 +4451,8 @@ class Account {
|
|
|
4436
4451
|
this.stateListeners.delete(listener);
|
|
4437
4452
|
};
|
|
4438
4453
|
}
|
|
4439
|
-
notifyListeners(listeners, label, ...args) {
|
|
4440
|
-
for (const listener of listeners) {
|
|
4441
|
-
try {
|
|
4442
|
-
listener(...args);
|
|
4443
|
-
} catch (err) {
|
|
4444
|
-
console.warn(`[spacemolt] ${label} listener threw: ${err}`);
|
|
4445
|
-
}
|
|
4446
|
-
}
|
|
4447
|
-
}
|
|
4448
4454
|
emitStateChange(changed) {
|
|
4449
|
-
|
|
4455
|
+
notifyListeners(this.stateListeners, "onStateChange", changed);
|
|
4450
4456
|
}
|
|
4451
4457
|
async logout() {
|
|
4452
4458
|
await this.query("spacemolt_auth", "logout");
|
|
@@ -4870,7 +4876,7 @@ class Account {
|
|
|
4870
4876
|
if (this.shouldReconnect(err)) {
|
|
4871
4877
|
this.reconnectLoop(err);
|
|
4872
4878
|
} else if (!this.userClosing) {
|
|
4873
|
-
|
|
4879
|
+
notifyListeners(this.disconnectedListeners, "onDisconnected", err);
|
|
4874
4880
|
}
|
|
4875
4881
|
}
|
|
4876
4882
|
shouldReconnect(err) {
|
|
@@ -4889,7 +4895,7 @@ class Account {
|
|
|
4889
4895
|
const cfg = this.reconnectConfig;
|
|
4890
4896
|
const retryAfterMs = retryAfterMsFromClose(err);
|
|
4891
4897
|
for (let attempt = 1;attempt <= cfg.maxRetries; attempt++) {
|
|
4892
|
-
|
|
4898
|
+
notifyListeners(this.reconnectingListeners, "onReconnecting", attempt);
|
|
4893
4899
|
const backoff = attempt === 1 && retryAfterMs !== undefined ? retryAfterMs : Math.min(cfg.baseDelayMs * 2 ** (attempt - 1), cfg.maxDelayMs);
|
|
4894
4900
|
await delay(backoff);
|
|
4895
4901
|
if (this.userClosing) {
|
|
@@ -4899,12 +4905,12 @@ class Account {
|
|
|
4899
4905
|
try {
|
|
4900
4906
|
await this.reconnectOnce();
|
|
4901
4907
|
this.reconnecting = false;
|
|
4902
|
-
|
|
4908
|
+
notifyListeners(this.reconnectedListeners, "onReconnected");
|
|
4903
4909
|
return;
|
|
4904
4910
|
} catch {}
|
|
4905
4911
|
}
|
|
4906
4912
|
this.reconnecting = false;
|
|
4907
|
-
|
|
4913
|
+
notifyListeners(this.disconnectedListeners, "onDisconnected", err);
|
|
4908
4914
|
}
|
|
4909
4915
|
async reconnectOnce() {
|
|
4910
4916
|
if (!this.credentialsProvider)
|
|
@@ -5188,16 +5194,13 @@ class SpacemoltClient {
|
|
|
5188
5194
|
return () => this.accountDisconnectedListeners.delete(listener);
|
|
5189
5195
|
}
|
|
5190
5196
|
notifyAccountConnected(account) {
|
|
5191
|
-
|
|
5192
|
-
listener(account);
|
|
5197
|
+
notifyListeners(this.accountConnectedListeners, "onAccountConnected", account);
|
|
5193
5198
|
}
|
|
5194
5199
|
notifyAccountReconnected(account) {
|
|
5195
|
-
|
|
5196
|
-
listener(account);
|
|
5200
|
+
notifyListeners(this.accountReconnectedListeners, "onAccountReconnected", account);
|
|
5197
5201
|
}
|
|
5198
5202
|
notifyAccountDisconnected(id, err) {
|
|
5199
|
-
|
|
5200
|
-
listener(id, err);
|
|
5203
|
+
notifyListeners(this.accountDisconnectedListeners, "onAccountDisconnected", id, err);
|
|
5201
5204
|
}
|
|
5202
5205
|
get httpBaseUrl() {
|
|
5203
5206
|
return this.opts.httpBaseUrl ?? (this.opts.url ? httpBaseFromWs(this.opts.url) : DEFAULT_HTTP_BASE);
|
package/dist/protocol.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* spec instead (see src/generated/). Endpoint: `/ws/v2`.
|
|
8
8
|
*/
|
|
9
9
|
import type { NotificationPayloads, TypedNotificationType } from './generated/notifications.gen.js';
|
|
10
|
-
import type { LoggedInPayload, RegisteredPayload, V2GameState, WelcomePayload } from './generated/openapi/types.gen.js';
|
|
10
|
+
import type { LoggedInPayload, NotificationActionError, NotificationActionResult, PendingActionResponse, RegisteredPayload, V2GameState, WelcomePayload } from './generated/openapi/types.gen.js';
|
|
11
11
|
/** Inbound frame: client -> server. `payload` is omitted when an action takes none. */
|
|
12
12
|
export interface InboundFrame {
|
|
13
13
|
tool: string;
|
|
@@ -27,36 +27,25 @@ export interface ResultFrame {
|
|
|
27
27
|
structuredContent?: Record<string, unknown>;
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
/** Mutation-ack: a `result` frame whose structuredContent flags `pending: true`. */
|
|
31
|
-
export interface PendingAck {
|
|
32
|
-
pending: true;
|
|
33
|
-
command: string;
|
|
34
|
-
message: string;
|
|
35
|
-
}
|
|
36
30
|
/** Outcome push for a queued mutation; echoes the original request_id. */
|
|
37
31
|
export interface ActionResultFrame {
|
|
38
32
|
type: 'action_result';
|
|
39
33
|
request_id?: string;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
/**
|
|
35
|
+
* The server's published `Notification_action_result`, except for `result`:
|
|
36
|
+
* the spec leaves it untyped because the v1 and v2 shapes differ, and on
|
|
37
|
+
* `/ws/v2` it is always the delta. Narrow it here rather than lose the type.
|
|
38
|
+
*/
|
|
39
|
+
payload: Omit<NotificationActionResult, 'result'> & {
|
|
43
40
|
/** A V2GameState delta — only the sections that changed. See StateDelta. */
|
|
44
41
|
result: StateDelta;
|
|
45
|
-
auto_docked?: boolean;
|
|
46
|
-
auto_undocked?: boolean;
|
|
47
42
|
};
|
|
48
43
|
}
|
|
49
44
|
/** Failure outcome for a queued mutation. */
|
|
50
45
|
export interface ActionErrorFrame {
|
|
51
46
|
type: 'action_error';
|
|
52
47
|
request_id?: string;
|
|
53
|
-
payload:
|
|
54
|
-
command: string;
|
|
55
|
-
tick: number;
|
|
56
|
-
code: string;
|
|
57
|
-
message: string;
|
|
58
|
-
details?: Record<string, unknown>;
|
|
59
|
-
};
|
|
48
|
+
payload: NotificationActionError;
|
|
60
49
|
}
|
|
61
50
|
/** Generic error frame emitted by the framing layer or a handler. */
|
|
62
51
|
export interface ErrorFrame {
|
|
@@ -163,11 +152,13 @@ export interface QueryResult<T = Record<string, unknown>> {
|
|
|
163
152
|
/** Raw JSON for programmatic consumption, typed to the command's response. */
|
|
164
153
|
structuredContent?: T;
|
|
165
154
|
}
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
155
|
+
/**
|
|
156
|
+
* The immediate `pending: true` acknowledgement for a queued mutation. The
|
|
157
|
+
* server's published `PendingActionResponse`, so the `auto_docked`/
|
|
158
|
+
* `auto_undocked` flags it carries reach the caller at ack time rather than
|
|
159
|
+
* only on the final outcome.
|
|
160
|
+
*/
|
|
161
|
+
export type MutationAck = PendingActionResponse;
|
|
171
162
|
/**
|
|
172
163
|
* Resolved value of a two-phase mutation, delivered when the action executes.
|
|
173
164
|
* `TDetails` is the action-specific shape of `delta.details` (e.g. `jump` ->
|
|
@@ -50,6 +50,5 @@ export declare class Correlator {
|
|
|
50
50
|
handle(frame: RawFrame): boolean;
|
|
51
51
|
/** Reject every in-flight request — used when the socket closes. */
|
|
52
52
|
rejectAll(err: ConnectionClosedError | SpacemoltError): void;
|
|
53
|
-
private settle;
|
|
54
53
|
private rejectInvalidResponse;
|
|
55
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spacemolt/lib",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.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",
|