@crowdedkingdomstudios/crowdyjs 1.0.0 → 1.0.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAEV,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AAcpB,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAUd;IAEF,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAuB;gBAExB,MAAM,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO;IAIhD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIxC,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,iBAAiB;IAoMzB,OAAO,CAAC,kBAAkB;IAmB1B,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,qBAAqB,CAAC,OAAO,EAAE,0BAA0B,GAAG,aAAa;IAYzE,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,qBAAqB,CAAC,OAAO,EAAE,0BAA0B,GAAG,aAAa;IAYzE,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa;IAYvD,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,cAAc,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa;IAY3D,OAAO,CAAC,wBAAwB;IAShC,KAAK,IAAI,IAAI;CAWd"}
1
+ {"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAEV,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AAcpB,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAUd;IAEF,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAuB;gBAExB,MAAM,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO;IAIhD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIxC,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,iBAAiB;IAiMzB,OAAO,CAAC,kBAAkB;IAmB1B,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,qBAAqB,CAAC,OAAO,EAAE,0BAA0B,GAAG,aAAa;IAYzE,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,qBAAqB,CAAC,OAAO,EAAE,0BAA0B,GAAG,aAAa;IAYzE,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa;IAYvD,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAYzD,cAAc,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa;IAY3D,OAAO,CAAC,wBAAwB;IAShC,KAAK,IAAI,IAAI;CAWd"}
@@ -24,7 +24,9 @@ export class SubscriptionManager {
24
24
  this.token = token;
25
25
  }
26
26
  ensureSubscription() {
27
- if (!this.wsClient || this.wsClient.readyState !== WebSocket.OPEN) {
27
+ if (!this.wsClient ||
28
+ (this.wsClient.readyState !== WebSocket.OPEN &&
29
+ this.wsClient.readyState !== WebSocket.CONNECTING)) {
28
30
  this.startSubscription();
29
31
  }
30
32
  }
@@ -32,27 +34,28 @@ export class SubscriptionManager {
32
34
  if (!this.token) {
33
35
  throw new Error('Must be authenticated to subscribe');
34
36
  }
35
- if (this.wsClient && this.wsClient.readyState === WebSocket.OPEN) {
36
- return; // Already connected
37
+ if (this.wsClient &&
38
+ (this.wsClient.readyState === WebSocket.OPEN ||
39
+ this.wsClient.readyState === WebSocket.CONNECTING)) {
40
+ return; // Already connected or connecting
37
41
  }
38
42
  const wsUrl = this.wsEndpoint;
39
43
  this.subscriptionId = 'udp-notifications-' + Date.now();
40
- this.wsClient = new WebSocket(wsUrl, 'graphql-ws');
41
- this.wsClient.onopen = () => {
42
- // Send connection_init message with authorization
43
- this.wsClient.send(JSON.stringify({
44
+ const ws = new WebSocket(wsUrl, 'graphql-ws');
45
+ this.wsClient = ws;
46
+ ws.onopen = () => {
47
+ ws.send(JSON.stringify({
44
48
  type: 'connection_init',
45
49
  payload: {
46
50
  authorization: `Bearer ${this.token}`,
47
- Authorization: `Bearer ${this.token}`, // Some servers expect capitalized
51
+ Authorization: `Bearer ${this.token}`,
48
52
  },
49
53
  }));
50
54
  };
51
- this.wsClient.onmessage = (event) => {
55
+ ws.onmessage = (event) => {
52
56
  try {
53
57
  const message = JSON.parse(event.data);
54
58
  if (message.type === 'connection_ack') {
55
- // Subscribe to udpNotifications
56
59
  const startMessage = {
57
60
  id: this.subscriptionId,
58
61
  type: 'start',
@@ -138,18 +141,15 @@ export class SubscriptionManager {
138
141
  }`,
139
142
  },
140
143
  };
141
- this.wsClient.send(JSON.stringify(startMessage));
144
+ ws.send(JSON.stringify(startMessage));
142
145
  }
143
146
  else if (message.type === 'connection_error') {
144
147
  console.error('Connection error:', message.payload);
145
148
  const errorMsg = message.payload?.message || 'Connection rejected - check authorization token';
146
- // Notify all handlers of error? Or just log?
147
149
  console.error('WebSocket connection error:', errorMsg);
148
150
  }
149
151
  else if (message.type === 'data') {
150
- // Handle null values (subscription is active but no notification yet)
151
152
  if (message.payload?.data?.udpNotifications === null) {
152
- // Don't call handlers for null values - subscription is working, just no data yet
153
153
  return;
154
154
  }
155
155
  if (message.payload?.data?.udpNotifications) {
@@ -177,38 +177,37 @@ export class SubscriptionManager {
177
177
  console.error('WebSocket error:', errorMsg);
178
178
  }
179
179
  else if (message.type === 'ping') {
180
- // Respond to ping with pong (graphql-ws protocol keepalive)
181
- this.wsClient.send(JSON.stringify({
182
- type: 'pong',
183
- }));
180
+ ws.send(JSON.stringify({ type: 'pong' }));
184
181
  }
185
182
  }
186
183
  catch (error) {
187
184
  console.error('Error parsing WebSocket message:', error);
188
185
  }
189
186
  };
190
- this.wsClient.onerror = (error) => {
187
+ ws.onerror = (error) => {
191
188
  console.error('WebSocket error:', error);
192
189
  };
193
- this.wsClient.onclose = (event) => {
190
+ ws.onclose = (event) => {
194
191
  if (event.code !== 1000) {
195
192
  console.warn(`WebSocket closed unexpectedly: ${event.reason || event.code}`);
196
193
  }
197
- this.wsClient = null;
194
+ if (this.wsClient === ws) {
195
+ this.wsClient = null;
196
+ }
198
197
  };
199
- // Store unsubscribe function
200
198
  this.wsUnsubscribe = () => {
201
- if (this.wsClient && this.wsClient.readyState === WebSocket.OPEN) {
202
- // Send stop message before closing
199
+ if (ws.readyState === WebSocket.OPEN) {
203
200
  if (this.subscriptionId) {
204
- this.wsClient.send(JSON.stringify({
201
+ ws.send(JSON.stringify({
205
202
  id: this.subscriptionId,
206
203
  type: 'stop',
207
204
  }));
208
205
  }
209
- this.wsClient.close();
206
+ ws.close();
207
+ }
208
+ if (this.wsClient === ws) {
209
+ this.wsClient = null;
210
210
  }
211
- this.wsClient = null;
212
211
  this.wsUnsubscribe = null;
213
212
  };
214
213
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdedkingdomstudios/crowdyjs",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Client SDK for Crowded Kingdoms GraphQL API with UDP proxy support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,7 +26,7 @@
26
26
  "keywords": [
27
27
  "crowded-kingdoms",
28
28
  "graphql",
29
- "udp-proxy",
29
+ "game-api",
30
30
  "multiplayer",
31
31
  "sdk"
32
32
  ],
@@ -34,7 +34,7 @@
34
34
  "license": "MIT",
35
35
  "devDependencies": {
36
36
  "@types/node": "^22.10.7",
37
- "typescript": "^5.7.3"
37
+ "typescript": "^5.7.3",
38
+ "ws": "^8.20.0"
38
39
  }
39
40
  }
40
-