@crowdedkingdomstudios/crowdyjs 5.0.0 → 5.0.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/README.md CHANGED
@@ -65,7 +65,7 @@ Auth and user reads always target `managementUrl`. Everything else targets `http
65
65
  ## Game-loop lifecycle
66
66
 
67
67
  1. Authenticate with `client.auth.login()` or restore a previous token through `client.session.restore()`.
68
- 2. Subscribe to UDP proxy notifications with `client.udp.subscribe()` (the SDK will open the realtime socket on demand).
68
+ 2. Subscribe to UDP proxy notifications with `client.udp.subscribe(handlers, appId)` — `appId` is **required** (the SDK opens the realtime socket on demand and scopes it to that app).
69
69
  3. Join a chunk by sending an initial actor update.
70
70
  4. Send actor, voxel, text, audio, and client-event updates through `client.udp` or the higher-level `client.world(appId)` helpers.
71
71
  5. Call `client.udp.disconnect()` when leaving the world.
@@ -76,43 +76,63 @@ Auth and user reads always target `managementUrl`. Everything else targets `http
76
76
  When a player is about to join an app, query its routing fields on the management API first:
77
77
 
78
78
  ```graphql
79
- query AppForRouting($id: BigInt!) {
80
- app(id: $id) {
79
+ query AppForRouting($appId: BigInt!) {
80
+ app(appId: $appId) {
81
81
  appId
82
82
  splitMode
83
+ deploymentTarget
83
84
  gameApiUrl
84
85
  }
85
86
  }
86
87
  ```
87
88
 
88
- If `splitMode && gameApiUrl`, the app lives behind its own Game API deployment. Build a **second** `CrowdyClient` with `httpUrl: gameApiUrl` (and the matching `wsUrl`) **sharing the same `tokenStore` as the first client**, then drive gameplay through that client. Apps without `splitMode` keep working against the default `httpUrl` you configured.
89
+ `gameApiUrl` is populated for **both** dedicated (`splitMode`) and shared
90
+ (`deploymentTarget: "shared"`) apps. When it's set, build a **second**
91
+ `CrowdyClient` with `httpUrl: gameApiUrl` (and the matching `wsUrl`) **sharing the
92
+ same `tokenStore` as the first client**, then drive gameplay through that client.
93
+ Apps with no `gameApiUrl` keep working against the default `httpUrl` you
94
+ configured.
89
95
 
90
96
  ## Realtime notifications
91
97
 
98
+ `subscribe` takes the handlers **and a required `appId`** (second argument). The
99
+ Game API scopes the realtime session to that app and rejects an app-agnostic
100
+ subscription with a `RealtimeConnectionEvent` (`code: 'APP_ID_REQUIRED'`). Run
101
+ one client per app (sharing the same `tokenStore`) when a player is in multiple
102
+ apps at once.
103
+
92
104
  ```ts
93
- const unsubscribe = client.udp.subscribe({
94
- actorUpdate: (event) => {
95
- console.log(event.uuid, event.state);
96
- },
97
- voxelUpdate: (event) => { /* ... */ },
98
- text: (event) => { /* ... */ },
99
- audio: (event) => { /* ... */ },
100
- clientEvent: (event) => { /* ... */ },
101
- serverEvent: (event) => { /* ... */ },
102
- singleActorMessage: (event) => {
103
- // A direct actor-to-actor message addressed to you.
104
- console.log(event.uuid, event.payload); // payload is base64
105
- },
106
- genericError: (event) => {
107
- console.warn(event.sequenceNumber, event.errorCode);
108
- },
109
- connectionEvent: (event) => {
110
- console.warn(event.code, event.message);
105
+ const appId = '1';
106
+
107
+ const unsubscribe = client.udp.subscribe(
108
+ {
109
+ actorUpdate: (event) => {
110
+ console.log(event.uuid, event.state);
111
+ },
112
+ voxelUpdate: (event) => { /* ... */ },
113
+ text: (event) => { /* ... */ },
114
+ audio: (event) => { /* ... */ },
115
+ clientEvent: (event) => { /* ... */ },
116
+ serverEvent: (event) => { /* ... */ },
117
+ singleActorMessage: (event) => {
118
+ // A direct actor-to-actor message addressed to you.
119
+ console.log(event.uuid, event.payload); // payload is base64
120
+ },
121
+ genericError: (event) => {
122
+ console.warn(event.sequenceNumber, event.errorCode);
123
+ },
124
+ connectionEvent: (event) => {
125
+ console.warn(event.code, event.message);
126
+ },
127
+ error: (error) => {
128
+ console.error(error.code, error.message);
129
+ },
111
130
  },
112
- error: (error) => {
113
- console.error(error.code, error.message);
114
- },
115
- });
131
+ appId,
132
+ );
133
+
134
+ // Or use the world helper, which passes its appId automatically:
135
+ // client.world(appId).subscribe(handlers);
116
136
 
117
137
  client.realtime.onStatus((status) => {
118
138
  console.log('realtime:', status);
@@ -1663,6 +1663,12 @@ export type JoinSessionInput = {
1663
1663
  role?: InputMaybe<Scalars['String']['input']>;
1664
1664
  sessionId: Scalars['String']['input'];
1665
1665
  };
1666
+ export type LinkAppToEnvironmentInput = {
1667
+ appId: Scalars['BigInt']['input'];
1668
+ /** Environment slug (cks_environments.slug) to link the app to. */
1669
+ environmentSlug: Scalars['String']['input'];
1670
+ orgId: Scalars['BigInt']['input'];
1671
+ };
1666
1672
  export type ListVoxelUpdatesByDistanceInput = {
1667
1673
  appId: Scalars['BigInt']['input'];
1668
1674
  centerCoordinate: ChunkCoordinatesInput;
@@ -1776,6 +1782,8 @@ export type Mutation = {
1776
1782
  leaveChannel: Scalars['Boolean']['output'];
1777
1783
  /** Leave a team. */
1778
1784
  leaveTeam: Scalars['Boolean']['output'];
1785
+ /** Links an unlinked app to an existing environment for split-mode routing. Refuses shared apps and apps already linked elsewhere. */
1786
+ linkAppToEnvironment: App;
1779
1787
  login: AuthResponse;
1780
1788
  logout: Scalars['Boolean']['output'];
1781
1789
  logoutAllDevices: Scalars['Boolean']['output'];
@@ -2067,6 +2075,9 @@ export type MutationLeaveChannelArgs = {
2067
2075
  export type MutationLeaveTeamArgs = {
2068
2076
  groupId: Scalars['BigInt']['input'];
2069
2077
  };
2078
+ export type MutationLinkAppToEnvironmentArgs = {
2079
+ input: LinkAppToEnvironmentInput;
2080
+ };
2070
2081
  export type MutationLoginArgs = {
2071
2082
  loginUserInput: LoginUserInput;
2072
2083
  };
@@ -2551,6 +2562,7 @@ export type Query = {
2551
2562
  environmentDatacenters: Array<CksOvhDatacenter>;
2552
2563
  /** Customer-selectable instance flavors in the datacenter with current availability and customer pricing. */
2553
2564
  environmentFlavors: Array<CksOvhFlavor>;
2565
+ environmentForwardVersions: Array<CksEnvironmentVersion>;
2554
2566
  /** Pricing quote for the selected flavors. Fails if any flavor is unavailable, hidden, or lacks customer pricing. */
2555
2567
  environmentQuote: CksEnvironmentQuote;
2556
2568
  /** Per-app usage totals for apps linked to an environment. */
@@ -2786,6 +2798,10 @@ export type QueryEffectiveQuotaArgs = {
2786
2798
  export type QueryEnvironmentFlavorsArgs = {
2787
2799
  datacenter: Scalars['String']['input'];
2788
2800
  };
2801
+ export type QueryEnvironmentForwardVersionsArgs = {
2802
+ orgId: Scalars['BigInt']['input'];
2803
+ slug: Scalars['String']['input'];
2804
+ };
2789
2805
  export type QueryEnvironmentQuoteArgs = {
2790
2806
  input: EnvironmentQuoteInput;
2791
2807
  };
@@ -3028,6 +3044,7 @@ export type RedeployEnvironmentInput = {
3028
3044
  deployMode?: InputMaybe<RedeployDeployMode>;
3029
3045
  orgId: Scalars['BigInt']['input'];
3030
3046
  slug: Scalars['String']['input'];
3047
+ version?: InputMaybe<Scalars['String']['input']>;
3031
3048
  };
3032
3049
  export type RegisterUserInput = {
3033
3050
  email: Scalars['String']['input'];