@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,1333 +0,0 @@
1
- import { createClient as createWsClient } from 'graphql-ws';
2
- import { print } from 'graphql';
3
- import {
4
- // Runtime (player) ops
5
- GameModelCreateSessionDocument, GameModelJoinSessionDocument, GameModelSetSessionTurnDocument, GameModelLeaveSessionDocument, GameModelSetSessionAdmissionDocument, GameModelTransferSessionHostDocument, GameModelEndSessionDocument, GameModelSessionSnapshotDocument, GameModelSessionEventsDocument, GameModelSessionInspectDocument, GameModelSessionChangedDocument, GameModelCreateContainerDocument, GameModelDeleteContainerDocument, GameModelSetPropertyDocument, GameModelAddEdgeDocument, GameModelDeleteEdgeDocument, GameModelInvokeDocument, GameModelContainerDocument, GameModelContainerChangedDocument, GameModelActivePlayerCountDocument, GameModelActivePlayerCountChangedDocument, GameModelContainersDocument, GameModelContainerStateDocument, GameModelContainerStatesDocument, GameModelTraverseDocument, GameModelSessionDocument, GameModelSessionsDocument, GameModelEventsDocument, GameModelFlowDocument,
6
- // Studio authoring ops
7
- GameModelSeedDocument, GameModelUpsertContainerTypeDocument, GameModelUpsertPropertyDefDocument, GameModelDeletePropertyDefDocument, GameModelDeleteContainerTypeDocument, GameModelUpsertFunctionDocument, GameModelDeleteFunctionDocument, GameModelDefineFeatureDocument, GameModelGrantTierFeatureDocument, GameModelSetPolicyDocument, GameModelTypeSchemaDocument, GameModelContainerTypesDocument, GameModelPropertyDefsDocument, GameModelFunctionDocument, GameModelFunctionsDocument, GameModelFeaturesDocument, GameModelTierFeaturesDocument, GameModelPolicyDocument, GameModelRevokeTierFeatureDocument, GameModelEventsConnectionDocument,
8
- // Automations (autonomous processes / NPCs)
9
- GameModelUpsertAutomationDocument, GameModelDeleteAutomationDocument, GameModelSetAutomationEnabledDocument, GameModelUpsertAutomationTriggerDocument, GameModelDeleteAutomationTriggerDocument, GameModelSetAutomationPolicyDocument, GameModelRunAutomationDocument, GameModelAutomationsDocument, GameModelAutomationDocument, GameModelAutomationTriggersDocument, GameModelAutomationPolicyDocument, GameModelAutomationRunsDocument, GameModelAutomationStatsDocument, GameModelAppDiagnosticsDocument, GameModelScheduleInvokeDocument, GameModelCancelTimerDocument, GameModelTimersDocument, } from '../generated/graphql.js';
10
- export class GameModelAPI {
11
- constructor(gql, ws) {
12
- this.gql = gql;
13
- this.ws = ws;
14
- }
15
- /**
16
- * **Player count** — read the best-known number of active gameplay sessions
17
- * for one app. Requires a bearer token scoped to exactly `appId`.
18
- *
19
- * This is a **session count**, not a distinct-user or actor count: one user
20
- * with multiple active sessions contributes more than once. A session that
21
- * disappears without a clean disconnect can remain counted for approximately
22
- * 120 seconds while its inactivity is recognized.
23
- *
24
- * Treat the result as authoritative only when `status === 'FRESH'`.
25
- * `PARTIAL` is an incomplete best-known count and `UNAVAILABLE` means no fresh
26
- * observation exists; neither status is an authoritative zero. `appId` and
27
- * the monotonic `revision` are generated `BigInt` scalars represented as
28
- * decimal strings.
29
- *
30
- * @param appId - App to count, as a decimal-string `BigInt`; it must match
31
- * the app scope of the bearer token.
32
- * @returns The generated snapshot payload: `appId`, `activePlayerCount`,
33
- * `status`, nullable `observedAt`, and `revision`.
34
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING` when the
35
- * token is missing or is not scoped to `appId`.
36
- */
37
- async activePlayerCount(appId) {
38
- const data = await this.gql.request(GameModelActivePlayerCountDocument, {
39
- appId,
40
- });
41
- return data.gameModelActivePlayerCount;
42
- }
43
- /**
44
- * **Player-count subscription** — stream complete active-session count
45
- * transitions for one app. Requires a bearer token scoped to exactly
46
- * `variables.appId` and a game-api `wsUrl` in the client config.
47
- *
48
- * This stream counts gameplay **sessions**, not distinct users or actors;
49
- * abandoned sessions can remain counted for approximately 120 seconds while
50
- * inactivity is recognized. It emits no initial/bootstrap event, so establish
51
- * the stream and then call {@link activePlayerCount} for the current snapshot.
52
- * `PARTIAL` and `UNAVAILABLE` observations neither emit transitions nor
53
- * represent an authoritative zero.
54
- *
55
- * Delivery is best-effort and may miss or repeat events across reconnects.
56
- * Deduplicate by the decimal-string `revision`. Requery
57
- * {@link activePlayerCount} after every reconnect or whenever revisions have
58
- * a gap; the query is the source of truth.
59
- *
60
- * @param variables - Exact call shape `{ appId }`, where `appId` is the
61
- * decimal-string `BigInt` matching the app-scoped bearer token.
62
- * @param handlers - `next` per transition; optional `error`, `complete`, and
63
- * `webSocketImpl` for runtimes without a global `WebSocket`.
64
- * @returns An unsubscribe function that disposes this subscription and its
65
- * graphql-transport-ws client.
66
- * @throws {Error} Synchronously when the client config has no `wsUrl`.
67
- */
68
- activePlayerCountChanged(variables, handlers) {
69
- if (!this.ws?.wsUrl) {
70
- throw new Error('activePlayerCountChanged requires a wsUrl in the client config (graphql-transport-ws endpoint)');
71
- }
72
- const client = createWsClient({
73
- url: this.ws.wsUrl,
74
- lazy: false,
75
- retryAttempts: 8,
76
- ...(handlers.webSocketImpl
77
- ? { webSocketImpl: handlers.webSocketImpl }
78
- : {}),
79
- connectionParams: () => {
80
- const token = this.ws?.getToken();
81
- return token ? { Authorization: `Bearer ${token}` } : {};
82
- },
83
- });
84
- const dispose = client.subscribe({ query: print(GameModelActivePlayerCountChangedDocument), variables }, {
85
- next: (msg) => {
86
- const data = msg.data;
87
- if (data?.gameModelActivePlayerCountChanged) {
88
- handlers.next(data.gameModelActivePlayerCountChanged);
89
- }
90
- else if (msg.errors) {
91
- handlers.error?.(msg.errors);
92
- }
93
- },
94
- error: (err) => handlers.error?.(err),
95
- complete: () => handlers.complete?.(),
96
- });
97
- return () => {
98
- dispose();
99
- void client.dispose();
100
- };
101
- }
102
- /**
103
- * **Subscriptions** — stream container-change notifications for an app
104
- * (`gameModelContainerChanged`): an invoke mutated a container, a direct
105
- * `setProperty` wrote it, or it was created/deleted. Events are
106
- * **metadata only** (containerId, typeName, changedKeys — no property
107
- * values): pull the visibility-filtered state with {@link containerState}
108
- * on receipt. Post-commit and best-effort, exactly like model-driven
109
- * notifications — replaces interval polling with pull-on-push. Requires a
110
- * game-api with the container-change feed (2026-07+) and a `wsUrl` in the
111
- * client config.
112
- *
113
- * @param variables - `{ appId, typeName?, sessionId? }` delivery filters.
114
- * @param handlers - `next` per change; optional `error` / `complete`.
115
- * @returns An unsubscribe function (closes this subscription's socket).
116
- */
117
- containerChanged(variables, handlers) {
118
- if (!this.ws?.wsUrl) {
119
- throw new Error('containerChanged requires a wsUrl in the client config (graphql-transport-ws endpoint)');
120
- }
121
- const client = createWsClient({
122
- url: this.ws.wsUrl,
123
- lazy: false,
124
- retryAttempts: 8,
125
- ...(handlers.webSocketImpl
126
- ? { webSocketImpl: handlers.webSocketImpl }
127
- : {}),
128
- connectionParams: () => {
129
- const token = this.ws?.getToken();
130
- return token ? { Authorization: `Bearer ${token}` } : {};
131
- },
132
- });
133
- const dispose = client.subscribe({ query: print(GameModelContainerChangedDocument), variables }, {
134
- next: (msg) => {
135
- const data = msg.data;
136
- if (data?.gameModelContainerChanged) {
137
- handlers.next(data.gameModelContainerChanged);
138
- }
139
- else if (msg.errors) {
140
- handlers.error?.(msg.errors);
141
- }
142
- },
143
- error: (err) => handlers.error?.(err),
144
- complete: () => handlers.complete?.(),
145
- });
146
- return () => {
147
- dispose();
148
- void client.dispose();
149
- };
150
- }
151
- /**
152
- * **Subscriptions** — stream the revisions of one session as they commit
153
- * (`gameModelSessionChanged`): joins, rejoins, leaves, presence expiries,
154
- * host changes, admission changes, turn changes and the end. There is no
155
- * bootstrap event: pull {@link sessionSnapshot} first, or pass
156
- * `afterRevision` to replay retained events from there. Revisions are
157
- * strictly increasing; on a gap or after a reconnect, pull the snapshot
158
- * again. Cross-replica and best-effort over a bounded buffer; the events
159
- * table ({@link sessionEvents}) is the record. Requires a `wsUrl` in the
160
- * client config.
161
- *
162
- * @param variables - `{ appId, sessionId, afterRevision? }`.
163
- * @param handlers - `next` per revision; optional `error` / `complete` /
164
- * `webSocketImpl`.
165
- * @returns An unsubscribe function (closes this subscription's socket).
166
- * @throws {Error} Synchronously when the client config has no `wsUrl`.
167
- */
168
- sessionChanged(variables, handlers) {
169
- if (!this.ws?.wsUrl) {
170
- throw new Error('sessionChanged requires a wsUrl in the client config (graphql-transport-ws endpoint)');
171
- }
172
- const client = createWsClient({
173
- url: this.ws.wsUrl,
174
- lazy: false,
175
- retryAttempts: 8,
176
- ...(handlers.webSocketImpl
177
- ? { webSocketImpl: handlers.webSocketImpl }
178
- : {}),
179
- connectionParams: () => {
180
- const token = this.ws?.getToken();
181
- return token ? { Authorization: `Bearer ${token}` } : {};
182
- },
183
- });
184
- const dispose = client.subscribe({ query: print(GameModelSessionChangedDocument), variables }, {
185
- next: (msg) => {
186
- const data = msg.data;
187
- if (data?.gameModelSessionChanged) {
188
- handlers.next(data.gameModelSessionChanged);
189
- }
190
- else if (msg.errors) {
191
- handlers.error?.(msg.errors);
192
- }
193
- },
194
- error: (err) => handlers.error?.(err),
195
- complete: () => handlers.complete?.(),
196
- });
197
- return () => {
198
- dispose();
199
- void client.dispose();
200
- };
201
- }
202
- // -- Runtime (player) -------------------------------------------------------
203
- /**
204
- * **Sessions** — create a runtime session: an isolated instance scope for
205
- * containers (e.g. a match, room, or save). Subject to the app's
206
- * session-creation policy ({@link setPolicy}); the caller becomes the creator
207
- * and a participant.
208
- *
209
- * **Presence mode.** `presence: 'actor'` (the default) expires a joined
210
- * participant with no fresh Buddy actor in the app after the join grace
211
- * window. `presence: 'none'` never expires anybody: use it for turn-based
212
- * play that talks GraphQL and channel pings and never replicates an actor
213
- * (`kit.matches` does), where the roster's only exits are
214
- * {@link leaveSession}, {@link endSession} and the empty timeout once
215
- * everyone has left. The mode is fixed at creation.
216
- *
217
- * @param input - {@link CreateSessionInput}: `appId` (decimal string), an
218
- * optional `name`, optional `metadataJson` (a JSON-object string),
219
- * optional `participantUserIds` (decimal-string ids of initial participants
220
- * besides the creator), optional `maxParticipants`, `admission`,
221
- * `emptyTimeoutSec`, `presence` and `idempotencyKey`.
222
- * Pass `seedFromApp: { typeNames, initialState? }` to stamp the app's keyed
223
- * template rows of those types (the rows a {@link seed} with `bindingKey`
224
- * wrote) into the new session inside the creation transaction: same
225
- * `bindingKey`, `displayName`, `metadataJson` and `ownerUserId` per row, so a
226
- * later `gameModelEnsureContainer` in the session finds every key present.
227
- * `initialState` is `'defaults'` (type defaults) or `'app'` (copy the app
228
- * rows' current properties). At most 2,000 rows per session; above that the
229
- * creation is refused and no session exists. The count is on the create
230
- * response as `seededContainerCount` (null on later reads) and on the
231
- * session's `created` event as `containersSeeded`. A template type must be
232
- * `instantiableBy: 'admin'` or carry a `bindPolicyJson` (a plain member
233
- * type is refused: a player may own one of its app keys); an `'app'`-scoped
234
- * type is refused. The copies are marked, and on a tier whose operator has
235
- * enabled retention (`GM_SESSION_CONTAINER_RETENTION_DAYS`; off by default)
236
- * they -- and only they -- are dropped once the session has been ended that
237
- * long; hand-made rows in the session are never purged.
238
- * @returns The created {@link GmSession} (`sessionId`, `status`, creator,
239
- * host, admission, `presence`, revision, `seededContainerCount`, …).
240
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING` if the token
241
- * is missing or not scoped to the app, `FORBIDDEN` if the session-creation
242
- * policy disallows the caller, or `BAD_USER_INPUT` for malformed input, an
243
- * undefined `seedFromApp` type, or more than 2,000 template rows.
244
- */
245
- async createSession(input) {
246
- const data = await this.gql.request(GameModelCreateSessionDocument, { input });
247
- return data.gameModelCreateSession;
248
- }
249
- /**
250
- * **Sessions** — join a session, or **reconnect** to one you are already in.
251
- * A rejoin returns your row with `incarnation + 1` and supersedes any older
252
- * client of yours; keep the returned `incarnation`, {@link leaveSession}
253
- * needs it. Pass `actorUuid` (your own Buddy actor, 32 hex chars — the uuid
254
- * you replicate with) to bind this participant's presence to that actor;
255
- * without it any fresh actor of yours in the app keeps you present.
256
- * **Presence is your actor** (in a `presence: 'actor'` session, the default):
257
- * a participant with no fresh Buddy actor in the app after the join grace
258
- * window is expired by the server (`participant_expired`); a client that only
259
- * speaks GraphQL must rejoin to come back. In a `presence: 'none'` session
260
- * nobody is expired and `actorUuid` is recorded but not judged.
261
- *
262
- * @param input - {@link JoinSessionInput}: `appId` (decimal string),
263
- * `sessionId`, optional `role`, optional `actorUuid`, optional
264
- * `idempotencyKey` (replaying returns the same incarnation).
265
- * @returns The {@link GmSessionParticipant} row (`state`, `incarnation`,
266
- * `actorUuid`, `joinedAt`, ...).
267
- * @throws {CrowdyGraphQLError} `SESSION_FULL` (every seat taken),
268
- * `SESSION_LOCKED` (admission locked and you never joined),
269
- * `SESSION_CLOSED`, `SESSION_ENDED`, `FORBIDDEN` (the `actorUuid` is not
270
- * yours or is already bound by another participant), `NOT_FOUND`,
271
- * `UNAUTHENTICATED` / `SCOPE_MISSING`.
272
- */
273
- async joinSession(input) {
274
- const data = await this.gql.request(GameModelJoinSessionDocument, { input });
275
- return data.gameModelJoinSession;
276
- }
277
- /**
278
- * **Sessions** — set or clear the session's current-turn user, for turn-based
279
- * play (turn authority is enforced by the service).
280
- *
281
- * @param input - {@link SetSessionTurnInput}: `appId` (decimal string),
282
- * `sessionId`, and `userId` (the decimal-string id of the user whose turn it
283
- * now is) — pass `userId: null` to **clear** the turn.
284
- * @returns The updated {@link GmSession} (with `currentTurnUserId` reflecting
285
- * the change).
286
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
287
- * `NOT_FOUND` if the session doesn't exist, or `FORBIDDEN` if the caller may
288
- * not change the turn.
289
- */
290
- async setSessionTurn(input) {
291
- const data = await this.gql.request(GameModelSetSessionTurnDocument, { input });
292
- return data.gameModelSetSessionTurn;
293
- }
294
- /**
295
- * **Sessions** — leave a session you are joined to. `incarnation` is
296
- * **required**: it is the value {@link joinSession} returned to *this*
297
- * client (a creator starts at 1), so a superseded client can never remove
298
- * the one that took over. Leaving an already-left row is a no-op. If you
299
- * were host, the longest-joined present participant succeeds you
300
- * (`host_changed`).
301
- *
302
- * @param input - {@link LeaveSessionInput}: `appId`, `sessionId`,
303
- * `incarnation`, optional `idempotencyKey`.
304
- * @returns Your {@link GmSessionParticipant} row, now `state: 'left'` with
305
- * `leftReason: 'left'`.
306
- * @throws {CrowdyGraphQLError} `SESSION_INCARNATION_STALE` (a newer client
307
- * rejoined as you — stop acting from this one, or rejoin),
308
- * `SESSION_NOT_PARTICIPANT`, `NOT_FOUND`.
309
- */
310
- async leaveSession(input) {
311
- const data = await this.gql.request(GameModelLeaveSessionDocument, { input });
312
- return data.gameModelLeaveSession;
313
- }
314
- /**
315
- * **Sessions** — change who may still join: `'open'` (anyone the app
316
- * admits), `'locked'` (only participants who already joined may reconnect —
317
- * set it when the match starts), `'closed'` (nobody). Session host or app
318
- * admin (`manage_apps`). Emits `admission_changed`.
319
- *
320
- * @param input - {@link SetSessionAdmissionInput}: `appId`, `sessionId`,
321
- * `admission`, optional `expectedHostTerm` (the `hostTerm` you last read:
322
- * refused if the host changed since), optional `idempotencyKey`.
323
- * @returns The updated {@link GmSession}.
324
- * @throws {CrowdyGraphQLError} `FORBIDDEN` (not host / admin),
325
- * `SESSION_HOST_TERM_STALE`, `SESSION_ENDED`, `NOT_FOUND`.
326
- */
327
- async setSessionAdmission(input) {
328
- const data = await this.gql.request(GameModelSetSessionAdmissionDocument, { input });
329
- return data.gameModelSetSessionAdmission;
330
- }
331
- /**
332
- * **Sessions** — hand the host role to another *joined* participant.
333
- * Session host or app admin. Increments `hostTerm` and emits
334
- * `host_changed` (reason `transferred`).
335
- *
336
- * @param input - {@link TransferSessionHostInput}: `appId`, `sessionId`,
337
- * `toUserId` (decimal string), optional `expectedHostTerm`, optional
338
- * `idempotencyKey`.
339
- * @returns The updated {@link GmSession} (`hostUserId`, `hostTerm`).
340
- * @throws {CrowdyGraphQLError} `FORBIDDEN`, `SESSION_HOST_TERM_STALE`,
341
- * `SESSION_TARGET_NOT_PARTICIPANT` (the user named is not joined; refetch
342
- * the snapshot and pick a participant), `SESSION_ENDED`.
343
- */
344
- async transferSessionHost(input) {
345
- const data = await this.gql.request(GameModelTransferSessionHostDocument, { input });
346
- return data.gameModelTransferSessionHost;
347
- }
348
- /**
349
- * **Sessions** — end a session as `'completed'` (default) or `'abandoned'`.
350
- * Every joined participant is marked left (`session_ended`), admission
351
- * becomes `closed`, `endedAt` / `endReason` are set and an `ended` event
352
- * closes the revision log. Session host or app admin. (The server also ends a
353
- * session nobody has been joined to for longer than its `emptyTimeoutSec` as
354
- * `abandoned` / `empty_timeout`.)
355
- *
356
- * @param input - {@link EndSessionInput}: `appId`, `sessionId`, optional
357
- * `reason`, optional `expectedHostTerm`, optional `idempotencyKey`.
358
- * @returns The ended {@link GmSession}.
359
- * @throws {CrowdyGraphQLError} `FORBIDDEN`, `SESSION_HOST_TERM_STALE`,
360
- * `SESSION_ENDED` (already ended), `NOT_FOUND`.
361
- */
362
- async endSession(input) {
363
- const data = await this.gql.request(GameModelEndSessionDocument, { input });
364
- return data.gameModelEndSession;
365
- }
366
- /**
367
- * **Containers** — instantiate a container (a runtime entity of a given type),
368
- * optionally within a session, with an owner and initial property values.
369
- * Subject to the type's `instantiableBy` rule (`admin | member | owner`).
370
- *
371
- * @param input - {@link CreateContainerInput}: `appId` (decimal string), an
372
- * optional `sessionId` (omit for an app-global container), the `typeName` to
373
- * instantiate, a `displayName`, optional `description`, optional
374
- * `ownerUserId` (decimal string; defaults to the caller for member/owner
375
- * instantiation), optional `metadataJson` (JSON-object string), and optional
376
- * initial `properties` (each `{ key, valueType, valueJson }` with a
377
- * JSON-encoded value).
378
- * @returns The created {@link GmContainer}.
379
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
380
- * `FORBIDDEN` if `instantiableBy` disallows the caller, `NOT_FOUND` for an
381
- * unknown type, or `BAD_USER_INPUT` for malformed properties.
382
- */
383
- async createContainer(input) {
384
- const data = await this.gql.request(GameModelCreateContainerDocument, { input });
385
- return data.gameModelCreateContainer;
386
- }
387
- /**
388
- * **Containers** — delete a container instance. Cascades its instance
389
- * properties and any edges connected to it. Allowed for an app admin or the
390
- * container owner. **Destructive.**
391
- *
392
- * @param variables - `{ appId, containerId }`: `appId` (decimal string) and
393
- * the container UUID to delete.
394
- * @returns `true` if a container was deleted, `false` if none matched.
395
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
396
- * `FORBIDDEN` if the caller is neither an app admin nor the owner.
397
- */
398
- async deleteContainer(variables) {
399
- const data = await this.gql.request(GameModelDeleteContainerDocument, variables);
400
- return data.gameModelDeleteContainer;
401
- }
402
- /**
403
- * **Containers** — set a single property value on a container directly (outside
404
- * a function). Allowed only when the property's `writable` rule
405
- * (`function | owner | admin`) permits the caller; the value is JSON-encoded
406
- * and coerced to the property's declared value type. For game-logic changes
407
- * prefer {@link invoke}, which enforces an authority policy and logs an event.
408
- *
409
- * @param input - {@link SetContainerPropertyInput}: `appId` (decimal string),
410
- * `containerId`, the property `key`, its `valueType` (must match the property
411
- * definition), and `valueJson` (the JSON-encoded value to write).
412
- * @returns The updated {@link GmContainer}.
413
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
414
- * `FORBIDDEN` if the property's `writable` rule forbids a direct write,
415
- * `NOT_FOUND` for an unknown container/property, or `BAD_USER_INPUT` for a
416
- * value-type mismatch.
417
- */
418
- async setProperty(input) {
419
- const data = await this.gql.request(GameModelSetPropertyDocument, { input });
420
- return data.gameModelSetProperty;
421
- }
422
- /**
423
- * **Edges** — create a directed relationship edge between two containers (the
424
- * game model is a graph), with a relationship type and optional weight.
425
- *
426
- * @param input - {@link AddEdgeInput}: `appId` (decimal string),
427
- * `fromContainerId` (source) and `toContainerId` (target), a
428
- * `relationshipType` label, an optional numeric `weight`, and optional
429
- * `metadataJson` (JSON-object string).
430
- * @returns The created {@link GmEdge} (`edgeId`, endpoints, type, weight).
431
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
432
- * `NOT_FOUND` if either container is unknown, or `BAD_USER_INPUT`.
433
- */
434
- async addEdge(input) {
435
- const data = await this.gql.request(GameModelAddEdgeDocument, { input });
436
- return data.gameModelAddEdge;
437
- }
438
- /**
439
- * **Edges** — delete a directed relationship edge. Allowed for an app admin or
440
- * the owner of the source (`from`) container. **Destructive.**
441
- *
442
- * @param variables - `{ appId, edgeId }`: `appId` (decimal string) and the
443
- * edge UUID to delete.
444
- * @returns `true` if an edge was deleted, `false` if none matched.
445
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
446
- * `FORBIDDEN` if the caller may not delete the edge.
447
- */
448
- async deleteEdge(variables) {
449
- const data = await this.gql.request(GameModelDeleteEdgeDocument, variables);
450
- return data.gameModelDeleteEdge;
451
- }
452
- /**
453
- * **Functions** — invoke a studio-defined function against a `self` container
454
- * with JSON params. This is the primary, *safe* way for players to mutate game
455
- * state: the server enforces the function's invoke policy (the authority rule
456
- * tree — `owner_of_self` / `is_host` / `is_current_turn` / `is_participant` /
457
- * `tier_feature` / `group_permission` / `grid_permission` / `condition`),
458
- * evaluates its expressions, atomically applies its declared property
459
- * mutations, and logs an {@link events | event}. Only `player`-scope functions
460
- * are invocable here.
461
- *
462
- * Note: an authority denial or an expression-evaluation error is **not** a
463
- * thrown exception — it comes back as a resolved result with `success: false`
464
- * and `fault.code` (`NOT_ALLOWED` for a policy refusal). Inspect
465
- * `result.success` rather than relying on `try/catch` for those cases.
466
- *
467
- * **The invoke policy applies to app admins too** (ck-api v1.89.0). Your own
468
- * account, testing your own game, is judged exactly like a player's. Before
469
- * that release a `manage_apps` holder skipped every policy implicitly, which
470
- * made policies look unenforced to the people who wrote them. Administrative
471
- * tooling that needs to run a function regardless of its policy sets
472
- * `bypassPolicy: true`: honoured only with `manage_apps` (a GraphQL
473
- * `NOT_ALLOWED` error otherwise, nothing runs), reported back as
474
- * `policyBypassed: true` on the result, and audit-logged server-side.
475
- *
476
- * @param input - {@link InvokeFunctionInput}: `appId` (decimal string), the
477
- * `functionName`, the `selfContainerId` (the container the function runs
478
- * against, referenced as `self` in expressions), an optional `sessionId`
479
- * context, `paramsJson` (a JSON-object string of params), and the optional
480
- * administrative `bypassPolicy` flag described above.
481
- * @returns A {@link GmInvokeResult}: `success`, the logged `eventId`, the
482
- * JSON-encoded `returnValueJson`, the `mutationsApplied` (each with
483
- * before/after JSON values), `fault` when `success` is `false`, and
484
- * `policyBypassed` when the call skipped the policy on purpose.
485
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
486
- * `NOT_FOUND` for an unknown function/container, `FORBIDDEN` if the function
487
- * isn't `player`-scope, `NOT_ALLOWED` for `bypassPolicy` without
488
- * `manage_apps`, or `BAD_USER_INPUT` for malformed params. (Authority and
489
- * evaluation failures surface as `success: false`, see above.)
490
- */
491
- async invoke(input) {
492
- const data = await this.gql.request(GameModelInvokeDocument, { input });
493
- return data.gameModelInvoke;
494
- }
495
- /**
496
- * **Containers** — fetch one container (instance) by id, with its full record
497
- * (unfiltered metadata). For a player-facing view whose property values are
498
- * filtered to what the caller may see, use {@link containerState} instead.
499
- *
500
- * @param variables - `{ appId, containerId }`: `appId` (decimal string) is the
501
- * owning app and `containerId` is the container UUID to fetch.
502
- * @returns The {@link GmContainer}.
503
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
504
- * `NOT_FOUND` if no such container.
505
- */
506
- async container(variables) {
507
- const data = await this.gql.request(GameModelContainerDocument, variables);
508
- return data.gameModelContainer;
509
- }
510
- /**
511
- * **Containers** — list containers in an app, optionally narrowed by container
512
- * type and/or session, filtered by property predicates, and paged.
513
- *
514
- * @param variables - `{ appId, typeName?, sessionId?, where?, limit?, offset? }`:
515
- * `appId` (decimal string); optional `typeName` (omit for all types);
516
- * optional `sessionId` (omit for all containers, including app-global
517
- * ones); optional `where` (max 8 AND-combined
518
- * `{ key, op, valueJson }` predicates — ops `==`, `!=`, `<`, `>`, `<=`,
519
- * `>=`; requires `typeName`; missing properties fall back to the type
520
- * default — the same predicate shape automation selectors use); optional
521
- * `limit`/`offset` paging applied after filtering over the stable
522
- * created-at ordering. `bindingKey` narrows to the one row ensured (or
523
- * seeded) under that key — with `typeName` and `sessionId` it is the
524
- * get-by-key read. **An omitted `limit` returns 200 rows and the
525
- * maximum is 1,000** (`BAD_REQUEST` above it); without `where` the page is
526
- * read in SQL, with `where` the predicates are evaluated after reading at
527
- * most 10,000 rows of the type and a larger type is refused. Requires
528
- * game-api with container predicates (2026-07 or later); older servers
529
- * reject the new arguments.
530
- * @returns The matching {@link GmContainer}s.
531
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
532
- * `BAD_USER_INPUT` for `where` without `typeName` / unsupported ops.
533
- */
534
- async containers(variables) {
535
- const data = await this.gql.request(GameModelContainersDocument, variables);
536
- return data.gameModelContainers;
537
- }
538
- /**
539
- * **Containers** — fetch a container together with its property values
540
- * filtered to what the **calling** user is allowed to see (`public` always;
541
- * `owner`/`hidden` depend on the caller's relationship to the container). Use
542
- * this for a player-facing view of an entity.
543
- *
544
- * @param variables - `{ appId, containerId }`: `appId` (decimal string) and
545
- * the `containerId` UUID whose visible state to fetch.
546
- * @returns A {@link GmContainerState}; its `propertiesJson` is a JSON-object
547
- * string of the properties visible to the caller (`JSON.parse` it).
548
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
549
- * `NOT_FOUND` if no such container.
550
- */
551
- async containerState(variables) {
552
- const data = await this.gql.request(GameModelContainerStateDocument, variables);
553
- return data.gameModelContainerState;
554
- }
555
- /**
556
- * **Containers** — the bulk twin of {@link containerState}: identity plus the
557
- * property state visible to the **calling** user for up to **500** containers
558
- * in one call, with the same per-row visibility rules. Ids the app does not
559
- * hold are omitted rather than errors, duplicates come back once, and the
560
- * order follows the input. After paging {@link containers} (default 200, max
561
- * 1,000 per page), two of these pull a page's state — a level of thousands of
562
- * placed objects loads in a handful of calls instead of one per object.
563
- *
564
- * @param variables - `{ appId, containerIds }`: `appId` (decimal string) and
565
- * up to 500 container UUIDs.
566
- * @returns An array of {@link GmContainerState}; each `propertiesJson` is a
567
- * JSON-object string of the properties visible to the caller.
568
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
569
- * `BAD_REQUEST` for more than 500 ids or a non-UUID id.
570
- */
571
- async containerStates(variables) {
572
- const data = await this.gql.request(GameModelContainerStatesDocument, variables);
573
- return data.gameModelContainerStates;
574
- }
575
- /**
576
- * **Edges** — traverse the container graph from a root container along a
577
- * relationship type up to a given depth, returning the reachable nodes and the
578
- * edges between them.
579
- *
580
- * @param variables - `{ appId, rootId, relationshipType, depth? }`: `appId`
581
- * (decimal string); the `rootId` container UUID to start from; the
582
- * `relationshipType` edge label to follow; and optional `depth`, the number
583
- * of edge hops to follow from the root (defaults to `1`).
584
- * @returns A {@link GmTraverseResult}: the `rootId`, the reachable `nodes`
585
- * ({@link GmContainer}[]), and the traversed `edges` ({@link GmEdge}[]).
586
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
587
- * `NOT_FOUND` if the root container is unknown.
588
- */
589
- async traverse(variables) {
590
- const data = await this.gql.request(GameModelTraverseDocument, variables);
591
- return data.gameModelTraverse;
592
- }
593
- /**
594
- * **Sessions** — fetch one session by id.
595
- *
596
- * @param variables - `{ appId, sessionId }`: `appId` (decimal string) and the
597
- * `sessionId` to fetch.
598
- * @returns The {@link GmSession}.
599
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
600
- * `NOT_FOUND` if no such session.
601
- */
602
- async session(variables) {
603
- const data = await this.gql.request(GameModelSessionDocument, variables);
604
- return data.gameModelSession;
605
- }
606
- /**
607
- * **Sessions** — list sessions in an app, newest first, optionally filtered
608
- * by `status` (`active | completed | abandoned`), `admission`
609
- * (`open | locked | closed` — `'open'` lists joinable lobbies) and/or
610
- * `hostUserId`.
611
- *
612
- * @param variables - `{ appId, status?, admission?, hostUserId?, limit? }`
613
- * (`limit` defaults to 200, max 1000).
614
- * @returns The matching {@link GmSession}s.
615
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`.
616
- */
617
- async sessions(variables) {
618
- const data = await this.gql.request(GameModelSessionsDocument, variables);
619
- return data.gameModelSessions;
620
- }
621
- /**
622
- * **Sessions** — the authoritative state of one session at one revision: the
623
- * session row and every *joined* participant. Pull it when you subscribe
624
- * with {@link sessionChanged}, after a reconnect, or when the stream shows a
625
- * revision gap; then apply only events whose `revision` is above
626
- * `snapshot.revision`.
627
- *
628
- * @param variables - `{ appId, sessionId }`.
629
- * @returns `{ revision, session, participants }`.
630
- * @throws {CrowdyGraphQLError} `NOT_FOUND`, `UNAUTHENTICATED` / `SCOPE_MISSING`.
631
- */
632
- async sessionSnapshot(variables) {
633
- const data = await this.gql.request(GameModelSessionSnapshotDocument, variables);
634
- return data.gameModelSessionSnapshot;
635
- }
636
- /**
637
- * **Sessions** — the events of a session with a revision strictly greater
638
- * than `afterRevision`, oldest first: the gap-fill read behind
639
- * {@link sessionChanged}. Events of ended sessions are retained for a bounded
640
- * period, then purged.
641
- *
642
- * @param variables - `{ appId, sessionId, afterRevision, limit? }`;
643
- * `afterRevision` is a decimal string (`'0'` for everything retained).
644
- * @returns The matching {@link GmSessionEvent}s.
645
- */
646
- async sessionEvents(variables) {
647
- const data = await this.gql.request(GameModelSessionEventsDocument, variables);
648
- return data.gameModelSessionEvents;
649
- }
650
- /**
651
- * **Sessions (operators)** — the full roster including departed participants
652
- * (with `leftReason` and `incarnation`), each joined participant's live
653
- * presence verdict (`fresh | grace | stale | legacy | left`), and the most
654
- * recent events. Requires app-admin (`manage_apps`).
655
- *
656
- * @param variables - `{ appId, sessionId }`.
657
- * @throws {CrowdyGraphQLError} `FORBIDDEN` without `manage_apps`.
658
- */
659
- async sessionInspect(variables) {
660
- const data = await this.gql.request(GameModelSessionInspectDocument, variables);
661
- return data.gameModelSessionInspect;
662
- }
663
- /**
664
- * **Events** — query the function-invocation event log (audit trail) with
665
- * optional filters and pagination. Useful for debugging functions or showing
666
- * recent activity.
667
- *
668
- * @param variables - `{ appId, sessionId?, selfContainerId?, functionName?,
669
- * success?, limit?, offset? }`: `appId` (decimal string); optional
670
- * `sessionId`; optional `selfContainerId` (the UUID the function ran
671
- * against); optional `functionName`; optional `success` (`true` = succeeded,
672
- * `false` = failed). `limit` (page size) and `offset` (rows to skip) are
673
- * **deprecated** — see below.
674
- * @returns The matching {@link GmEvent}s (each with `paramsJson`,
675
- * `mutationsAppliedJson`, `returnValueJson`, `success`, `errorMessage`, and
676
- * `executedAt`).
677
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`.
678
- * @remarks The `limit`/`offset` fields use deprecated offset pagination. For
679
- * large logs prefer the Relay-style `gameModelEventsConnection(first:, after:)`
680
- * cursor query (available on the schema via `client.graphql`). See
681
- * https://docs.crowdedkingdoms.com/overview/pagination.
682
- */
683
- async events(variables) {
684
- const data = await this.gql.request(GameModelEventsDocument, variables);
685
- return data.gameModelEvents;
686
- }
687
- /**
688
- * **Events** — Relay-style cursor pagination over the function-invocation
689
- * event log; the preferred alternative to {@link events} for large logs. Page
690
- * with `first` plus the previous page's `pageInfo.endCursor` as `after`. See
691
- * https://docs.crowdedkingdoms.com/overview/pagination.
692
- *
693
- * @param variables - `{ appId, first?, after?, sessionId?, selfContainerId?,
694
- * functionName?, success? }`.
695
- * @returns A {@link GameModelEventsConnection} (`edges { cursor node }`,
696
- * `pageInfo`, `totalCount`).
697
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`.
698
- */
699
- async eventsConnection(variables) {
700
- const data = await this.gql.request(GameModelEventsConnectionDocument, variables);
701
- return data.gameModelEventsConnection;
702
- }
703
- /**
704
- * **Diagnostics** — stitch one flow correlation id into a single
705
- * cross-engine timeline: the model **events** ({@link events} rows), the
706
- * **automationRuns**, and the compute **moduleRuns** that share the
707
- * `flowId` minted at the entry edge (a player {@link invoke}, an automation
708
- * run, or a `computeInvoke`) and propagated across `model_invoke`, the
709
- * event bus, and `emit_compute_event`. Each array is ordered by time
710
- * ascending, so the three together read as one causal trace — "what
711
- * happened to this kill's reward" in one query instead of three
712
- * hand-joined ones. Take the `flowId` from the `flowId` field on any
713
- * {@link GmEvent}, {@link GmAutomationRun}, or {@link WasmModuleRun}
714
- * (selected by the default fragments since SDK 8.13.0).
715
- *
716
- * Requires the app-admin **`manage_apps`** permission (a diagnostics
717
- * surface, like {@link automationRuns}) and a game-api with the
718
- * `gameModelFlow` query (2026-07-19 or later; older servers reject the
719
- * operation with a validation error).
720
- *
721
- * @param variables - `{ appId, flowId }`: `appId` (decimal string) and the
722
- * flow correlation id (a UUID string). An unknown `flowId` returns three
723
- * empty arrays.
724
- * @returns The {@link GmFlowTimeline}: `flowId`, `events`,
725
- * `automationRuns`, and `moduleRuns`, each time-ascending.
726
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
727
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_REQUEST`
728
- * if `flowId` is not a UUID.
729
- */
730
- async flow(variables) {
731
- const data = await this.gql.request(GameModelFlowDocument, variables);
732
- return data.gameModelFlow;
733
- }
734
- // -- Studio authoring -------------------------------------------------------
735
- /**
736
- * **Seed** — bulk-create game-model definitions (container types, property
737
- * defs, functions) and optionally instances (containers + edges) in one
738
- * transaction; used to initialize or import a model.
739
- *
740
- * Requires the app-admin **`manage_apps`** permission.
741
- *
742
- * @param input - {@link SeedGameModelInput}: `appId` (decimal string); an
743
- * optional `sessionId` to seed instances into (omit/`null` = app-global);
744
- * and arrays of `containerTypes`, `propertyDefinitions`, `functions`,
745
- * `containers`, and `edges` to create. Seed containers carry a developer
746
- * `tempId`; seed edges reference containers by those temp ids
747
- * (`fromTempId`/`toTempId`). A container may name its own `bindingKey`
748
- * (on a type that is `instantiableBy: 'admin'` or carries a `bindPolicyJson`,
749
- * and not beginning with `seed:`) so a runtime `gameModelEnsureContainer` later
750
- * resolves the same row; otherwise it binds as `seed:` + `tempId`. A
751
- * caller-keyed row that already exists is adopted only if its `ownerUserId`
752
- * matches (a re-seed); a row a player claimed first is refused and nothing
753
- * is written. At most
754
- * **1,000 containers per call**, all-or-nothing; the same key on two types
755
- * is two rows. A container type may declare `scope: 'app'` (one row per key
756
- * for the whole app) or `'session'` (default). Seeded rows fire no
757
- * `container_created` automation triggers or change-feed events.
758
- * @returns A {@link GmSeedResult}: the counts created, non-fatal `warnings`,
759
- * and `idMapJson` — a JSON-object string mapping each seed `tempId` to the
760
- * created container UUID (`JSON.parse` it to wire up follow-up calls).
761
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
762
- * `FORBIDDEN` (with `extensions.requiredPermission === 'manage_apps'`) if the
763
- * caller lacks app-admin, or `BAD_USER_INPUT` for malformed definitions.
764
- */
765
- async seed(input) {
766
- const data = await this.gql.request(GameModelSeedDocument, { input });
767
- return data.gameModelSeed;
768
- }
769
- /**
770
- * **Container types** — create or update a container type: the studio-defined
771
- * schema for a kind of runtime entity (like a class). Idempotent on
772
- * `(appId, typeName)`.
773
- *
774
- * Requires the app-admin **`manage_apps`** permission.
775
- *
776
- * @param input - {@link UpsertContainerTypeInput}: `appId` (decimal string);
777
- * the `typeName` (the stable upsert key, unique per app); a `displayName`;
778
- * optional `description`; optional `instantiableBy` (`admin | member |
779
- * owner`); optional `defaultPropertyVisibility` (`public | owner | hidden`);
780
- * optional `bindPolicyJson` (who may claim a `bindingKey` on
781
- * `ensureContainer`; omit to leave the type unbound); optional `scope`
782
- * (`'session'` default — one row per key per session; `'app'` — one row
783
- * per key for the whole app, on which `ensureContainer` /
784
- * `createContainer` with a `sessionId` are refused with
785
- * `CONTAINER_TYPE_APP_SCOPED`; changing to `'app'` is refused while the
786
- * type holds session-scoped rows); and optional `metadataJson`
787
- * (JSON-object string).
788
- * @returns The upserted {@link GmContainerType}.
789
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
790
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`.
791
- */
792
- async upsertContainerType(input) {
793
- const data = await this.gql.request(GameModelUpsertContainerTypeDocument, { input });
794
- return data.gameModelUpsertContainerType;
795
- }
796
- /**
797
- * **Property definitions** — create or update a typed property on a container
798
- * type (a field with a default value, read visibility, and writability).
799
- * Idempotent on `(appId, containerTypeName, key)`.
800
- *
801
- * Requires the app-admin **`manage_apps`** permission.
802
- *
803
- * @param input - {@link UpsertPropertyDefInput}: `appId` (decimal string); the
804
- * `containerTypeName` to define on; the property `key` (part of the upsert
805
- * key); a `valueType` (`int | float | string | bool | array | object |
806
- * container_ref`); optional `defaultValueJson` (JSON-encoded default);
807
- * optional `visibility` (`public | owner | hidden`); optional `writable`
808
- * (`function | owner | admin`); and optional `description`.
809
- * @returns The upserted {@link GmPropertyDef}.
810
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
811
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), `NOT_FOUND` for an
812
- * unknown container type, or `BAD_USER_INPUT`.
813
- */
814
- async upsertPropertyDef(input) {
815
- const data = await this.gql.request(GameModelUpsertPropertyDefDocument, { input });
816
- return data.gameModelUpsertPropertyDef;
817
- }
818
- /**
819
- * **Property definitions** — delete a property definition from a container
820
- * type. Does **not** remove instance property values already stored on
821
- * containers. **Destructive.**
822
- *
823
- * Requires the app-admin **`manage_apps`** permission.
824
- *
825
- * @param variables - `{ appId, containerTypeName, key }`.
826
- * @returns `true` if a definition was deleted, `false` if none matched.
827
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
828
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`).
829
- */
830
- async deletePropertyDef(variables) {
831
- const data = await this.gql.request(GameModelDeletePropertyDefDocument, variables);
832
- return data.gameModelDeletePropertyDef;
833
- }
834
- /**
835
- * **Container types** — delete a container type and its property definitions.
836
- * Refuses if live containers of that type exist, or if functions are bound to
837
- * it — delete those first. **Destructive.**
838
- *
839
- * Requires the app-admin **`manage_apps`** permission.
840
- *
841
- * @param variables - `{ appId, typeName }`.
842
- * @returns `true` if a type was deleted, `false` if none matched.
843
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
844
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`
845
- * when containers or bound functions still exist.
846
- */
847
- async deleteContainerType(variables) {
848
- const data = await this.gql.request(GameModelDeleteContainerTypeDocument, variables);
849
- return data.gameModelDeleteContainerType;
850
- }
851
- /**
852
- * **Functions** — create or update a studio-defined function: a named,
853
- * sandboxed behaviour with typed parameters, declared property mutations
854
- * (expressions compiled to an AST server-side — never `eval`'d), an optional
855
- * return expression, an invoke scope, and an invoke policy (authority rule
856
- * tree). Idempotent on `(appId, name)`. Players run these via {@link invoke}.
857
- *
858
- * Requires the app-admin **`manage_apps`** permission.
859
- *
860
- * @param input - {@link UpsertFunctionInput}: `appId` (decimal string); the
861
- * `name` (upsert key, used to invoke it); optional `containerTypeName` to
862
- * bind to (omit for a global function); optional `description`; optional
863
- * `returnType`; `parameters` (typed `{ name, valueType, required?,
864
- * defaultValueJson?, … }`); `mutations` (declared writes `{ target, property,
865
- * expression }`, applied atomically); optional `returnExpression`;
866
- * `invokeScope` (`player | server | internal`); and `invokePolicyJson` (a
867
- * JSON-encoded authority rule tree).
868
- * @returns The upserted {@link GmFunction}, including any non-fatal
869
- * static-analysis `warnings` from this upload.
870
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
871
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`
872
- * for an expression/policy that fails to compile.
873
- */
874
- async upsertFunction(input) {
875
- const data = await this.gql.request(GameModelUpsertFunctionDocument, { input });
876
- return data.gameModelUpsertFunction;
877
- }
878
- /**
879
- * **Functions** — delete a studio-defined function by name. **Destructive.**
880
- *
881
- * Requires the app-admin **`manage_apps`** permission.
882
- *
883
- * @param variables - `{ appId, name }`: `appId` (decimal string) and the
884
- * function `name` to delete.
885
- * @returns `true` if a function was deleted, `false` if none matched.
886
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
887
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`) if the caller lacks
888
- * app-admin.
889
- */
890
- async deleteFunction(variables) {
891
- const data = await this.gql.request(GameModelDeleteFunctionDocument, variables);
892
- return data.gameModelDeleteFunction;
893
- }
894
- /**
895
- * **App features** — define an app feature key that functions can gate on (via
896
- * a `tier_feature` authority rule) and that access tiers can be granted.
897
- * Idempotent on `(appId, featureKey)`.
898
- *
899
- * Requires the app-admin **`manage_apps`** permission.
900
- *
901
- * @param input - {@link DefineAppFeatureInput}: `appId` (decimal string); the
902
- * `featureKey` (referenced by `tier_feature` rules); and an optional
903
- * `description`.
904
- * @returns The defined {@link GmAppFeature}.
905
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
906
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`.
907
- */
908
- async defineFeature(input) {
909
- const data = await this.gql.request(GameModelDefineFeatureDocument, { input });
910
- return data.gameModelDefineFeature;
911
- }
912
- /**
913
- * **App features** — grant a feature key to an access tier, so users on that
914
- * tier satisfy `tier_feature` authority checks for it.
915
- *
916
- * Requires the app-admin **`manage_apps`** permission.
917
- *
918
- * @param input - {@link GrantTierFeatureInput}: `appId` (decimal string); the
919
- * `tierId` (decimal string) of the access tier; and the `featureKey` to
920
- * grant to that tier.
921
- * @returns The {@link GmTierFeature} grant record.
922
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
923
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `NOT_FOUND` for an
924
- * unknown tier/feature.
925
- */
926
- async grantTierFeature(input) {
927
- const data = await this.gql.request(GameModelGrantTierFeatureDocument, { input });
928
- return data.gameModelGrantTierFeature;
929
- }
930
- /**
931
- * **Policy** — set the app's game-model runtime policy: who may create
932
- * sessions and the default role assigned to new session participants.
933
- *
934
- * Requires the app-admin **`manage_apps`** permission.
935
- *
936
- * @param input - {@link SetGameModelPolicyInput}: `appId` (decimal string); an
937
- * optional `sessionCreationPolicy` (`admin | member | anyone`); and an
938
- * optional `defaultParticipantRole`.
939
- * @returns The updated {@link GmAppPolicy}.
940
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
941
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`.
942
- */
943
- async setPolicy(input) {
944
- const data = await this.gql.request(GameModelSetPolicyDocument, { input });
945
- return data.gameModelSetPolicy;
946
- }
947
- /**
948
- * **Container types** — fetch a container type's full schema: its property
949
- * definitions plus the functions available on it. A studio/authoring read.
950
- *
951
- * Requires the app-admin **`manage_apps`** permission.
952
- *
953
- * @param variables - `{ appId, typeName }`: `appId` (decimal string) and the
954
- * `typeName` whose schema to fetch.
955
- * @returns A {@link GmTypeSchema}: the `typeName`, its `propertyDefinitions`
956
- * ({@link GmPropertyDef}[]), and its `functions` ({@link GmFunction}[]).
957
- * @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
958
- * `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `NOT_FOUND` for an
959
- * unknown type.
960
- */
961
- async typeSchema(variables) {
962
- const data = await this.gql.request(GameModelTypeSchemaDocument, variables);
963
- return data.gameModelTypeSchema;
964
- }
965
- /**
966
- * **Container types** — list every container type defined for an app. A
967
- * studio/authoring read. Requires the app-admin **`manage_apps`** permission.
968
- *
969
- * @param variables - `{ appId }`.
970
- * @returns The app's {@link GmContainerType}s.
971
- */
972
- async containerTypes(variables) {
973
- const data = await this.gql.request(GameModelContainerTypesDocument, variables);
974
- return data.gameModelContainerTypes;
975
- }
976
- /**
977
- * **Property definitions** — list the property definitions for one container
978
- * type. A studio/authoring read. Requires the app-admin **`manage_apps`**
979
- * permission.
980
- *
981
- * @param variables - `{ appId, typeName }`.
982
- * @returns The type's {@link GmPropertyDef}s.
983
- */
984
- async propertyDefs(variables) {
985
- const data = await this.gql.request(GameModelPropertyDefsDocument, variables);
986
- return data.gameModelPropertyDefs;
987
- }
988
- /**
989
- * **Functions** — fetch one studio-defined function by name (including its
990
- * parameters, mutations, and notification effects). Requires the app-admin
991
- * **`manage_apps`** permission.
992
- *
993
- * @param variables - `{ appId, name }`.
994
- * @returns The {@link GmFunction}.
995
- */
996
- async getFunction(variables) {
997
- const data = await this.gql.request(GameModelFunctionDocument, variables);
998
- return data.gameModelFunction;
999
- }
1000
- /**
1001
- * **Functions** — list studio-defined functions for an app, optionally
1002
- * filtered to those bound to a container type. Requires the app-admin
1003
- * **`manage_apps`** permission.
1004
- *
1005
- * @param variables - `{ appId, containerTypeName? }`.
1006
- * @returns The matching {@link GmFunction}s.
1007
- */
1008
- async functions(variables) {
1009
- const data = await this.gql.request(GameModelFunctionsDocument, variables);
1010
- return data.gameModelFunctions;
1011
- }
1012
- /**
1013
- * **App features** — list the feature keys defined for an app. Requires the
1014
- * app-admin **`manage_apps`** permission.
1015
- *
1016
- * @param variables - `{ appId }`.
1017
- * @returns The app's {@link GmAppFeature}s.
1018
- */
1019
- async features(variables) {
1020
- const data = await this.gql.request(GameModelFeaturesDocument, variables);
1021
- return data.gameModelFeatures;
1022
- }
1023
- /**
1024
- * **App features** — list tier→feature grants for an app, optionally filtered
1025
- * to one tier. Requires the app-admin **`manage_apps`** permission.
1026
- *
1027
- * @param variables - `{ appId, tierId? }`.
1028
- * @returns The {@link GmTierFeature} grants.
1029
- */
1030
- async tierFeatures(variables) {
1031
- const data = await this.gql.request(GameModelTierFeaturesDocument, variables);
1032
- return data.gameModelTierFeatures;
1033
- }
1034
- /**
1035
- * **App features** — revoke a feature key from an access tier (the inverse of
1036
- * {@link grantTierFeature}). Requires the app-admin **`manage_apps`**
1037
- * permission.
1038
- *
1039
- * @param input - {@link GrantTierFeatureInput} (`appId`, `tierId`, `featureKey`).
1040
- * @returns `true` if a grant was removed.
1041
- */
1042
- async revokeTierFeature(input) {
1043
- const data = await this.gql.request(GameModelRevokeTierFeatureDocument, {
1044
- input,
1045
- });
1046
- return data.gameModelRevokeTierFeature;
1047
- }
1048
- /**
1049
- * **Policy** — read the app's game-model runtime policy (session-creation
1050
- * policy + default participant role). Requires the app-admin **`manage_apps`**
1051
- * permission.
1052
- *
1053
- * @param variables - `{ appId }`.
1054
- * @returns The {@link GmAppPolicy}.
1055
- */
1056
- async policy(variables) {
1057
- const data = await this.gql.request(GameModelPolicyDocument, variables);
1058
- return data.gameModelPolicy;
1059
- }
1060
- // -- Automations (autonomous processes / NPCs) ------------------------------
1061
- /**
1062
- * **Automations** — create or update an autonomous process ("automation" /
1063
- * NPC): a server-driven entry-point function bound to a trigger
1064
- * (`schedule | event | manual`), an optional run-as identity, a target/
1065
- * candidate selector, and a per-automation safety budget. The entry-point
1066
- * function must be marked `autonomousInvocable` (see {@link upsertFunction}).
1067
- * Idempotent on `(appId, name)`. The game-api dispatcher runs it headlessly;
1068
- * a tick is just "invoke a function on behalf of the server".
1069
- *
1070
- * **Only while the app has a player in it** (2026-09-01). A scheduled
1071
- * automation that comes due while the app is empty is skipped silently and
1072
- * rescheduled from the moment a player returns; the missed runs are never made
1073
- * up. Write the entry point so it is idempotent in ELAPSED TIME -- advance the
1074
- * world by `now - lastRun` rather than by one step per tick -- or it will
1075
- * silently fall behind whenever nobody is playing. `event` and `manual`
1076
- * triggers are unaffected: something already asked for those.
1077
- *
1078
- * Requires the app-admin **`manage_apps`** permission.
1079
- *
1080
- * @param input - {@link UpsertAutomationInput}: `appId`; `name` (upsert key);
1081
- * the action — `actionKind: 'model_function'` (default) with
1082
- * `functionName`, or `actionKind: 'compute_invoke'` with
1083
- * `computeModuleName` + `computeExport` (invokes a compute-module invoke
1084
- * export on the trusted server path; `targetMode` forced to `global`,
1085
- * selectors don't apply — requires game-api 2026-07+); `targetMode`
1086
- * (`container | type | global`) with `selfContainerId` /
1087
- * `targetTypeName`; optional `sessionId`, `paramsJson`, `selectorJson`
1088
- * (model-data candidate selection), `runAsUserId`; the trigger
1089
- * (`triggerType`, `scheduleKind`, `intervalMs` / `cronExpr`); and the safety
1090
- * budget (`maxTargets`, `maxFnDepth`, `gasLimit`, `runTimeoutMs`,
1091
- * `maxRunsPerMinute`, `failureThreshold`, `cooldownMs`).
1092
- * @returns The upserted {@link GmAutomation}, including circuit-breaker state.
1093
- */
1094
- async upsertAutomation(input) {
1095
- const data = await this.gql.request(GameModelUpsertAutomationDocument, { input });
1096
- return data.gameModelUpsertAutomation;
1097
- }
1098
- /**
1099
- * **Automations** — delete an automation by name (also removes its event
1100
- * triggers). **Destructive.** Requires the app-admin **`manage_apps`**
1101
- * permission.
1102
- *
1103
- * @param variables - `{ appId, name }`.
1104
- * @returns `true` if one was deleted.
1105
- */
1106
- async deleteAutomation(variables) {
1107
- const data = await this.gql.request(GameModelDeleteAutomationDocument, variables);
1108
- return data.gameModelDeleteAutomation;
1109
- }
1110
- /**
1111
- * **Automations** — enable or disable an automation. Re-enabling also resets
1112
- * its circuit breaker so a tripped automation resumes. Requires the app-admin
1113
- * **`manage_apps`** permission.
1114
- *
1115
- * @param variables - `{ appId, name, enabled }`.
1116
- * @returns The updated {@link GmAutomation}.
1117
- */
1118
- async setAutomationEnabled(variables) {
1119
- const data = await this.gql.request(GameModelSetAutomationEnabledDocument, variables);
1120
- return data.gameModelSetAutomationEnabled;
1121
- }
1122
- /**
1123
- * **Automations** — create an event trigger that fires an automation in
1124
- * reaction to model activity (`function_invoked` | `property_changed` |
1125
- * `container_created` | `player_count_changed`), matched in the API server
1126
- * post-commit. Requires the app-admin **`manage_apps`** permission.
1127
- *
1128
- * Each event matches on its own filters, and a filter the event does not
1129
- * match on is rejected rather than silently never firing:
1130
- * `function_invoked` takes `functionName` and `containerTypeName` (the type
1131
- * of the invocation's `self` container); `property_changed` takes
1132
- * `containerTypeName`, `propertyKey`, and `writeSource`;
1133
- * `container_created` takes `containerTypeName`; `player_count_changed`
1134
- * takes none.
1135
- *
1136
- * `writeSource` decides which writes a `property_changed` trigger sees:
1137
- * `direct` (a {@link GameModelAPI.setProperty} call), `function` (a mutation
1138
- * applied inside an invoke, automation run, or timer fire), or `any`
1139
- * (default). Most game logic writes properties from inside functions, so a
1140
- * trigger watching such a property needs `function` or `any`.
1141
- *
1142
- * @param input - {@link UpsertAutomationTriggerInput}: `appId`,
1143
- * `automationName`, `onEvent`, the filters valid for that event, and
1144
- * `debounceMs`.
1145
- * @returns The created {@link GmAutomationTrigger}.
1146
- */
1147
- async upsertAutomationTrigger(input) {
1148
- const data = await this.gql.request(GameModelUpsertAutomationTriggerDocument, { input });
1149
- return data.gameModelUpsertAutomationTrigger;
1150
- }
1151
- /**
1152
- * **Automations** — delete an event trigger by id. Requires the app-admin
1153
- * **`manage_apps`** permission.
1154
- *
1155
- * @param variables - `{ appId, triggerId }`.
1156
- * @returns `true` if one was deleted.
1157
- */
1158
- async deleteAutomationTrigger(variables) {
1159
- const data = await this.gql.request(GameModelDeleteAutomationTriggerDocument, variables);
1160
- return data.gameModelDeleteAutomationTrigger;
1161
- }
1162
- /**
1163
- * **Automations** — set the app's automation policy (platform guardrails: the
1164
- * kill switch, max automations, the minimum schedule interval floor, max
1165
- * fan-out, max event cascade depth, the aggregate per-minute run ceiling, and
1166
- * the timer floor / pending-timer ceiling).
1167
- * Requires the app-admin **`manage_apps`** permission.
1168
- *
1169
- * @param input - {@link SetAutomationPolicyInput}.
1170
- * @returns The updated {@link GmAutomationPolicy}.
1171
- */
1172
- async setAutomationPolicy(input) {
1173
- const data = await this.gql.request(GameModelSetAutomationPolicyDocument, { input });
1174
- return data.gameModelSetAutomationPolicy;
1175
- }
1176
- /**
1177
- * **Automations** — run an automation once, immediately (manual trigger),
1178
- * regardless of its schedule. Applies the same guard chain and records a run.
1179
- * Useful for testing an NPC. Requires the app-admin **`manage_apps`**
1180
- * permission.
1181
- *
1182
- * @param variables - `{ appId, name }`.
1183
- * @returns The recorded {@link GmAutomationRun}.
1184
- */
1185
- async runAutomation(variables) {
1186
- const data = await this.gql.request(GameModelRunAutomationDocument, variables);
1187
- return data.gameModelRunAutomation;
1188
- }
1189
- /**
1190
- * **Automations** — list the automations defined for an app (with
1191
- * circuit-breaker state). Requires the app-admin **`manage_apps`** permission.
1192
- *
1193
- * @param variables - `{ appId }`.
1194
- * @returns The {@link GmAutomation}s.
1195
- */
1196
- async automations(variables) {
1197
- const data = await this.gql.request(GameModelAutomationsDocument, variables);
1198
- return data.gameModelAutomations;
1199
- }
1200
- /**
1201
- * **Automations** — fetch one automation by name. Requires the app-admin
1202
- * **`manage_apps`** permission.
1203
- *
1204
- * @param variables - `{ appId, name }`.
1205
- * @returns The {@link GmAutomation}.
1206
- */
1207
- async automation(variables) {
1208
- const data = await this.gql.request(GameModelAutomationDocument, variables);
1209
- return data.gameModelAutomation;
1210
- }
1211
- /**
1212
- * **Automations** — list event triggers for an app, optionally filtered to one
1213
- * automation by name. Requires the app-admin **`manage_apps`** permission.
1214
- *
1215
- * Use this to debug a trigger that isn't firing: `warnings` reports filters
1216
- * that can never match, `lastMatchedAt` is null until the trigger has
1217
- * actually dispatched a run, and `matchCount24h` shows recent activity.
1218
- *
1219
- * @param variables - `{ appId, automationName? }`.
1220
- * @returns The {@link GmAutomationTrigger}s.
1221
- */
1222
- async automationTriggers(variables) {
1223
- const data = await this.gql.request(GameModelAutomationTriggersDocument, variables);
1224
- return data.gameModelAutomationTriggers;
1225
- }
1226
- /**
1227
- * **Automations** — read the app's automation policy. Requires the app-admin
1228
- * **`manage_apps`** permission.
1229
- *
1230
- * @param variables - `{ appId }`.
1231
- * @returns The {@link GmAutomationPolicy}.
1232
- */
1233
- async automationPolicy(variables) {
1234
- const data = await this.gql.request(GameModelAutomationPolicyDocument, variables);
1235
- return data.gameModelAutomationPolicy;
1236
- }
1237
- /**
1238
- * **Automations** — list automation runs (the monitoring/audit trail), newest
1239
- * first, optionally filtered by automation name and/or outcome. Requires the
1240
- * app-admin **`manage_apps`** permission.
1241
- *
1242
- * @param variables - `{ appId, automationName?, success?, limit?, offset? }`.
1243
- * @returns The {@link GmAutomationRun}s.
1244
- */
1245
- async automationRuns(variables) {
1246
- const data = await this.gql.request(GameModelAutomationRunsDocument, variables);
1247
- return data.gameModelAutomationRuns;
1248
- }
1249
- /**
1250
- * **Automations** — aggregate automation activity over a recent window
1251
- * (throughput, failure rate, compute, per-automation breakdown). The
1252
- * "what are my NPCs doing" view. Requires the app-admin **`manage_apps`**
1253
- * permission.
1254
- *
1255
- * @param variables - `{ appId, windowMinutes? }` (default 60, max 1440).
1256
- * @returns The {@link GmAutomationStats}.
1257
- */
1258
- async automationStats(variables) {
1259
- const data = await this.gql.request(GameModelAutomationStatsDocument, variables);
1260
- return data.gameModelAutomationStats;
1261
- }
1262
- /**
1263
- * **Diagnostics** — a snapshot of an app's game-model footprint and recent
1264
- * activity (row counts + 24h invocation activity + top functions). Helps
1265
- * developers understand what is in their game and their database. Requires the
1266
- * app-admin **`manage_apps`** permission.
1267
- *
1268
- * @param variables - `{ appId }`.
1269
- * @returns The {@link GmAppDiagnostics}.
1270
- */
1271
- async appDiagnostics(variables) {
1272
- const data = await this.gql.request(GameModelAppDiagnosticsDocument, variables);
1273
- return data.gameModelAppDiagnostics;
1274
- }
1275
- /**
1276
- * **Timers** — arm a one-shot timer: invoke a function once, after a delay.
1277
- * The timer is durable (it survives an API restart) and claimed by exactly one
1278
- * replica, so it fires once. Requires the app-admin **`manage_apps`**
1279
- * permission, because a timer fires headlessly with system authority rather
1280
- * than a player's.
1281
- *
1282
- * A timer whose deadline passes while the app has no players **waits** rather
1283
- * than firing into an empty world: the sweep only claims timers for apps with a
1284
- * player present, so it is still armed and fires when somebody returns. It is
1285
- * therefore late, not lost -- read the current time in the handler rather than
1286
- * assuming the delay you asked for is the delay that elapsed.
1287
- *
1288
- * For player-driven delays, declare a `timers` effect on the function instead
1289
- * (see {@link GameModelAPI.upsertFunction}) so the delay is part of your game
1290
- * logic and is armed atomically with that invocation's mutations.
1291
- *
1292
- * The target function must be `autonomousInvocable`. Pass `dedupeKey` to make
1293
- * re-arming replace the pending timer instead of queueing another fire, which
1294
- * is how you implement "reset the countdown".
1295
- *
1296
- * @param input - {@link ScheduleInvokeInput}: `appId`, `functionName`,
1297
- * `selfContainerId`, `delayMs`, and optional `paramsJson`, `sessionId`, and
1298
- * `dedupeKey`.
1299
- * @returns The armed {@link GmTimer}.
1300
- */
1301
- async scheduleInvoke(input) {
1302
- const data = await this.gql.request(GameModelScheduleInvokeDocument, { input });
1303
- return data.gameModelScheduleInvoke;
1304
- }
1305
- /**
1306
- * **Timers** — cancel pending timers by id or by dedupe key. A timer already
1307
- * claimed for execution cannot be cancelled. Requires the app-admin
1308
- * **`manage_apps`** permission.
1309
- *
1310
- * @param variables - `{ appId, timerId?, dedupeKey? }` (supply at least one
1311
- * selector).
1312
- * @returns How many pending timers were removed.
1313
- */
1314
- async cancelTimer(variables) {
1315
- const data = await this.gql.request(GameModelCancelTimerDocument, variables);
1316
- return data.gameModelCancelTimer;
1317
- }
1318
- /**
1319
- * **Timers** — list pending one-shot timers, soonest first. A timer leaves
1320
- * this list the instant it is claimed for execution, so an empty list means
1321
- * nothing is *scheduled* — not that nothing ran. Fires that already happened
1322
- * appear in {@link GameModelAPI.automationRuns} with
1323
- * `triggerSource: 'timer'`. Requires the app-admin **`manage_apps`**
1324
- * permission.
1325
- *
1326
- * @param variables - `{ appId, sessionId?, limit? }` (limit 1-200, default 50).
1327
- * @returns The pending {@link GmTimer}s.
1328
- */
1329
- async timers(variables) {
1330
- const data = await this.gql.request(GameModelTimersDocument, variables);
1331
- return data.gameModelTimers;
1332
- }
1333
- }