@crowdedkingdomstudios/crowdyjs 2.1.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/MIGRATION.md +26 -0
  2. package/README.md +155 -749
  3. package/dist/auth-state.d.ts +6 -16
  4. package/dist/auth-state.d.ts.map +1 -1
  5. package/dist/auth-state.js +9 -26
  6. package/dist/client.d.ts +14 -5
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +24 -17
  9. package/dist/crowdy-client.d.ts +62 -16
  10. package/dist/crowdy-client.d.ts.map +1 -1
  11. package/dist/crowdy-client.js +70 -28
  12. package/dist/domains/apps.d.ts +48 -20
  13. package/dist/domains/apps.d.ts.map +1 -1
  14. package/dist/domains/apps.js +58 -35
  15. package/dist/domains/auth.d.ts +33 -22
  16. package/dist/domains/auth.d.ts.map +1 -1
  17. package/dist/domains/auth.js +51 -33
  18. package/dist/domains/serverStatus.d.ts +2 -1
  19. package/dist/domains/serverStatus.d.ts.map +1 -1
  20. package/dist/domains/serverStatus.js +5 -1
  21. package/dist/domains/udp.d.ts +28 -3
  22. package/dist/domains/udp.d.ts.map +1 -1
  23. package/dist/domains/udp.js +52 -1
  24. package/dist/domains/users.d.ts +19 -16
  25. package/dist/domains/users.d.ts.map +1 -1
  26. package/dist/domains/users.js +21 -39
  27. package/dist/errors.d.ts +42 -0
  28. package/dist/errors.d.ts.map +1 -0
  29. package/dist/errors.js +42 -0
  30. package/dist/generated/graphql.d.ts +1473 -11
  31. package/dist/generated/graphql.d.ts.map +1 -1
  32. package/dist/generated/graphql.js +17 -8
  33. package/dist/index.d.ts +37 -18
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +37 -20
  36. package/dist/logger.d.ts +8 -0
  37. package/dist/logger.d.ts.map +1 -0
  38. package/dist/logger.js +1 -0
  39. package/dist/realtime.d.ts +89 -0
  40. package/dist/realtime.d.ts.map +1 -0
  41. package/dist/realtime.js +273 -0
  42. package/dist/session.d.ts +27 -0
  43. package/dist/session.d.ts.map +1 -0
  44. package/dist/session.js +61 -0
  45. package/dist/subscriptions.d.ts +1 -48
  46. package/dist/subscriptions.d.ts.map +1 -1
  47. package/dist/subscriptions.js +1 -192
  48. package/dist/types.d.ts +2 -31
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types.js +5 -33
  51. package/dist/utils.d.ts +12 -0
  52. package/dist/utils.d.ts.map +1 -0
  53. package/dist/utils.js +50 -0
  54. package/dist/world.d.ts +44 -0
  55. package/dist/world.d.ts.map +1 -0
  56. package/dist/world.js +105 -0
  57. package/package.json +12 -3
  58. package/dist/domains/appAccess.d.ts +0 -23
  59. package/dist/domains/appAccess.d.ts.map +0 -1
  60. package/dist/domains/appAccess.js +0 -42
  61. package/dist/domains/billing.d.ts +0 -17
  62. package/dist/domains/billing.d.ts.map +0 -1
  63. package/dist/domains/billing.js +0 -31
  64. package/dist/domains/organizations.d.ts +0 -33
  65. package/dist/domains/organizations.d.ts.map +0 -1
  66. package/dist/domains/organizations.js +0 -90
  67. package/dist/domains/payments.d.ts +0 -20
  68. package/dist/domains/payments.d.ts.map +0 -1
  69. package/dist/domains/payments.js +0 -28
  70. package/dist/domains/quotas.d.ts +0 -20
  71. package/dist/domains/quotas.d.ts.map +0 -1
  72. package/dist/domains/quotas.js +0 -34
@@ -1,21 +1,11 @@
1
+ import { SessionStore, type SessionListener, type TokenStore } from './session.js';
2
+ export type AuthStateListener = SessionListener;
1
3
  /**
2
- * Single source of truth for the auth token within one CrowdyClient instance.
3
- *
4
- * Both the HTTP client (`GraphQLClient`) and the WebSocket subscription
5
- * manager observe this. Anything that mutates auth state - the typed
6
- * `client.auth.login()` / `register()` / `logout()` family, or external
7
- * callers - flows through `setToken()` so subscription requests can never
8
- * silently fail with "Must be authenticated to subscribe".
9
- *
10
- * (Replaces the previous arrangement where GraphQLClient and
11
- * SubscriptionManager each held their own copy of the token.)
4
+ * Backwards-compatible internal name for the v3 SessionStore. Public callers
5
+ * should use `client.session`; older domain wrappers still accept AuthState.
12
6
  */
13
- export type AuthStateListener = (token: string | null) => void;
14
- export declare class AuthState {
15
- private token;
16
- private listeners;
17
- getToken(): string | null;
18
- setToken(token: string | null): void;
7
+ export declare class AuthState extends SessionStore {
8
+ constructor(tokenStore?: TokenStore);
19
9
  subscribe(listener: AuthStateListener): () => void;
20
10
  }
21
11
  //# sourceMappingURL=auth-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-state.d.ts","sourceRoot":"","sources":["../src/auth-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;AAE/D,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,SAAS,CAAgC;IAEjD,QAAQ,IAAI,MAAM,GAAG,IAAI;IAIzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAYpC,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI;CAQnD"}
1
+ {"version":3,"file":"auth-state.d.ts","sourceRoot":"","sources":["../src/auth-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEnF,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD;;;GAGG;AACH,qBAAa,SAAU,SAAQ,YAAY;gBAC7B,UAAU,CAAC,EAAE,UAAU;IAInC,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI;CAGnD"}
@@ -1,30 +1,13 @@
1
- export class AuthState {
2
- constructor() {
3
- this.token = null;
4
- this.listeners = new Set();
5
- }
6
- getToken() {
7
- return this.token;
8
- }
9
- setToken(token) {
10
- if (token === this.token)
11
- return;
12
- this.token = token;
13
- for (const listener of this.listeners) {
14
- try {
15
- listener(token);
16
- }
17
- catch (error) {
18
- console.error('AuthState listener threw:', error);
19
- }
20
- }
1
+ import { SessionStore } from './session.js';
2
+ /**
3
+ * Backwards-compatible internal name for the v3 SessionStore. Public callers
4
+ * should use `client.session`; older domain wrappers still accept AuthState.
5
+ */
6
+ export class AuthState extends SessionStore {
7
+ constructor(tokenStore) {
8
+ super(tokenStore);
21
9
  }
22
10
  subscribe(listener) {
23
- this.listeners.add(listener);
24
- // Replay current value immediately so listeners initialize correctly.
25
- listener(this.token);
26
- return () => {
27
- this.listeners.delete(listener);
28
- };
11
+ return this.onChange(listener);
29
12
  }
30
13
  }
package/dist/client.d.ts CHANGED
@@ -7,27 +7,36 @@
7
7
  * `client.auth.login`, `client.udp.sendActorUpdate`).
8
8
  */
9
9
  import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
10
- import { AuthState } from './auth-state.js';
10
+ import type { SessionStore } from './session.js';
11
+ import type { CrowdyLogger } from './logger.js';
11
12
  export interface GraphQLClientConfig {
13
+ httpUrl?: string;
12
14
  graphqlEndpoint?: string;
13
15
  timeout?: number;
16
+ logger?: CrowdyLogger;
14
17
  }
15
18
  export declare class GraphQLClient {
16
19
  private readonly graphqlEndpoint;
17
20
  private readonly timeout;
18
- private readonly authState;
19
- constructor(config: GraphQLClientConfig | undefined, authState: AuthState);
21
+ private readonly session;
22
+ private readonly logger;
23
+ constructor(config: GraphQLClientConfig | undefined, session: SessionStore);
20
24
  getEndpoint(): string;
21
25
  /**
22
26
  * Execute a typed GraphQL operation produced by codegen and return the
23
27
  * `data` payload. Throws on transport errors, GraphQL errors, or timeouts.
24
28
  */
25
- request<TResult, TVariables>(document: TypedDocumentNode<TResult, TVariables>, variables?: TVariables): Promise<TResult>;
29
+ request<TResult, TVariables>(document: TypedDocumentNode<TResult, TVariables>, variables?: TVariables, options?: {
30
+ signal?: AbortSignal;
31
+ }): Promise<TResult>;
26
32
  /**
27
33
  * Internal escape hatch for raw query strings (used by hand-written
28
34
  * adapters that haven't migrated to typed documents yet). Prefer
29
35
  * `request()` with a `TypedDocumentNode`.
30
36
  */
31
- query<T = any>(query: string, variables?: Record<string, any>): Promise<T>;
37
+ query<T = any>(query: string, variables?: Record<string, unknown>, options?: {
38
+ signal?: AbortSignal;
39
+ }): Promise<T>;
32
40
  }
41
+ export { GraphQLClient as GraphQLTransport };
33
42
  //# sourceMappingURL=client.d.ts.map
@@ -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,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,WAAW,mBAAmB;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,MAAM,EAAE,mBAAmB,YAAK,EAAE,SAAS,EAAE,SAAS;IAOlE,WAAW,IAAI,MAAM;IAIrB;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,UAAU,EAC/B,QAAQ,EAAE,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC,EAChD,SAAS,CAAC,EAAE,UAAU,GACrB,OAAO,CAAC,OAAO,CAAC;IAKnB;;;;OAIG;IACG,KAAK,CAAC,CAAC,GAAG,GAAG,EACjB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAClC,OAAO,CAAC,CAAC,CAAC;CAgDd"}
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;AAWhD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAE1B,MAAM,EAAE,mBAAmB,YAAK,EAAE,OAAO,EAAE,YAAY;IAUnE,WAAW,IAAI,MAAM;IAIrB;;;OAGG;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;;;;OAIG;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;CA+Cd;AAED,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
package/dist/client.js CHANGED
@@ -7,12 +7,17 @@
7
7
  * `client.auth.login`, `client.udp.sendActorUpdate`).
8
8
  */
9
9
  import { print } from 'graphql';
10
+ import { silentLogger } from './logger.js';
11
+ import { CrowdyError, CrowdyGraphQLError, CrowdyHttpError, CrowdyNetworkError, CrowdyTimeoutError, } from './errors.js';
10
12
  export class GraphQLClient {
11
- constructor(config = {}, authState) {
13
+ constructor(config = {}, session) {
12
14
  this.graphqlEndpoint =
13
- config.graphqlEndpoint || 'http://localhost:3000/graphql';
15
+ config.graphqlEndpoint ||
16
+ config.httpUrl ||
17
+ 'http://localhost:3000/graphql';
14
18
  this.timeout = config.timeout || 60000;
15
- this.authState = authState;
19
+ this.session = session;
20
+ this.logger = config.logger ?? silentLogger;
16
21
  }
17
22
  getEndpoint() {
18
23
  return this.graphqlEndpoint;
@@ -21,19 +26,20 @@ export class GraphQLClient {
21
26
  * Execute a typed GraphQL operation produced by codegen and return the
22
27
  * `data` payload. Throws on transport errors, GraphQL errors, or timeouts.
23
28
  */
24
- async request(document, variables) {
29
+ async request(document, variables, options = {}) {
25
30
  const queryStr = print(document);
26
- return this.query(queryStr, (variables ?? {}));
31
+ return this.query(queryStr, (variables ?? {}), options);
27
32
  }
28
33
  /**
29
34
  * Internal escape hatch for raw query strings (used by hand-written
30
35
  * adapters that haven't migrated to typed documents yet). Prefer
31
36
  * `request()` with a `TypedDocumentNode`.
32
37
  */
33
- async query(query, variables = {}) {
38
+ async query(query, variables = {}, options = {}) {
34
39
  const controller = new AbortController();
35
40
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
36
- const token = this.authState.getToken();
41
+ const token = this.session.getToken();
42
+ const signal = options.signal ?? controller.signal;
37
43
  try {
38
44
  const requestBody = { query, variables };
39
45
  const response = await fetch(this.graphqlEndpoint, {
@@ -43,32 +49,33 @@ export class GraphQLClient {
43
49
  ...(token ? { Authorization: `Bearer ${token}` } : {}),
44
50
  },
45
51
  body: JSON.stringify(requestBody),
46
- signal: controller.signal,
52
+ signal,
47
53
  });
48
54
  clearTimeout(timeoutId);
49
55
  if (!response.ok) {
50
56
  const errorText = await response.text();
51
- throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`);
57
+ throw new CrowdyHttpError(response.status, errorText);
52
58
  }
53
59
  const result = await response.json();
54
60
  if (result.errors) {
55
- const error = result.errors[0];
56
- const errorMessage = Array.isArray(error.message)
57
- ? error.message.join(', ')
58
- : error.message;
59
- throw new Error(errorMessage);
61
+ throw new CrowdyGraphQLError(result.errors);
60
62
  }
61
63
  return result.data;
62
64
  }
63
65
  catch (error) {
64
66
  clearTimeout(timeoutId);
65
67
  if (error instanceof Error && error.name === 'AbortError') {
66
- throw new Error('Request timeout exceeded when trying to connect');
68
+ throw new CrowdyTimeoutError(this.timeout);
67
69
  }
68
- if (error instanceof Error) {
70
+ if (error instanceof CrowdyError) {
69
71
  throw error;
70
72
  }
71
- throw new Error(`Network error: ${error}`);
73
+ if (error instanceof Error) {
74
+ throw new CrowdyNetworkError(error);
75
+ }
76
+ this.logger.error?.('GraphQL request failed', error);
77
+ throw new CrowdyNetworkError(error);
72
78
  }
73
79
  }
74
80
  }
81
+ export { GraphQLClient as GraphQLTransport };
@@ -1,18 +1,34 @@
1
1
  /**
2
2
  * Public surface of the SDK. Construct one `CrowdyClient` per session and
3
3
  * access everything via the typed sub-clients (`client.auth`, `client.udp`,
4
- * `client.orgs`, ...). The legacy `client.login()` / `client.sendActorUpdate`
5
- * shortcuts are gone - use `client.auth.login()` / `client.udp.sendActorUpdate()`
6
- * instead.
4
+ * `client.chunks`, ...).
5
+ *
6
+ * The management/game-api split means CrowdyJS now talks to **two** GraphQL
7
+ * endpoints behind the scenes:
8
+ *
9
+ * - `managementUrl` / `managementGraphqlEndpoint` -> `cks-management-api`
10
+ * used by `auth` (login, register, logout, password / email flows) and
11
+ * `users` (me, updateGamertag, deleteMyAccount). This is also where
12
+ * `game_tokens` are minted.
13
+ *
14
+ * - `httpUrl` / `graphqlEndpoint` -> `cks-game-api`
15
+ * used by every game / world / replication sub-client
16
+ * (`chunks`, `voxels`, `actors`, `teleport`, `state`, `serverStatus`,
17
+ * `udp`). WebSocket subscriptions (`wsUrl`) also target this endpoint.
18
+ *
19
+ * A single `AuthState` is shared across both clients, so once
20
+ * `client.auth.login()` returns, every subsequent SDK call (against either
21
+ * endpoint) carries the Bearer token automatically.
7
22
  */
23
+ import { AuthState } from './auth-state.js';
24
+ import { GraphQLClient } from './client.js';
25
+ import { SubscriptionManager } from './subscriptions.js';
26
+ import type { CrowdyLogger } from './logger.js';
27
+ import type { TokenStore } from './session.js';
28
+ import { WorldClient } from './world.js';
8
29
  import { AuthAPI } from './domains/auth.js';
9
30
  import { UsersAPI } from './domains/users.js';
10
- import { OrganizationsAPI } from './domains/organizations.js';
11
31
  import { AppsAPI } from './domains/apps.js';
12
- import { AppAccessAPI } from './domains/appAccess.js';
13
- import { BillingAPI } from './domains/billing.js';
14
- import { QuotasAPI } from './domains/quotas.js';
15
- import { PaymentsAPI } from './domains/payments.js';
16
32
  import { ChunksAPI } from './domains/chunks.js';
17
33
  import { VoxelsAPI } from './domains/voxels.js';
18
34
  import { ActorsAPI } from './domains/actors.js';
@@ -21,22 +37,46 @@ import { StateAPI } from './domains/state.js';
21
37
  import { ServerStatusAPI } from './domains/serverStatus.js';
22
38
  import { UdpAPI } from './domains/udp.js';
23
39
  export interface CrowdyClientConfig {
40
+ /** game-api HTTP root (e.g. `https://dev-game-api.crowdedkingdoms.com`). */
41
+ httpUrl?: string;
42
+ /** game-api WS root. */
43
+ wsUrl?: string;
44
+ /** game-api GraphQL endpoint. Defaults to `${httpUrl}/graphql`. */
24
45
  graphqlEndpoint?: string;
46
+ /** game-api WS endpoint. Defaults to `${wsUrl}/graphql`. */
25
47
  wsEndpoint?: string;
48
+ /**
49
+ * management-api HTTP root (e.g.
50
+ * `https://dev-management-api.crowdedkingdoms.com`). When set,
51
+ * `client.auth` and `client.users` route here. If left empty the SDK
52
+ * falls back to `httpUrl` for backwards-compatibility with the legacy
53
+ * single-endpoint deployment, but new code should set this explicitly.
54
+ */
55
+ managementUrl?: string;
56
+ /** management-api GraphQL endpoint. Defaults to `${managementUrl}/graphql`. */
57
+ managementGraphqlEndpoint?: string;
26
58
  timeout?: number;
59
+ tokenStore?: TokenStore;
60
+ logger?: CrowdyLogger;
61
+ realtime?: {
62
+ retryAttempts?: number;
63
+ retryInitialDelayMs?: number;
64
+ retryMaxDelayMs?: number;
65
+ waitTimeoutMs?: number;
66
+ };
27
67
  }
28
68
  export declare class CrowdyClient {
29
- private readonly authState;
30
- private readonly client;
31
- private readonly subscriptions;
69
+ /** Shared token state for both game-api and management-api requests. */
70
+ readonly session: AuthState;
71
+ /** game-api HTTP client. */
72
+ readonly graphql: GraphQLClient;
73
+ /** game-api WebSocket subscription manager. */
74
+ readonly realtime: SubscriptionManager;
75
+ /** management-api HTTP client. Same `AuthState` as `graphql`. */
76
+ readonly management: GraphQLClient;
32
77
  readonly auth: AuthAPI;
33
78
  readonly users: UsersAPI;
34
- readonly orgs: OrganizationsAPI;
35
79
  readonly apps: AppsAPI;
36
- readonly appAccess: AppAccessAPI;
37
- readonly billing: BillingAPI;
38
- readonly quotas: QuotasAPI;
39
- readonly payments: PaymentsAPI;
40
80
  readonly chunks: ChunksAPI;
41
81
  readonly voxels: VoxelsAPI;
42
82
  readonly actors: ActorsAPI;
@@ -45,7 +85,13 @@ export declare class CrowdyClient {
45
85
  readonly serverStatus: ServerStatusAPI;
46
86
  readonly udp: UdpAPI;
47
87
  constructor(config?: CrowdyClientConfig);
88
+ /** Imperatively set the Bearer token (useful for SSO / token rehydrate). */
89
+ setToken(token: string | null): void;
90
+ /** Read the current Bearer token (null if no session). */
91
+ getToken(): string | null;
92
+ world(appId: string): WorldClient;
48
93
  /** Closes the WebSocket and clears the in-memory auth token. */
49
94
  close(): void;
50
95
  }
96
+ export declare function createCrowdyClient(config?: CrowdyClientConfig): CrowdyClient;
51
97
  //# sourceMappingURL=crowdy-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crowdy-client.d.ts","sourceRoot":"","sources":["../src/crowdy-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,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,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,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,YAAY;IAGvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IAGpD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAET,MAAM,GAAE,kBAAuB;IA4B3C,gEAAgE;IAChE,KAAK,IAAI,IAAI;CAId"}
1
+ {"version":3,"file":"crowdy-client.d.ts","sourceRoot":"","sources":["../src/crowdy-client.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,32 @@
1
1
  /**
2
2
  * Public surface of the SDK. Construct one `CrowdyClient` per session and
3
3
  * access everything via the typed sub-clients (`client.auth`, `client.udp`,
4
- * `client.orgs`, ...). The legacy `client.login()` / `client.sendActorUpdate`
5
- * shortcuts are gone - use `client.auth.login()` / `client.udp.sendActorUpdate()`
6
- * instead.
4
+ * `client.chunks`, ...).
5
+ *
6
+ * The management/game-api split means CrowdyJS now talks to **two** GraphQL
7
+ * endpoints behind the scenes:
8
+ *
9
+ * - `managementUrl` / `managementGraphqlEndpoint` -> `cks-management-api`
10
+ * used by `auth` (login, register, logout, password / email flows) and
11
+ * `users` (me, updateGamertag, deleteMyAccount). This is also where
12
+ * `game_tokens` are minted.
13
+ *
14
+ * - `httpUrl` / `graphqlEndpoint` -> `cks-game-api`
15
+ * used by every game / world / replication sub-client
16
+ * (`chunks`, `voxels`, `actors`, `teleport`, `state`, `serverStatus`,
17
+ * `udp`). WebSocket subscriptions (`wsUrl`) also target this endpoint.
18
+ *
19
+ * A single `AuthState` is shared across both clients, so once
20
+ * `client.auth.login()` returns, every subsequent SDK call (against either
21
+ * endpoint) carries the Bearer token automatically.
7
22
  */
8
23
  import { AuthState } from './auth-state.js';
9
24
  import { GraphQLClient } from './client.js';
10
25
  import { SubscriptionManager } from './subscriptions.js';
26
+ import { WorldClient } from './world.js';
11
27
  import { AuthAPI } from './domains/auth.js';
12
28
  import { UsersAPI } from './domains/users.js';
13
- import { OrganizationsAPI } from './domains/organizations.js';
14
29
  import { AppsAPI } from './domains/apps.js';
15
- import { AppAccessAPI } from './domains/appAccess.js';
16
- import { BillingAPI } from './domains/billing.js';
17
- import { QuotasAPI } from './domains/quotas.js';
18
- import { PaymentsAPI } from './domains/payments.js';
19
30
  import { ChunksAPI } from './domains/chunks.js';
20
31
  import { VoxelsAPI } from './domains/voxels.js';
21
32
  import { ActorsAPI } from './domains/actors.js';
@@ -25,28 +36,59 @@ import { ServerStatusAPI } from './domains/serverStatus.js';
25
36
  import { UdpAPI } from './domains/udp.js';
26
37
  export class CrowdyClient {
27
38
  constructor(config = {}) {
28
- this.authState = new AuthState();
29
- this.client = new GraphQLClient({ graphqlEndpoint: config.graphqlEndpoint, timeout: config.timeout }, this.authState);
30
- this.subscriptions = new SubscriptionManager({ wsEndpoint: config.wsEndpoint }, this.authState);
31
- this.auth = new AuthAPI(this.client, this.authState);
32
- this.users = new UsersAPI(this.client);
33
- this.orgs = new OrganizationsAPI(this.client);
34
- this.apps = new AppsAPI(this.client);
35
- this.appAccess = new AppAccessAPI(this.client);
36
- this.billing = new BillingAPI(this.client);
37
- this.quotas = new QuotasAPI(this.client);
38
- this.payments = new PaymentsAPI(this.client);
39
- this.chunks = new ChunksAPI(this.client);
40
- this.voxels = new VoxelsAPI(this.client);
41
- this.actors = new ActorsAPI(this.client);
42
- this.teleport = new TeleportAPI(this.client);
43
- this.state = new StateAPI(this.client);
44
- this.serverStatus = new ServerStatusAPI(this.client);
45
- this.udp = new UdpAPI(this.client, this.subscriptions);
39
+ this.session = new AuthState(config.tokenStore);
40
+ this.graphql = new GraphQLClient({
41
+ httpUrl: config.httpUrl,
42
+ graphqlEndpoint: config.graphqlEndpoint,
43
+ timeout: config.timeout,
44
+ logger: config.logger,
45
+ }, this.session);
46
+ this.realtime = new SubscriptionManager({
47
+ wsUrl: config.wsUrl,
48
+ wsEndpoint: config.wsEndpoint,
49
+ logger: config.logger,
50
+ ...config.realtime,
51
+ }, this.session);
52
+ const managementGraphqlEndpoint = config.managementGraphqlEndpoint ??
53
+ (config.managementUrl
54
+ ? `${config.managementUrl.replace(/\/$/, '')}/graphql`
55
+ : config.graphqlEndpoint);
56
+ // Management-api client. Falls back to game-api endpoint if the caller
57
+ // hasn't configured `managementUrl` yet (single-endpoint legacy mode).
58
+ this.management = new GraphQLClient({
59
+ httpUrl: config.managementUrl ?? config.httpUrl,
60
+ graphqlEndpoint: managementGraphqlEndpoint,
61
+ timeout: config.timeout,
62
+ logger: config.logger,
63
+ }, this.session);
64
+ this.auth = new AuthAPI(this.management, this.session);
65
+ this.users = new UsersAPI(this.management);
66
+ this.apps = new AppsAPI(this.management);
67
+ this.chunks = new ChunksAPI(this.graphql);
68
+ this.voxels = new VoxelsAPI(this.graphql);
69
+ this.actors = new ActorsAPI(this.graphql);
70
+ this.teleport = new TeleportAPI(this.graphql);
71
+ this.state = new StateAPI(this.graphql);
72
+ this.serverStatus = new ServerStatusAPI(this.graphql);
73
+ this.udp = new UdpAPI(this.graphql, this.realtime);
74
+ }
75
+ /** Imperatively set the Bearer token (useful for SSO / token rehydrate). */
76
+ setToken(token) {
77
+ this.session.setToken(token);
78
+ }
79
+ /** Read the current Bearer token (null if no session). */
80
+ getToken() {
81
+ return this.session.getToken();
82
+ }
83
+ world(appId) {
84
+ return new WorldClient(appId, this.udp);
46
85
  }
47
86
  /** Closes the WebSocket and clears the in-memory auth token. */
48
87
  close() {
49
- this.subscriptions.close();
50
- this.authState.setToken(null);
88
+ this.realtime.close();
89
+ this.session.setToken(null);
51
90
  }
52
91
  }
92
+ export function createCrowdyClient(config = {}) {
93
+ return new CrowdyClient(config);
94
+ }
@@ -1,27 +1,55 @@
1
- import type { GraphQLClient } from '../client.js';
2
- import { type AppQuery, type AppQueryVariables, type AppBySlugQuery, type AppBySlugQueryVariables, type MyAppsQuery, type AppsForOrgQuery, type AppsForOrgQueryVariables, type MarketplaceAppsQuery, type MarketplaceAppsQueryVariables, type CreateAppMutation, type CreateAppMutationVariables, type UpdateAppMutation, type UpdateAppMutationVariables, type ArchiveAppMutationVariables, type SetAppVisibilityMutation, type SetAppVisibilityMutationVariables } from '../generated/graphql.js';
3
1
  /**
4
- * App (game / world) lifecycle and discovery. Exposed as `client.apps`.
2
+ * Apps sub-client. Targets `cks-management-api` (where the apps catalog
3
+ * lives). After the DB split each app may be served by its own per-tenant
4
+ * cks-game-api; the marketplace returns `gameApiUrl` for those rows so the
5
+ * caller can build a per-app `CrowdyClient` against the correct endpoint.
6
+ *
7
+ * Typical pattern:
5
8
  *
6
- * `marketplace()` is a public listing (no auth) of every app where
7
- * visibility = PUBLIC and status = LIVE; the rest of the methods require
8
- * either org-membership permissions or super admin.
9
+ * const baseClient = createCrowdyClient({
10
+ * managementUrl: 'https://api.example.com',
11
+ * httpUrl: 'https://legacy-game-api.example.com', // pre-split fallback
12
+ * });
13
+ * await baseClient.auth.login({ email, password });
14
+ *
15
+ * const route = await baseClient.apps.routeFor(appId);
16
+ * if (route.splitMode && route.gameApiUrl) {
17
+ * const perAppClient = createCrowdyClient({
18
+ * managementUrl: 'https://api.example.com',
19
+ * httpUrl: route.gameApiUrl,
20
+ * wsUrl: route.gameApiUrl.replace(/^https?/, 'wss'),
21
+ * tokenStore: baseClient.session.tokenStore,
22
+ * });
23
+ * // drive gameplay through perAppClient
24
+ * }
9
25
  */
26
+ import type { GraphQLClient } from '../client.js';
27
+ import { type AppQuery, type AppBySlugQuery, type MyAppsQuery } from '../generated/graphql.js';
28
+ /**
29
+ * Subset of an `App` row that the SDK exposes for routing decisions. The
30
+ * fields are typed loosely as `unknown` because the generated types lag
31
+ * behind the `splitMode` / `gameApiUrl` selection until codegen runs.
32
+ */
33
+ export interface AppRoute {
34
+ appId: string;
35
+ splitMode: boolean;
36
+ gameApiUrl: string | null;
37
+ }
10
38
  export declare class AppsAPI {
11
- private gql;
12
- constructor(gql: GraphQLClient);
13
- marketplace(args?: MarketplaceAppsQueryVariables): Promise<MarketplaceAppsQuery['apps']>;
14
- byId(appId: AppQueryVariables['appId']): Promise<AppQuery['app']>;
15
- bySlug(args: AppBySlugQueryVariables): Promise<AppBySlugQuery['appBySlug']>;
39
+ private readonly management;
40
+ constructor(management: GraphQLClient);
41
+ /** Fetch a single app by id. */
42
+ app(appId: string): Promise<AppQuery['app']>;
43
+ /** Fetch by org slug + app slug (marketplace links). */
44
+ appBySlug(orgSlug: string, appSlug: string): Promise<AppBySlugQuery['appBySlug']>;
45
+ /** Apps the caller can play (org membership OR active access). */
16
46
  myApps(): Promise<MyAppsQuery['myApps']>;
17
- forOrg(orgSlug: AppsForOrgQueryVariables['orgSlug']): Promise<AppsForOrgQuery['appsForOrg']>;
18
- create(input: CreateAppMutationVariables['input']): Promise<CreateAppMutation['createApp']>;
19
- update(args: UpdateAppMutationVariables): Promise<UpdateAppMutation['updateApp']>;
20
- archive(appId: ArchiveAppMutationVariables['appId']): Promise<{
21
- appId: any;
22
- status: string;
23
- updatedAt: any;
24
- }>;
25
- setVisibility(args: SetAppVisibilityMutationVariables): Promise<SetAppVisibilityMutation['setAppVisibility']>;
47
+ /**
48
+ * Convenience: returns just the routing tuple for a given app. If the
49
+ * app row is missing or the API does not expose split-mode fields yet,
50
+ * returns `{ appId, splitMode: false, gameApiUrl: null }` so the caller
51
+ * keeps using the legacy single-endpoint deployment.
52
+ */
53
+ routeFor(appId: string): Promise<AppRoute>;
26
54
  }
27
55
  //# sourceMappingURL=apps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/domains/apps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,iBAAiB,EAEtB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAE5B,KAAK,WAAW,EAEhB,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAE7B,KAAK,oBAAoB,EACzB,KAAK,6BAA6B,EAElC,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAE/B,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAE/B,KAAK,2BAA2B,EAEhC,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EACvC,MAAM,yBAAyB,CAAC;AAEjC;;;;;;GAMG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,aAAa;IAEhC,WAAW,CACf,IAAI,GAAE,6BAAkC,GACvC,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAKlC,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAKjE,MAAM,CACV,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IAKjC,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAKxC,MAAM,CACV,OAAO,EAAE,wBAAwB,CAAC,SAAS,CAAC,GAC3C,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IAKnC,MAAM,CACV,KAAK,EAAE,0BAA0B,CAAC,OAAO,CAAC,GACzC,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAKpC,MAAM,CACV,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAKpC,OAAO,CACX,KAAK,EAAE,2BAA2B,CAAC,OAAO,CAAC,GAC1C,OAAO,CAAC;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,GAAG,CAAA;KAAE,CAAC;IAKpD,aAAa,CACjB,IAAI,EAAE,iCAAiC,GACtC,OAAO,CAAC,wBAAwB,CAAC,kBAAkB,CAAC,CAAC;CAIzD"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/domains/apps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAIL,KAAK,QAAQ,EAEb,KAAK,cAAc,EAEnB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAcD,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,aAAa;IAEtD,gCAAgC;IAC1B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAQlD,wDAAwD;IAClD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IAQvC,kEAAkE;IAC5D,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAQ9C;;;;;OAKG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;CAUjD"}