@crowdedkingdoms/crowdyjs 13.9.0 → 14.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +44 -0
- package/README.md +68 -33
- package/dist/binary-relay.d.ts +1 -1
- package/dist/binary-relay.js +1 -1
- package/dist/client.d.ts +27 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +61 -2
- package/dist/crowdy-client.d.ts +29 -34
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +67 -40
- package/dist/datacenter-redirect.d.ts +49 -0
- package/dist/datacenter-redirect.d.ts.map +1 -0
- package/dist/datacenter-redirect.js +62 -0
- package/dist/domains/appAccess.d.ts +3 -3
- package/dist/domains/appAccess.d.ts.map +1 -1
- package/dist/domains/appAccess.js +16 -16
- package/dist/domains/apps.d.ts +4 -8
- package/dist/domains/apps.d.ts.map +1 -1
- package/dist/domains/apps.js +19 -23
- package/dist/domains/auth.d.ts +1 -1
- package/dist/domains/billing.d.ts +3 -3
- package/dist/domains/billing.d.ts.map +1 -1
- package/dist/domains/billing.js +9 -9
- package/dist/domains/controlPlane.d.ts +2 -2
- package/dist/domains/controlPlane.d.ts.map +1 -1
- package/dist/domains/controlPlane.js +4 -4
- package/dist/domains/discovery.d.ts +50 -0
- package/dist/domains/discovery.d.ts.map +1 -0
- package/dist/domains/discovery.js +35 -0
- package/dist/domains/marketplace.d.ts +4 -5
- package/dist/domains/marketplace.d.ts.map +1 -1
- package/dist/domains/marketplace.js +25 -26
- package/dist/domains/organizations.d.ts +3 -3
- package/dist/domains/organizations.d.ts.map +1 -1
- package/dist/domains/organizations.js +22 -22
- package/dist/domains/payments.d.ts +3 -3
- package/dist/domains/payments.d.ts.map +1 -1
- package/dist/domains/payments.js +11 -11
- package/dist/domains/platform.d.ts +5 -6
- package/dist/domains/platform.d.ts.map +1 -1
- package/dist/domains/platform.js +6 -7
- package/dist/domains/portal.d.ts +19 -2
- package/dist/domains/portal.d.ts.map +1 -1
- package/dist/domains/portal.js +12 -12
- package/dist/domains/quotas.d.ts +3 -3
- package/dist/domains/quotas.d.ts.map +1 -1
- package/dist/domains/quotas.js +8 -8
- package/dist/domains/serverStatus.d.ts +1 -2
- package/dist/domains/serverStatus.d.ts.map +1 -1
- package/dist/domains/serverStatus.js +1 -2
- package/dist/domains/sharedEnvironment.d.ts +3 -3
- package/dist/domains/sharedEnvironment.d.ts.map +1 -1
- package/dist/domains/sharedEnvironment.js +15 -15
- package/dist/domains/udp.d.ts +1 -1
- package/dist/domains/udp.js +1 -1
- package/dist/domains/usage.d.ts +2 -2
- package/dist/domains/usage.d.ts.map +1 -1
- package/dist/domains/usage.js +5 -5
- package/dist/domains/users.d.ts +1 -1
- package/dist/domains/users.js +1 -1
- package/dist/errors.d.ts +56 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +64 -0
- package/dist/generated/graphql.d.ts +65 -16
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +1 -0
- package/dist/index.d.ts +13 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -17
- package/dist/kit/decks.d.ts +1 -1
- package/dist/kit/npcs.d.ts +2 -2
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/kit/worldsim.d.ts +1 -1
- package/dist/realtime.d.ts +26 -0
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +83 -0
- package/dist/rediscover.d.ts +7 -3
- package/dist/rediscover.d.ts.map +1 -1
- package/dist/rediscover.js +7 -3
- package/dist/session.d.ts +21 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +23 -0
- package/package.json +1 -1
package/MIGRATION.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
# CrowdyJS v14 — one endpoint (breaking)
|
|
2
|
+
|
|
3
|
+
v13 made the two GraphQL origins optional-but-supported. v14 removes the second
|
|
4
|
+
one entirely, because `cks-management-api` has been retired: the management
|
|
5
|
+
surface is served by the unified API, and there is nothing else to point at.
|
|
6
|
+
|
|
7
|
+
**What changed**
|
|
8
|
+
|
|
9
|
+
- **`managementUrl` and `managementGraphqlEndpoint` removed** from
|
|
10
|
+
`CrowdyClientConfig`. Passing either now **throws** rather than being ignored —
|
|
11
|
+
a JavaScript caller that kept the old option would otherwise have its identity
|
|
12
|
+
calls silently redirected to `httpUrl`, or nowhere at all if `managementUrl`
|
|
13
|
+
was the only URL it set.
|
|
14
|
+
- **`client.management` removed.** Use `client.graphql`; it reaches every
|
|
15
|
+
surface. `MarketplaceAPI` also collapsed from two transports to one.
|
|
16
|
+
|
|
17
|
+
**What did not change:** the two-**token** model. An identity session token is
|
|
18
|
+
still rejected for gameplay, and you still mint a short-lived app-scoped token
|
|
19
|
+
per app. Keep using two clients — one per token — they just no longer need a
|
|
20
|
+
shared management URL.
|
|
21
|
+
|
|
22
|
+
**Upgrading**
|
|
23
|
+
|
|
24
|
+
```diff
|
|
25
|
+
const client = createCrowdyClient({
|
|
26
|
+
- httpUrl: 'https://game.example.com',
|
|
27
|
+
- wsUrl: 'wss://game.example.com',
|
|
28
|
+
- managementUrl: 'https://management.example.com',
|
|
29
|
+
+ httpUrl: 'https://api.example.com/graphql',
|
|
30
|
+
+ wsUrl: 'wss://api.example.com/graphql',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
-await client.management.request(SomeDocument);
|
|
34
|
+
+await client.graphql.request(SomeDocument);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If you configured both to the same origin under v13, delete the `managementUrl`
|
|
38
|
+
line and you are done.
|
|
39
|
+
|
|
40
|
+
**One thing worth getting right:** the per-game client should use the
|
|
41
|
+
`gameApiUrl` / `gameApiWsUrl` that `mintAppToken` returns, not a hardcoded host.
|
|
42
|
+
An app lives in a single datacenter, and those fields name it. The identity
|
|
43
|
+
client can stay on the shared origin.
|
|
44
|
+
|
|
1
45
|
# CrowdyJS v13 — unified galaxy API (breaking)
|
|
2
46
|
|
|
3
47
|
The platform merged the Management API and Game API into ONE server on the
|
package/README.md
CHANGED
|
@@ -39,11 +39,9 @@ import {
|
|
|
39
39
|
} from '@crowdedkingdoms/crowdyjs';
|
|
40
40
|
|
|
41
41
|
const client = createCrowdyClient({
|
|
42
|
-
//
|
|
43
|
-
httpUrl: 'https://
|
|
44
|
-
wsUrl: 'wss://
|
|
45
|
-
// Management API (passwordless sign-in, profile, admin)
|
|
46
|
-
managementUrl: 'https://management.example.com',
|
|
42
|
+
// One API: identity, studio admin, world data and the UDP proxy.
|
|
43
|
+
httpUrl: 'https://api.example.com/graphql',
|
|
44
|
+
wsUrl: 'wss://api.example.com/graphql',
|
|
47
45
|
tokenStore: new BrowserLocalStorageTokenStore(),
|
|
48
46
|
realtime: {
|
|
49
47
|
retryAttempts: 8,
|
|
@@ -61,33 +59,34 @@ if (!client.session.getToken()) {
|
|
|
61
59
|
// Or dev/test only (server has DEV_AUTH_BYPASS): client.auth.devLogin('player@example.com')
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
// Passwordless sign-in returns an identity SESSION token (
|
|
62
|
+
// Passwordless sign-in returns an identity SESSION token (rejected for gameplay);
|
|
65
63
|
// the account is created on first sign-in. Identity reads run on it:
|
|
66
64
|
const me = await client.users.me();
|
|
67
65
|
console.log(me.email);
|
|
68
66
|
```
|
|
69
67
|
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
There is one endpoint. `managementUrl` was removed in v14 — see
|
|
69
|
+
[MIGRATION.md](MIGRATION.md).
|
|
72
70
|
|
|
73
71
|
**Gameplay needs an app-scoped token, not the session token.** Mint one per
|
|
74
|
-
app and drive the
|
|
72
|
+
app and drive the world/UDP surface from a per-game client — see
|
|
75
73
|
[Authentication](#authentication-session-token-vs-app-scoped-tokens).
|
|
76
74
|
|
|
77
75
|
## Authentication: session token vs app-scoped tokens
|
|
78
76
|
|
|
79
|
-
Passwordless sign-in returns an **identity session token**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
Passwordless sign-in returns an **identity session token** good for account,
|
|
78
|
+
studio admin and token minting, and **rejected for gameplay**. Each game is
|
|
79
|
+
entered with a short-lived **app-scoped token** confined to that one app, so a
|
|
80
|
+
game stack never receives the player's full session.
|
|
83
81
|
|
|
84
82
|
Use two clients: an Overworld/identity client (session token) and a per-game
|
|
85
|
-
client (app token),
|
|
83
|
+
client (app token). They never share a token store, and they need not share a
|
|
84
|
+
URL — `mintAppToken` returns the endpoint for the app's own datacenter.
|
|
86
85
|
|
|
87
86
|
```ts
|
|
88
87
|
// Overworld/identity client
|
|
89
88
|
const overworld = createCrowdyClient({
|
|
90
|
-
|
|
89
|
+
httpUrl: apiUrl,
|
|
91
90
|
tokenStore: new BrowserLocalStorageTokenStore('crowdyjs:session'),
|
|
92
91
|
});
|
|
93
92
|
// Passwordless sign-in (magic link, social/OIDC, or dev bypass) yields the session token.
|
|
@@ -99,7 +98,6 @@ const t = await overworld.portal.mintAppToken(appId);
|
|
|
99
98
|
const game = createCrowdyClient({
|
|
100
99
|
httpUrl: t.gameApiUrl!,
|
|
101
100
|
wsUrl: t.gameApiWsUrl!,
|
|
102
|
-
managementUrl,
|
|
103
101
|
tokenStore: new BrowserLocalStorageTokenStore('crowdyjs:app:' + appId),
|
|
104
102
|
});
|
|
105
103
|
game.setToken(t.token);
|
|
@@ -158,7 +156,7 @@ lifecycle to preserve.
|
|
|
158
156
|
|
|
159
157
|
1. Sign in (passwordless) on the identity client with `client.auth`, or
|
|
160
158
|
restore a stored session with `client.session.restore()`. This yields the
|
|
161
|
-
**session token
|
|
159
|
+
**session token**, which gameplay rejects.
|
|
162
160
|
2. Mint an **app-scoped token** for the app (`identity.portal.mintAppToken(appId)`,
|
|
163
161
|
or the PKCE portal flow across origins) and build a per-game client holding
|
|
164
162
|
it (`game.setToken(token)`). The gameplay steps below run on that **game**
|
|
@@ -224,12 +222,11 @@ grouped under `client.admin` and mirrored at the top level):
|
|
|
224
222
|
|---|---|
|
|
225
223
|
| `client.operator` | Platform compute ceilings (`computePlatformCeilings`, `setComputePlatformCeilings`). Infrastructure operations live in the separate infra-control-plane service, not this SDK. |
|
|
226
224
|
|
|
227
|
-
Auth, user reads
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
token** for that app.
|
|
225
|
+
Auth, user reads and the studio-admin / operator surfaces use the **identity
|
|
226
|
+
session token**; the world/UDP surfaces require an **app-scoped token** for that
|
|
227
|
+
app. Both go to the same endpoint.
|
|
231
228
|
|
|
232
|
-
CrowdyJS wraps the full public
|
|
229
|
+
CrowdyJS wraps the full public API surface — every
|
|
233
230
|
non-deprecated public root field has a typed method, with Relay `*Connection`
|
|
234
231
|
cursor-pagination variants alongside the legacy offset lists. The SDK never
|
|
235
232
|
relaxes server-side authorization: exposing an operation here just gives you a
|
|
@@ -241,7 +238,7 @@ not from an untrusted browser.
|
|
|
241
238
|
|
|
242
239
|
`mintAppToken` returns `gameApiUrl` / `gameApiWsUrl`, so you rarely need a
|
|
243
240
|
separate routing query. When you do (e.g. pre-flight discovery), query the
|
|
244
|
-
app's routing fields
|
|
241
|
+
app's routing fields:
|
|
245
242
|
|
|
246
243
|
```graphql
|
|
247
244
|
query AppForRouting($appId: BigInt!) {
|
|
@@ -323,6 +320,45 @@ while `AUTH_REQUIRED` / `APP_ID_REQUIRED` must be fixed by the caller first.
|
|
|
323
320
|
Unsubscribing stops delivery only; call `client.udp.disconnect()` to close the
|
|
324
321
|
UDP proxy session.
|
|
325
322
|
|
|
323
|
+
### Surviving the loss of an instance (direct connect)
|
|
324
|
+
|
|
325
|
+
**If your environment uses direct connect, set `realtime.discoveryUrl`.** Under
|
|
326
|
+
direct connect `mintAppToken` hands the client ONE api instance, and without a way
|
|
327
|
+
to ask for another the client cannot leave it: it re-dials a dead host until its
|
|
328
|
+
retries run out and then sits there, connected to nothing.
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
const bootstrap = await client.udp.gameClientBootstrap(appId);
|
|
332
|
+
|
|
333
|
+
const client = createCrowdyClient({
|
|
334
|
+
httpUrl: bootstrap.gameApiUrl,
|
|
335
|
+
wsUrl: bootstrap.gameApiWsUrl,
|
|
336
|
+
realtime: {
|
|
337
|
+
// The LOAD BALANCER, not the instance above. A discovery URL that dies with
|
|
338
|
+
// the instance it exists to replace is worse than none.
|
|
339
|
+
discoveryUrl: bootstrap.discoveryUrl,
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
That is the whole integration — the SDK builds re-discovery from the URL itself,
|
|
345
|
+
so recovery does not depend on every game remembering to write a callback. Pass an
|
|
346
|
+
explicit `realtime.rediscover` only to override it (e.g. `createMintRediscover`
|
|
347
|
+
when you hold an identity client and would rather re-mint than reuse a token near
|
|
348
|
+
expiry).
|
|
349
|
+
|
|
350
|
+
**Requires 13.9.0 or later, and the version matters more than it looks.** Before
|
|
351
|
+
13.9.0 the escalation to re-discovery was reachable only by a client that had
|
|
352
|
+
NEVER connected: a session that was working and then lost its instance re-dialled
|
|
353
|
+
one dead address forever, logging only `Binary relay socket error`. Setting
|
|
354
|
+
`discoveryUrl` on an older build therefore changes nothing in the case you set it
|
|
355
|
+
for. `ck-api` must be v1.20.0+ to return `discoveryUrl` at all.
|
|
356
|
+
|
|
357
|
+
**Pass a `logger`.** Everything the SDK knows about losing an instance it says
|
|
358
|
+
through that logger, including an explicit warning when it cannot move. With none
|
|
359
|
+
wired, a client that failed to re-discover and one that never tried look
|
|
360
|
+
identical.
|
|
361
|
+
|
|
326
362
|
## Spatial sends
|
|
327
363
|
|
|
328
364
|
```ts
|
|
@@ -671,8 +707,7 @@ The key parameter is optional and trailing, so it's safe to omit.
|
|
|
671
707
|
## Low-level GraphQL access
|
|
672
708
|
|
|
673
709
|
Typed sub-client methods are first-class, but generated operation documents
|
|
674
|
-
are also available through a transport escape hatch
|
|
675
|
-
Game API and `client.management` for the Management API:
|
|
710
|
+
are also available through a transport escape hatch, `client.graphql`:
|
|
676
711
|
|
|
677
712
|
```ts
|
|
678
713
|
import { VersionInfoDocument } from '@crowdedkingdoms/crowdyjs/generated';
|
|
@@ -680,8 +715,9 @@ import { VersionInfoDocument } from '@crowdedkingdoms/crowdyjs/generated';
|
|
|
680
715
|
const data = await client.graphql.request(VersionInfoDocument);
|
|
681
716
|
```
|
|
682
717
|
|
|
683
|
-
For any brand-new server field not yet wrapped, `client.graphql.request(...)`
|
|
684
|
-
`client.management
|
|
718
|
+
For any brand-new server field not yet wrapped, `client.graphql.request(...)`
|
|
719
|
+
always works. (`client.management` was removed in v14 along with the second
|
|
720
|
+
endpoint; `client.graphql` reaches every surface.)
|
|
685
721
|
|
|
686
722
|
## Maintainers: schema artifacts and fixtures
|
|
687
723
|
|
|
@@ -689,20 +725,19 @@ CrowdyJS is a standalone public package: a clean clone builds with
|
|
|
689
725
|
`npm install && npm run build` using the artifacts committed to this repo —
|
|
690
726
|
no other repositories and no network access required:
|
|
691
727
|
|
|
692
|
-
- `schema.gql` —
|
|
728
|
+
- `schema.gql` — the unified API SDL (management and game surfaces).
|
|
693
729
|
- `src/generated/graphql.ts` — generated TypeScript operation types.
|
|
694
730
|
|
|
695
|
-
Schema refresh is explicit, from the published
|
|
696
|
-
|
|
697
|
-
[game-api.graphql](https://docs.crowdedkingdoms.com/schema/game-api.graphql)):
|
|
731
|
+
Schema refresh is explicit, from the published
|
|
732
|
+
[SDL](https://docs.crowdedkingdoms.com/schema/game-api.graphql):
|
|
698
733
|
|
|
699
734
|
```bash
|
|
700
735
|
npm run schema:sync:prod
|
|
701
736
|
npm run codegen
|
|
702
737
|
```
|
|
703
738
|
|
|
704
|
-
(`npm run schema:sync:paths -- --
|
|
705
|
-
|
|
739
|
+
(`npm run schema:sync:paths -- --schema <file-or-url>` accepts an explicit
|
|
740
|
+
source, and `npm run schema:sync:local` reads `../cks-game-api/schema.gql`.) Commit `schema.gql` and `src/generated/graphql.ts`
|
|
706
741
|
together whenever the public GraphQL surface changes; `npm run check:schema`
|
|
707
742
|
detects drift in CI/release work.
|
|
708
743
|
|
package/dist/binary-relay.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ export interface BinaryRelayCallbacks {
|
|
|
49
49
|
* than an unbalanced fleet.
|
|
50
50
|
*
|
|
51
51
|
* Compares the last two labels, so `ck-api-4.pgc.prod.cp.cks-env.com` and
|
|
52
|
-
* `ck.
|
|
52
|
+
* `ck.prod.cp.cks-env.com` match, and `evil.example.com` does not.
|
|
53
53
|
*/
|
|
54
54
|
export declare function isSameEstate(current: string, candidate: string): boolean;
|
|
55
55
|
export interface BinaryRelayConfig {
|
package/dist/binary-relay.js
CHANGED
|
@@ -38,7 +38,7 @@ const UNAVAILABLE_AFTER_RECONNECT_FAILURES = 3;
|
|
|
38
38
|
* than an unbalanced fleet.
|
|
39
39
|
*
|
|
40
40
|
* Compares the last two labels, so `ck-api-4.pgc.prod.cp.cks-env.com` and
|
|
41
|
-
* `ck.
|
|
41
|
+
* `ck.prod.cp.cks-env.com` match, and `evil.example.com` does not.
|
|
42
42
|
*/
|
|
43
43
|
export function isSameEstate(current, candidate) {
|
|
44
44
|
const host = (raw) => {
|
package/dist/client.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
10
10
|
import type { SessionStore } from './session.js';
|
|
11
11
|
import type { CrowdyLogger } from './logger.js';
|
|
12
|
+
import { type DatacenterMove } from './datacenter-redirect.js';
|
|
12
13
|
import type { LbCookieStore } from './lb-cookie-store.js';
|
|
13
14
|
/**
|
|
14
15
|
* Configuration for {@link GraphQLClient}, the low-level HTTP transport. You
|
|
@@ -28,6 +29,20 @@ export interface GraphQLClientConfig {
|
|
|
28
29
|
* both are provided.
|
|
29
30
|
*/
|
|
30
31
|
graphqlEndpoint?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Called when the server refuses an operation with `WRONG_DATACENTER`, naming
|
|
34
|
+
* the endpoint the app actually lives at.
|
|
35
|
+
*
|
|
36
|
+
* Return `true` once the client has been moved and the operation is worth
|
|
37
|
+
* retrying; return `false` to leave the endpoint alone and let the original
|
|
38
|
+
* error surface. `CrowdyClient` supplies this for you and moves BOTH the HTTP
|
|
39
|
+
* endpoint and the websocket together — a client with its HTTP on one instance
|
|
40
|
+
* and its subscription on another gets no realtime traffic at all, which is the
|
|
41
|
+
* failure the sticky load-balancer cookie was invented to prevent.
|
|
42
|
+
*
|
|
43
|
+
* You only need to set this when constructing a bare {@link GraphQLClient}.
|
|
44
|
+
*/
|
|
45
|
+
onWrongDatacenter?: (move: DatacenterMove) => boolean | Promise<boolean>;
|
|
31
46
|
/**
|
|
32
47
|
* Per-request timeout in **milliseconds**. When it elapses the request is
|
|
33
48
|
* aborted and a {@link CrowdyTimeoutError} is thrown. Defaults to `60000`
|
|
@@ -74,6 +89,7 @@ export declare class GraphQLClient {
|
|
|
74
89
|
private readonly session;
|
|
75
90
|
private readonly logger;
|
|
76
91
|
private readonly lbCookieStore?;
|
|
92
|
+
private onWrongDatacenter?;
|
|
77
93
|
/**
|
|
78
94
|
* @param config - Endpoint, timeout, and logger options; see
|
|
79
95
|
* {@link GraphQLClientConfig}.
|
|
@@ -82,6 +98,15 @@ export declare class GraphQLClient {
|
|
|
82
98
|
* HTTP auth always tracks the active session.
|
|
83
99
|
*/
|
|
84
100
|
constructor(config: GraphQLClientConfig | undefined, session: SessionStore);
|
|
101
|
+
/**
|
|
102
|
+
* Install the datacenter-redirect handler after construction.
|
|
103
|
+
*
|
|
104
|
+
* `CrowdyClient` needs this because the handler has to move the websocket as
|
|
105
|
+
* well as the HTTP endpoint, and the realtime client is built AFTER the
|
|
106
|
+
* transport it is given. Passing a half-built client into its own constructor
|
|
107
|
+
* is the alternative, and it is worse.
|
|
108
|
+
*/
|
|
109
|
+
setWrongDatacenterHandler(handler: (move: DatacenterMove) => boolean | Promise<boolean>): void;
|
|
85
110
|
/**
|
|
86
111
|
* The resolved GraphQL endpoint URL this client POSTs to.
|
|
87
112
|
*
|
|
@@ -148,6 +173,8 @@ export declare class GraphQLClient {
|
|
|
148
173
|
query<T = any>(query: string, variables?: Record<string, unknown>, options?: {
|
|
149
174
|
signal?: AbortSignal;
|
|
150
175
|
}): Promise<T>;
|
|
176
|
+
/** One HTTP round trip. {@link query} wraps this to handle a redirect. */
|
|
177
|
+
private attempt;
|
|
151
178
|
}
|
|
152
179
|
/**
|
|
153
180
|
* Alias for {@link GraphQLClient}, provided so callers can refer to the HTTP
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAYhD,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAa;IACxB,yEAAyE;IACzE,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAgB;IAC/C,OAAO,CAAC,iBAAiB,CAAC,CAEM;IAEhC;;;;;;OAMG;gBACS,MAAM,EAAE,mBAAmB,YAAK,EAAE,OAAO,EAAE,YAAY;IAYnE;;;;;;;OAOG;IACH,yBAAyB,CACvB,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAC5D,IAAI;IAIP;;;;OAIG;IACH,WAAW,IAAI,MAAM;IAIrB;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAInC;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,OAAO,CAAC,OAAO,EAAE,UAAU,EAC/B,QAAQ,EAAE,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC,EAChD,SAAS,CAAC,EAAE,UAAU,EACtB,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GACrC,OAAO,CAAC,OAAO,CAAC;IASnB;;;;;;;;;;;;;;;;;;;OAmBG;IACG,KAAK,CAAC,CAAC,GAAG,GAAG,EACjB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACvC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GACrC,OAAO,CAAC,CAAC,CAAC;IA0Cb,0EAA0E;YAC5D,OAAO;CAiEtB;AAED;;;GAGG;AACH,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
|
package/dist/client.js
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { print } from 'graphql';
|
|
10
10
|
import { silentLogger } from './logger.js';
|
|
11
|
-
import { CrowdyError, CrowdyGraphQLError, CrowdyHttpError, CrowdyNetworkError, CrowdyTimeoutError, } from './errors.js';
|
|
11
|
+
import { APP_UNAVAILABLE_CODE, CrowdyAppUnavailableError, CrowdyError, CrowdyGraphQLError, CrowdyHttpError, CrowdyNetworkError, CrowdyTimeoutError, } from './errors.js';
|
|
12
|
+
import { moveFromErrors } from './datacenter-redirect.js';
|
|
12
13
|
/**
|
|
13
14
|
* Low-level HTTP transport for GraphQL operations against the game or
|
|
14
15
|
* management API. It POSTs operations to a single endpoint, attaches the
|
|
@@ -47,6 +48,18 @@ export class GraphQLClient {
|
|
|
47
48
|
this.session = session;
|
|
48
49
|
this.logger = config.logger ?? silentLogger;
|
|
49
50
|
this.lbCookieStore = config.lbCookieStore;
|
|
51
|
+
this.onWrongDatacenter = config.onWrongDatacenter;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Install the datacenter-redirect handler after construction.
|
|
55
|
+
*
|
|
56
|
+
* `CrowdyClient` needs this because the handler has to move the websocket as
|
|
57
|
+
* well as the HTTP endpoint, and the realtime client is built AFTER the
|
|
58
|
+
* transport it is given. Passing a half-built client into its own constructor
|
|
59
|
+
* is the alternative, and it is worse.
|
|
60
|
+
*/
|
|
61
|
+
setWrongDatacenterHandler(handler) {
|
|
62
|
+
this.onWrongDatacenter = handler;
|
|
50
63
|
}
|
|
51
64
|
/**
|
|
52
65
|
* The resolved GraphQL endpoint URL this client POSTs to.
|
|
@@ -117,6 +130,44 @@ export class GraphQLClient {
|
|
|
117
130
|
* timeout.
|
|
118
131
|
*/
|
|
119
132
|
async query(query, variables = {}, options = {}) {
|
|
133
|
+
try {
|
|
134
|
+
return await this.attempt(query, variables, options);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
const move = error instanceof CrowdyGraphQLError
|
|
138
|
+
? moveFromErrors(error.graphqlErrors)
|
|
139
|
+
: null;
|
|
140
|
+
if (!move || !this.onWrongDatacenter)
|
|
141
|
+
throw error;
|
|
142
|
+
// ONE retry, and only after the endpoint actually moved.
|
|
143
|
+
//
|
|
144
|
+
// Without a retry the redirect is useless: every call would fail once and
|
|
145
|
+
// the application would have to know to repeat it, which is the SDK's job.
|
|
146
|
+
// Without the "actually moved" check it is worse than useless -- if the
|
|
147
|
+
// handler declines, or moves to where we already are, retrying re-sends to
|
|
148
|
+
// the same instance and is refused identically, forever.
|
|
149
|
+
//
|
|
150
|
+
// The retry is not itself retried. A second WRONG_DATACENTER after a
|
|
151
|
+
// successful move means two datacenters each believe the app is in the
|
|
152
|
+
// other, which is a placement problem an operator has to see rather than
|
|
153
|
+
// one a client should smooth over by looping between them.
|
|
154
|
+
let moved = false;
|
|
155
|
+
try {
|
|
156
|
+
moved = (await this.onWrongDatacenter(move)) === true;
|
|
157
|
+
}
|
|
158
|
+
catch (hookError) {
|
|
159
|
+
this.logger.warn?.('datacenter redirect handler failed; surfacing the original error', hookError);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
if (!moved)
|
|
163
|
+
throw error;
|
|
164
|
+
this.logger.info?.(`moved to ${move.appDatacenter ?? 'the app\u2019s datacenter'} at ` +
|
|
165
|
+
`${move.gameApiUrl} and retrying`);
|
|
166
|
+
return await this.attempt(query, variables, options);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/** One HTTP round trip. {@link query} wraps this to handle a redirect. */
|
|
170
|
+
async attempt(query, variables, options) {
|
|
120
171
|
const controller = new AbortController();
|
|
121
172
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
122
173
|
const token = this.session.getToken();
|
|
@@ -143,7 +194,15 @@ export class GraphQLClient {
|
|
|
143
194
|
}
|
|
144
195
|
const result = await response.json();
|
|
145
196
|
if (result.errors) {
|
|
146
|
-
|
|
197
|
+
const errors = result.errors;
|
|
198
|
+
// A typed subclass rather than a code an application has to remember to
|
|
199
|
+
// check. `CrowdyAppUnavailableError extends CrowdyGraphQLError`, so every
|
|
200
|
+
// existing catch keeps working and only code that WANTS to tell "your app
|
|
201
|
+
// is offline" apart from "you are not allowed" has to change.
|
|
202
|
+
if (errors.some((e) => e?.extensions?.code === APP_UNAVAILABLE_CODE)) {
|
|
203
|
+
throw new CrowdyAppUnavailableError(errors);
|
|
204
|
+
}
|
|
205
|
+
throw new CrowdyGraphQLError(errors);
|
|
147
206
|
}
|
|
148
207
|
return result.data;
|
|
149
208
|
}
|
package/dist/crowdy-client.d.ts
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
* access everything via the typed sub-clients (`client.auth`, `client.udp`,
|
|
4
4
|
* `client.chunks`, ...).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* All sub-clients share ONE GraphQL endpoint: `httpUrl` / `graphqlEndpoint`, with
|
|
7
|
+
* `wsUrl` / `wsEndpoint` for subscriptions. Identity (`auth`, `users`, `portal`) and
|
|
8
|
+
* world/replication (`chunks`, `voxels`, `actors`, `udp`, ...) are surfaces of the
|
|
9
|
+
* same API, not separate services.
|
|
8
10
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* BREAKING in v14: `managementUrl` and `managementGraphqlEndpoint` were removed,
|
|
12
|
+
* along with the `client.management` escape hatch, when `cks-management-api` was
|
|
13
|
+
* retired and its surface absorbed into the unified API. Set `httpUrl` and use
|
|
14
|
+
* `client.graphql`.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* `client.auth.login()` returns, every subsequent SDK call (against either
|
|
21
|
-
* endpoint) carries the Bearer token automatically.
|
|
16
|
+
* One `AuthState` backs the whole client, so once `client.auth` has a token every
|
|
17
|
+
* subsequent call carries it. Note that this is per-client by design: drive identity
|
|
18
|
+
* from a client holding the session token and gameplay from a per-app client holding
|
|
19
|
+
* that app's app-scoped token, because a session token is rejected for gameplay.
|
|
20
|
+
* Those two clients may point at different origins — an app lives in one datacenter,
|
|
21
|
+
* and `mintAppToken` returns its `gameApiUrl` / `gameApiWsUrl`.
|
|
22
22
|
*/
|
|
23
23
|
import { AuthState } from './auth-state.js';
|
|
24
24
|
import { GraphQLClient } from './client.js';
|
|
@@ -63,26 +63,17 @@ import { CrowdyAgentGraphQLTransport } from './crowdy-agent/graphql-transport.js
|
|
|
63
63
|
import { PlayerWalletAPI } from './domains/playerWallet.js';
|
|
64
64
|
import { MarketplaceAPI } from './domains/marketplace.js';
|
|
65
65
|
import { PlayerModelAPI } from './domains/playerModel.js';
|
|
66
|
+
import { DiscoveryDomain } from './domains/discovery.js';
|
|
66
67
|
export interface CrowdyClientConfig {
|
|
67
|
-
/**
|
|
68
|
+
/** HTTP root (e.g. `https://api.crowdedkingdoms.com`). */
|
|
68
69
|
httpUrl?: string;
|
|
69
|
-
/**
|
|
70
|
+
/** WS root. */
|
|
70
71
|
wsUrl?: string;
|
|
71
|
-
/**
|
|
72
|
+
/** GraphQL endpoint. Defaults to `${httpUrl}/graphql`. */
|
|
72
73
|
graphqlEndpoint?: string;
|
|
73
|
-
/**
|
|
74
|
+
/** WS endpoint. Defaults to `${wsUrl}/graphql`. */
|
|
74
75
|
wsEndpoint?: string;
|
|
75
|
-
/**
|
|
76
|
-
* management-api HTTP root (e.g.
|
|
77
|
-
* `https://dev-management-api.crowdedkingdoms.com`). When set,
|
|
78
|
-
* `client.auth` and `client.users` route here. If left empty the SDK
|
|
79
|
-
* falls back to `httpUrl` for backwards-compatibility with the legacy
|
|
80
|
-
* single-endpoint deployment, but new code should set this explicitly.
|
|
81
|
-
*/
|
|
82
|
-
managementUrl?: string;
|
|
83
|
-
/** management-api GraphQL endpoint. Defaults to `${managementUrl}/graphql`. */
|
|
84
|
-
managementGraphqlEndpoint?: string;
|
|
85
|
-
/** Per-request HTTP timeout in milliseconds (applies to both endpoints). */
|
|
76
|
+
/** Per-request HTTP timeout in milliseconds. */
|
|
86
77
|
timeout?: number;
|
|
87
78
|
/**
|
|
88
79
|
* Persistence for the Bearer token across reloads. `BrowserLocalStorageTokenStore`
|
|
@@ -176,9 +167,9 @@ export interface CrowdyClientConfig {
|
|
|
176
167
|
}
|
|
177
168
|
export declare class CrowdyClient {
|
|
178
169
|
private gameplayTokenRefresh;
|
|
179
|
-
/** Shared token state for
|
|
170
|
+
/** Shared token state for every request this client makes. */
|
|
180
171
|
readonly session: AuthState;
|
|
181
|
-
/**
|
|
172
|
+
/** HTTP client for the API. */
|
|
182
173
|
readonly graphql: GraphQLClient;
|
|
183
174
|
/** game-api WebSocket subscription manager. */
|
|
184
175
|
readonly realtime: SubscriptionManager;
|
|
@@ -191,8 +182,6 @@ export declare class CrowdyClient {
|
|
|
191
182
|
* fields (not wire framing). See {@link RealtimeMetrics}.
|
|
192
183
|
*/
|
|
193
184
|
readonly metrics: RealtimeMetrics;
|
|
194
|
-
/** management-api HTTP client. Same `AuthState` as `graphql`. */
|
|
195
|
-
readonly management: GraphQLClient;
|
|
196
185
|
/** Auth + session: login, register, logout, password/email flows. */
|
|
197
186
|
readonly auth: AuthAPI;
|
|
198
187
|
/** Current-user identity: `me`, gamertag, account deletion. */
|
|
@@ -205,6 +194,12 @@ export declare class CrowdyClient {
|
|
|
205
194
|
* app token.
|
|
206
195
|
*/
|
|
207
196
|
readonly portal: PortalAPI;
|
|
197
|
+
/**
|
|
198
|
+
* Where each app lives. Unauthenticated, and meant to be called BEFORE login against
|
|
199
|
+
* the shared origin, so the session and the app token are both written in the app's
|
|
200
|
+
* own datacenter rather than wherever DNS happened to point.
|
|
201
|
+
*/
|
|
202
|
+
readonly discovery: DiscoveryDomain;
|
|
208
203
|
/** Public platform discovery (shared game-api URL, free app quota). */
|
|
209
204
|
readonly platform: PlatformAPI;
|
|
210
205
|
/** Organizations, members, RBAC roles, and org API tokens (studio admin). */
|
|
@@ -224,7 +219,7 @@ export declare class CrowdyClient {
|
|
|
224
219
|
/** Operator (control-plane) surface — requires `is_operator`. */
|
|
225
220
|
readonly operator: ControlPlaneAPI;
|
|
226
221
|
/**
|
|
227
|
-
* Studio-admin facade grouping the privileged management sub-clients
|
|
222
|
+
* Studio-admin facade grouping the privileged management-surface sub-clients
|
|
228
223
|
* (`organizations`, `appAccess`, `billing`, `payments`, `quotas`,
|
|
229
224
|
* `usage`, `sharedEnvironment`, `grids`) under one namespace.
|
|
230
225
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crowdy-client.d.ts","sourceRoot":"","sources":["../src/crowdy-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"crowdy-client.d.ts","sourceRoot":"","sources":["../src/crowdy-client.ts"],"names":[],"mappings":"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"}
|