@crowdedkingdoms/crowdyjs 8.2.0 → 8.3.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.
Files changed (102) hide show
  1. package/README.md +21 -3
  2. package/dist/crowdy-client.d.ts.map +1 -1
  3. package/dist/crowdy-client.js +5 -1
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -2
  7. package/dist/kit/blueprints/combat.d.ts +75 -0
  8. package/dist/kit/blueprints/combat.d.ts.map +1 -0
  9. package/dist/kit/blueprints/combat.js +351 -0
  10. package/dist/kit/blueprints/core.d.ts +222 -0
  11. package/dist/kit/blueprints/core.d.ts.map +1 -0
  12. package/dist/kit/blueprints/core.js +185 -0
  13. package/dist/kit/blueprints/decks.d.ts +50 -0
  14. package/dist/kit/blueprints/decks.d.ts.map +1 -0
  15. package/dist/kit/blueprints/decks.js +163 -0
  16. package/dist/kit/blueprints/economy.d.ts +88 -0
  17. package/dist/kit/blueprints/economy.d.ts.map +1 -0
  18. package/dist/kit/blueprints/economy.js +533 -0
  19. package/dist/kit/blueprints/guild.d.ts +51 -0
  20. package/dist/kit/blueprints/guild.d.ts.map +1 -0
  21. package/dist/kit/blueprints/guild.js +50 -0
  22. package/dist/kit/blueprints/index.d.ts +21 -0
  23. package/dist/kit/blueprints/index.d.ts.map +1 -0
  24. package/dist/kit/blueprints/index.js +20 -0
  25. package/dist/kit/blueprints/inventory.d.ts +38 -0
  26. package/dist/kit/blueprints/inventory.d.ts.map +1 -0
  27. package/dist/kit/blueprints/inventory.js +157 -0
  28. package/dist/kit/blueprints/leaderboards.d.ts +49 -0
  29. package/dist/kit/blueprints/leaderboards.d.ts.map +1 -0
  30. package/dist/kit/blueprints/leaderboards.js +126 -0
  31. package/dist/kit/blueprints/locks.d.ts +82 -0
  32. package/dist/kit/blueprints/locks.d.ts.map +1 -0
  33. package/dist/kit/blueprints/locks.js +155 -0
  34. package/dist/kit/blueprints/loot.d.ts +84 -0
  35. package/dist/kit/blueprints/loot.d.ts.map +1 -0
  36. package/dist/kit/blueprints/loot.js +228 -0
  37. package/dist/kit/blueprints/matches.d.ts +59 -0
  38. package/dist/kit/blueprints/matches.d.ts.map +1 -0
  39. package/dist/kit/blueprints/matches.js +246 -0
  40. package/dist/kit/blueprints/npcs.d.ts +71 -0
  41. package/dist/kit/blueprints/npcs.d.ts.map +1 -0
  42. package/dist/kit/blueprints/npcs.js +122 -0
  43. package/dist/kit/blueprints/plots.d.ts +54 -0
  44. package/dist/kit/blueprints/plots.d.ts.map +1 -0
  45. package/dist/kit/blueprints/plots.js +146 -0
  46. package/dist/kit/blueprints/progression.d.ts +68 -0
  47. package/dist/kit/blueprints/progression.d.ts.map +1 -0
  48. package/dist/kit/blueprints/progression.js +324 -0
  49. package/dist/kit/blueprints/quests.d.ts +65 -0
  50. package/dist/kit/blueprints/quests.d.ts.map +1 -0
  51. package/dist/kit/blueprints/quests.js +284 -0
  52. package/dist/kit/blueprints/worldsim.d.ts +84 -0
  53. package/dist/kit/blueprints/worldsim.d.ts.map +1 -0
  54. package/dist/kit/blueprints/worldsim.js +461 -0
  55. package/dist/kit/combat.d.ts +103 -0
  56. package/dist/kit/combat.d.ts.map +1 -0
  57. package/dist/kit/combat.js +151 -0
  58. package/dist/kit/decks.d.ts +123 -0
  59. package/dist/kit/decks.d.ts.map +1 -0
  60. package/dist/kit/decks.js +138 -0
  61. package/dist/kit/economy.d.ts +244 -0
  62. package/dist/kit/economy.d.ts.map +1 -0
  63. package/dist/kit/economy.js +365 -0
  64. package/dist/kit/features.d.ts +60 -0
  65. package/dist/kit/features.d.ts.map +1 -0
  66. package/dist/kit/features.js +65 -0
  67. package/dist/kit/index.d.ts +13 -2
  68. package/dist/kit/index.d.ts.map +1 -1
  69. package/dist/kit/index.js +12 -1
  70. package/dist/kit/inventory.d.ts +5 -0
  71. package/dist/kit/inventory.d.ts.map +1 -1
  72. package/dist/kit/inventory.js +14 -1
  73. package/dist/kit/kit.d.ts +58 -2
  74. package/dist/kit/kit.d.ts.map +1 -1
  75. package/dist/kit/kit.js +24 -2
  76. package/dist/kit/leaderboards.d.ts +66 -0
  77. package/dist/kit/leaderboards.d.ts.map +1 -0
  78. package/dist/kit/leaderboards.js +94 -0
  79. package/dist/kit/loot.d.ts +106 -0
  80. package/dist/kit/loot.d.ts.map +1 -0
  81. package/dist/kit/loot.js +120 -0
  82. package/dist/kit/matches.d.ts +140 -0
  83. package/dist/kit/matches.d.ts.map +1 -0
  84. package/dist/kit/matches.js +253 -0
  85. package/dist/kit/objects.js +1 -1
  86. package/dist/kit/plots.js +1 -1
  87. package/dist/kit/progression.d.ts +181 -0
  88. package/dist/kit/progression.d.ts.map +1 -0
  89. package/dist/kit/progression.js +265 -0
  90. package/dist/kit/quests.d.ts +110 -0
  91. package/dist/kit/quests.d.ts.map +1 -0
  92. package/dist/kit/quests.js +158 -0
  93. package/dist/kit/social.d.ts +267 -0
  94. package/dist/kit/social.d.ts.map +1 -0
  95. package/dist/kit/social.js +230 -0
  96. package/dist/kit/worldsim.d.ts +225 -0
  97. package/dist/kit/worldsim.d.ts.map +1 -0
  98. package/dist/kit/worldsim.js +231 -0
  99. package/package.json +1 -1
  100. package/dist/kit/blueprints.d.ts +0 -370
  101. package/dist/kit/blueprints.d.ts.map +0 -1
  102. package/dist/kit/blueprints.js +0 -643
@@ -0,0 +1,151 @@
1
+ import { combatNames } from './blueprints/index.js';
2
+ import { kitContainerProperties, kitInvoke, } from './shared.js';
3
+ /**
4
+ * Runtime helpers for the {@link combatBlueprint} conventions: spawn
5
+ * combatants, attack (server-side damage formula + death flip), arm status
6
+ * effects the tick automation applies over time, respawn, and — with
7
+ * `hostSynced` — persist host-simulated hp. Denials resolve with
8
+ * `success: false`.
9
+ *
10
+ * Obtained via `client.kit(appId).combat`.
11
+ */
12
+ export class CombatKit {
13
+ constructor(appId, gameModel, options = {}) {
14
+ this.appId = appId;
15
+ this.gameModel = gameModel;
16
+ this.names = combatNames(options.typePrefix ?? '');
17
+ }
18
+ /**
19
+ * Spawn a combatant with a unique `combat_key` (the status-effect join
20
+ * key) and the `owner_user_id` mirror.
21
+ */
22
+ async spawnCombatant(input) {
23
+ const combatKey = input.combatKey ?? `ck-${input.ownerUserId}-${Math.random().toString(16).slice(2, 10)}`;
24
+ const maxHp = input.maxHp ?? 100;
25
+ return this.gameModel.createContainer({
26
+ appId: this.appId,
27
+ typeName: this.names.combatantType,
28
+ displayName: input.displayName,
29
+ ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),
30
+ properties: [
31
+ { key: 'owner_user_id', valueType: 'int', valueJson: String(input.ownerUserId) },
32
+ { key: 'combat_key', valueType: 'string', valueJson: JSON.stringify(combatKey) },
33
+ { key: 'hp', valueType: 'int', valueJson: String(input.hp ?? maxHp) },
34
+ { key: 'max_hp', valueType: 'int', valueJson: String(maxHp) },
35
+ { key: 'attack', valueType: 'int', valueJson: String(input.attack ?? 10) },
36
+ { key: 'defense', valueType: 'int', valueJson: String(input.defense ?? 0) },
37
+ ...(input.properties ?? []),
38
+ ],
39
+ });
40
+ }
41
+ /** Read one combatant's state. */
42
+ async state(combatantId) {
43
+ const container = await this.gameModel.container({
44
+ appId: this.appId,
45
+ containerId: combatantId,
46
+ });
47
+ const props = await kitContainerProperties(this.gameModel, String(this.appId), combatantId);
48
+ return {
49
+ containerId: container.containerId,
50
+ displayName: container.displayName,
51
+ ownerUserId: container.ownerUserId != null ? String(container.ownerUserId) : null,
52
+ combatKey: String(props.combat_key ?? ''),
53
+ hp: Number(props.hp ?? 0),
54
+ maxHp: Number(props.max_hp ?? 0),
55
+ attack: Number(props.attack ?? 0),
56
+ defense: Number(props.defense ?? 0),
57
+ alive: props.alive === true,
58
+ };
59
+ }
60
+ /**
61
+ * Attack a target with your combatant. The damage formula and the death
62
+ * flip run server-side. Resolves with the target's remaining hp.
63
+ */
64
+ async attack(attackerId, targetId) {
65
+ return kitInvoke(this.gameModel, {
66
+ appId: String(this.appId),
67
+ functionName: this.names.attackFn,
68
+ selfContainerId: attackerId,
69
+ params: { target_id: targetId },
70
+ });
71
+ }
72
+ /**
73
+ * Arm a status effect against a target's `combat_key`: creates the
74
+ * caller's StatusEffect container (when `effectContainerId` is omitted)
75
+ * and invokes the gated apply function; the interval automation then
76
+ * ticks it server-side.
77
+ */
78
+ async applyEffect(input) {
79
+ let effectId = input.effectContainerId;
80
+ if (!effectId) {
81
+ const created = await this.gameModel.createContainer({
82
+ appId: this.appId,
83
+ typeName: this.names.effectType,
84
+ displayName: `Effect ${input.effectId}`,
85
+ ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),
86
+ });
87
+ effectId = created.containerId;
88
+ }
89
+ return kitInvoke(this.gameModel, {
90
+ appId: String(this.appId),
91
+ functionName: this.names.applyEffectFn,
92
+ selfContainerId: effectId,
93
+ params: {
94
+ target_key: input.targetKey,
95
+ effect_id: input.effectId,
96
+ magnitude: input.magnitude,
97
+ ticks: input.ticks,
98
+ },
99
+ });
100
+ }
101
+ /** List the active status effects targeting a combat_key. */
102
+ async effects(targetKey) {
103
+ const containers = await this.gameModel.containers({
104
+ appId: this.appId,
105
+ typeName: this.names.effectType,
106
+ });
107
+ const all = await Promise.all(containers.map(async (c) => {
108
+ const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
109
+ return {
110
+ containerId: c.containerId,
111
+ displayName: c.displayName,
112
+ ownerUserId: c.ownerUserId != null ? String(c.ownerUserId) : null,
113
+ effectId: String(props.effect_id ?? ''),
114
+ targetKey: String(props.target_key ?? ''),
115
+ magnitude: Number(props.magnitude ?? 0),
116
+ ticksLeft: Number(props.ticks_left ?? 0),
117
+ };
118
+ }));
119
+ return all.filter((e) => e.ticksLeft > 0 && (targetKey === undefined || e.targetKey === targetKey));
120
+ }
121
+ /** Respawn your downed combatant at full hp. */
122
+ async respawn(combatantId) {
123
+ return kitInvoke(this.gameModel, {
124
+ appId: String(this.appId),
125
+ functionName: this.names.respawnFn,
126
+ selfContainerId: combatantId,
127
+ params: {},
128
+ });
129
+ }
130
+ /** Revive a downed combatant (blueprint deployed with `reviveGroup`). */
131
+ async revive(combatantId) {
132
+ return kitInvoke(this.gameModel, {
133
+ appId: String(this.appId),
134
+ functionName: this.names.reviveFn,
135
+ selfContainerId: combatantId,
136
+ params: {},
137
+ });
138
+ }
139
+ /**
140
+ * Persist host-simulated hp (blueprint deployed with `hostSynced: true`;
141
+ * `is_host` enforced server-side). Resolves with the clamped hp.
142
+ */
143
+ async syncCombatant(combatantId, hp) {
144
+ return kitInvoke(this.gameModel, {
145
+ appId: String(this.appId),
146
+ functionName: this.names.syncFn,
147
+ selfContainerId: combatantId,
148
+ params: { hp },
149
+ });
150
+ }
151
+ }
@@ -0,0 +1,123 @@
1
+ import type { GameModelAPI } from '../domains/gameModel.js';
2
+ import type { Scalars } from '../generated/graphql.js';
3
+ import { type KitInvokeResult } from './shared.js';
4
+ /** Options for {@link DecksKit}. Must match the deployed decks blueprint. */
5
+ export interface DecksKitOptions {
6
+ /** The `typePrefix` the decks blueprint was deployed with. */
7
+ typePrefix?: string;
8
+ }
9
+ /** A parsed view of one card instance, as visible to the CALLER. */
10
+ export interface KitCard {
11
+ containerId: string;
12
+ displayName: string;
13
+ ownerUserId: string | null;
14
+ /**
15
+ * The hidden identity — non-empty only when the caller may see it (their
16
+ * own cards, or any revealed card via `revealedCardId`).
17
+ */
18
+ cardId: string;
19
+ /** The public identity (empty until played/discarded). */
20
+ revealedCardId: string;
21
+ zone: string;
22
+ position: number;
23
+ }
24
+ /**
25
+ * Runtime helpers for the {@link decksBlueprint} conventions: deal
26
+ * session-scoped cards, shuffle by dealing random positions (admin-run
27
+ * automation), and draw/play/discard through the zone-guarded functions.
28
+ * Hidden information is enforced by property visibility server-side: reads
29
+ * go through `containerState`, which strips other players' `card_id`.
30
+ *
31
+ * Obtained via `client.kit(appId).decks`.
32
+ */
33
+ export declare class DecksKit {
34
+ private readonly appId;
35
+ private readonly gameModel;
36
+ private readonly names;
37
+ constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: DecksKitOptions);
38
+ /**
39
+ * Deal a deck to a player: creates one CardInstance per card id (zone
40
+ * `deck`), owned by the player. Run {@link shuffle} afterwards to deal
41
+ * random positions.
42
+ */
43
+ deal(input: {
44
+ ownerUserId: Scalars['BigInt']['input'];
45
+ cardIds: string[];
46
+ sessionId?: string;
47
+ }): Promise<{
48
+ __typename?: "GmContainer";
49
+ containerId: string;
50
+ appId: string;
51
+ sessionId: string | null;
52
+ typeName: string;
53
+ displayName: string;
54
+ description: string | null;
55
+ ownerUserId: string | null;
56
+ metadataJson: string;
57
+ }[]>;
58
+ /**
59
+ * Shuffle every deck-zone card by running the manual `assign_position`
60
+ * automation (admin): each card gets a fresh `rand_int` position
61
+ * server-side.
62
+ */
63
+ shuffle(): Promise<{
64
+ __typename?: "GmAutomationRun";
65
+ runId: string;
66
+ appId: string;
67
+ automationId: string;
68
+ automationName: string;
69
+ triggerSource: string;
70
+ parentRunId: string | null;
71
+ cascadeDepth: number;
72
+ startedAt: string;
73
+ finishedAt: string | null;
74
+ durationUs: number;
75
+ targets: number;
76
+ invocations: number;
77
+ mutations: number;
78
+ fnCalls: number;
79
+ gasUsed: number;
80
+ success: boolean;
81
+ errorMessage: string | null;
82
+ circuitAction: string | null;
83
+ computeUnits: number;
84
+ }>;
85
+ /** A player's cards in one zone, as visible to the caller. */
86
+ cards(ownerUserId: Scalars['BigInt']['input'] | null, options?: {
87
+ zone?: string;
88
+ sessionId?: string;
89
+ }): Promise<KitCard[]>;
90
+ /** Your hand (owner-visible card ids included by the server). */
91
+ myHand(ownerUserId: Scalars['BigInt']['input'], options?: {
92
+ sessionId?: string;
93
+ }): Promise<KitCard[]>;
94
+ /** Every card on the board (public: revealed ids). */
95
+ board(options?: {
96
+ sessionId?: string;
97
+ }): Promise<KitCard[]>;
98
+ /**
99
+ * Draw the top of your deck (lowest position — positions were dealt by
100
+ * the shuffle automation). The server enforces ownership, turn (when
101
+ * `turnBased`), and the deck→hand zone transition.
102
+ */
103
+ draw(ownerUserId: Scalars['BigInt']['input'], options?: {
104
+ sessionId?: string;
105
+ }): Promise<KitInvokeResult<string>>;
106
+ /** Draw one specific deck card (prefer {@link draw} for top-of-deck). */
107
+ drawCard(cardInstanceId: string, options?: {
108
+ sessionId?: string;
109
+ }): Promise<KitInvokeResult<string>>;
110
+ /**
111
+ * Play a card from your hand: the zone flip and the public reveal commit
112
+ * together. Resolves with the revealed card id.
113
+ */
114
+ play(cardInstanceId: string, options?: {
115
+ sessionId?: string;
116
+ }): Promise<KitInvokeResult<string>>;
117
+ /** Discard a card face-up. */
118
+ discard(cardInstanceId: string, options?: {
119
+ sessionId?: string;
120
+ }): Promise<KitInvokeResult<string>>;
121
+ private toCard;
122
+ }
123
+ //# sourceMappingURL=decks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decks.d.ts","sourceRoot":"","sources":["../../src/kit/decks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,oEAAoE;AACpE,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,qBAAa,QAAQ;IAIjB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;gBAGhB,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACxC,OAAO,GAAE,eAAoB;IAK/B;;;;OAIG;IACG,IAAI,CAAC,KAAK,EAAE;QAChB,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;IAwBD;;;;OAIG;IACG,OAAO;;;;;;;;;;;;;;;;;;;;;;IAOb,8DAA8D;IACxD,KAAK,CACT,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,EAC9C,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAClD,OAAO,CAAC,OAAO,EAAE,CAAC;IA2BrB,iEAAiE;IAC3D,MAAM,CACV,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,OAAO,EAAE,CAAC;IAIrB,sDAAsD;IAChD,KAAK,CAAC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAIrE;;;;OAIG;IACG,IAAI,CACR,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IASnC,yEAAyE;IACnE,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAUnC;;;OAGG;IACG,IAAI,CACR,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAUnC,8BAA8B;IACxB,OAAO,CACX,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAUrB,MAAM;CAsBrB"}
@@ -0,0 +1,138 @@
1
+ import { decksNames } from './blueprints/index.js';
2
+ import { kitContainerProperties, kitInvoke, } from './shared.js';
3
+ /**
4
+ * Runtime helpers for the {@link decksBlueprint} conventions: deal
5
+ * session-scoped cards, shuffle by dealing random positions (admin-run
6
+ * automation), and draw/play/discard through the zone-guarded functions.
7
+ * Hidden information is enforced by property visibility server-side: reads
8
+ * go through `containerState`, which strips other players' `card_id`.
9
+ *
10
+ * Obtained via `client.kit(appId).decks`.
11
+ */
12
+ export class DecksKit {
13
+ constructor(appId, gameModel, options = {}) {
14
+ this.appId = appId;
15
+ this.gameModel = gameModel;
16
+ this.names = decksNames(options.typePrefix ?? '');
17
+ }
18
+ /**
19
+ * Deal a deck to a player: creates one CardInstance per card id (zone
20
+ * `deck`), owned by the player. Run {@link shuffle} afterwards to deal
21
+ * random positions.
22
+ */
23
+ async deal(input) {
24
+ const created = [];
25
+ for (const [index, cardId] of input.cardIds.entries()) {
26
+ created.push(await this.gameModel.createContainer({
27
+ appId: this.appId,
28
+ typeName: this.names.cardType,
29
+ displayName: `Card ${index + 1}`,
30
+ ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),
31
+ properties: [
32
+ {
33
+ key: 'owner_user_id',
34
+ valueType: 'int',
35
+ valueJson: String(input.ownerUserId),
36
+ },
37
+ { key: 'card_id', valueType: 'string', valueJson: JSON.stringify(cardId) },
38
+ { key: 'position', valueType: 'int', valueJson: String(index) },
39
+ ],
40
+ }));
41
+ }
42
+ return created;
43
+ }
44
+ /**
45
+ * Shuffle every deck-zone card by running the manual `assign_position`
46
+ * automation (admin): each card gets a fresh `rand_int` position
47
+ * server-side.
48
+ */
49
+ async shuffle() {
50
+ return this.gameModel.runAutomation({
51
+ appId: this.appId,
52
+ name: this.names.shuffleAutomation,
53
+ });
54
+ }
55
+ /** A player's cards in one zone, as visible to the caller. */
56
+ async cards(ownerUserId, options = {}) {
57
+ const containers = await this.gameModel.containers({
58
+ appId: this.appId,
59
+ typeName: this.names.cardType,
60
+ ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
61
+ });
62
+ const filtered = ownerUserId === null
63
+ ? containers
64
+ : containers.filter((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
65
+ const cards = await Promise.all(filtered.map((c) => this.toCard(c.containerId, c.displayName, c.ownerUserId != null ? String(c.ownerUserId) : null)));
66
+ return options.zone !== undefined
67
+ ? cards.filter((c) => c.zone === options.zone)
68
+ : cards;
69
+ }
70
+ /** Your hand (owner-visible card ids included by the server). */
71
+ async myHand(ownerUserId, options = {}) {
72
+ return this.cards(ownerUserId, { ...options, zone: 'hand' });
73
+ }
74
+ /** Every card on the board (public: revealed ids). */
75
+ async board(options = {}) {
76
+ return this.cards(null, { ...options, zone: 'board' });
77
+ }
78
+ /**
79
+ * Draw the top of your deck (lowest position — positions were dealt by
80
+ * the shuffle automation). The server enforces ownership, turn (when
81
+ * `turnBased`), and the deck→hand zone transition.
82
+ */
83
+ async draw(ownerUserId, options = {}) {
84
+ const deck = await this.cards(ownerUserId, { ...options, zone: 'deck' });
85
+ if (deck.length === 0) {
86
+ throw new Error('Deck is empty — nothing to draw');
87
+ }
88
+ const top = deck.reduce((a, b) => (b.position < a.position ? b : a));
89
+ return this.drawCard(top.containerId, options);
90
+ }
91
+ /** Draw one specific deck card (prefer {@link draw} for top-of-deck). */
92
+ async drawCard(cardInstanceId, options = {}) {
93
+ return kitInvoke(this.gameModel, {
94
+ appId: String(this.appId),
95
+ functionName: this.names.drawFn,
96
+ selfContainerId: cardInstanceId,
97
+ ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
98
+ params: {},
99
+ });
100
+ }
101
+ /**
102
+ * Play a card from your hand: the zone flip and the public reveal commit
103
+ * together. Resolves with the revealed card id.
104
+ */
105
+ async play(cardInstanceId, options = {}) {
106
+ return kitInvoke(this.gameModel, {
107
+ appId: String(this.appId),
108
+ functionName: this.names.playFn,
109
+ selfContainerId: cardInstanceId,
110
+ ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
111
+ params: {},
112
+ });
113
+ }
114
+ /** Discard a card face-up. */
115
+ async discard(cardInstanceId, options = {}) {
116
+ return kitInvoke(this.gameModel, {
117
+ appId: String(this.appId),
118
+ functionName: this.names.discardFn,
119
+ selfContainerId: cardInstanceId,
120
+ ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
121
+ params: {},
122
+ });
123
+ }
124
+ async toCard(containerId, displayName, ownerUserId) {
125
+ // containerState filters properties by visibility: other players' hands
126
+ // come back WITHOUT card_id — the hidden-info guarantee is server-side.
127
+ const props = await kitContainerProperties(this.gameModel, String(this.appId), containerId);
128
+ return {
129
+ containerId,
130
+ displayName,
131
+ ownerUserId,
132
+ cardId: String(props.card_id ?? ''),
133
+ revealedCardId: String(props.revealed_card_id ?? ''),
134
+ zone: String(props.zone ?? ''),
135
+ position: Number(props.position ?? 0),
136
+ };
137
+ }
138
+ }
@@ -0,0 +1,244 @@
1
+ import type { GameModelAPI } from '../domains/gameModel.js';
2
+ import type { Scalars, SeedPropertyInput } from '../generated/graphql.js';
3
+ import { type KitInvokeResult } from './shared.js';
4
+ /** Options for {@link EconomyKit}. Must match the deployed economy blueprint. */
5
+ export interface EconomyKitOptions {
6
+ /** The `typePrefix` the economy blueprint was deployed with. */
7
+ typePrefix?: string;
8
+ /** The `currencies` the blueprint was deployed with. Defaults to `['gold']`. */
9
+ currencies?: string[];
10
+ }
11
+ /** A parsed view of one wallet. */
12
+ export interface KitWallet {
13
+ containerId: string;
14
+ displayName: string;
15
+ ownerUserId: string | null;
16
+ /** Balance per currency property. */
17
+ balances: Record<string, number>;
18
+ }
19
+ /** A parsed view of one shop listing. */
20
+ export interface KitShopListing {
21
+ containerId: string;
22
+ displayName: string;
23
+ itemId: string;
24
+ price: number;
25
+ stock: number;
26
+ maxStock: number;
27
+ }
28
+ /** A parsed view of one escrow trade offer. */
29
+ export interface KitTradeOffer {
30
+ containerId: string;
31
+ displayName: string;
32
+ /** The offer creator (server-assigned container owner). */
33
+ fromUserId: string | null;
34
+ toUserId: number;
35
+ giveStackId: string;
36
+ receiveStackId: string;
37
+ giveItemId: string;
38
+ giveQty: number;
39
+ wantItemId: string;
40
+ wantQty: number;
41
+ status: string;
42
+ }
43
+ /** A parsed view of one market listing. */
44
+ export interface KitMarketListing {
45
+ containerId: string;
46
+ displayName: string;
47
+ /** The seller (server-assigned container owner). */
48
+ sellerUserId: string | null;
49
+ stackId: string;
50
+ itemId: string;
51
+ quantity: number;
52
+ price: number;
53
+ active: boolean;
54
+ }
55
+ /**
56
+ * Runtime helpers for the {@link economyBlueprint} conventions: wallets with
57
+ * per-currency balances, shop purchases, escrow trades, and player market
58
+ * listings. Every movement of currency or items is a single gated invoke —
59
+ * balances, stock, item identity, and ownership are all verified
60
+ * server-side, and a denial resolves with `success: false` (never an
61
+ * exception).
62
+ *
63
+ * `earn` is a trusted grant: with the default blueprint authority
64
+ * (`'server'`) it succeeds only for app admins — call it from studio/backend
65
+ * code, or drive grants through automations instead.
66
+ *
67
+ * Obtained via `client.kit(appId).economy`.
68
+ */
69
+ export declare class EconomyKit {
70
+ private readonly appId;
71
+ private readonly gameModel;
72
+ private readonly names;
73
+ private readonly typePrefix;
74
+ private readonly currencies;
75
+ constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: EconomyKitOptions);
76
+ private get defaultCurrency();
77
+ /**
78
+ * Find the player's wallet, creating it when absent (member-instantiable;
79
+ * the server assigns ownership to the caller). Sets the `owner_user_id`
80
+ * mirror property the blueprint's guards read.
81
+ *
82
+ * @param ownerUserId - The calling player's user id (decimal string).
83
+ */
84
+ ensureWallet(ownerUserId: Scalars['BigInt']['input'], options?: {
85
+ displayName?: string;
86
+ sessionId?: string;
87
+ }): Promise<{
88
+ __typename?: "GmContainer";
89
+ containerId: string;
90
+ appId: string;
91
+ sessionId: string | null;
92
+ typeName: string;
93
+ displayName: string;
94
+ description: string | null;
95
+ ownerUserId: string | null;
96
+ metadataJson: string;
97
+ }>;
98
+ /** Read one currency balance (default: the blueprint's first currency). */
99
+ balance(walletId: string, currency?: string): Promise<number>;
100
+ /** Read a wallet with every configured currency balance parsed. */
101
+ wallet(walletId: string): Promise<KitWallet>;
102
+ /**
103
+ * Mint currency into a wallet — a **trusted** grant (default blueprint
104
+ * authority: app admins only). Resolves with the new balance.
105
+ */
106
+ earn(walletId: string, amount: number, currency?: string): Promise<KitInvokeResult<number>>;
107
+ /**
108
+ * Spend currency from the caller's own wallet. The server refuses to
109
+ * overdraw. Resolves with the new balance.
110
+ */
111
+ spend(walletId: string, amount: number, currency?: string): Promise<KitInvokeResult<number>>;
112
+ /** Shop (admin-priced listings; atomic buys). */
113
+ readonly shop: {
114
+ /**
115
+ * Create a shop listing (admin — the type is admin-instantiable).
116
+ * `maxStock` feeds the optional restock automation.
117
+ */
118
+ create: (input: {
119
+ displayName: string;
120
+ itemId: string;
121
+ price: number;
122
+ stock?: number;
123
+ maxStock?: number;
124
+ properties?: SeedPropertyInput[];
125
+ }) => Promise<{
126
+ __typename?: "GmContainer";
127
+ containerId: string;
128
+ appId: string;
129
+ sessionId: string | null;
130
+ typeName: string;
131
+ displayName: string;
132
+ description: string | null;
133
+ ownerUserId: string | null;
134
+ metadataJson: string;
135
+ }>;
136
+ /** List shop listings with parsed state. */
137
+ list: () => Promise<KitShopListing[]>;
138
+ /**
139
+ * Buy one unit: wallet debit + stock decrement + item grant into
140
+ * `toStackId` (a stack of the listed item), all in one transaction.
141
+ * Resolves with the wallet's remaining balance.
142
+ */
143
+ buy: (input: {
144
+ listingId: string;
145
+ walletId: string;
146
+ toStackId: string;
147
+ }) => Promise<KitInvokeResult<number>>;
148
+ };
149
+ /** Escrow trades (player↔player item swaps, atomic on accept). */
150
+ readonly trades: {
151
+ /**
152
+ * Create a trade offer to another player. The stacks named here are the
153
+ * OFFERER's: `giveStackId` is the escrowed source, `receiveStackId`
154
+ * receives the wanted items when the trade is accepted. The offer's
155
+ * container ownership (server-assigned to the caller) is what the accept
156
+ * guards trust — a forged offer over someone else's stacks can never be
157
+ * accepted.
158
+ */
159
+ offer: (input: {
160
+ toUserId: Scalars["BigInt"]["input"];
161
+ giveStackId: string;
162
+ giveItemId: string;
163
+ giveQty: number;
164
+ wantItemId: string;
165
+ wantQty: number;
166
+ receiveStackId: string;
167
+ displayName?: string;
168
+ sessionId?: string;
169
+ }) => Promise<{
170
+ __typename?: "GmContainer";
171
+ containerId: string;
172
+ appId: string;
173
+ sessionId: string | null;
174
+ typeName: string;
175
+ displayName: string;
176
+ description: string | null;
177
+ ownerUserId: string | null;
178
+ metadataJson: string;
179
+ }>;
180
+ /**
181
+ * Accept a trade as the invited player, supplying YOUR two stacks: the
182
+ * one paying the wanted items and the one receiving the given items. The
183
+ * offerer's stacks come from the offer record. All four quantity writes
184
+ * commit atomically or not at all.
185
+ */
186
+ accept: (input: {
187
+ offerId: string;
188
+ wantStackId: string;
189
+ toGiveStackId: string;
190
+ }) => Promise<KitInvokeResult<string>>;
191
+ /** Cancel an open trade (either party may). */
192
+ cancel: (offerId: string) => Promise<KitInvokeResult<string>>;
193
+ /** Read one trade offer with parsed state. */
194
+ get: (offerId: string) => Promise<KitTradeOffer>;
195
+ /** List trades the user created or was invited to (open ones first). */
196
+ listMine: (userId: Scalars["BigInt"]["input"]) => Promise<KitTradeOffer[]>;
197
+ };
198
+ /** Player market (list a stack for currency; atomic purchases). */
199
+ readonly market: {
200
+ /**
201
+ * List items for sale: names YOUR escrowed source stack and the ask
202
+ * price. Payment lands straight in your wallet when someone buys.
203
+ */
204
+ list: (input: {
205
+ stackId: string;
206
+ itemId: string;
207
+ quantity: number;
208
+ price: number;
209
+ displayName?: string;
210
+ sessionId?: string;
211
+ }) => Promise<{
212
+ __typename?: "GmContainer";
213
+ containerId: string;
214
+ appId: string;
215
+ sessionId: string | null;
216
+ typeName: string;
217
+ displayName: string;
218
+ description: string | null;
219
+ ownerUserId: string | null;
220
+ metadataJson: string;
221
+ }>;
222
+ /** Browse market listings (active ones only by default). */
223
+ browse: (options?: {
224
+ includeInactive?: boolean;
225
+ }) => Promise<KitMarketListing[]>;
226
+ /**
227
+ * Buy a market listing: pays the seller's wallet and transfers the items
228
+ * into `toStackId` in one transaction. The seller's wallet and source
229
+ * stack are resolved from the listing. Resolves with the buyer wallet's
230
+ * remaining balance.
231
+ */
232
+ buy: (input: {
233
+ listingId: string;
234
+ walletId: string;
235
+ toStackId: string;
236
+ }) => Promise<KitInvokeResult<number>>;
237
+ /** Take a listing down (seller only). */
238
+ cancel: (listingId: string) => Promise<KitInvokeResult<boolean>>;
239
+ };
240
+ /** Find an existing wallet container id for a user (no creation). */
241
+ private ensureSellerWallet;
242
+ private toTrade;
243
+ }
244
+ //# sourceMappingURL=economy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"economy.d.ts","sourceRoot":"","sources":["../../src/kit/economy.ts"],"names":[],"mappings":"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"}