@crowdedkingdoms/crowdyjs 17.14.0-dev.1 → 18.0.1-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.
Files changed (289) hide show
  1. package/MIGRATION.md +129 -1
  2. package/README.md +97 -164
  3. package/dist/crowdy-client.d.ts +12 -31
  4. package/dist/crowdy-client.d.ts.map +1 -1
  5. package/dist/crowdy-client.js +15 -37
  6. package/dist/crowdy-dsh/bridge.d.ts.map +1 -1
  7. package/dist/crowdy-dsh/bridge.js +3 -6
  8. package/dist/crowdy-studio/controller.d.ts +34 -59
  9. package/dist/crowdy-studio/controller.d.ts.map +1 -1
  10. package/dist/crowdy-studio/controller.js +96 -225
  11. package/dist/crowdy-studio/diagnostics.d.ts +3 -12
  12. package/dist/crowdy-studio/diagnostics.d.ts.map +1 -1
  13. package/dist/crowdy-studio/dom-shell.d.ts +2 -4
  14. package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
  15. package/dist/crowdy-studio/dom-shell.js +16 -49
  16. package/dist/crowdy-studio/embed/hud-layer.d.ts +1 -2
  17. package/dist/crowdy-studio/embed/hud-layer.d.ts.map +1 -1
  18. package/dist/crowdy-studio/embed/panel.d.ts +3 -13
  19. package/dist/crowdy-studio/embed/panel.d.ts.map +1 -1
  20. package/dist/crowdy-studio/embed/panel.js +3 -6
  21. package/dist/crowdy-studio/index.d.ts +1 -3
  22. package/dist/crowdy-studio/index.d.ts.map +1 -1
  23. package/dist/crowdy-studio/index.js +0 -2
  24. package/dist/crowdy-studio/models.d.ts +3 -4
  25. package/dist/crowdy-studio/models.d.ts.map +1 -1
  26. package/dist/crowdy-studio/starter-projects.d.ts +8 -12
  27. package/dist/crowdy-studio/starter-projects.d.ts.map +1 -1
  28. package/dist/crowdy-studio/starter-projects.js +12 -103
  29. package/dist/domains/appAccess.d.ts +14 -1
  30. package/dist/domains/appAccess.d.ts.map +1 -1
  31. package/dist/domains/appAccess.js +37 -1
  32. package/dist/domains/apps.d.ts +1 -10
  33. package/dist/domains/apps.d.ts.map +1 -1
  34. package/dist/domains/apps.js +1 -16
  35. package/dist/domains/host.d.ts +3 -3
  36. package/dist/domains/host.js +3 -3
  37. package/dist/domains/hosting.d.ts +0 -6
  38. package/dist/domains/hosting.d.ts.map +1 -1
  39. package/dist/domains/hosting.js +1 -16
  40. package/dist/domains/marketplace.d.ts +9 -70
  41. package/dist/domains/marketplace.d.ts.map +1 -1
  42. package/dist/domains/marketplace.js +9 -120
  43. package/dist/domains/organizations.d.ts +1 -9
  44. package/dist/domains/organizations.d.ts.map +1 -1
  45. package/dist/domains/organizations.js +1 -15
  46. package/dist/domains/payments.d.ts +5 -48
  47. package/dist/domains/payments.d.ts.map +1 -1
  48. package/dist/domains/payments.js +5 -57
  49. package/dist/domains/playerWallet.d.ts +6 -12
  50. package/dist/domains/playerWallet.d.ts.map +1 -1
  51. package/dist/domains/playerWallet.js +6 -21
  52. package/dist/domains/quotas.d.ts +20 -7
  53. package/dist/domains/quotas.d.ts.map +1 -1
  54. package/dist/domains/quotas.js +15 -6
  55. package/dist/domains/users.d.ts +7 -74
  56. package/dist/domains/users.d.ts.map +1 -1
  57. package/dist/domains/users.js +7 -105
  58. package/dist/errors.d.ts +7 -13
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js +6 -10
  61. package/dist/generated/graphql.d.ts +955 -8272
  62. package/dist/generated/graphql.d.ts.map +1 -1
  63. package/dist/generated/graphql.js +5 -329
  64. package/dist/grid-mods/exec-client-halves.d.ts +19 -3
  65. package/dist/grid-mods/exec-client-halves.d.ts.map +1 -1
  66. package/dist/grid-mods/exec-client-halves.js +17 -2
  67. package/dist/grid-mods/grid-host-calls.d.ts +29 -17
  68. package/dist/grid-mods/grid-host-calls.d.ts.map +1 -1
  69. package/dist/grid-mods/grid-host-calls.js +40 -46
  70. package/dist/grid-mods/mod-runtime.d.ts +18 -11
  71. package/dist/grid-mods/mod-runtime.d.ts.map +1 -1
  72. package/dist/grid-mods/mod-runtime.js +4 -2
  73. package/dist/grid-scope.d.ts +0 -189
  74. package/dist/grid-scope.d.ts.map +1 -1
  75. package/dist/grid-scope.js +0 -70
  76. package/dist/index.d.ts +12 -18
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +10 -16
  79. package/dist/kit/actions.d.ts +5 -9
  80. package/dist/kit/actions.d.ts.map +1 -1
  81. package/dist/kit/actions.js +5 -9
  82. package/dist/kit/index.d.ts +2 -33
  83. package/dist/kit/index.d.ts.map +1 -1
  84. package/dist/kit/index.js +1 -32
  85. package/dist/kit/kit.d.ts +8 -208
  86. package/dist/kit/kit.d.ts.map +1 -1
  87. package/dist/kit/kit.js +5 -163
  88. package/dist/kit/social.d.ts +1 -3
  89. package/dist/kit/social.d.ts.map +1 -1
  90. package/dist/kit/social.js +1 -3
  91. package/dist/kit/wire.d.ts +16 -5
  92. package/dist/kit/wire.d.ts.map +1 -1
  93. package/dist/kit/wire.js +19 -5
  94. package/dist/live-coding/assets/browser-authoring-index.json +1 -1
  95. package/dist/live-coding/assets/manifest.json +1 -1
  96. package/dist/live-coding/browser-authoring-index.generated.d.ts.map +1 -1
  97. package/dist/live-coding/browser-authoring-index.generated.js +1496 -4386
  98. package/dist/live-coding/rust-analysis.d.ts.map +1 -1
  99. package/dist/live-coding/rust-analysis.js +30 -34
  100. package/dist/player-runtime/client-host-calls.d.ts +8 -0
  101. package/dist/player-runtime/client-host-calls.d.ts.map +1 -0
  102. package/dist/player-runtime/client-host-calls.js +28 -0
  103. package/dist/player-runtime/glue-runtime.d.ts +24 -20
  104. package/dist/player-runtime/glue-runtime.d.ts.map +1 -1
  105. package/dist/player-runtime/glue-runtime.js +26 -55
  106. package/dist/player-runtime/glue-sab.d.ts +2 -2
  107. package/dist/player-runtime/glue-sab.js +2 -2
  108. package/dist/player-runtime/player-code-broker.d.ts +70 -43
  109. package/dist/player-runtime/player-code-broker.d.ts.map +1 -1
  110. package/dist/player-runtime/player-code-broker.js +159 -64
  111. package/dist/player-runtime/player-glue-worker.d.ts +8 -9
  112. package/dist/player-runtime/player-glue-worker.d.ts.map +1 -1
  113. package/dist/player-runtime/player-glue-worker.js +26 -11
  114. package/dist/stores/inbox.d.ts +1 -1
  115. package/dist/stores/inbox.d.ts.map +1 -1
  116. package/dist/stores/index.d.ts +0 -11
  117. package/dist/stores/index.d.ts.map +1 -1
  118. package/dist/stores/index.js +0 -4
  119. package/dist/stores/session.d.ts +0 -2
  120. package/dist/stores/session.d.ts.map +1 -1
  121. package/package.json +1 -1
  122. package/dist/crowdy-studio/model-lint-log.d.ts +0 -76
  123. package/dist/crowdy-studio/model-lint-log.d.ts.map +0 -1
  124. package/dist/crowdy-studio/model-lint-log.js +0 -93
  125. package/dist/crowdy-studio/model-lint.d.ts +0 -61
  126. package/dist/crowdy-studio/model-lint.d.ts.map +0 -1
  127. package/dist/crowdy-studio/model-lint.js +0 -45
  128. package/dist/domains/compute.d.ts +0 -208
  129. package/dist/domains/compute.d.ts.map +0 -1
  130. package/dist/domains/compute.js +0 -274
  131. package/dist/domains/controlPlane.d.ts +0 -38
  132. package/dist/domains/controlPlane.d.ts.map +0 -1
  133. package/dist/domains/controlPlane.js +0 -43
  134. package/dist/domains/gameModel.d.ts +0 -1174
  135. package/dist/domains/gameModel.d.ts.map +0 -1
  136. package/dist/domains/gameModel.js +0 -1333
  137. package/dist/domains/playerCompute.d.ts +0 -91
  138. package/dist/domains/playerCompute.d.ts.map +0 -1
  139. package/dist/domains/playerCompute.js +0 -136
  140. package/dist/domains/playerModel.d.ts +0 -20
  141. package/dist/domains/playerModel.d.ts.map +0 -1
  142. package/dist/domains/playerModel.js +0 -54
  143. package/dist/kit/abilities.d.ts +0 -66
  144. package/dist/kit/abilities.d.ts.map +0 -1
  145. package/dist/kit/abilities.js +0 -71
  146. package/dist/kit/blueprints/combat.d.ts +0 -81
  147. package/dist/kit/blueprints/combat.d.ts.map +0 -1
  148. package/dist/kit/blueprints/combat.js +0 -357
  149. package/dist/kit/blueprints/core.d.ts +0 -222
  150. package/dist/kit/blueprints/core.d.ts.map +0 -1
  151. package/dist/kit/blueprints/core.js +0 -185
  152. package/dist/kit/blueprints/decks.d.ts +0 -50
  153. package/dist/kit/blueprints/decks.d.ts.map +0 -1
  154. package/dist/kit/blueprints/decks.js +0 -163
  155. package/dist/kit/blueprints/economy.d.ts +0 -88
  156. package/dist/kit/blueprints/economy.d.ts.map +0 -1
  157. package/dist/kit/blueprints/economy.js +0 -533
  158. package/dist/kit/blueprints/guild.d.ts +0 -51
  159. package/dist/kit/blueprints/guild.d.ts.map +0 -1
  160. package/dist/kit/blueprints/guild.js +0 -50
  161. package/dist/kit/blueprints/index.d.ts +0 -23
  162. package/dist/kit/blueprints/index.d.ts.map +0 -1
  163. package/dist/kit/blueprints/index.js +0 -22
  164. package/dist/kit/blueprints/inventory.d.ts +0 -84
  165. package/dist/kit/blueprints/inventory.d.ts.map +0 -1
  166. package/dist/kit/blueprints/inventory.js +0 -257
  167. package/dist/kit/blueprints/leaderboards.d.ts +0 -49
  168. package/dist/kit/blueprints/leaderboards.d.ts.map +0 -1
  169. package/dist/kit/blueprints/leaderboards.js +0 -126
  170. package/dist/kit/blueprints/liveops.d.ts +0 -42
  171. package/dist/kit/blueprints/liveops.d.ts.map +0 -1
  172. package/dist/kit/blueprints/liveops.js +0 -170
  173. package/dist/kit/blueprints/locks.d.ts +0 -82
  174. package/dist/kit/blueprints/locks.d.ts.map +0 -1
  175. package/dist/kit/blueprints/locks.js +0 -155
  176. package/dist/kit/blueprints/loot.d.ts +0 -90
  177. package/dist/kit/blueprints/loot.d.ts.map +0 -1
  178. package/dist/kit/blueprints/loot.js +0 -229
  179. package/dist/kit/blueprints/matches.d.ts +0 -84
  180. package/dist/kit/blueprints/matches.d.ts.map +0 -1
  181. package/dist/kit/blueprints/matches.js +0 -349
  182. package/dist/kit/blueprints/moderation.d.ts +0 -32
  183. package/dist/kit/blueprints/moderation.d.ts.map +0 -1
  184. package/dist/kit/blueprints/moderation.js +0 -140
  185. package/dist/kit/blueprints/npcs.d.ts +0 -78
  186. package/dist/kit/blueprints/npcs.d.ts.map +0 -1
  187. package/dist/kit/blueprints/npcs.js +0 -125
  188. package/dist/kit/blueprints/plots.d.ts +0 -63
  189. package/dist/kit/blueprints/plots.d.ts.map +0 -1
  190. package/dist/kit/blueprints/plots.js +0 -151
  191. package/dist/kit/blueprints/progression.d.ts +0 -68
  192. package/dist/kit/blueprints/progression.d.ts.map +0 -1
  193. package/dist/kit/blueprints/progression.js +0 -324
  194. package/dist/kit/blueprints/quests.d.ts +0 -72
  195. package/dist/kit/blueprints/quests.d.ts.map +0 -1
  196. package/dist/kit/blueprints/quests.js +0 -285
  197. package/dist/kit/blueprints/worldsim.d.ts +0 -91
  198. package/dist/kit/blueprints/worldsim.d.ts.map +0 -1
  199. package/dist/kit/blueprints/worldsim.js +0 -468
  200. package/dist/kit/combat.d.ts +0 -141
  201. package/dist/kit/combat.d.ts.map +0 -1
  202. package/dist/kit/combat.js +0 -196
  203. package/dist/kit/decks.d.ts +0 -157
  204. package/dist/kit/decks.d.ts.map +0 -1
  205. package/dist/kit/decks.js +0 -186
  206. package/dist/kit/director.d.ts +0 -88
  207. package/dist/kit/director.d.ts.map +0 -1
  208. package/dist/kit/director.js +0 -86
  209. package/dist/kit/economy.d.ts +0 -289
  210. package/dist/kit/economy.d.ts.map +0 -1
  211. package/dist/kit/economy.js +0 -427
  212. package/dist/kit/engine.d.ts +0 -48
  213. package/dist/kit/engine.d.ts.map +0 -1
  214. package/dist/kit/engine.js +0 -113
  215. package/dist/kit/features.d.ts +0 -60
  216. package/dist/kit/features.d.ts.map +0 -1
  217. package/dist/kit/features.js +0 -65
  218. package/dist/kit/instances.d.ts +0 -52
  219. package/dist/kit/instances.d.ts.map +0 -1
  220. package/dist/kit/instances.js +0 -60
  221. package/dist/kit/inventory.d.ts +0 -129
  222. package/dist/kit/inventory.d.ts.map +0 -1
  223. package/dist/kit/inventory.js +0 -200
  224. package/dist/kit/leaderboards.d.ts +0 -86
  225. package/dist/kit/leaderboards.d.ts.map +0 -1
  226. package/dist/kit/leaderboards.js +0 -133
  227. package/dist/kit/liveops.d.ts +0 -112
  228. package/dist/kit/liveops.d.ts.map +0 -1
  229. package/dist/kit/liveops.js +0 -183
  230. package/dist/kit/loot.d.ts +0 -128
  231. package/dist/kit/loot.d.ts.map +0 -1
  232. package/dist/kit/loot.js +0 -160
  233. package/dist/kit/matches.d.ts +0 -301
  234. package/dist/kit/matches.d.ts.map +0 -1
  235. package/dist/kit/matches.js +0 -458
  236. package/dist/kit/matchmaking.d.ts +0 -57
  237. package/dist/kit/matchmaking.d.ts.map +0 -1
  238. package/dist/kit/matchmaking.js +0 -59
  239. package/dist/kit/minigames.d.ts +0 -30
  240. package/dist/kit/minigames.d.ts.map +0 -1
  241. package/dist/kit/minigames.js +0 -38
  242. package/dist/kit/mobs.d.ts +0 -90
  243. package/dist/kit/mobs.d.ts.map +0 -1
  244. package/dist/kit/mobs.js +0 -98
  245. package/dist/kit/moderation.d.ts +0 -73
  246. package/dist/kit/moderation.d.ts.map +0 -1
  247. package/dist/kit/moderation.js +0 -103
  248. package/dist/kit/movement.d.ts +0 -78
  249. package/dist/kit/movement.d.ts.map +0 -1
  250. package/dist/kit/movement.js +0 -103
  251. package/dist/kit/notifications.d.ts +0 -45
  252. package/dist/kit/notifications.d.ts.map +0 -1
  253. package/dist/kit/notifications.js +0 -67
  254. package/dist/kit/npcs.d.ts +0 -226
  255. package/dist/kit/npcs.d.ts.map +0 -1
  256. package/dist/kit/npcs.js +0 -141
  257. package/dist/kit/objects.d.ts +0 -116
  258. package/dist/kit/objects.d.ts.map +0 -1
  259. package/dist/kit/objects.js +0 -119
  260. package/dist/kit/pets.d.ts +0 -85
  261. package/dist/kit/pets.d.ts.map +0 -1
  262. package/dist/kit/pets.js +0 -96
  263. package/dist/kit/plots.d.ts +0 -85
  264. package/dist/kit/plots.d.ts.map +0 -1
  265. package/dist/kit/plots.js +0 -113
  266. package/dist/kit/progression.d.ts +0 -181
  267. package/dist/kit/progression.d.ts.map +0 -1
  268. package/dist/kit/progression.js +0 -265
  269. package/dist/kit/quests.d.ts +0 -171
  270. package/dist/kit/quests.d.ts.map +0 -1
  271. package/dist/kit/quests.js +0 -237
  272. package/dist/kit/racing.d.ts +0 -85
  273. package/dist/kit/racing.d.ts.map +0 -1
  274. package/dist/kit/racing.js +0 -99
  275. package/dist/kit/shared.d.ts +0 -73
  276. package/dist/kit/shared.d.ts.map +0 -1
  277. package/dist/kit/shared.js +0 -101
  278. package/dist/kit/telemetry.d.ts +0 -66
  279. package/dist/kit/telemetry.d.ts.map +0 -1
  280. package/dist/kit/telemetry.js +0 -133
  281. package/dist/kit/territory.d.ts +0 -97
  282. package/dist/kit/territory.d.ts.map +0 -1
  283. package/dist/kit/territory.js +0 -114
  284. package/dist/kit/worldsim.d.ts +0 -263
  285. package/dist/kit/worldsim.d.ts.map +0 -1
  286. package/dist/kit/worldsim.js +0 -268
  287. package/dist/stores/model.d.ts +0 -81
  288. package/dist/stores/model.d.ts.map +0 -1
  289. package/dist/stores/model.js +0 -163
@@ -1,265 +0,0 @@
1
- import { progressionNames, } from './blueprints/index.js';
2
- import { kitContainerProperties, kitInvoke, } from './shared.js';
3
- /**
4
- * Runtime helpers for the {@link progressionBlueprint} conventions: ensure a
5
- * player's `Progress`, grant XP (trusted — app admins by default), buy
6
- * skills against the catalog's costs and prerequisites, unlock threshold
7
- * achievements, and apply match rating results. Everything is
8
- * authority-checked server-side; denials resolve with `success: false`.
9
- *
10
- * Obtained via `client.kit(appId).progression`.
11
- */
12
- export class ProgressionKit {
13
- constructor(appId, gameModel, options = {}) {
14
- this.appId = appId;
15
- this.gameModel = gameModel;
16
- this.names = progressionNames(options.typePrefix ?? '');
17
- }
18
- /**
19
- * Find the player's Progress container, creating it when absent (with the
20
- * `owner_user_id` mirror the guards read).
21
- */
22
- async ensure(ownerUserId, options = {}) {
23
- const existing = await this.gameModel.containers({
24
- appId: this.appId,
25
- typeName: this.names.progressType,
26
- ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
27
- });
28
- const mine = existing.find((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
29
- if (mine)
30
- return mine;
31
- return this.gameModel.createContainer({
32
- appId: this.appId,
33
- typeName: this.names.progressType,
34
- displayName: options.displayName ?? `Progress ${ownerUserId}`,
35
- ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
36
- properties: [
37
- { key: 'owner_user_id', valueType: 'int', valueJson: String(ownerUserId) },
38
- ],
39
- });
40
- }
41
- /** Read one player's progression state. */
42
- async state(progressId) {
43
- const container = await this.gameModel.container({
44
- appId: this.appId,
45
- containerId: progressId,
46
- });
47
- const props = await kitContainerProperties(this.gameModel, String(this.appId), progressId);
48
- return {
49
- containerId: container.containerId,
50
- displayName: container.displayName,
51
- ownerUserId: container.ownerUserId != null ? String(container.ownerUserId) : null,
52
- xp: Number(props.xp ?? 0),
53
- level: Number(props.level ?? 1),
54
- skillPoints: Number(props.skill_points ?? 0),
55
- rating: Number(props.rating ?? 0),
56
- };
57
- }
58
- /**
59
- * Grant XP — a **trusted** call (default blueprint authority: app admins
60
- * via server scope; or drive it from an event automation). Awards skill
61
- * points and levels up when the curve is crossed. Resolves with the new
62
- * level.
63
- */
64
- async grantXp(progressId, amount) {
65
- return kitInvoke(this.gameModel, {
66
- appId: String(this.appId),
67
- functionName: this.names.grantXpFn,
68
- selfContainerId: progressId,
69
- params: { amount },
70
- });
71
- }
72
- /** List the skill catalog (admin-seeded SkillDef containers). */
73
- async skillCatalog() {
74
- const containers = await this.gameModel.containers({
75
- appId: this.appId,
76
- typeName: this.names.skillDefType,
77
- });
78
- return Promise.all(containers.map(async (c) => {
79
- const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
80
- return {
81
- containerId: c.containerId,
82
- displayName: c.displayName,
83
- skillId: String(props.skill_id ?? ''),
84
- cost: Number(props.cost ?? 1),
85
- requiresSkillId: String(props.requires_skill_id ?? ''),
86
- maxRank: Number(props.max_rank ?? 1),
87
- };
88
- }));
89
- }
90
- /** Define a skill (admin — the catalog type is admin-instantiable). */
91
- async defineSkill(input) {
92
- return this.gameModel.createContainer({
93
- appId: this.appId,
94
- typeName: this.names.skillDefType,
95
- displayName: input.displayName ?? `Skill ${input.skillId}`,
96
- properties: [
97
- { key: 'skill_id', valueType: 'string', valueJson: JSON.stringify(input.skillId) },
98
- { key: 'cost', valueType: 'int', valueJson: String(input.cost ?? 1) },
99
- {
100
- key: 'requires_skill_id',
101
- valueType: 'string',
102
- valueJson: JSON.stringify(input.requiresSkillId ?? ''),
103
- },
104
- { key: 'max_rank', valueType: 'int', valueJson: String(input.maxRank ?? 1) },
105
- ...(input.properties ?? []),
106
- ],
107
- });
108
- }
109
- /**
110
- * Find-or-create the caller's SkillRank row for a skill (rank 0 until
111
- * bought).
112
- */
113
- async ensureSkillRank(ownerUserId, skillId, options = {}) {
114
- const mine = await this.skills(ownerUserId);
115
- const existing = mine.find((s) => s.skillId === skillId);
116
- if (existing) {
117
- return this.gameModel.container({
118
- appId: this.appId,
119
- containerId: existing.containerId,
120
- });
121
- }
122
- return this.gameModel.createContainer({
123
- appId: this.appId,
124
- typeName: this.names.skillRankType,
125
- displayName: options.displayName ?? `Skill ${skillId} ${ownerUserId}`,
126
- properties: [
127
- { key: 'owner_user_id', valueType: 'int', valueJson: String(ownerUserId) },
128
- { key: 'skill_id', valueType: 'string', valueJson: JSON.stringify(skillId) },
129
- ],
130
- });
131
- }
132
- /**
133
- * Buy one rank of a skill. `prereqRankId` is the caller's SkillRank for
134
- * the prerequisite skill; omit it for skills without one (the rank row
135
- * itself is passed to satisfy the required param — the condition ignores
136
- * it when the def declares no prerequisite).
137
- */
138
- async buySkill(input) {
139
- return kitInvoke(this.gameModel, {
140
- appId: String(this.appId),
141
- functionName: this.names.buySkillFn,
142
- selfContainerId: input.skillRankId,
143
- params: {
144
- progress_id: input.progressId,
145
- def_id: input.skillDefId,
146
- prereq_id: input.prereqRankId ?? input.skillRankId,
147
- },
148
- });
149
- }
150
- /** List a player's skill ranks. */
151
- async skills(ownerUserId) {
152
- const containers = await this.gameModel.containers({
153
- appId: this.appId,
154
- typeName: this.names.skillRankType,
155
- });
156
- const mine = containers.filter((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
157
- return Promise.all(mine.map(async (c) => {
158
- const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
159
- return {
160
- containerId: c.containerId,
161
- displayName: c.displayName,
162
- ownerUserId: c.ownerUserId != null ? String(c.ownerUserId) : null,
163
- skillId: String(props.skill_id ?? ''),
164
- rank: Number(props.rank ?? 0),
165
- };
166
- }));
167
- }
168
- /** List the achievement catalog (admin-seeded AchievementDef containers). */
169
- async achievementCatalog() {
170
- const containers = await this.gameModel.containers({
171
- appId: this.appId,
172
- typeName: this.names.achievementDefType,
173
- });
174
- return Promise.all(containers.map(async (c) => {
175
- const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
176
- return {
177
- containerId: c.containerId,
178
- displayName: c.displayName,
179
- achievementId: String(props.achievement_id ?? ''),
180
- threshold: Number(props.threshold ?? 0),
181
- };
182
- }));
183
- }
184
- /** Define an achievement (admin). */
185
- async defineAchievement(input) {
186
- return this.gameModel.createContainer({
187
- appId: this.appId,
188
- typeName: this.names.achievementDefType,
189
- displayName: input.displayName ?? `Achievement ${input.achievementId}`,
190
- properties: [
191
- {
192
- key: 'achievement_id',
193
- valueType: 'string',
194
- valueJson: JSON.stringify(input.achievementId),
195
- },
196
- { key: 'threshold', valueType: 'int', valueJson: String(input.threshold) },
197
- ],
198
- });
199
- }
200
- /** List a player's achievement unlocks. */
201
- async achievements(ownerUserId) {
202
- const containers = await this.gameModel.containers({
203
- appId: this.appId,
204
- typeName: this.names.achievementUnlockType,
205
- });
206
- const mine = containers.filter((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
207
- return Promise.all(mine.map(async (c) => {
208
- const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
209
- return {
210
- containerId: c.containerId,
211
- displayName: c.displayName,
212
- ownerUserId: c.ownerUserId != null ? String(c.ownerUserId) : null,
213
- achievementId: String(props.achievement_id ?? ''),
214
- unlocked: props.unlocked === true,
215
- };
216
- }));
217
- }
218
- /**
219
- * Unlock an achievement once its xp threshold is met. Creates the caller's
220
- * unlock row when absent, then invokes the gated function (idempotent).
221
- */
222
- async unlockAchievement(input) {
223
- const mine = await this.achievements(input.ownerUserId);
224
- let unlockId = mine.find((a) => a.achievementId === input.achievementId)?.containerId;
225
- if (!unlockId) {
226
- const created = await this.gameModel.createContainer({
227
- appId: this.appId,
228
- typeName: this.names.achievementUnlockType,
229
- displayName: `Achievement ${input.achievementId} ${input.ownerUserId}`,
230
- properties: [
231
- {
232
- key: 'owner_user_id',
233
- valueType: 'int',
234
- valueJson: String(input.ownerUserId),
235
- },
236
- {
237
- key: 'achievement_id',
238
- valueType: 'string',
239
- valueJson: JSON.stringify(input.achievementId),
240
- },
241
- ],
242
- });
243
- unlockId = created.containerId;
244
- }
245
- return kitInvoke(this.gameModel, {
246
- appId: String(this.appId),
247
- functionName: this.names.unlockAchievementFn,
248
- selfContainerId: unlockId,
249
- params: { progress_id: input.progressId, def_id: input.achievementDefId },
250
- });
251
- }
252
- /**
253
- * Apply a match result as a rating delta (trusted — host-gated by
254
- * default; `kit.matches` computes the delta). Resolves with the new
255
- * rating.
256
- */
257
- async applyMatchResult(progressId, delta) {
258
- return kitInvoke(this.gameModel, {
259
- appId: String(this.appId),
260
- functionName: this.names.adjustRatingFn,
261
- selfContainerId: progressId,
262
- params: { delta },
263
- });
264
- }
265
- }
@@ -1,171 +0,0 @@
1
- import type { GameModelAPI } from '../domains/gameModel.js';
2
- import type { Scalars, SeedPropertyInput } from '../generated/graphql.js';
3
- import { type KitOwnerIdKind } from './blueprints/index.js';
4
- import { type KitInvokeResult } from './shared.js';
5
- /** Options for {@link QuestsKit}. Must match the deployed quests blueprint. */
6
- export interface QuestsKitOptions {
7
- /** The `typePrefix` the quests blueprint was deployed with. */
8
- typePrefix?: string;
9
- /** Must match questsBlueprint.ownerIdKind. Defaults to `int`. */
10
- ownerIdKind?: KitOwnerIdKind;
11
- }
12
- /** A parsed view of one quest catalog row. */
13
- export interface KitQuestDef {
14
- containerId: string;
15
- displayName: string;
16
- questId: string;
17
- targetCount: number;
18
- rewardItemId: string;
19
- rewardQty: number;
20
- rewardGold: number;
21
- repeatable: boolean;
22
- daily: boolean;
23
- }
24
- /** A parsed view of one player's quest progress. */
25
- export interface KitQuestProgress {
26
- containerId: string;
27
- displayName: string;
28
- ownerUserId: string | null;
29
- questId: string;
30
- count: number;
31
- target: number;
32
- completed: boolean;
33
- claimed: boolean;
34
- daily: boolean;
35
- }
36
- /**
37
- * Runtime helpers for the {@link questsBlueprint} conventions: browse the
38
- * quest catalog, accept quests into per-player progress rows, advance them
39
- * (trusted — app admins or event automations), and claim rewards atomically
40
- * into a stack + wallet. Denials resolve with `success: false`.
41
- *
42
- * Obtained via `client.kit(appId).quests`.
43
- */
44
- export declare class QuestsKit {
45
- private readonly appId;
46
- private readonly gameModel;
47
- private readonly names;
48
- private readonly ownerIdKind;
49
- constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: QuestsKitOptions);
50
- /** List the quest catalog (admin-seeded QuestDef containers). */
51
- catalog(): Promise<KitQuestDef[]>;
52
- /** Define a quest (admin — the catalog type is admin-instantiable). */
53
- defineQuest(input: {
54
- questId: string;
55
- targetCount?: number;
56
- rewardItemId?: string;
57
- rewardQty?: number;
58
- rewardGold?: number;
59
- repeatable?: boolean;
60
- daily?: boolean;
61
- displayName?: string;
62
- properties?: SeedPropertyInput[];
63
- }): Promise<{
64
- __typename?: "GmContainer";
65
- containerId: string;
66
- appId: string;
67
- sessionId: string | null;
68
- typeName: string;
69
- displayName: string;
70
- description: string | null;
71
- ownerUserId: string | null;
72
- metadataJson: string;
73
- }>;
74
- /**
75
- * Accept a quest: creates the caller's progress row seeded from the def
76
- * (target and daily flag copied at accept time).
77
- */
78
- accept(ownerUserId: Scalars['BigInt']['input'], questDefId: string, options?: {
79
- displayName?: string;
80
- sessionId?: string;
81
- }): Promise<{
82
- __typename?: "GmContainer";
83
- containerId: string;
84
- appId: string;
85
- sessionId: string | null;
86
- typeName: string;
87
- displayName: string;
88
- description: string | null;
89
- ownerUserId: string | null;
90
- metadataJson: string;
91
- }>;
92
- /** List a player's quest progress rows. */
93
- mine(ownerUserId: Scalars['BigInt']['input']): Promise<KitQuestProgress[]>;
94
- /**
95
- * STUDIO (admin) — define an ordered tutorial chain as quest defs. Steps
96
- * are plain quests whose `questId` encodes the chain + index
97
- * (`"<chain>:<i>"`), so no new server surface is involved: the sequencing
98
- * is a read-side convention enforced by {@link tutorial} /
99
- * {@link acceptNextTutorialStep} (a step is `locked` until every earlier
100
- * step completes).
101
- */
102
- defineTutorial(input: {
103
- /** Chain id (one app can ship several tutorials). Defaults to `'ftue'`. */
104
- chain?: string;
105
- steps: Array<{
106
- displayName: string;
107
- targetCount?: number;
108
- rewardItemId?: string;
109
- rewardQty?: number;
110
- rewardGold?: number;
111
- }>;
112
- }): Promise<{
113
- __typename?: "GmContainer";
114
- containerId: string;
115
- appId: string;
116
- sessionId: string | null;
117
- typeName: string;
118
- displayName: string;
119
- description: string | null;
120
- ownerUserId: string | null;
121
- metadataJson: string;
122
- }[]>;
123
- /** One tutorial step joined with the player's progress. */
124
- /**
125
- * A player's view of a tutorial chain: steps in order, each `locked`
126
- * (an earlier step is incomplete), `active` (the first incomplete step),
127
- * or `complete`. The client shows/drives only the `active` step; the
128
- * trusted advance authority is unchanged (players still cannot complete
129
- * their own quests).
130
- */
131
- tutorial(ownerUserId: Scalars['BigInt']['input'], chain?: string): Promise<Array<{
132
- stepIndex: number;
133
- def: KitQuestDef;
134
- progress: KitQuestProgress | null;
135
- status: 'locked' | 'active' | 'complete';
136
- }>>;
137
- /**
138
- * Ensure the player's ACTIVE tutorial step has a progress row (accepting
139
- * it when missing) and return the step. Returns null when the chain is
140
- * complete. Calling this for a locked step is impossible by construction —
141
- * it always targets the first incomplete step.
142
- */
143
- acceptNextTutorialStep(ownerUserId: Scalars['BigInt']['input'], chain?: string, options?: {
144
- sessionId?: string;
145
- }): Promise<{
146
- stepIndex: number;
147
- def: KitQuestDef;
148
- progress: KitQuestProgress | null;
149
- status: "locked" | "active" | "complete";
150
- } | null>;
151
- /** Read one progress row. */
152
- state(progressId: string): Promise<KitQuestProgress>;
153
- /**
154
- * Advance quest progress — a **trusted** call (default blueprint
155
- * authority: app admins; or wire `advanceOn` event automations). Resolves
156
- * with the new count.
157
- */
158
- advance(progressId: string, amount?: number): Promise<KitInvokeResult<number>>;
159
- /**
160
- * Turn in a completed quest: marks it claimed AND grants the item +
161
- * currency rewards in one transaction. Resolves with the wallet's new
162
- * balance.
163
- */
164
- claim(input: {
165
- progressId: string;
166
- questDefId: string;
167
- toStackId: string;
168
- walletId: string;
169
- }): Promise<KitInvokeResult<number>>;
170
- }
171
- //# sourceMappingURL=quests.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"quests.d.ts","sourceRoot":"","sources":["../../src/kit/quests.ts"],"names":[],"mappings":"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"}
@@ -1,237 +0,0 @@
1
- import { questsNames, } from './blueprints/index.js';
2
- import { kitContainerProperties, kitInvoke, } from './shared.js';
3
- /**
4
- * Runtime helpers for the {@link questsBlueprint} conventions: browse the
5
- * quest catalog, accept quests into per-player progress rows, advance them
6
- * (trusted — app admins or event automations), and claim rewards atomically
7
- * into a stack + wallet. Denials resolve with `success: false`.
8
- *
9
- * Obtained via `client.kit(appId).quests`.
10
- */
11
- export class QuestsKit {
12
- constructor(appId, gameModel, options = {}) {
13
- this.appId = appId;
14
- this.gameModel = gameModel;
15
- this.names = questsNames(options.typePrefix ?? '');
16
- this.ownerIdKind = options.ownerIdKind ?? 'int';
17
- }
18
- /** List the quest catalog (admin-seeded QuestDef containers). */
19
- async catalog() {
20
- const containers = await this.gameModel.containers({
21
- appId: this.appId,
22
- typeName: this.names.defType,
23
- });
24
- return Promise.all(containers.map(async (c) => {
25
- const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
26
- return {
27
- containerId: c.containerId,
28
- displayName: c.displayName,
29
- questId: String(props.quest_id ?? ''),
30
- targetCount: Number(props.target_count ?? 1),
31
- rewardItemId: String(props.reward_item_id ?? ''),
32
- rewardQty: Number(props.reward_qty ?? 0),
33
- rewardGold: Number(props.reward_gold ?? 0),
34
- repeatable: props.repeatable === true,
35
- daily: props.daily === true,
36
- };
37
- }));
38
- }
39
- /** Define a quest (admin — the catalog type is admin-instantiable). */
40
- async defineQuest(input) {
41
- return this.gameModel.createContainer({
42
- appId: this.appId,
43
- typeName: this.names.defType,
44
- displayName: input.displayName ?? `Quest ${input.questId}`,
45
- properties: [
46
- { key: 'quest_id', valueType: 'string', valueJson: JSON.stringify(input.questId) },
47
- {
48
- key: 'target_count',
49
- valueType: 'int',
50
- valueJson: String(input.targetCount ?? 1),
51
- },
52
- {
53
- key: 'reward_item_id',
54
- valueType: 'string',
55
- valueJson: JSON.stringify(input.rewardItemId ?? ''),
56
- },
57
- { key: 'reward_qty', valueType: 'int', valueJson: String(input.rewardQty ?? 0) },
58
- {
59
- key: 'reward_gold',
60
- valueType: 'int',
61
- valueJson: String(input.rewardGold ?? 0),
62
- },
63
- {
64
- key: 'repeatable',
65
- valueType: 'bool',
66
- valueJson: String(input.repeatable ?? false),
67
- },
68
- { key: 'daily', valueType: 'bool', valueJson: String(input.daily ?? false) },
69
- ...(input.properties ?? []),
70
- ],
71
- });
72
- }
73
- /**
74
- * Accept a quest: creates the caller's progress row seeded from the def
75
- * (target and daily flag copied at accept time).
76
- */
77
- async accept(ownerUserId, questDefId, options = {}) {
78
- const props = await kitContainerProperties(this.gameModel, String(this.appId), questDefId);
79
- const questId = String(props.quest_id ?? '');
80
- return this.gameModel.createContainer({
81
- appId: this.appId,
82
- typeName: this.names.progressType,
83
- displayName: options.displayName ?? `Quest ${questId} ${ownerUserId}`,
84
- ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
85
- properties: [
86
- {
87
- key: 'owner_user_id',
88
- valueType: this.ownerIdKind,
89
- valueJson: this.ownerIdKind === 'string'
90
- ? JSON.stringify(String(ownerUserId))
91
- : String(ownerUserId),
92
- },
93
- { key: 'quest_id', valueType: 'string', valueJson: JSON.stringify(questId) },
94
- {
95
- key: 'target',
96
- valueType: 'int',
97
- valueJson: String(Number(props.target_count ?? 1)),
98
- },
99
- {
100
- key: 'daily',
101
- valueType: 'bool',
102
- valueJson: String(props.daily === true),
103
- },
104
- ],
105
- });
106
- }
107
- /** List a player's quest progress rows. */
108
- async mine(ownerUserId) {
109
- const containers = await this.gameModel.containers({
110
- appId: this.appId,
111
- typeName: this.names.progressType,
112
- });
113
- const mine = containers.filter((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
114
- return Promise.all(mine.map((c) => this.state(c.containerId)));
115
- }
116
- // -- FTUE / tutorial step sequencing (Wave 2) -----------------------------
117
- /**
118
- * STUDIO (admin) — define an ordered tutorial chain as quest defs. Steps
119
- * are plain quests whose `questId` encodes the chain + index
120
- * (`"<chain>:<i>"`), so no new server surface is involved: the sequencing
121
- * is a read-side convention enforced by {@link tutorial} /
122
- * {@link acceptNextTutorialStep} (a step is `locked` until every earlier
123
- * step completes).
124
- */
125
- async defineTutorial(input) {
126
- const chain = input.chain ?? 'ftue';
127
- const created = [];
128
- for (const [index, step] of input.steps.entries()) {
129
- created.push(await this.defineQuest({
130
- questId: `${chain}:${index}`,
131
- displayName: step.displayName,
132
- targetCount: step.targetCount ?? 1,
133
- rewardItemId: step.rewardItemId,
134
- rewardQty: step.rewardQty,
135
- rewardGold: step.rewardGold,
136
- }));
137
- }
138
- return created;
139
- }
140
- /** One tutorial step joined with the player's progress. */
141
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- documented shape
142
- /**
143
- * A player's view of a tutorial chain: steps in order, each `locked`
144
- * (an earlier step is incomplete), `active` (the first incomplete step),
145
- * or `complete`. The client shows/drives only the `active` step; the
146
- * trusted advance authority is unchanged (players still cannot complete
147
- * their own quests).
148
- */
149
- async tutorial(ownerUserId, chain = 'ftue') {
150
- const prefix = `${chain}:`;
151
- const defs = (await this.catalog())
152
- .filter((def) => def.questId.startsWith(prefix))
153
- .map((def) => ({ def, stepIndex: Number(def.questId.slice(prefix.length)) }))
154
- .filter(({ stepIndex }) => Number.isFinite(stepIndex))
155
- .sort((a, b) => a.stepIndex - b.stepIndex);
156
- const progressRows = await this.mine(ownerUserId);
157
- let blocked = false;
158
- return defs.map(({ def, stepIndex }) => {
159
- const progress = progressRows.find((p) => p.questId === def.questId) ?? null;
160
- const complete = progress?.completed === true;
161
- const status = complete
162
- ? 'complete'
163
- : blocked
164
- ? 'locked'
165
- : 'active';
166
- if (!complete)
167
- blocked = true;
168
- return { stepIndex, def, progress, status };
169
- });
170
- }
171
- /**
172
- * Ensure the player's ACTIVE tutorial step has a progress row (accepting
173
- * it when missing) and return the step. Returns null when the chain is
174
- * complete. Calling this for a locked step is impossible by construction —
175
- * it always targets the first incomplete step.
176
- */
177
- async acceptNextTutorialStep(ownerUserId, chain = 'ftue', options = {}) {
178
- const steps = await this.tutorial(ownerUserId, chain);
179
- const active = steps.find((step) => step.status === 'active');
180
- if (!active)
181
- return null;
182
- if (active.progress)
183
- return active;
184
- await this.accept(ownerUserId, active.def.containerId, options);
185
- const refreshed = await this.tutorial(ownerUserId, chain);
186
- return refreshed.find((step) => step.stepIndex === active.stepIndex) ?? null;
187
- }
188
- /** Read one progress row. */
189
- async state(progressId) {
190
- const container = await this.gameModel.container({
191
- appId: this.appId,
192
- containerId: progressId,
193
- });
194
- const props = await kitContainerProperties(this.gameModel, String(this.appId), progressId);
195
- return {
196
- containerId: container.containerId,
197
- displayName: container.displayName,
198
- ownerUserId: container.ownerUserId != null ? String(container.ownerUserId) : null,
199
- questId: String(props.quest_id ?? ''),
200
- count: Number(props.count ?? 0),
201
- target: Number(props.target ?? 1),
202
- completed: props.completed === true,
203
- claimed: props.claimed === true,
204
- daily: props.daily === true,
205
- };
206
- }
207
- /**
208
- * Advance quest progress — a **trusted** call (default blueprint
209
- * authority: app admins; or wire `advanceOn` event automations). Resolves
210
- * with the new count.
211
- */
212
- async advance(progressId, amount = 1) {
213
- return kitInvoke(this.gameModel, {
214
- appId: String(this.appId),
215
- functionName: this.names.advanceFn,
216
- selfContainerId: progressId,
217
- params: { amount },
218
- });
219
- }
220
- /**
221
- * Turn in a completed quest: marks it claimed AND grants the item +
222
- * currency rewards in one transaction. Resolves with the wallet's new
223
- * balance.
224
- */
225
- async claim(input) {
226
- return kitInvoke(this.gameModel, {
227
- appId: String(this.appId),
228
- functionName: this.names.claimFn,
229
- selfContainerId: input.progressId,
230
- params: {
231
- def_id: input.questDefId,
232
- to_stack_id: input.toStackId,
233
- wallet_id: input.walletId,
234
- },
235
- });
236
- }
237
- }