@crowdedkingdomstudios/crowdyjs 5.1.0 → 5.2.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.
- package/MIGRATION.md +64 -0
- package/README.md +19 -0
- package/dist/client.d.ts +98 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +74 -5
- package/dist/crowdy-client.d.ts +31 -0
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +8 -0
- package/dist/domains/actors.d.ts +88 -5
- package/dist/domains/actors.d.ts.map +1 -1
- package/dist/domains/actors.js +89 -6
- package/dist/domains/apps.d.ts +95 -41
- package/dist/domains/apps.d.ts.map +1 -1
- package/dist/domains/apps.js +80 -33
- package/dist/domains/auth.d.ts +139 -19
- package/dist/domains/auth.d.ts.map +1 -1
- package/dist/domains/auth.js +137 -17
- package/dist/domains/channels.d.ts +264 -5
- package/dist/domains/channels.d.ts.map +1 -1
- package/dist/domains/channels.js +264 -5
- package/dist/domains/chunks.d.ts +116 -3
- package/dist/domains/chunks.d.ts.map +1 -1
- package/dist/domains/chunks.js +116 -3
- package/dist/domains/gameModel.d.ts +412 -6
- package/dist/domains/gameModel.d.ts.map +1 -1
- package/dist/domains/gameModel.js +412 -6
- package/dist/domains/platform.d.ts +36 -20
- package/dist/domains/platform.d.ts.map +1 -1
- package/dist/domains/platform.js +29 -18
- package/dist/domains/serverStatus.d.ts +74 -6
- package/dist/domains/serverStatus.d.ts.map +1 -1
- package/dist/domains/serverStatus.js +74 -6
- package/dist/domains/state.d.ts +50 -2
- package/dist/domains/state.d.ts.map +1 -1
- package/dist/domains/state.js +50 -2
- package/dist/domains/teams.d.ts +265 -7
- package/dist/domains/teams.d.ts.map +1 -1
- package/dist/domains/teams.js +267 -9
- package/dist/domains/teleport.d.ts +30 -2
- package/dist/domains/teleport.d.ts.map +1 -1
- package/dist/domains/teleport.js +30 -2
- package/dist/domains/udp.d.ts +341 -5
- package/dist/domains/udp.d.ts.map +1 -1
- package/dist/domains/udp.js +341 -5
- package/dist/domains/users.d.ts +42 -11
- package/dist/domains/users.d.ts.map +1 -1
- package/dist/domains/users.js +41 -10
- package/dist/domains/voxels.d.ts +107 -2
- package/dist/domains/voxels.d.ts.map +1 -1
- package/dist/domains/voxels.js +107 -2
- package/dist/errors.d.ts +116 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +100 -0
- package/dist/generated/graphql.d.ts +1787 -110
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +75 -9
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/realtime.d.ts +226 -0
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +90 -0
- package/dist/session.d.ts +46 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +35 -0
- package/dist/types.d.ts +429 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +53 -0
- package/dist/utils.d.ts +86 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +86 -0
- package/dist/world.d.ts +192 -0
- package/dist/world.d.ts.map +1 -1
- package/dist/world.js +170 -0
- package/package.json +1 -1
|
@@ -4,109 +4,515 @@ GameModelCreateSessionDocument, GameModelJoinSessionDocument, GameModelSetSessio
|
|
|
4
4
|
// Studio authoring ops
|
|
5
5
|
GameModelSeedDocument, GameModelUpsertContainerTypeDocument, GameModelUpsertPropertyDefDocument, GameModelUpsertFunctionDocument, GameModelDeleteFunctionDocument, GameModelDefineFeatureDocument, GameModelGrantTierFeatureDocument, GameModelSetPolicyDocument, GameModelTypeSchemaDocument, } from '../generated/graphql.js';
|
|
6
6
|
/**
|
|
7
|
-
* Abstract game
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Abstract **game-model** sub-client on the **game-api** — a schema-driven,
|
|
8
|
+
* server-authoritative layer for modelling game/world logic on top of the
|
|
9
|
+
* spatial voxel world. Studios *author* the model; players *query* state and
|
|
10
|
+
* *invoke* functions at runtime. Exposed as `client.gameModel`.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
12
|
+
* The model is a typed graph of entities:
|
|
13
|
+
* - **Container types** are the schemas (like classes) for a kind of entity.
|
|
14
|
+
* **Property definitions** are their typed fields, each with a default value,
|
|
15
|
+
* a read **visibility** (`public | owner | hidden`) and a **writability**
|
|
16
|
+
* (`function | owner | admin`). See {@link upsertContainerType} /
|
|
17
|
+
* {@link upsertPropertyDef} / {@link typeSchema}.
|
|
18
|
+
* - **Containers** are the runtime instances of a type, optionally scoped to a
|
|
19
|
+
* session and carrying property values. See {@link createContainer},
|
|
20
|
+
* {@link container}, {@link containers}, {@link containerState}.
|
|
21
|
+
* - **Functions** are named, sandboxed behaviours over containers: typed
|
|
22
|
+
* parameters, declared property **mutations** (expressions compiled to an AST
|
|
23
|
+
* server-side — never `eval`'d), an optional return expression, an
|
|
24
|
+
* `invokeScope` (`player | server | internal`), and an **invoke policy** — an
|
|
25
|
+
* authority rule tree of `owner_of_self`, `is_host`, `is_current_turn`,
|
|
26
|
+
* `is_participant`, `tier_feature`, `group_permission`, `grid_permission`, and
|
|
27
|
+
* `condition` rules. {@link invoke} is the primary, *safe* way for players to
|
|
28
|
+
* mutate state: the server checks the policy, evaluates the expressions,
|
|
29
|
+
* applies the mutations atomically, and logs an **event**.
|
|
30
|
+
* - **Sessions** are isolated instance scopes (a match, room, or save) with
|
|
31
|
+
* **participants**, a creator, and an optional current-**turn** user for
|
|
32
|
+
* turn-based play. See {@link createSession}, {@link joinSession},
|
|
33
|
+
* {@link setSessionTurn}, {@link session}, {@link sessions}.
|
|
34
|
+
* - **Edges** are directed, typed relationships between containers (the model is
|
|
35
|
+
* a graph); {@link traverse} walks them from a root up to a depth. See
|
|
36
|
+
* {@link addEdge}.
|
|
37
|
+
* - **Events** are an audit log of every function invocation and its outcome.
|
|
38
|
+
* See {@link events}.
|
|
39
|
+
* - **App features** are keys functions gate on (via `tier_feature` rules) and
|
|
40
|
+
* that **access tiers** can be granted ({@link defineFeature},
|
|
41
|
+
* {@link grantTierFeature}); **policy** governs who may create sessions and the
|
|
42
|
+
* default participant role ({@link setPolicy}).
|
|
43
|
+
* - {@link seed} bulk-creates definitions *and* instances in one transaction for
|
|
44
|
+
* model init/import.
|
|
13
45
|
*
|
|
14
|
-
*
|
|
46
|
+
* **Encoding.** `BigInt` ids (`appId`, `tierId`, every `*UserId`) are sent and
|
|
47
|
+
* received as decimal **strings**. Container, session, function, edge, and event
|
|
48
|
+
* ids are opaque **UUID strings**. All structured values travel as JSON-encoded
|
|
49
|
+
* strings in the `*Json` fields (`metadataJson`, `propertiesJson`, `paramsJson`,
|
|
50
|
+
* `valueJson`, `returnValueJson`, `invokePolicyJson`, `idMapJson`, …) — callers
|
|
51
|
+
* `JSON.parse` / `JSON.stringify` around them. (Unlike actor/state blobs, these
|
|
52
|
+
* are JSON text, not base64.)
|
|
53
|
+
*
|
|
54
|
+
* **Auth.** Every call requires an authenticated session (a Bearer token set via
|
|
55
|
+
* `client.auth.login()` or `client.setToken()`) scoped to the target app, or it
|
|
56
|
+
* throws {@link CrowdyGraphQLError} (`UNAUTHENTICATED` / `SCOPE_MISSING`). The
|
|
57
|
+
* **studio-authoring** methods ({@link seed}, {@link upsertContainerType},
|
|
58
|
+
* {@link upsertPropertyDef}, {@link upsertFunction}, {@link deleteFunction},
|
|
59
|
+
* {@link defineFeature}, {@link grantTierFeature}, {@link setPolicy}) and the
|
|
60
|
+
* {@link typeSchema} query additionally require the app-admin **`manage_apps`**
|
|
61
|
+
* permission (otherwise `FORBIDDEN`, with `extensions.requiredPermission ===
|
|
62
|
+
* 'manage_apps'`); the runtime/player methods need only a valid token plus
|
|
63
|
+
* whatever per-operation policy applies (session-creation policy, a type's
|
|
64
|
+
* `instantiableBy` rule, a property's `writable` rule, or a function's invoke
|
|
65
|
+
* policy).
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* // Studio authors a type, then a player creates a session and invokes a function.
|
|
70
|
+
* await client.gameModel.upsertContainerType({ appId, typeName: 'Player', displayName: 'Player' });
|
|
71
|
+
* const session = await client.gameModel.createSession({ appId, name: 'Match 1' });
|
|
72
|
+
* const result = await client.gameModel.invoke({
|
|
73
|
+
* appId,
|
|
74
|
+
* functionName: 'takeDamage',
|
|
75
|
+
* selfContainerId,
|
|
76
|
+
* paramsJson: JSON.stringify({ amount: 10 }),
|
|
77
|
+
* });
|
|
78
|
+
* if (!result.success) console.warn(result.errorMessage); // authority/eval failures don't throw
|
|
79
|
+
* ```
|
|
15
80
|
*/
|
|
16
81
|
export class GameModelAPI {
|
|
17
82
|
constructor(gql) {
|
|
18
83
|
this.gql = gql;
|
|
19
84
|
}
|
|
20
85
|
// -- Runtime (player) -------------------------------------------------------
|
|
86
|
+
/**
|
|
87
|
+
* **Sessions** — create a runtime session: an isolated instance scope for
|
|
88
|
+
* containers (e.g. a match, room, or save). Subject to the app's
|
|
89
|
+
* session-creation policy ({@link setPolicy}); the caller becomes the creator
|
|
90
|
+
* and a participant.
|
|
91
|
+
*
|
|
92
|
+
* @param input - {@link CreateSessionInput}: `appId` (decimal string), an
|
|
93
|
+
* optional `name`, optional `metadataJson` (a JSON-object string), and
|
|
94
|
+
* optional `participantUserIds` (decimal-string ids of initial participants
|
|
95
|
+
* besides the creator).
|
|
96
|
+
* @returns The created {@link GmSession} (`sessionId`, `status`, creator,
|
|
97
|
+
* current turn, metadata, …).
|
|
98
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING` if the token
|
|
99
|
+
* is missing or not scoped to the app, `FORBIDDEN` if the session-creation
|
|
100
|
+
* policy disallows the caller, or `BAD_USER_INPUT` for malformed input.
|
|
101
|
+
*/
|
|
21
102
|
async createSession(input) {
|
|
22
103
|
const data = await this.gql.request(GameModelCreateSessionDocument, { input });
|
|
23
104
|
return data.gameModelCreateSession;
|
|
24
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* **Sessions** — join an existing session as a participant, optionally with a
|
|
108
|
+
* role. Requires a valid token and access to the app.
|
|
109
|
+
*
|
|
110
|
+
* @param input - {@link JoinSessionInput}: `appId` (decimal string),
|
|
111
|
+
* `sessionId`, and an optional participant `role`.
|
|
112
|
+
* @returns The {@link GmSessionParticipant} record (`sessionId`, `userId`,
|
|
113
|
+
* `role`).
|
|
114
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
115
|
+
* `NOT_FOUND` if no such session, or `FORBIDDEN` if joining isn't permitted.
|
|
116
|
+
*/
|
|
25
117
|
async joinSession(input) {
|
|
26
118
|
const data = await this.gql.request(GameModelJoinSessionDocument, { input });
|
|
27
119
|
return data.gameModelJoinSession;
|
|
28
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* **Sessions** — set or clear the session's current-turn user, for turn-based
|
|
123
|
+
* play (turn authority is enforced by the service).
|
|
124
|
+
*
|
|
125
|
+
* @param input - {@link SetSessionTurnInput}: `appId` (decimal string),
|
|
126
|
+
* `sessionId`, and `userId` (the decimal-string id of the user whose turn it
|
|
127
|
+
* now is) — pass `userId: null` to **clear** the turn.
|
|
128
|
+
* @returns The updated {@link GmSession} (with `currentTurnUserId` reflecting
|
|
129
|
+
* the change).
|
|
130
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
131
|
+
* `NOT_FOUND` if the session doesn't exist, or `FORBIDDEN` if the caller may
|
|
132
|
+
* not change the turn.
|
|
133
|
+
*/
|
|
29
134
|
async setSessionTurn(input) {
|
|
30
135
|
const data = await this.gql.request(GameModelSetSessionTurnDocument, { input });
|
|
31
136
|
return data.gameModelSetSessionTurn;
|
|
32
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* **Containers** — instantiate a container (a runtime entity of a given type),
|
|
140
|
+
* optionally within a session, with an owner and initial property values.
|
|
141
|
+
* Subject to the type's `instantiableBy` rule (`admin | member | owner`).
|
|
142
|
+
*
|
|
143
|
+
* @param input - {@link CreateContainerInput}: `appId` (decimal string), an
|
|
144
|
+
* optional `sessionId` (omit for an app-global container), the `typeName` to
|
|
145
|
+
* instantiate, a `displayName`, optional `description`, optional
|
|
146
|
+
* `ownerUserId` (decimal string; defaults to the caller for member/owner
|
|
147
|
+
* instantiation), optional `metadataJson` (JSON-object string), and optional
|
|
148
|
+
* initial `properties` (each `{ key, valueType, valueJson }` with a
|
|
149
|
+
* JSON-encoded value).
|
|
150
|
+
* @returns The created {@link GmContainer}.
|
|
151
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
152
|
+
* `FORBIDDEN` if `instantiableBy` disallows the caller, `NOT_FOUND` for an
|
|
153
|
+
* unknown type, or `BAD_USER_INPUT` for malformed properties.
|
|
154
|
+
*/
|
|
33
155
|
async createContainer(input) {
|
|
34
156
|
const data = await this.gql.request(GameModelCreateContainerDocument, { input });
|
|
35
157
|
return data.gameModelCreateContainer;
|
|
36
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* **Containers** — set a single property value on a container directly (outside
|
|
161
|
+
* a function). Allowed only when the property's `writable` rule
|
|
162
|
+
* (`function | owner | admin`) permits the caller; the value is JSON-encoded
|
|
163
|
+
* and coerced to the property's declared value type. For game-logic changes
|
|
164
|
+
* prefer {@link invoke}, which enforces an authority policy and logs an event.
|
|
165
|
+
*
|
|
166
|
+
* @param input - {@link SetContainerPropertyInput}: `appId` (decimal string),
|
|
167
|
+
* `containerId`, the property `key`, its `valueType` (must match the property
|
|
168
|
+
* definition), and `valueJson` (the JSON-encoded value to write).
|
|
169
|
+
* @returns The updated {@link GmContainer}.
|
|
170
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
171
|
+
* `FORBIDDEN` if the property's `writable` rule forbids a direct write,
|
|
172
|
+
* `NOT_FOUND` for an unknown container/property, or `BAD_USER_INPUT` for a
|
|
173
|
+
* value-type mismatch.
|
|
174
|
+
*/
|
|
37
175
|
async setProperty(input) {
|
|
38
176
|
const data = await this.gql.request(GameModelSetPropertyDocument, { input });
|
|
39
177
|
return data.gameModelSetProperty;
|
|
40
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* **Edges** — create a directed relationship edge between two containers (the
|
|
181
|
+
* game model is a graph), with a relationship type and optional weight.
|
|
182
|
+
*
|
|
183
|
+
* @param input - {@link AddEdgeInput}: `appId` (decimal string),
|
|
184
|
+
* `fromContainerId` (source) and `toContainerId` (target), a
|
|
185
|
+
* `relationshipType` label, an optional numeric `weight`, and optional
|
|
186
|
+
* `metadataJson` (JSON-object string).
|
|
187
|
+
* @returns The created {@link GmEdge} (`edgeId`, endpoints, type, weight).
|
|
188
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
189
|
+
* `NOT_FOUND` if either container is unknown, or `BAD_USER_INPUT`.
|
|
190
|
+
*/
|
|
41
191
|
async addEdge(input) {
|
|
42
192
|
const data = await this.gql.request(GameModelAddEdgeDocument, { input });
|
|
43
193
|
return data.gameModelAddEdge;
|
|
44
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* **Functions** — invoke a studio-defined function against a `self` container
|
|
197
|
+
* with JSON params. This is the primary, *safe* way for players to mutate game
|
|
198
|
+
* state: the server enforces the function's invoke policy (the authority rule
|
|
199
|
+
* tree — `owner_of_self` / `is_host` / `is_current_turn` / `is_participant` /
|
|
200
|
+
* `tier_feature` / `group_permission` / `grid_permission` / `condition`),
|
|
201
|
+
* evaluates its expressions, atomically applies its declared property
|
|
202
|
+
* mutations, and logs an {@link events | event}. Only `player`-scope functions
|
|
203
|
+
* are invocable here.
|
|
204
|
+
*
|
|
205
|
+
* Note: an authority denial or an expression-evaluation error is **not** a
|
|
206
|
+
* thrown exception — it comes back as a resolved result with `success: false`
|
|
207
|
+
* and an `errorMessage`. Inspect `result.success` rather than relying on
|
|
208
|
+
* `try/catch` for those cases.
|
|
209
|
+
*
|
|
210
|
+
* @param input - {@link InvokeFunctionInput}: `appId` (decimal string), the
|
|
211
|
+
* `functionName`, the `selfContainerId` (the container the function runs
|
|
212
|
+
* against, referenced as `self` in expressions), an optional `sessionId`
|
|
213
|
+
* context, and `paramsJson` (a JSON-object string of params).
|
|
214
|
+
* @returns A {@link GmInvokeResult}: `success`, the logged `eventId`, the
|
|
215
|
+
* JSON-encoded `returnValueJson`, the `mutationsApplied` (each with
|
|
216
|
+
* before/after JSON values), and `errorMessage` when `success` is `false`.
|
|
217
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
218
|
+
* `NOT_FOUND` for an unknown function/container, `FORBIDDEN` if the function
|
|
219
|
+
* isn't `player`-scope, or `BAD_USER_INPUT` for malformed params. (Authority
|
|
220
|
+
* and evaluation failures surface as `success: false`, see above.)
|
|
221
|
+
*/
|
|
45
222
|
async invoke(input) {
|
|
46
223
|
const data = await this.gql.request(GameModelInvokeDocument, { input });
|
|
47
224
|
return data.gameModelInvoke;
|
|
48
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* **Containers** — fetch one container (instance) by id, with its full record
|
|
228
|
+
* (unfiltered metadata). For a player-facing view whose property values are
|
|
229
|
+
* filtered to what the caller may see, use {@link containerState} instead.
|
|
230
|
+
*
|
|
231
|
+
* @param variables - `{ appId, containerId }`: `appId` (decimal string) is the
|
|
232
|
+
* owning app and `containerId` is the container UUID to fetch.
|
|
233
|
+
* @returns The {@link GmContainer}.
|
|
234
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
|
|
235
|
+
* `NOT_FOUND` if no such container.
|
|
236
|
+
*/
|
|
49
237
|
async container(variables) {
|
|
50
238
|
const data = await this.gql.request(GameModelContainerDocument, variables);
|
|
51
239
|
return data.gameModelContainer;
|
|
52
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* **Containers** — list containers in an app, optionally narrowed by container
|
|
243
|
+
* type and/or session.
|
|
244
|
+
*
|
|
245
|
+
* @param variables - `{ appId, typeName?, sessionId? }`: `appId` (decimal
|
|
246
|
+
* string); optional `typeName` (omit for all types); optional `sessionId`
|
|
247
|
+
* (omit for all containers, including app-global ones).
|
|
248
|
+
* @returns The matching {@link GmContainer}s.
|
|
249
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`.
|
|
250
|
+
*/
|
|
53
251
|
async containers(variables) {
|
|
54
252
|
const data = await this.gql.request(GameModelContainersDocument, variables);
|
|
55
253
|
return data.gameModelContainers;
|
|
56
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* **Containers** — fetch a container together with its property values
|
|
257
|
+
* filtered to what the **calling** user is allowed to see (`public` always;
|
|
258
|
+
* `owner`/`hidden` depend on the caller's relationship to the container). Use
|
|
259
|
+
* this for a player-facing view of an entity.
|
|
260
|
+
*
|
|
261
|
+
* @param variables - `{ appId, containerId }`: `appId` (decimal string) and
|
|
262
|
+
* the `containerId` UUID whose visible state to fetch.
|
|
263
|
+
* @returns A {@link GmContainerState}; its `propertiesJson` is a JSON-object
|
|
264
|
+
* string of the properties visible to the caller (`JSON.parse` it).
|
|
265
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
|
|
266
|
+
* `NOT_FOUND` if no such container.
|
|
267
|
+
*/
|
|
57
268
|
async containerState(variables) {
|
|
58
269
|
const data = await this.gql.request(GameModelContainerStateDocument, variables);
|
|
59
270
|
return data.gameModelContainerState;
|
|
60
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* **Edges** — traverse the container graph from a root container along a
|
|
274
|
+
* relationship type up to a given depth, returning the reachable nodes and the
|
|
275
|
+
* edges between them.
|
|
276
|
+
*
|
|
277
|
+
* @param variables - `{ appId, rootId, relationshipType, depth? }`: `appId`
|
|
278
|
+
* (decimal string); the `rootId` container UUID to start from; the
|
|
279
|
+
* `relationshipType` edge label to follow; and optional `depth`, the number
|
|
280
|
+
* of edge hops to follow from the root (defaults to `1`).
|
|
281
|
+
* @returns A {@link GmTraverseResult}: the `rootId`, the reachable `nodes`
|
|
282
|
+
* ({@link GmContainer}[]), and the traversed `edges` ({@link GmEdge}[]).
|
|
283
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
|
|
284
|
+
* `NOT_FOUND` if the root container is unknown.
|
|
285
|
+
*/
|
|
61
286
|
async traverse(variables) {
|
|
62
287
|
const data = await this.gql.request(GameModelTraverseDocument, variables);
|
|
63
288
|
return data.gameModelTraverse;
|
|
64
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* **Sessions** — fetch one session by id.
|
|
292
|
+
*
|
|
293
|
+
* @param variables - `{ appId, sessionId }`: `appId` (decimal string) and the
|
|
294
|
+
* `sessionId` to fetch.
|
|
295
|
+
* @returns The {@link GmSession}.
|
|
296
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
|
|
297
|
+
* `NOT_FOUND` if no such session.
|
|
298
|
+
*/
|
|
65
299
|
async session(variables) {
|
|
66
300
|
const data = await this.gql.request(GameModelSessionDocument, variables);
|
|
67
301
|
return data.gameModelSession;
|
|
68
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* **Sessions** — list sessions in an app, optionally filtered by status.
|
|
305
|
+
*
|
|
306
|
+
* @param variables - `{ appId, status? }`: `appId` (decimal string) and an
|
|
307
|
+
* optional `status` filter (e.g. `'active'`; omit for all statuses).
|
|
308
|
+
* @returns The matching {@link GmSession}s.
|
|
309
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`.
|
|
310
|
+
*/
|
|
69
311
|
async sessions(variables) {
|
|
70
312
|
const data = await this.gql.request(GameModelSessionsDocument, variables);
|
|
71
313
|
return data.gameModelSessions;
|
|
72
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* **Events** — query the function-invocation event log (audit trail) with
|
|
317
|
+
* optional filters and pagination. Useful for debugging functions or showing
|
|
318
|
+
* recent activity.
|
|
319
|
+
*
|
|
320
|
+
* @param variables - `{ appId, sessionId?, selfContainerId?, functionName?,
|
|
321
|
+
* success?, limit?, offset? }`: `appId` (decimal string); optional
|
|
322
|
+
* `sessionId`; optional `selfContainerId` (the UUID the function ran
|
|
323
|
+
* against); optional `functionName`; optional `success` (`true` = succeeded,
|
|
324
|
+
* `false` = failed). `limit` (page size) and `offset` (rows to skip) are
|
|
325
|
+
* **deprecated** — see below.
|
|
326
|
+
* @returns The matching {@link GmEvent}s (each with `paramsJson`,
|
|
327
|
+
* `mutationsAppliedJson`, `returnValueJson`, `success`, `errorMessage`, and
|
|
328
|
+
* `executedAt`).
|
|
329
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`.
|
|
330
|
+
* @remarks The `limit`/`offset` fields use deprecated offset pagination. For
|
|
331
|
+
* large logs prefer the Relay-style `gameModelEventsConnection(first:, after:)`
|
|
332
|
+
* cursor query (available on the schema via `client.graphql`). See
|
|
333
|
+
* https://docs.crowdedkingdoms.com/overview/pagination.
|
|
334
|
+
*/
|
|
73
335
|
async events(variables) {
|
|
74
336
|
const data = await this.gql.request(GameModelEventsDocument, variables);
|
|
75
337
|
return data.gameModelEvents;
|
|
76
338
|
}
|
|
77
339
|
// -- Studio authoring -------------------------------------------------------
|
|
340
|
+
/**
|
|
341
|
+
* **Seed** — bulk-create game-model definitions (container types, property
|
|
342
|
+
* defs, functions) and optionally instances (containers + edges) in one
|
|
343
|
+
* transaction; used to initialize or import a model.
|
|
344
|
+
*
|
|
345
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
346
|
+
*
|
|
347
|
+
* @param input - {@link SeedGameModelInput}: `appId` (decimal string); an
|
|
348
|
+
* optional `sessionId` to seed instances into (omit/`null` = app-global);
|
|
349
|
+
* and arrays of `containerTypes`, `propertyDefinitions`, `functions`,
|
|
350
|
+
* `containers`, and `edges` to create. Seed containers carry a developer
|
|
351
|
+
* `tempId`; seed edges reference containers by those temp ids
|
|
352
|
+
* (`fromTempId`/`toTempId`).
|
|
353
|
+
* @returns A {@link GmSeedResult}: the counts created, non-fatal `warnings`,
|
|
354
|
+
* and `idMapJson` — a JSON-object string mapping each seed `tempId` to the
|
|
355
|
+
* created container UUID (`JSON.parse` it to wire up follow-up calls).
|
|
356
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
357
|
+
* `FORBIDDEN` (with `extensions.requiredPermission === 'manage_apps'`) if the
|
|
358
|
+
* caller lacks app-admin, or `BAD_USER_INPUT` for malformed definitions.
|
|
359
|
+
*/
|
|
78
360
|
async seed(input) {
|
|
79
361
|
const data = await this.gql.request(GameModelSeedDocument, { input });
|
|
80
362
|
return data.gameModelSeed;
|
|
81
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* **Container types** — create or update a container type: the studio-defined
|
|
366
|
+
* schema for a kind of runtime entity (like a class). Idempotent on
|
|
367
|
+
* `(appId, typeName)`.
|
|
368
|
+
*
|
|
369
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
370
|
+
*
|
|
371
|
+
* @param input - {@link UpsertContainerTypeInput}: `appId` (decimal string);
|
|
372
|
+
* the `typeName` (the stable upsert key, unique per app); a `displayName`;
|
|
373
|
+
* optional `description`; optional `instantiableBy` (`admin | member |
|
|
374
|
+
* owner`); optional `defaultPropertyVisibility` (`public | owner | hidden`);
|
|
375
|
+
* and optional `metadataJson` (JSON-object string).
|
|
376
|
+
* @returns The upserted {@link GmContainerType}.
|
|
377
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
378
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`.
|
|
379
|
+
*/
|
|
82
380
|
async upsertContainerType(input) {
|
|
83
381
|
const data = await this.gql.request(GameModelUpsertContainerTypeDocument, { input });
|
|
84
382
|
return data.gameModelUpsertContainerType;
|
|
85
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* **Property definitions** — create or update a typed property on a container
|
|
386
|
+
* type (a field with a default value, read visibility, and writability).
|
|
387
|
+
* Idempotent on `(appId, containerTypeName, key)`.
|
|
388
|
+
*
|
|
389
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
390
|
+
*
|
|
391
|
+
* @param input - {@link UpsertPropertyDefInput}: `appId` (decimal string); the
|
|
392
|
+
* `containerTypeName` to define on; the property `key` (part of the upsert
|
|
393
|
+
* key); a `valueType` (`int | float | string | bool | array | object |
|
|
394
|
+
* container_ref`); optional `defaultValueJson` (JSON-encoded default);
|
|
395
|
+
* optional `visibility` (`public | owner | hidden`); optional `writable`
|
|
396
|
+
* (`function | owner | admin`); and optional `description`.
|
|
397
|
+
* @returns The upserted {@link GmPropertyDef}.
|
|
398
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
399
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`), `NOT_FOUND` for an
|
|
400
|
+
* unknown container type, or `BAD_USER_INPUT`.
|
|
401
|
+
*/
|
|
86
402
|
async upsertPropertyDef(input) {
|
|
87
403
|
const data = await this.gql.request(GameModelUpsertPropertyDefDocument, { input });
|
|
88
404
|
return data.gameModelUpsertPropertyDef;
|
|
89
405
|
}
|
|
406
|
+
/**
|
|
407
|
+
* **Functions** — create or update a studio-defined function: a named,
|
|
408
|
+
* sandboxed behaviour with typed parameters, declared property mutations
|
|
409
|
+
* (expressions compiled to an AST server-side — never `eval`'d), an optional
|
|
410
|
+
* return expression, an invoke scope, and an invoke policy (authority rule
|
|
411
|
+
* tree). Idempotent on `(appId, name)`. Players run these via {@link invoke}.
|
|
412
|
+
*
|
|
413
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
414
|
+
*
|
|
415
|
+
* @param input - {@link UpsertFunctionInput}: `appId` (decimal string); the
|
|
416
|
+
* `name` (upsert key, used to invoke it); optional `containerTypeName` to
|
|
417
|
+
* bind to (omit for a global function); optional `description`; optional
|
|
418
|
+
* `returnType`; `parameters` (typed `{ name, valueType, required?,
|
|
419
|
+
* defaultValueJson?, … }`); `mutations` (declared writes `{ target, property,
|
|
420
|
+
* expression }`, applied atomically); optional `returnExpression`;
|
|
421
|
+
* `invokeScope` (`player | server | internal`); and `invokePolicyJson` (a
|
|
422
|
+
* JSON-encoded authority rule tree).
|
|
423
|
+
* @returns The upserted {@link GmFunction}, including any non-fatal
|
|
424
|
+
* static-analysis `warnings` from this upload.
|
|
425
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
426
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`
|
|
427
|
+
* for an expression/policy that fails to compile.
|
|
428
|
+
*/
|
|
90
429
|
async upsertFunction(input) {
|
|
91
430
|
const data = await this.gql.request(GameModelUpsertFunctionDocument, { input });
|
|
92
431
|
return data.gameModelUpsertFunction;
|
|
93
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* **Functions** — delete a studio-defined function by name. **Destructive.**
|
|
435
|
+
*
|
|
436
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
437
|
+
*
|
|
438
|
+
* @param variables - `{ appId, name }`: `appId` (decimal string) and the
|
|
439
|
+
* function `name` to delete.
|
|
440
|
+
* @returns `true` if a function was deleted, `false` if none matched.
|
|
441
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`, or
|
|
442
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`) if the caller lacks
|
|
443
|
+
* app-admin.
|
|
444
|
+
*/
|
|
94
445
|
async deleteFunction(variables) {
|
|
95
446
|
const data = await this.gql.request(GameModelDeleteFunctionDocument, variables);
|
|
96
447
|
return data.gameModelDeleteFunction;
|
|
97
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* **App features** — define an app feature key that functions can gate on (via
|
|
451
|
+
* a `tier_feature` authority rule) and that access tiers can be granted.
|
|
452
|
+
* Idempotent on `(appId, featureKey)`.
|
|
453
|
+
*
|
|
454
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
455
|
+
*
|
|
456
|
+
* @param input - {@link DefineAppFeatureInput}: `appId` (decimal string); the
|
|
457
|
+
* `featureKey` (referenced by `tier_feature` rules); and an optional
|
|
458
|
+
* `description`.
|
|
459
|
+
* @returns The defined {@link GmAppFeature}.
|
|
460
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
461
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`.
|
|
462
|
+
*/
|
|
98
463
|
async defineFeature(input) {
|
|
99
464
|
const data = await this.gql.request(GameModelDefineFeatureDocument, { input });
|
|
100
465
|
return data.gameModelDefineFeature;
|
|
101
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* **App features** — grant a feature key to an access tier, so users on that
|
|
469
|
+
* tier satisfy `tier_feature` authority checks for it.
|
|
470
|
+
*
|
|
471
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
472
|
+
*
|
|
473
|
+
* @param input - {@link GrantTierFeatureInput}: `appId` (decimal string); the
|
|
474
|
+
* `tierId` (decimal string) of the access tier; and the `featureKey` to
|
|
475
|
+
* grant to that tier.
|
|
476
|
+
* @returns The {@link GmTierFeature} grant record.
|
|
477
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
478
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `NOT_FOUND` for an
|
|
479
|
+
* unknown tier/feature.
|
|
480
|
+
*/
|
|
102
481
|
async grantTierFeature(input) {
|
|
103
482
|
const data = await this.gql.request(GameModelGrantTierFeatureDocument, { input });
|
|
104
483
|
return data.gameModelGrantTierFeature;
|
|
105
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* **Policy** — set the app's game-model runtime policy: who may create
|
|
487
|
+
* sessions and the default role assigned to new session participants.
|
|
488
|
+
*
|
|
489
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
490
|
+
*
|
|
491
|
+
* @param input - {@link SetGameModelPolicyInput}: `appId` (decimal string); an
|
|
492
|
+
* optional `sessionCreationPolicy` (`admin | member | anyone`); and an
|
|
493
|
+
* optional `defaultParticipantRole`.
|
|
494
|
+
* @returns The updated {@link GmAppPolicy}.
|
|
495
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
496
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `BAD_USER_INPUT`.
|
|
497
|
+
*/
|
|
106
498
|
async setPolicy(input) {
|
|
107
499
|
const data = await this.gql.request(GameModelSetPolicyDocument, { input });
|
|
108
500
|
return data.gameModelSetPolicy;
|
|
109
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* **Container types** — fetch a container type's full schema: its property
|
|
504
|
+
* definitions plus the functions available on it. A studio/authoring read.
|
|
505
|
+
*
|
|
506
|
+
* Requires the app-admin **`manage_apps`** permission.
|
|
507
|
+
*
|
|
508
|
+
* @param variables - `{ appId, typeName }`: `appId` (decimal string) and the
|
|
509
|
+
* `typeName` whose schema to fetch.
|
|
510
|
+
* @returns A {@link GmTypeSchema}: the `typeName`, its `propertyDefinitions`
|
|
511
|
+
* ({@link GmPropertyDef}[]), and its `functions` ({@link GmFunction}[]).
|
|
512
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `SCOPE_MISSING`,
|
|
513
|
+
* `FORBIDDEN` (`requiredPermission === 'manage_apps'`), or `NOT_FOUND` for an
|
|
514
|
+
* unknown type.
|
|
515
|
+
*/
|
|
110
516
|
async typeSchema(variables) {
|
|
111
517
|
const data = await this.gql.request(GameModelTypeSchemaDocument, variables);
|
|
112
518
|
return data.gameModelTypeSchema;
|
|
@@ -1,33 +1,49 @@
|
|
|
1
|
+
import type { GraphQLClient } from '../client.js';
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
* find the shared game-api
|
|
4
|
-
*
|
|
5
|
-
* against it.
|
|
6
|
-
*
|
|
7
|
-
* Typical pattern:
|
|
8
|
-
*
|
|
9
|
-
* const base = createCrowdyClient({ managementUrl: 'https://api.example.com' });
|
|
10
|
-
* const cfg = await base.platform.config();
|
|
11
|
-
* const gameClient = createCrowdyClient({
|
|
12
|
-
* managementUrl: 'https://api.example.com',
|
|
13
|
-
* httpUrl: cfg.sharedGameApiUrl ?? undefined,
|
|
14
|
-
* wsUrl: cfg.sharedGameApiWsUrl ?? undefined,
|
|
15
|
-
* tokenStore: base.session.tokenStore,
|
|
16
|
-
* });
|
|
3
|
+
* Public platform discovery returned by {@link PlatformAPI.config}: how SDKs
|
|
4
|
+
* find the shared game-api so they can route apps deployed to the shared
|
|
5
|
+
* environment. All fields are public (no auth required to read them).
|
|
17
6
|
*/
|
|
18
|
-
import type { GraphQLClient } from '../client.js';
|
|
19
7
|
export interface PlatformConfig {
|
|
20
|
-
/** Shared game-api HTTP/GraphQL root for shared-environment apps. */
|
|
8
|
+
/** Shared game-api HTTP/GraphQL root for shared-environment apps; `null` if unset. */
|
|
21
9
|
sharedGameApiUrl: string | null;
|
|
22
|
-
/** Shared game-api WebSocket root (subscriptions / UDP proxy). */
|
|
10
|
+
/** Shared game-api WebSocket root (subscriptions / UDP proxy); `null` if unset. */
|
|
23
11
|
sharedGameApiWsUrl: string | null;
|
|
24
|
-
/** Free shared app slots an org gets before a paid subscription. */
|
|
12
|
+
/** Free shared app slots an org gets before a paid subscription is required. */
|
|
25
13
|
freeAppsPerOrg: number;
|
|
26
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Public platform discovery — exposed as `client.platform`.
|
|
17
|
+
*
|
|
18
|
+
* Targets the **management-api** (every call routes to `managementUrl`).
|
|
19
|
+
* **Public**: no authentication required. Lets a client discover the shared
|
|
20
|
+
* game-api URL (for apps published to the shared environment) *before* it has a
|
|
21
|
+
* per-app endpoint, then build a game-api `CrowdyClient` against it.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const base = createCrowdyClient({ managementUrl: 'https://api.example.com' });
|
|
26
|
+
* const cfg = await base.platform.config();
|
|
27
|
+
* const gameClient = createCrowdyClient({
|
|
28
|
+
* managementUrl: 'https://api.example.com',
|
|
29
|
+
* httpUrl: cfg.sharedGameApiUrl ?? undefined,
|
|
30
|
+
* wsUrl: cfg.sharedGameApiWsUrl ?? undefined,
|
|
31
|
+
* tokenStore: base.session.tokenStore,
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
27
35
|
export declare class PlatformAPI {
|
|
28
36
|
private readonly management;
|
|
29
37
|
constructor(management: GraphQLClient);
|
|
30
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Fetch public platform discovery: the shared game-api URL clients use for
|
|
40
|
+
* shared-environment apps, plus the free shared-app quota. **Public** — no
|
|
41
|
+
* authentication required.
|
|
42
|
+
*
|
|
43
|
+
* @returns A {@link PlatformConfig} (`sharedGameApiUrl`, `sharedGameApiWsUrl`,
|
|
44
|
+
* and `freeAppsPerOrg`).
|
|
45
|
+
* @throws {CrowdyGraphQLError} on transport/validation failures.
|
|
46
|
+
*/
|
|
31
47
|
config(): Promise<PlatformConfig>;
|
|
32
48
|
}
|
|
33
49
|
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/domains/platform.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/domains/platform.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,sFAAsF;IACtF,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mFAAmF;IACnF,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;CACxB;AAiBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,aAAa;IAEtD;;;;;;;;OAQG;IACG,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;CAIxC"}
|
package/dist/domains/platform.js
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Platform discovery sub-client. Targets `cks-management-api`. Lets a client
|
|
3
|
-
* find the shared game-api URL (for apps published to the shared environment)
|
|
4
|
-
* BEFORE it has a per-app endpoint, then build a game-api `CrowdyClient`
|
|
5
|
-
* against it.
|
|
6
|
-
*
|
|
7
|
-
* Typical pattern:
|
|
8
|
-
*
|
|
9
|
-
* const base = createCrowdyClient({ managementUrl: 'https://api.example.com' });
|
|
10
|
-
* const cfg = await base.platform.config();
|
|
11
|
-
* const gameClient = createCrowdyClient({
|
|
12
|
-
* managementUrl: 'https://api.example.com',
|
|
13
|
-
* httpUrl: cfg.sharedGameApiUrl ?? undefined,
|
|
14
|
-
* wsUrl: cfg.sharedGameApiWsUrl ?? undefined,
|
|
15
|
-
* tokenStore: base.session.tokenStore,
|
|
16
|
-
* });
|
|
17
|
-
*/
|
|
18
1
|
import { parse } from 'graphql';
|
|
19
2
|
// Hand-written document so the SDK can discover the shared game-api URL even
|
|
20
3
|
// before codegen picks up the new schema (see src/operations/platform/).
|
|
@@ -27,11 +10,39 @@ const PlatformConfigDocument = parse(/* GraphQL */ `
|
|
|
27
10
|
}
|
|
28
11
|
}
|
|
29
12
|
`);
|
|
13
|
+
/**
|
|
14
|
+
* Public platform discovery — exposed as `client.platform`.
|
|
15
|
+
*
|
|
16
|
+
* Targets the **management-api** (every call routes to `managementUrl`).
|
|
17
|
+
* **Public**: no authentication required. Lets a client discover the shared
|
|
18
|
+
* game-api URL (for apps published to the shared environment) *before* it has a
|
|
19
|
+
* per-app endpoint, then build a game-api `CrowdyClient` against it.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const base = createCrowdyClient({ managementUrl: 'https://api.example.com' });
|
|
24
|
+
* const cfg = await base.platform.config();
|
|
25
|
+
* const gameClient = createCrowdyClient({
|
|
26
|
+
* managementUrl: 'https://api.example.com',
|
|
27
|
+
* httpUrl: cfg.sharedGameApiUrl ?? undefined,
|
|
28
|
+
* wsUrl: cfg.sharedGameApiWsUrl ?? undefined,
|
|
29
|
+
* tokenStore: base.session.tokenStore,
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
30
33
|
export class PlatformAPI {
|
|
31
34
|
constructor(management) {
|
|
32
35
|
this.management = management;
|
|
33
36
|
}
|
|
34
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Fetch public platform discovery: the shared game-api URL clients use for
|
|
39
|
+
* shared-environment apps, plus the free shared-app quota. **Public** — no
|
|
40
|
+
* authentication required.
|
|
41
|
+
*
|
|
42
|
+
* @returns A {@link PlatformConfig} (`sharedGameApiUrl`, `sharedGameApiWsUrl`,
|
|
43
|
+
* and `freeAppsPerOrg`).
|
|
44
|
+
* @throws {CrowdyGraphQLError} on transport/validation failures.
|
|
45
|
+
*/
|
|
35
46
|
async config() {
|
|
36
47
|
const data = await this.management.request(PlatformConfigDocument, {});
|
|
37
48
|
return data.platformConfig;
|