@crowdedkingdoms/crowdy-dsh 0.4.7-dev.1 → 0.4.8-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "package": "@crowdedkingdoms/crowdy-dsh",
3
- "version": "0.4.7",
4
- "builtAt": "2026-10-15T20:11:28.339Z",
3
+ "version": "0.4.8",
4
+ "builtAt": "2026-10-15T22:43:35.458Z",
5
5
  "source": {
6
6
  "repository": "CrowdedKingdoms/crowdy-dsh",
7
- "commit": "5809199d9f08d3adcef9fa0cb25ecb2694c41caf",
7
+ "commit": "6be157fc87333ca64a2688d5e2ab77c9e57101dc",
8
8
  "dirty": false
9
9
  },
10
10
  "upstream": {
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "crowdyjs": {
17
17
  "name": "@crowdedkingdoms/crowdyjs",
18
- "version": "18.11.0-dev.1",
18
+ "version": "18.12.0-dev.1",
19
19
  "source": "node_modules"
20
20
  },
21
21
  "files": {
@@ -112,7 +112,7 @@
112
112
  "manifest.webmanifest": "sha256:9b54d57eea00f2fdd1affe6e7999a4209a515755f12ac1a3299da2d55e178d4c",
113
113
  "preview/bootstrap-CYECZNXt.js": "sha256:9f303a0485c0badfdd19fad0c357ef050c5b9a343744ab5bf0c70015e7d95092",
114
114
  "preview/crowdy-boot-Cklh1qNl.js": "sha256:b21e8eb126e1cd8a52159d2d577e610df6c8af36a436f9ed5028cfabd11a85ff",
115
- "preview/vfs-image.tar.gz": "sha256:a399e9c5b46f89f6aad3eab2a9b97bc18acdbd6450bcb0abd754efafaeae00b5",
115
+ "preview/vfs-image.tar.gz": "sha256:95c3425e186deba4ce4355980db01d6451cca0404591c372180bef6c33ea2e5b",
116
116
  "preview/worker-C8-_ANaz.js": "sha256:81099e5732dfe0c32bacd5897316b7956c5a0a22da01b4a0c6e21d0a3b9d9aa1"
117
117
  }
118
118
  }
@@ -10595,6 +10595,316 @@ var CollectionMirror = class extends TopicMirror {
10595
10595
  return this.get()?.get(id);
10596
10596
  }
10597
10597
  };
10598
+ var PrivateState = class {
10599
+ constructor(runtime, source) {
10600
+ this.runtime = runtime;
10601
+ this.source = source;
10602
+ this.reading = null;
10603
+ this.again = false;
10604
+ this.stopSub = null;
10605
+ this.offReconnect = null;
10606
+ this.listeners = /* @__PURE__ */ new Set();
10607
+ this.watching = null;
10608
+ this.whats = new Set(typeof source.what === "string" ? [source.what] : source.what);
10609
+ }
10610
+ /** Subscribes and reads the first value. Idempotent. */
10611
+ start() {
10612
+ if (!this.watching) {
10613
+ this.watching = (async () => {
10614
+ this.offReconnect = this.runtime.onReconnect(() => void this.refresh().catch(() => void 0));
10615
+ this.stopSub = await this.runtime.subscribe(this.source.nodeType, this.source.key, this.source.topic, (p) => this.onPush(p));
10616
+ return this.refresh();
10617
+ })().catch((e) => {
10618
+ this.watching = null;
10619
+ throw e;
10620
+ });
10621
+ }
10622
+ return this.watching;
10623
+ }
10624
+ async stop() {
10625
+ this.offReconnect?.();
10626
+ this.offReconnect = null;
10627
+ const stop = this.stopSub;
10628
+ this.stopSub = null;
10629
+ this.watching = null;
10630
+ await stop?.();
10631
+ }
10632
+ /** Reads the value again (one read at a time; a request during one runs after it). */
10633
+ refresh() {
10634
+ if (this.reading) {
10635
+ this.again = true;
10636
+ return this.reading;
10637
+ }
10638
+ this.reading = (async () => {
10639
+ try {
10640
+ let v;
10641
+ do {
10642
+ this.again = false;
10643
+ v = await this.source.read();
10644
+ } while (this.again);
10645
+ this.value = v;
10646
+ for (const l of [...this.listeners])
10647
+ l(v);
10648
+ return v;
10649
+ } finally {
10650
+ this.reading = null;
10651
+ }
10652
+ })();
10653
+ return this.reading;
10654
+ }
10655
+ get() {
10656
+ return this.value;
10657
+ }
10658
+ subscribe(listener) {
10659
+ this.listeners.add(listener);
10660
+ return () => this.listeners.delete(listener);
10661
+ }
10662
+ onPush(push) {
10663
+ const msg = splitKitMessage(push.value);
10664
+ if (!msg || msg.header.kind !== "changed" || !this.whats.has(msg.body.what))
10665
+ return;
10666
+ const who = Array.isArray(msg.body.who) ? msg.body.who.map(String) : [];
10667
+ void this.runtime.playerId().then((me) => {
10668
+ if (me === null || who.includes(me))
10669
+ void this.refresh().catch(() => void 0);
10670
+ });
10671
+ }
10672
+ };
10673
+
10674
+ var ArenasKit = class {
10675
+ constructor(runtime, nodeType = "arena") {
10676
+ this.runtime = runtime;
10677
+ this.nodeType = nodeType;
10678
+ this.arenas = /* @__PURE__ */ new Map();
10679
+ }
10680
+ arena(key) {
10681
+ let a = this.arenas.get(key);
10682
+ if (!a) {
10683
+ a = new ArenaMatch(this.runtime, this.nodeType, key);
10684
+ this.arenas.set(key, a);
10685
+ }
10686
+ return a;
10687
+ }
10688
+ };
10689
+ var ArenaMatch = class {
10690
+ constructor(runtime, nodeType, key) {
10691
+ this.runtime = runtime;
10692
+ this.nodeType = nodeType;
10693
+ this.key = key;
10694
+ this.view = new HubState(runtime, nodeType, key, "arena");
10695
+ }
10696
+ watch() {
10697
+ return this.view.start();
10698
+ }
10699
+ unwatch() {
10700
+ return this.view.stop();
10701
+ }
10702
+ /** Joins as `heroClass` (the starter's are `warrior` and `mage`). @throws {KitError} `bad_request`, `full`, `started`. */
10703
+ join(heroClass) {
10704
+ return this.runtime.call(this.nodeType, this.key, "join", { class: heroClass }, { action: true });
10705
+ }
10706
+ leave() {
10707
+ return this.runtime.call(this.nodeType, this.key, "leave", null, { action: true });
10708
+ }
10709
+ /** The first to join, or a developer. @throws {KitError} `forbidden`, `not_ready` (one fighter), `started`. */
10710
+ start() {
10711
+ return this.runtime.call(this.nodeType, this.key, "start", null, { action: true });
10712
+ }
10713
+ /**
10714
+ * Reports where the player is; resolves with the position the hub kept (a move too fast is cut
10715
+ * short, a jump refused). Not sent with an action id: the next report replaces it.
10716
+ * @throws {KitError} `forbidden` (removed for movement the warden refused), `conflict` (down).
10717
+ */
10718
+ move(x, z) {
10719
+ return this.runtime.call(this.nodeType, this.key, "move", { x, z });
10720
+ }
10721
+ /**
10722
+ * Casts `ability` aimed at `(x, z)`; resolves with whether a hit-scan strike hit someone at once
10723
+ * (a projectile or an area lands later, as an `impact` event).
10724
+ * @throws {KitError} `cooldown`, `insufficient` (resource), `out_of_reach`, `not_found` (not the class's).
10725
+ */
10726
+ cast(ability, x, z) {
10727
+ return this.runtime.call(this.nodeType, this.key, "cast", { ability, x, z }, { action: true });
10728
+ }
10729
+ };
10730
+
10731
+ var EncountersKit = class {
10732
+ constructor(runtime, nodeType = "director") {
10733
+ this.runtime = runtime;
10734
+ this.nodeType = nodeType;
10735
+ this.encounters = /* @__PURE__ */ new Map();
10736
+ }
10737
+ encounter(key) {
10738
+ let e = this.encounters.get(key);
10739
+ if (!e) {
10740
+ e = new Encounter(this.runtime, this.nodeType, key);
10741
+ this.encounters.set(key, e);
10742
+ }
10743
+ return e;
10744
+ }
10745
+ };
10746
+ var Encounter = class {
10747
+ constructor(runtime, nodeType, key) {
10748
+ this.runtime = runtime;
10749
+ this.nodeType = nodeType;
10750
+ this.key = key;
10751
+ this.view = new HubState(runtime, nodeType, key, "encounter");
10752
+ }
10753
+ watch() {
10754
+ return this.view.start();
10755
+ }
10756
+ unwatch() {
10757
+ return this.view.stop();
10758
+ }
10759
+ /** @throws {KitError} `full`. */
10760
+ join() {
10761
+ return this.runtime.call(this.nodeType, this.key, "join", null, { action: true });
10762
+ }
10763
+ /** The first to join, or a developer. @throws {KitError} `forbidden`, `started`, `bad_request` (no way to the base). */
10764
+ start() {
10765
+ return this.runtime.call(this.nodeType, this.key, "start", null, { action: true });
10766
+ }
10767
+ /**
10768
+ * Builds a tower at `(x, z)`; resolves with the gold left.
10769
+ * @throws {KitError} `blocks_lane`, `insufficient` (gold), `conflict` (taken), `bad_request`, `not_member`.
10770
+ */
10771
+ build(x, z) {
10772
+ return this.runtime.call(this.nodeType, this.key, "build", { x, z }, { action: true });
10773
+ }
10774
+ /** Strikes enemy `enemy`; resolves with its hp left. @throws {KitError} `cooldown`, `not_found`, `not_member`. */
10775
+ hit(enemy) {
10776
+ return this.runtime.call(this.nodeType, this.key, "hit", { enemy }, { action: true });
10777
+ }
10778
+ };
10779
+
10780
+ var InstancesKit = class {
10781
+ constructor(runtime, nodeType = "instance") {
10782
+ this.runtime = runtime;
10783
+ this.nodeType = nodeType;
10784
+ this.runs = /* @__PURE__ */ new Map();
10785
+ }
10786
+ /** The run with key `key` (a key the game makes up, one per run). */
10787
+ run(key) {
10788
+ let r = this.runs.get(key);
10789
+ if (!r) {
10790
+ r = new InstanceRun(this.runtime, this.nodeType, key);
10791
+ this.runs.set(key, r);
10792
+ }
10793
+ return r;
10794
+ }
10795
+ };
10796
+ var InstanceRun = class {
10797
+ constructor(runtime, nodeType, key) {
10798
+ this.runtime = runtime;
10799
+ this.nodeType = nodeType;
10800
+ this.key = key;
10801
+ this.view = new HubState(runtime, nodeType, key, "run");
10802
+ }
10803
+ watch() {
10804
+ return this.view.start();
10805
+ }
10806
+ unwatch() {
10807
+ return this.view.stop();
10808
+ }
10809
+ /**
10810
+ * Opens the run as its owner (a developer kit opens one for `party`); resolves with its seed.
10811
+ * @throws {KitError} `started`, `bad_request` (party size), `conflict` (its grid could not be reserved).
10812
+ */
10813
+ open(options = {}) {
10814
+ const args = {};
10815
+ if (options.seed !== void 0)
10816
+ args.seed = options.seed;
10817
+ if (options.party?.length)
10818
+ args.party = options.party.map(Number);
10819
+ return this.runtime.call(this.nodeType, this.key, "open", args, { action: true });
10820
+ }
10821
+ /** The owner invites a player. @throws {KitError} `forbidden`, `full`. */
10822
+ invite(player) {
10823
+ return this.runtime.call(this.nodeType, this.key, "invite", { player: Number(player) }, { action: true });
10824
+ }
10825
+ /** An invited player joins. @throws {KitError} `forbidden`. */
10826
+ join() {
10827
+ return this.runtime.call(this.nodeType, this.key, "join", null, { action: true });
10828
+ }
10829
+ /**
10830
+ * Resolves the room the party is at; resolves with what happened, as the log has it.
10831
+ * @throws {KitError} `not_member`, `forbidden` (the caller is down), `conflict` (descend first), `finished`.
10832
+ */
10833
+ enter() {
10834
+ return this.runtime.call(this.nodeType, this.key, "enter", null, { action: true });
10835
+ }
10836
+ /** The owner leads the party to the next floor; resolves with it. @throws {KitError} `not_ready` (rooms left), `forbidden`. */
10837
+ descend() {
10838
+ return this.runtime.call(this.nodeType, this.key, "descend", null, { action: true });
10839
+ }
10840
+ /** The owner (or a developer) ends the run. */
10841
+ abandon() {
10842
+ return this.runtime.call(this.nodeType, this.key, "abandon", null, { action: true });
10843
+ }
10844
+ };
10845
+
10846
+ var LeaderboardsKit = class {
10847
+ constructor(runtime, nodeType = "leaderboard") {
10848
+ this.runtime = runtime;
10849
+ this.nodeType = nodeType;
10850
+ this.boards = /* @__PURE__ */ new Map();
10851
+ }
10852
+ /** The board named `name` (`weekly-score`, `fastest-lap`, ...). */
10853
+ board(name) {
10854
+ let b = this.boards.get(name);
10855
+ if (!b) {
10856
+ b = new LeaderboardHandle(this.runtime, this.nodeType, name);
10857
+ this.boards.set(name, b);
10858
+ }
10859
+ return b;
10860
+ }
10861
+ };
10862
+ var LeaderboardHandle = class {
10863
+ constructor(runtime, nodeType, name) {
10864
+ this.runtime = runtime;
10865
+ this.nodeType = nodeType;
10866
+ this.name = name;
10867
+ this.view = new HubState(runtime, nodeType, name, "board");
10868
+ }
10869
+ watch() {
10870
+ return this.view.start();
10871
+ }
10872
+ unwatch() {
10873
+ return this.view.stop();
10874
+ }
10875
+ /** A page of the board, best first. */
10876
+ top(options = {}) {
10877
+ return this.runtime.call(this.nodeType, this.name, "top", options);
10878
+ }
10879
+ /** The places around a player (the caller's own, without `player`). */
10880
+ around(options = {}) {
10881
+ const args = {};
10882
+ if (options.player !== void 0)
10883
+ args.player = Number(options.player);
10884
+ if (options.radius !== void 0)
10885
+ args.radius = options.radius;
10886
+ return this.runtime.call(this.nodeType, this.name, "around", args);
10887
+ }
10888
+ /** The caller's own place, or null without a score this season. */
10889
+ me() {
10890
+ return this.runtime.call(this.nodeType, this.name, "me");
10891
+ }
10892
+ season() {
10893
+ return this.runtime.call(this.nodeType, this.name, "season");
10894
+ }
10895
+ /** Submits a score for `player`. Developers only (a developer kit); players are refused. */
10896
+ submit(player, score) {
10897
+ return this.runtime.call(this.nodeType, this.name, "submit", { player: Number(player), score }, { action: true });
10898
+ }
10899
+ /** Sets the board's config. Developers only. */
10900
+ configure(config) {
10901
+ return this.runtime.call(this.nodeType, this.name, "configure", config, { action: true });
10902
+ }
10903
+ /** Ends the season now; resolves with the new season. Developers only. */
10904
+ roll() {
10905
+ return this.runtime.call(this.nodeType, this.name, "roll", null, { action: true });
10906
+ }
10907
+ };
10598
10908
 
10599
10909
  var WritableKitStore = class {
10600
10910
  constructor(initial) {
@@ -10721,6 +11031,55 @@ var MatchQueue = class {
10721
11031
  }
10722
11032
  };
10723
11033
 
11034
+ var MinigamesKit = class {
11035
+ constructor(runtime, nodeType = "minigame") {
11036
+ this.runtime = runtime;
11037
+ this.nodeType = nodeType;
11038
+ this.duels = /* @__PURE__ */ new Map();
11039
+ }
11040
+ duel(key) {
11041
+ let d = this.duels.get(key);
11042
+ if (!d) {
11043
+ d = new Duel(this.runtime, this.nodeType, key);
11044
+ this.duels.set(key, d);
11045
+ }
11046
+ return d;
11047
+ }
11048
+ };
11049
+ var Duel = class {
11050
+ constructor(runtime, nodeType, key) {
11051
+ this.runtime = runtime;
11052
+ this.nodeType = nodeType;
11053
+ this.key = key;
11054
+ this.view = new HubState(runtime, nodeType, key, "duel");
11055
+ }
11056
+ watch() {
11057
+ return this.view.start();
11058
+ }
11059
+ unwatch() {
11060
+ return this.view.stop();
11061
+ }
11062
+ /** Takes a seat; resolves with whether this seat started the first round. @throws {KitError} `full`. */
11063
+ join() {
11064
+ return this.runtime.call(this.nodeType, this.key, "join", null, { action: true });
11065
+ }
11066
+ /** Before the duel starts. @throws {KitError} `started`. */
11067
+ leave() {
11068
+ return this.runtime.call(this.nodeType, this.key, "leave", null, { action: true });
11069
+ }
11070
+ /**
11071
+ * The caller's hidden throw this round; resolves with whether it completed the round.
11072
+ * @throws {KitError} `conflict` (already in, or no round open), `bad_request` (not a hand), `not_member`.
11073
+ */
11074
+ throw(hand) {
11075
+ return this.runtime.call(this.nodeType, this.key, "throw", { hand }, { action: true });
11076
+ }
11077
+ /** Once it is over: play again. @throws {KitError} `conflict`, `not_member`. */
11078
+ rematch() {
11079
+ return this.runtime.call(this.nodeType, this.key, "rematch", null, { action: true });
11080
+ }
11081
+ };
11082
+
10724
11083
  var NpcsKit = class {
10725
11084
  constructor(runtime, options = {}) {
10726
11085
  this.runtime = runtime;
@@ -10921,6 +11280,105 @@ var EmotesKit = class {
10921
11280
  }
10922
11281
  };
10923
11282
 
11283
+ var RacingKit = class {
11284
+ constructor(runtime, raceType = "race", ballType = "ball") {
11285
+ this.runtime = runtime;
11286
+ this.raceType = raceType;
11287
+ this.ballType = ballType;
11288
+ this.races = /* @__PURE__ */ new Map();
11289
+ this.matches = /* @__PURE__ */ new Map();
11290
+ }
11291
+ /** The race with key `key`. */
11292
+ race(key) {
11293
+ let r = this.races.get(key);
11294
+ if (!r) {
11295
+ r = new Race(this.runtime, this.raceType, key);
11296
+ this.races.set(key, r);
11297
+ }
11298
+ return r;
11299
+ }
11300
+ /** The ball game with key `key`. */
11301
+ ball(key) {
11302
+ let m = this.matches.get(key);
11303
+ if (!m) {
11304
+ m = new BallMatch(this.runtime, this.ballType, key);
11305
+ this.matches.set(key, m);
11306
+ }
11307
+ return m;
11308
+ }
11309
+ };
11310
+ var Race = class {
11311
+ constructor(runtime, nodeType, key) {
11312
+ this.runtime = runtime;
11313
+ this.nodeType = nodeType;
11314
+ this.key = key;
11315
+ this.view = new HubState(runtime, nodeType, key, "race");
11316
+ }
11317
+ watch() {
11318
+ return this.view.start();
11319
+ }
11320
+ unwatch() {
11321
+ return this.view.stop();
11322
+ }
11323
+ /** @throws {KitError} `started`, `full`. */
11324
+ join() {
11325
+ return this.runtime.call(this.nodeType, this.key, "join", null, { action: true });
11326
+ }
11327
+ leave() {
11328
+ return this.runtime.call(this.nodeType, this.key, "leave", null, { action: true });
11329
+ }
11330
+ /** Starts the countdown (the first to join, or a developer). @throws {KitError} `forbidden`, `started`. */
11331
+ start() {
11332
+ return this.runtime.call(this.nodeType, this.key, "start", null, { action: true });
11333
+ }
11334
+ /** Reports where the racer is; resolves with the position the hub kept. */
11335
+ pos(x, z) {
11336
+ return this.runtime.call(this.nodeType, this.key, "pos", { x, z });
11337
+ }
11338
+ /** The winner's run, once there is one. */
11339
+ ghost() {
11340
+ return this.runtime.call(this.nodeType, this.key, "ghost");
11341
+ }
11342
+ };
11343
+ var BallMatch = class {
11344
+ constructor(runtime, nodeType, key) {
11345
+ this.runtime = runtime;
11346
+ this.nodeType = nodeType;
11347
+ this.key = key;
11348
+ this.view = new HubState(runtime, nodeType, key, "ball");
11349
+ }
11350
+ watch() {
11351
+ return this.view.start();
11352
+ }
11353
+ unwatch() {
11354
+ return this.view.stop();
11355
+ }
11356
+ /** @throws {KitError} `bad_request` (red or blue), `full`, `started`. */
11357
+ join(team) {
11358
+ return this.runtime.call(this.nodeType, this.key, "join", { team }, { action: true });
11359
+ }
11360
+ /** @throws {KitError} `forbidden`, `not_ready` (each team needs a player), `started`. */
11361
+ start() {
11362
+ return this.runtime.call(this.nodeType, this.key, "start", null, { action: true });
11363
+ }
11364
+ /** Reports where the player is; resolves with the position the hub kept. */
11365
+ pos(x, z) {
11366
+ return this.runtime.call(this.nodeType, this.key, "pos", { x, z });
11367
+ }
11368
+ /** Claims the ball. @throws {KitError} `out_of_reach`, `cooldown` (too soon, or its holder's protection), `conflict` (a teammate has it). */
11369
+ claim() {
11370
+ return this.runtime.call(this.nodeType, this.key, "claim", null, { action: true });
11371
+ }
11372
+ /** Passes to a teammate. @throws {KitError} `conflict` (not the holder), `bad_request` (not a teammate). */
11373
+ pass(to) {
11374
+ return this.runtime.call(this.nodeType, this.key, "pass", { to: Number(to) }, { action: true });
11375
+ }
11376
+ /** Shoots toward `(x, z)`. @throws {KitError} `conflict` (not the holder). */
11377
+ shoot(x, z) {
11378
+ return this.runtime.call(this.nodeType, this.key, "shoot", { x, z }, { action: true });
11379
+ }
11380
+ };
11381
+
10924
11382
  var SessionsKit = class {
10925
11383
  constructor(runtime, options = {}) {
10926
11384
  this.runtime = runtime;
@@ -10998,6 +11456,206 @@ var GameSessionHandle = class {
10998
11456
  }
10999
11457
  };
11000
11458
 
11459
+ var TablesKit = class {
11460
+ constructor(runtime, nodeType = "deck") {
11461
+ this.runtime = runtime;
11462
+ this.nodeType = nodeType;
11463
+ this.tables = /* @__PURE__ */ new Map();
11464
+ }
11465
+ table(key) {
11466
+ let t = this.tables.get(key);
11467
+ if (!t) {
11468
+ t = new CardTable(this.runtime, this.nodeType, key);
11469
+ this.tables.set(key, t);
11470
+ }
11471
+ return t;
11472
+ }
11473
+ };
11474
+ var CardTable = class {
11475
+ constructor(runtime, nodeType, key) {
11476
+ this.runtime = runtime;
11477
+ this.nodeType = nodeType;
11478
+ this.key = key;
11479
+ this.table = new HubState(runtime, nodeType, key, "table");
11480
+ this.hand = new PrivateState(runtime, {
11481
+ nodeType,
11482
+ key,
11483
+ topic: "table",
11484
+ what: "hand",
11485
+ read: () => runtime.call(nodeType, key, "hand")
11486
+ });
11487
+ }
11488
+ /** Mirrors the table and the caller's hand. */
11489
+ async watch() {
11490
+ const [view] = await Promise.all([this.table.start(), this.hand.start()]);
11491
+ return view;
11492
+ }
11493
+ async unwatch() {
11494
+ await Promise.all([this.table.stop(), this.hand.stop()]);
11495
+ }
11496
+ /** @throws {KitError} `started`, `full`. */
11497
+ join() {
11498
+ return this.runtime.call(this.nodeType, this.key, "join", null, { action: true });
11499
+ }
11500
+ leave() {
11501
+ return this.runtime.call(this.nodeType, this.key, "leave", null, { action: true });
11502
+ }
11503
+ /** Deals (the host, from two players). @throws {KitError} `forbidden`, `too_few_players`, `started`. */
11504
+ start() {
11505
+ return this.runtime.call(this.nodeType, this.key, "start", null, { action: true });
11506
+ }
11507
+ /**
11508
+ * Plays a card from the caller's hand; an eight names `suit` (`S`, `H`, `D` or `C`).
11509
+ * @throws {KitError} `not_your_turn`, `not_found` (not in the hand), `not_playable` (the rule),
11510
+ * `bad_request` (an eight without a suit).
11511
+ */
11512
+ play(card, suit) {
11513
+ const args = suit === void 0 ? { card } : { card, suit };
11514
+ return this.runtime.call(this.nodeType, this.key, "play", args, { action: true });
11515
+ }
11516
+ /** Draws a card (once a turn). @throws {KitError} `not_your_turn`, `conflict`, `empty`. */
11517
+ draw() {
11518
+ return this.runtime.call(this.nodeType, this.key, "draw", null, { action: true });
11519
+ }
11520
+ /** Passes, after drawing. @throws {KitError} `conflict` (draw first). */
11521
+ pass() {
11522
+ return this.runtime.call(this.nodeType, this.key, "pass", null, { action: true });
11523
+ }
11524
+ };
11525
+
11526
+ var TacticsKit = class {
11527
+ constructor(runtime, nodeType = "tactics") {
11528
+ this.runtime = runtime;
11529
+ this.nodeType = nodeType;
11530
+ this.battles = /* @__PURE__ */ new Map();
11531
+ }
11532
+ battle(key) {
11533
+ let b = this.battles.get(key);
11534
+ if (!b) {
11535
+ b = new TacticsBattle(this.runtime, this.nodeType, key);
11536
+ this.battles.set(key, b);
11537
+ }
11538
+ return b;
11539
+ }
11540
+ };
11541
+ var TacticsBattle = class {
11542
+ constructor(runtime, nodeType, key) {
11543
+ this.runtime = runtime;
11544
+ this.nodeType = nodeType;
11545
+ this.key = key;
11546
+ this.battle = new HubState(runtime, nodeType, key, "battle");
11547
+ }
11548
+ watch() {
11549
+ return this.battle.start();
11550
+ }
11551
+ unwatch() {
11552
+ return this.battle.stop();
11553
+ }
11554
+ /** The player's units, as the mirror last saw them. */
11555
+ async myUnits() {
11556
+ const me = await this.runtime.playerId();
11557
+ return (this.battle.get()?.units ?? []).filter((u) => me !== null && String(u.owner) === me);
11558
+ }
11559
+ /** @throws {KitError} `started`, `full`. */
11560
+ join() {
11561
+ return this.runtime.call(this.nodeType, this.key, "join", null, { action: true });
11562
+ }
11563
+ /** @throws {KitError} `forbidden` (the host starts it), `started`. */
11564
+ start() {
11565
+ return this.runtime.call(this.nodeType, this.key, "start", null, { action: true });
11566
+ }
11567
+ /**
11568
+ * Moves the player's unit to `(x, z)`.
11569
+ * @throws {KitError} `not_your_turn`, `conflict` (it moved), `out_of_reach`, `not_member`.
11570
+ */
11571
+ move(x, z) {
11572
+ return this.runtime.call(this.nodeType, this.key, "move", { x, z }, { action: true });
11573
+ }
11574
+ /**
11575
+ * Attacks unit `target` with the player's unit.
11576
+ * @throws {KitError} `not_your_turn`, `conflict` (it attacked), `out_of_reach`, `forbidden` (its own side), `not_found`.
11577
+ */
11578
+ attack(target) {
11579
+ return this.runtime.call(this.nodeType, this.key, "attack", { target }, { action: true });
11580
+ }
11581
+ /** Ends the player's turn this phase. */
11582
+ endTurn() {
11583
+ return this.runtime.call(this.nodeType, this.key, "end_turn", null, { action: true });
11584
+ }
11585
+ };
11586
+
11587
+ var TerritoryKit = class {
11588
+ constructor(runtime, territoryType = "territory", zoneType = "zone") {
11589
+ this.runtime = runtime;
11590
+ this.territoryType = territoryType;
11591
+ this.zoneType = zoneType;
11592
+ this.maps = /* @__PURE__ */ new Map();
11593
+ this.zones = /* @__PURE__ */ new Map();
11594
+ }
11595
+ /** The war on map `key`. */
11596
+ map(key) {
11597
+ let m = this.maps.get(key);
11598
+ if (!m) {
11599
+ m = new TerritoryMap(this.runtime, this.territoryType, key);
11600
+ this.maps.set(key, m);
11601
+ }
11602
+ return m;
11603
+ }
11604
+ /** The circle of match `key`. */
11605
+ zone(key) {
11606
+ let z = this.zones.get(key);
11607
+ if (!z) {
11608
+ z = new ZoneMatch(this.runtime, this.zoneType, key);
11609
+ this.zones.set(key, z);
11610
+ }
11611
+ return z;
11612
+ }
11613
+ };
11614
+ var TerritoryMap = class {
11615
+ constructor(runtime, nodeType, key) {
11616
+ this.runtime = runtime;
11617
+ this.nodeType = nodeType;
11618
+ this.key = key;
11619
+ this.view = new HubState(runtime, nodeType, key, "territory");
11620
+ }
11621
+ watch() {
11622
+ return this.view.start();
11623
+ }
11624
+ unwatch() {
11625
+ return this.view.stop();
11626
+ }
11627
+ /** Joins a faction, once: a player keeps theirs. @throws {KitError} `conflict`, `bad_request`, `full`. */
11628
+ join(faction) {
11629
+ return this.runtime.call(this.nodeType, this.key, "join", { faction }, { action: true });
11630
+ }
11631
+ /** A new war. Developers only. */
11632
+ reset() {
11633
+ return this.runtime.call(this.nodeType, this.key, "reset", null, { action: true });
11634
+ }
11635
+ };
11636
+ var ZoneMatch = class {
11637
+ constructor(runtime, nodeType, key) {
11638
+ this.runtime = runtime;
11639
+ this.nodeType = nodeType;
11640
+ this.key = key;
11641
+ this.view = new HubState(runtime, nodeType, key, "zone");
11642
+ }
11643
+ watch() {
11644
+ return this.view.start();
11645
+ }
11646
+ unwatch() {
11647
+ return this.view.stop();
11648
+ }
11649
+ /** @throws {KitError} `started`, `full`. */
11650
+ join() {
11651
+ return this.runtime.call(this.nodeType, this.key, "join", null, { action: true });
11652
+ }
11653
+ /** The first to join, or a developer. @throws {KitError} `forbidden`, `not_ready`, `started`. */
11654
+ start() {
11655
+ return this.runtime.call(this.nodeType, this.key, "start", null, { action: true });
11656
+ }
11657
+ };
11658
+
11001
11659
  var WorldKit = class {
11002
11660
  constructor(runtime, options = {}) {
11003
11661
  this.runtime = runtime;
@@ -11578,6 +12236,15 @@ var GameKitClient = class {
11578
12236
  this.spectateKit = null;
11579
12237
  this.emotesKit = null;
11580
12238
  this.shardKit = null;
12239
+ this.leaderboardsKit = null;
12240
+ this.tablesKit = null;
12241
+ this.tacticsKit = null;
12242
+ this.encountersKit = null;
12243
+ this.minigamesKit = null;
12244
+ this.instancesKit = null;
12245
+ this.arenasKit = null;
12246
+ this.racingKit = null;
12247
+ this.territoryKit = null;
11581
12248
  this.social = new SocialKit(appId, domains.teams, domains.channels, domains.udp, gameApps, options.social);
11582
12249
  this.runtime = new KitRuntime(String(appId), domains.exec, options, domains.whoAmI);
11583
12250
  }
@@ -11601,6 +12268,42 @@ var GameKitClient = class {
11601
12268
  const opts = { nodeType: this.options.nodes?.npcs, areaSize: this.options.areaSize };
11602
12269
  return this.npcsKit ?? (this.npcsKit = new NpcsKit(this.runtime, opts));
11603
12270
  }
12271
+ /** Leaderboards the hubs rank (a client never submits its own score). */
12272
+ get leaderboards() {
12273
+ return this.leaderboardsKit ?? (this.leaderboardsKit = new LeaderboardsKit(this.runtime, this.options.nodes?.leaderboard));
12274
+ }
12275
+ /** Card tables with hidden hands the hub holds. */
12276
+ get tables() {
12277
+ return this.tablesKit ?? (this.tablesKit = new TablesKit(this.runtime, this.options.nodes?.deck));
12278
+ }
12279
+ /** Grid battles in turns, against the hub's units. */
12280
+ get tactics() {
12281
+ return this.tacticsKit ?? (this.tacticsKit = new TacticsKit(this.runtime, this.options.nodes?.tactics));
12282
+ }
12283
+ /** Encounters: waves down a lane, towers, a boss with phases. */
12284
+ get encounters() {
12285
+ return this.encountersKit ?? (this.encountersKit = new EncountersKit(this.runtime, this.options.nodes?.director));
12286
+ }
12287
+ /** Duels of hidden throws, revealed together. */
12288
+ get minigames() {
12289
+ return this.minigamesKit ?? (this.minigamesKit = new MinigamesKit(this.runtime, this.options.nodes?.minigame));
12290
+ }
12291
+ /** Private runs for one party: seeded floors, permadeath, expiry. */
12292
+ get instances() {
12293
+ return this.instancesKit ?? (this.instancesKit = new InstancesKit(this.runtime, this.options.nodes?.instance));
12294
+ }
12295
+ /** Real-time arenas: classes, abilities, the hub's referee. */
12296
+ get arenas() {
12297
+ return this.arenasKit ?? (this.arenasKit = new ArenasKit(this.runtime, this.options.nodes?.arena));
12298
+ }
12299
+ /** Races and ball games, on positions the hub's warden keeps. */
12300
+ get racing() {
12301
+ return this.racingKit ?? (this.racingKit = new RacingKit(this.runtime, this.options.nodes?.race, this.options.nodes?.ball));
12302
+ }
12303
+ /** Control points factions capture, and shrinking circles. */
12304
+ get territory() {
12305
+ return this.territoryKit ?? (this.territoryKit = new TerritoryKit(this.runtime, this.options.nodes?.territory, this.options.nodes?.zone));
12306
+ }
11604
12307
  /** Composing and deploying the app's tree of starter hubs (developers). */
11605
12308
  get topology() {
11606
12309
  return this.topologyKit ?? (this.topologyKit = new KitTopology(String(this.appId), this.domains.exec));
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@crowdedkingdoms/crowdyjs",
3
- "version": "18.11.0-dev.1",
3
+ "version": "18.12.0-dev.1",
4
4
  "source": "node_modules"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdedkingdoms/crowdy-dsh",
3
- "version": "0.4.7-dev.1",
3
+ "version": "0.4.8-dev.1",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -94,11 +94,11 @@
94
94
  "crowdyDsh": {
95
95
  "build": {
96
96
  "package": "@crowdedkingdoms/crowdy-dsh",
97
- "version": "0.4.7",
98
- "builtAt": "2026-10-15T20:11:28.339Z",
97
+ "version": "0.4.8",
98
+ "builtAt": "2026-10-15T22:43:35.458Z",
99
99
  "source": {
100
100
  "repository": "CrowdedKingdoms/crowdy-dsh",
101
- "commit": "5809199d9f08d3adcef9fa0cb25ecb2694c41caf",
101
+ "commit": "6be157fc87333ca64a2688d5e2ab77c9e57101dc",
102
102
  "dirty": false
103
103
  },
104
104
  "upstream": {
@@ -109,7 +109,7 @@
109
109
  },
110
110
  "crowdyjs": {
111
111
  "name": "@crowdedkingdoms/crowdyjs",
112
- "version": "18.11.0-dev.1",
112
+ "version": "18.12.0-dev.1",
113
113
  "source": "node_modules"
114
114
  },
115
115
  "files": {
@@ -206,7 +206,7 @@
206
206
  "manifest.webmanifest": "sha256:9b54d57eea00f2fdd1affe6e7999a4209a515755f12ac1a3299da2d55e178d4c",
207
207
  "preview/bootstrap-CYECZNXt.js": "sha256:9f303a0485c0badfdd19fad0c357ef050c5b9a343744ab5bf0c70015e7d95092",
208
208
  "preview/crowdy-boot-Cklh1qNl.js": "sha256:b21e8eb126e1cd8a52159d2d577e610df6c8af36a436f9ed5028cfabd11a85ff",
209
- "preview/vfs-image.tar.gz": "sha256:a399e9c5b46f89f6aad3eab2a9b97bc18acdbd6450bcb0abd754efafaeae00b5",
209
+ "preview/vfs-image.tar.gz": "sha256:95c3425e186deba4ce4355980db01d6451cca0404591c372180bef6c33ea2e5b",
210
210
  "preview/worker-C8-_ANaz.js": "sha256:81099e5732dfe0c32bacd5897316b7956c5a0a22da01b4a0c6e21d0a3b9d9aa1"
211
211
  }
212
212
  }