@crowdedkingdomstudios/crowdyjs 1.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.
- package/LICENSE +21 -0
- package/README.md +219 -0
- package/dist/client.d.ts +27 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +243 -0
- package/dist/crowdy-client.d.ts +31 -0
- package/dist/crowdy-client.d.ts.map +1 -0
- package/dist/crowdy-client.js +91 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/subscriptions.d.ts +31 -0
- package/dist/subscriptions.d.ts.map +1 -0
- package/dist/subscriptions.js +350 -0
- package/dist/types.d.ts +225 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +36 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CrowdedKingdoms
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# CrowdyJS SDK
|
|
2
|
+
|
|
3
|
+
Client SDK for Crowded Kingdoms GraphQL API with UDP proxy support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @crowdedkingdomstudios/crowdyjs
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For local development:
|
|
12
|
+
```bash
|
|
13
|
+
npm link @crowdedkingdomstudios/crowdyjs
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### Basic Setup
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
import { CrowdyClient } from '@crowdedkingdomstudios/crowdyjs';
|
|
22
|
+
|
|
23
|
+
const client = new CrowdyClient({
|
|
24
|
+
graphqlEndpoint: 'http://localhost:3000/graphql',
|
|
25
|
+
wsEndpoint: 'ws://localhost:3000/graphql',
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Authentication
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
// Login
|
|
33
|
+
const authResponse = await client.login(email, password);
|
|
34
|
+
console.log('Logged in as:', authResponse.user.email);
|
|
35
|
+
|
|
36
|
+
// Register
|
|
37
|
+
const authResponse = await client.register(email, password, gamertag);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### UDP Proxy Connection
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
// Connect to UDP proxy
|
|
44
|
+
const status = await client.connectUdpProxy();
|
|
45
|
+
console.log('Connected to server:', status.serverIp6);
|
|
46
|
+
|
|
47
|
+
// Check connection status
|
|
48
|
+
const status = await client.getConnectionStatus();
|
|
49
|
+
|
|
50
|
+
// Disconnect
|
|
51
|
+
await client.disconnectUdpProxy();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Sending Actor Updates
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// Create 96-byte binary state (position, rotation, velocity, etc.)
|
|
58
|
+
const stateBuffer = new ArrayBuffer(96);
|
|
59
|
+
const view = new DataView(stateBuffer);
|
|
60
|
+
view.setFloat32(0, x, true); // position x
|
|
61
|
+
view.setFloat32(4, y, true); // position y
|
|
62
|
+
// ... populate rest of state
|
|
63
|
+
|
|
64
|
+
// Convert to base64
|
|
65
|
+
const base64State = btoa(String.fromCharCode(...new Uint8Array(stateBuffer)));
|
|
66
|
+
|
|
67
|
+
// Send update
|
|
68
|
+
await client.sendActorUpdate({
|
|
69
|
+
mapId: '1',
|
|
70
|
+
chunk: { x: '0', y: '0', z: '0' },
|
|
71
|
+
uuid: 'your-32-byte-uuid',
|
|
72
|
+
state: base64State,
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Type-Specific Subscription Handlers
|
|
77
|
+
|
|
78
|
+
The SDK provides type-specific handlers so you don't need to switch on `__typename`:
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
// Actor update notifications
|
|
82
|
+
const unsubscribe1 = client.onActorUpdate((notification) => {
|
|
83
|
+
// notification is typed as ActorUpdateNotification
|
|
84
|
+
console.log('Actor updated:', notification.uuid);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Actor update responses (from your own requests)
|
|
88
|
+
const unsubscribe2 = client.onActorUpdateResponse((response) => {
|
|
89
|
+
// response is typed as ActorUpdateResponse
|
|
90
|
+
if (response.errorCode === 'NO_ERROR') {
|
|
91
|
+
console.log('Update successful');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Voxel updates
|
|
96
|
+
const unsubscribe3 = client.onVoxelUpdate((notification) => {
|
|
97
|
+
// notification is typed as VoxelUpdateNotification
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Client audio (voice chat)
|
|
101
|
+
const unsubscribe4 = client.onClientAudio((notification) => {
|
|
102
|
+
// notification is typed as ClientAudioNotification
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Client text (chat messages)
|
|
106
|
+
const unsubscribe5 = client.onClientText((notification) => {
|
|
107
|
+
// notification is typed as ClientTextNotification
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Client events
|
|
111
|
+
const unsubscribe6 = client.onClientEvent((notification) => {
|
|
112
|
+
// notification is typed as ClientEventNotification
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Server events
|
|
116
|
+
const unsubscribe7 = client.onServerEvent((notification) => {
|
|
117
|
+
// notification is typed as ServerEventNotification
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Unsubscribe when done
|
|
121
|
+
unsubscribe1();
|
|
122
|
+
unsubscribe2();
|
|
123
|
+
// ... etc
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Complete Example
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
import { CrowdyClient } from '@crowdedkingdomstudios/crowdyjs';
|
|
130
|
+
|
|
131
|
+
const client = new CrowdyClient({
|
|
132
|
+
graphqlEndpoint: 'http://localhost:3000/graphql',
|
|
133
|
+
wsEndpoint: 'ws://localhost:3000/graphql',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Login
|
|
137
|
+
await client.login('user@example.com', 'password');
|
|
138
|
+
|
|
139
|
+
// Connect to UDP proxy
|
|
140
|
+
await client.connectUdpProxy();
|
|
141
|
+
|
|
142
|
+
// Subscribe to actor updates
|
|
143
|
+
const unsubscribe = client.onActorUpdate((notification) => {
|
|
144
|
+
console.log('Actor update:', notification.uuid);
|
|
145
|
+
// Handle the update...
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Send actor updates
|
|
149
|
+
setInterval(async () => {
|
|
150
|
+
await client.sendActorUpdate({
|
|
151
|
+
mapId: '1',
|
|
152
|
+
chunk: { x: '0', y: '0', z: '0' },
|
|
153
|
+
uuid: 'your-uuid',
|
|
154
|
+
state: 'base64-state-data',
|
|
155
|
+
});
|
|
156
|
+
}, 100);
|
|
157
|
+
|
|
158
|
+
// Cleanup
|
|
159
|
+
unsubscribe();
|
|
160
|
+
await client.disconnectUdpProxy();
|
|
161
|
+
client.close();
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## API Reference
|
|
165
|
+
|
|
166
|
+
### CrowdyClient
|
|
167
|
+
|
|
168
|
+
Main client class for interacting with the API.
|
|
169
|
+
|
|
170
|
+
#### Constructor
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
new CrowdyClient(config?: CrowdyClientConfig)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Config options:**
|
|
177
|
+
- `graphqlEndpoint?: string` - GraphQL HTTP endpoint (default: `http://localhost:3000/graphql`)
|
|
178
|
+
- `wsEndpoint?: string` - WebSocket endpoint (default: `ws://localhost:3000/graphql`)
|
|
179
|
+
- `timeout?: number` - Request timeout in ms (default: `60000`)
|
|
180
|
+
|
|
181
|
+
#### Methods
|
|
182
|
+
|
|
183
|
+
**Authentication:**
|
|
184
|
+
- `login(email: string, password: string): Promise<AuthResponse>`
|
|
185
|
+
- `register(email: string, password: string, gamertag?: string): Promise<AuthResponse>`
|
|
186
|
+
- `getAuthToken(): string | null`
|
|
187
|
+
|
|
188
|
+
**UDP Proxy:**
|
|
189
|
+
- `connectUdpProxy(): Promise<UdpProxyConnectionStatus>`
|
|
190
|
+
- `disconnectUdpProxy(): Promise<boolean>`
|
|
191
|
+
- `getConnectionStatus(): Promise<UdpProxyConnectionStatus>`
|
|
192
|
+
|
|
193
|
+
**Sending Updates:**
|
|
194
|
+
- `sendActorUpdate(input: ActorUpdateRequestInput): Promise<boolean>`
|
|
195
|
+
- `sendVoxelUpdate(input: VoxelUpdateRequestInput): Promise<boolean>`
|
|
196
|
+
- `sendAudioPacket(input: ClientAudioPacketInput): Promise<boolean>`
|
|
197
|
+
- `sendTextPacket(input: ClientTextPacketInput): Promise<boolean>`
|
|
198
|
+
- `sendClientEvent(input: ClientEventNotificationInput): Promise<boolean>`
|
|
199
|
+
|
|
200
|
+
**Subscriptions:**
|
|
201
|
+
- `onActorUpdate(handler: ActorUpdateHandler): UnsubscribeFn`
|
|
202
|
+
- `onActorUpdateResponse(handler: ActorUpdateResponseHandler): UnsubscribeFn`
|
|
203
|
+
- `onVoxelUpdate(handler: VoxelUpdateHandler): UnsubscribeFn`
|
|
204
|
+
- `onVoxelUpdateResponse(handler: VoxelUpdateResponseHandler): UnsubscribeFn`
|
|
205
|
+
- `onClientAudio(handler: ClientAudioHandler): UnsubscribeFn`
|
|
206
|
+
- `onClientText(handler: ClientTextHandler): UnsubscribeFn`
|
|
207
|
+
- `onClientEvent(handler: ClientEventHandler): UnsubscribeFn`
|
|
208
|
+
- `onServerEvent(handler: ServerEventHandler): UnsubscribeFn`
|
|
209
|
+
|
|
210
|
+
**Cleanup:**
|
|
211
|
+
- `close(): void` - Closes all subscriptions and cleans up
|
|
212
|
+
|
|
213
|
+
## TypeScript Support
|
|
214
|
+
|
|
215
|
+
The SDK is written in TypeScript and includes full type definitions. All notification types are properly typed, so you get full IDE autocomplete and type safety.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core GraphQL client for HTTP queries and mutations
|
|
3
|
+
*/
|
|
4
|
+
import type { AuthResponse, UdpProxyConnectionStatus, ActorUpdateRequestInput, VoxelUpdateRequestInput, ClientAudioPacketInput, ClientTextPacketInput, ClientEventNotificationInput } from './types.js';
|
|
5
|
+
export declare class GraphQLClient {
|
|
6
|
+
private token;
|
|
7
|
+
private graphqlEndpoint;
|
|
8
|
+
private timeout;
|
|
9
|
+
constructor(config?: {
|
|
10
|
+
graphqlEndpoint?: string;
|
|
11
|
+
timeout?: number;
|
|
12
|
+
});
|
|
13
|
+
setAuthToken(token: string | null): void;
|
|
14
|
+
getAuthToken(): string | null;
|
|
15
|
+
query<T = any>(query: string, variables?: Record<string, any>): Promise<T>;
|
|
16
|
+
login(email: string, password: string): Promise<AuthResponse>;
|
|
17
|
+
register(email: string, password: string, gamertag?: string): Promise<AuthResponse>;
|
|
18
|
+
connectUdpProxy(): Promise<UdpProxyConnectionStatus>;
|
|
19
|
+
disconnectUdpProxy(): Promise<boolean>;
|
|
20
|
+
getConnectionStatus(): Promise<UdpProxyConnectionStatus>;
|
|
21
|
+
sendActorUpdate(input: ActorUpdateRequestInput): Promise<boolean>;
|
|
22
|
+
sendVoxelUpdate(input: VoxelUpdateRequestInput): Promise<boolean>;
|
|
23
|
+
sendAudioPacket(input: ClientAudioPacketInput): Promise<boolean>;
|
|
24
|
+
sendTextPacket(input: ClientTextPacketInput): Promise<boolean>;
|
|
25
|
+
sendClientEvent(input: ClientEventNotificationInput): Promise<boolean>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AAEpB,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,GAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAKvE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIxC,YAAY,IAAI,MAAM,GAAG,IAAI;IAIvB,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IA+C9E,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA2B7D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BnF,eAAe,IAAI,OAAO,CAAC,wBAAwB,CAAC;IAgBpD,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAWtC,mBAAmB,IAAI,OAAO,CAAC,wBAAwB,CAAC;IAgBxD,eAAe,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BjE,eAAe,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IA4BjE,eAAe,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BhE,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0B9D,eAAe,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,OAAO,CAAC;CA0B7E"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core GraphQL client for HTTP queries and mutations
|
|
3
|
+
*/
|
|
4
|
+
export class GraphQLClient {
|
|
5
|
+
constructor(config = {}) {
|
|
6
|
+
this.token = null;
|
|
7
|
+
this.graphqlEndpoint = config.graphqlEndpoint || 'http://localhost:3000/graphql';
|
|
8
|
+
this.timeout = config.timeout || 60000;
|
|
9
|
+
}
|
|
10
|
+
setAuthToken(token) {
|
|
11
|
+
this.token = token;
|
|
12
|
+
}
|
|
13
|
+
getAuthToken() {
|
|
14
|
+
return this.token;
|
|
15
|
+
}
|
|
16
|
+
async query(query, variables = {}) {
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
19
|
+
try {
|
|
20
|
+
const requestBody = { query, variables };
|
|
21
|
+
const response = await fetch(this.graphqlEndpoint, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
...(this.token && { Authorization: `Bearer ${this.token}` }),
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify(requestBody),
|
|
28
|
+
signal: controller.signal,
|
|
29
|
+
});
|
|
30
|
+
clearTimeout(timeoutId);
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
const errorText = await response.text();
|
|
33
|
+
throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`);
|
|
34
|
+
}
|
|
35
|
+
const result = await response.json();
|
|
36
|
+
if (result.errors) {
|
|
37
|
+
const error = result.errors[0];
|
|
38
|
+
const errorMessage = Array.isArray(error.message)
|
|
39
|
+
? error.message.join(', ')
|
|
40
|
+
: error.message;
|
|
41
|
+
console.error('GraphQL error:', error);
|
|
42
|
+
throw new Error(errorMessage);
|
|
43
|
+
}
|
|
44
|
+
return result.data;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
clearTimeout(timeoutId);
|
|
48
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
49
|
+
throw new Error('Request timeout exceeded when trying to connect');
|
|
50
|
+
}
|
|
51
|
+
if (error instanceof Error) {
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`Network error: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async login(email, password) {
|
|
58
|
+
const data = await this.query(`
|
|
59
|
+
mutation Login($input: LoginUserInput!) {
|
|
60
|
+
login(loginUserInput: $input) {
|
|
61
|
+
token
|
|
62
|
+
gameTokenId
|
|
63
|
+
user {
|
|
64
|
+
userId
|
|
65
|
+
email
|
|
66
|
+
gamertag
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
`, {
|
|
71
|
+
input: { email, password },
|
|
72
|
+
});
|
|
73
|
+
if (data.login?.token) {
|
|
74
|
+
this.setAuthToken(data.login.token);
|
|
75
|
+
return data.login;
|
|
76
|
+
}
|
|
77
|
+
throw new Error('Login failed');
|
|
78
|
+
}
|
|
79
|
+
async register(email, password, gamertag) {
|
|
80
|
+
const data = await this.query(`
|
|
81
|
+
mutation Register($input: RegisterUserInput!) {
|
|
82
|
+
register(registerUserInput: $input) {
|
|
83
|
+
token
|
|
84
|
+
gameTokenId
|
|
85
|
+
user {
|
|
86
|
+
userId
|
|
87
|
+
email
|
|
88
|
+
gamertag
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
`, {
|
|
93
|
+
input: { email, password, gamertag },
|
|
94
|
+
});
|
|
95
|
+
if (data.register?.token) {
|
|
96
|
+
this.setAuthToken(data.register.token);
|
|
97
|
+
return data.register;
|
|
98
|
+
}
|
|
99
|
+
throw new Error('Registration failed');
|
|
100
|
+
}
|
|
101
|
+
async connectUdpProxy() {
|
|
102
|
+
const data = await this.query(`
|
|
103
|
+
mutation ConnectUdpProxy {
|
|
104
|
+
connectUdpProxy(input: { _placeholder: true }) {
|
|
105
|
+
connected
|
|
106
|
+
serverIp6
|
|
107
|
+
serverClientPort
|
|
108
|
+
lastMessageTime
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
`);
|
|
112
|
+
return data.connectUdpProxy;
|
|
113
|
+
}
|
|
114
|
+
async disconnectUdpProxy() {
|
|
115
|
+
const data = await this.query(`
|
|
116
|
+
mutation DisconnectUdpProxy {
|
|
117
|
+
disconnectUdpProxy
|
|
118
|
+
}
|
|
119
|
+
`);
|
|
120
|
+
return data.disconnectUdpProxy;
|
|
121
|
+
}
|
|
122
|
+
async getConnectionStatus() {
|
|
123
|
+
const data = await this.query(`
|
|
124
|
+
query GetConnectionStatus {
|
|
125
|
+
udpProxyConnectionStatus {
|
|
126
|
+
connected
|
|
127
|
+
serverIp6
|
|
128
|
+
serverClientPort
|
|
129
|
+
lastMessageTime
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
`);
|
|
133
|
+
return data.udpProxyConnectionStatus;
|
|
134
|
+
}
|
|
135
|
+
async sendActorUpdate(input) {
|
|
136
|
+
const normalizedInput = {
|
|
137
|
+
mapId: String(Number(input.mapId)),
|
|
138
|
+
chunk: {
|
|
139
|
+
x: String(Number(input.chunk.x)),
|
|
140
|
+
y: String(Number(input.chunk.y)),
|
|
141
|
+
z: String(Number(input.chunk.z)),
|
|
142
|
+
},
|
|
143
|
+
uuid: String(input.uuid),
|
|
144
|
+
state: String(input.state),
|
|
145
|
+
distance: input.distance ?? 8,
|
|
146
|
+
decayRate: input.decayRate ?? 1,
|
|
147
|
+
...(input.sequenceNumber != null && { sequenceNumber: input.sequenceNumber }),
|
|
148
|
+
};
|
|
149
|
+
const data = await this.query(`
|
|
150
|
+
mutation SendActorUpdate($input: ActorUpdateRequestInput!) {
|
|
151
|
+
sendActorUpdate(input: $input)
|
|
152
|
+
}
|
|
153
|
+
`, { input: normalizedInput });
|
|
154
|
+
return data.sendActorUpdate;
|
|
155
|
+
}
|
|
156
|
+
async sendVoxelUpdate(input) {
|
|
157
|
+
const normalizedInput = {
|
|
158
|
+
mapId: String(Number(input.mapId)),
|
|
159
|
+
chunk: {
|
|
160
|
+
x: String(Number(input.chunk.x)),
|
|
161
|
+
y: String(Number(input.chunk.y)),
|
|
162
|
+
z: String(Number(input.chunk.z)),
|
|
163
|
+
},
|
|
164
|
+
uuid: String(input.uuid),
|
|
165
|
+
voxel: input.voxel,
|
|
166
|
+
voxelType: input.voxelType,
|
|
167
|
+
voxelState: String(input.voxelState),
|
|
168
|
+
distance: input.distance ?? 8,
|
|
169
|
+
decayRate: input.decayRate ?? 0,
|
|
170
|
+
...(input.sequenceNumber != null && { sequenceNumber: input.sequenceNumber }),
|
|
171
|
+
};
|
|
172
|
+
const data = await this.query(`
|
|
173
|
+
mutation SendVoxelUpdate($input: VoxelUpdateRequestInput!) {
|
|
174
|
+
sendVoxelUpdate(input: $input)
|
|
175
|
+
}
|
|
176
|
+
`, { input: normalizedInput });
|
|
177
|
+
return data.sendVoxelUpdate;
|
|
178
|
+
}
|
|
179
|
+
async sendAudioPacket(input) {
|
|
180
|
+
const normalizedInput = {
|
|
181
|
+
mapId: String(Number(input.mapId)),
|
|
182
|
+
chunk: {
|
|
183
|
+
x: String(Number(input.chunk.x)),
|
|
184
|
+
y: String(Number(input.chunk.y)),
|
|
185
|
+
z: String(Number(input.chunk.z)),
|
|
186
|
+
},
|
|
187
|
+
uuid: String(input.uuid),
|
|
188
|
+
audioData: String(input.audioData),
|
|
189
|
+
distance: input.distance ?? 1,
|
|
190
|
+
decayRate: input.decayRate ?? 0,
|
|
191
|
+
...(input.sequenceNumber != null && { sequenceNumber: input.sequenceNumber }),
|
|
192
|
+
};
|
|
193
|
+
const data = await this.query(`
|
|
194
|
+
mutation SendAudioPacket($input: ClientAudioPacketInput!) {
|
|
195
|
+
sendAudioPacket(input: $input)
|
|
196
|
+
}
|
|
197
|
+
`, { input: normalizedInput });
|
|
198
|
+
return data.sendAudioPacket;
|
|
199
|
+
}
|
|
200
|
+
async sendTextPacket(input) {
|
|
201
|
+
const normalizedInput = {
|
|
202
|
+
mapId: String(Number(input.mapId)),
|
|
203
|
+
chunk: {
|
|
204
|
+
x: String(Number(input.chunk.x)),
|
|
205
|
+
y: String(Number(input.chunk.y)),
|
|
206
|
+
z: String(Number(input.chunk.z)),
|
|
207
|
+
},
|
|
208
|
+
uuid: String(input.uuid),
|
|
209
|
+
text: String(input.text),
|
|
210
|
+
distance: input.distance ?? 1,
|
|
211
|
+
decayRate: input.decayRate ?? 0,
|
|
212
|
+
...(input.sequenceNumber != null && { sequenceNumber: input.sequenceNumber }),
|
|
213
|
+
};
|
|
214
|
+
const data = await this.query(`
|
|
215
|
+
mutation SendTextPacket($input: ClientTextPacketInput!) {
|
|
216
|
+
sendTextPacket(input: $input)
|
|
217
|
+
}
|
|
218
|
+
`, { input: normalizedInput });
|
|
219
|
+
return data.sendTextPacket;
|
|
220
|
+
}
|
|
221
|
+
async sendClientEvent(input) {
|
|
222
|
+
const normalizedInput = {
|
|
223
|
+
mapId: String(Number(input.mapId)),
|
|
224
|
+
chunk: {
|
|
225
|
+
x: String(Number(input.chunk.x)),
|
|
226
|
+
y: String(Number(input.chunk.y)),
|
|
227
|
+
z: String(Number(input.chunk.z)),
|
|
228
|
+
},
|
|
229
|
+
uuid: String(input.uuid),
|
|
230
|
+
eventType: input.eventType,
|
|
231
|
+
state: String(input.state),
|
|
232
|
+
distance: input.distance ?? 8,
|
|
233
|
+
decayRate: input.decayRate ?? 0,
|
|
234
|
+
...(input.sequenceNumber != null && { sequenceNumber: input.sequenceNumber }),
|
|
235
|
+
};
|
|
236
|
+
const data = await this.query(`
|
|
237
|
+
mutation SendClientEvent($input: ClientEventNotificationInput!) {
|
|
238
|
+
sendClientEvent(input: $input)
|
|
239
|
+
}
|
|
240
|
+
`, { input: normalizedInput });
|
|
241
|
+
return data.sendClientEvent;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main CrowdyClient class - public API for the SDK
|
|
3
|
+
*/
|
|
4
|
+
import type { CrowdyClientConfig, AuthResponse, UdpProxyConnectionStatus, ActorUpdateRequestInput, VoxelUpdateRequestInput, ClientAudioPacketInput, ClientTextPacketInput, ClientEventNotificationInput, ActorUpdateHandler, ActorUpdateResponseHandler, VoxelUpdateHandler, VoxelUpdateResponseHandler, ClientAudioHandler, ClientTextHandler, ClientEventHandler, ServerEventHandler, GenericErrorHandler, UnsubscribeFn } from './types.js';
|
|
5
|
+
export declare class CrowdyClient {
|
|
6
|
+
private client;
|
|
7
|
+
private subscriptions;
|
|
8
|
+
constructor(config?: CrowdyClientConfig);
|
|
9
|
+
login(email: string, password: string): Promise<AuthResponse>;
|
|
10
|
+
register(email: string, password: string, gamertag?: string): Promise<AuthResponse>;
|
|
11
|
+
getAuthToken(): string | null;
|
|
12
|
+
connectUdpProxy(): Promise<UdpProxyConnectionStatus>;
|
|
13
|
+
disconnectUdpProxy(): Promise<boolean>;
|
|
14
|
+
getConnectionStatus(): Promise<UdpProxyConnectionStatus>;
|
|
15
|
+
sendActorUpdate(input: ActorUpdateRequestInput): Promise<boolean>;
|
|
16
|
+
sendVoxelUpdate(input: VoxelUpdateRequestInput): Promise<boolean>;
|
|
17
|
+
sendAudioPacket(input: ClientAudioPacketInput): Promise<boolean>;
|
|
18
|
+
sendTextPacket(input: ClientTextPacketInput): Promise<boolean>;
|
|
19
|
+
sendClientEvent(input: ClientEventNotificationInput): Promise<boolean>;
|
|
20
|
+
onActorUpdate(handler: ActorUpdateHandler): UnsubscribeFn;
|
|
21
|
+
onActorUpdateResponse(handler: ActorUpdateResponseHandler): UnsubscribeFn;
|
|
22
|
+
onVoxelUpdate(handler: VoxelUpdateHandler): UnsubscribeFn;
|
|
23
|
+
onVoxelUpdateResponse(handler: VoxelUpdateResponseHandler): UnsubscribeFn;
|
|
24
|
+
onClientAudio(handler: ClientAudioHandler): UnsubscribeFn;
|
|
25
|
+
onClientText(handler: ClientTextHandler): UnsubscribeFn;
|
|
26
|
+
onClientEvent(handler: ClientEventHandler): UnsubscribeFn;
|
|
27
|
+
onServerEvent(handler: ServerEventHandler): UnsubscribeFn;
|
|
28
|
+
onGenericError(handler: GenericErrorHandler): UnsubscribeFn;
|
|
29
|
+
close(): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=crowdy-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crowdy-client.d.ts","sourceRoot":"","sources":["../src/crowdy-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,EAC5B,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,aAAa,CAAsB;gBAE/B,MAAM,GAAE,kBAAuB;IAYrC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAM7D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAMzF,YAAY,IAAI,MAAM,GAAG,IAAI;IAKvB,eAAe,IAAI,OAAO,CAAC,wBAAwB,CAAC;IAIpD,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAItC,mBAAmB,IAAI,OAAO,CAAC,wBAAwB,CAAC;IAKxD,eAAe,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAKjE,eAAe,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAKjE,eAAe,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhE,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9D,eAAe,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,OAAO,CAAC;IAK5E,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAIzD,qBAAqB,CAAC,OAAO,EAAE,0BAA0B,GAAG,aAAa;IAIzE,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAIzD,qBAAqB,CAAC,OAAO,EAAE,0BAA0B,GAAG,aAAa;IAIzE,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAIzD,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa;IAIvD,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAIzD,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;IAIzD,cAAc,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa;IAK3D,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main CrowdyClient class - public API for the SDK
|
|
3
|
+
*/
|
|
4
|
+
import { GraphQLClient } from './client.js';
|
|
5
|
+
import { SubscriptionManager } from './subscriptions.js';
|
|
6
|
+
export class CrowdyClient {
|
|
7
|
+
constructor(config = {}) {
|
|
8
|
+
this.client = new GraphQLClient({
|
|
9
|
+
graphqlEndpoint: config.graphqlEndpoint,
|
|
10
|
+
timeout: config.timeout,
|
|
11
|
+
});
|
|
12
|
+
this.subscriptions = new SubscriptionManager({
|
|
13
|
+
wsEndpoint: config.wsEndpoint,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
// Authentication
|
|
17
|
+
async login(email, password) {
|
|
18
|
+
const response = await this.client.login(email, password);
|
|
19
|
+
this.subscriptions.setAuthToken(response.token);
|
|
20
|
+
return response;
|
|
21
|
+
}
|
|
22
|
+
async register(email, password, gamertag) {
|
|
23
|
+
const response = await this.client.register(email, password, gamertag);
|
|
24
|
+
this.subscriptions.setAuthToken(response.token);
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
getAuthToken() {
|
|
28
|
+
return this.client.getAuthToken();
|
|
29
|
+
}
|
|
30
|
+
// UDP Proxy
|
|
31
|
+
async connectUdpProxy() {
|
|
32
|
+
return this.client.connectUdpProxy();
|
|
33
|
+
}
|
|
34
|
+
async disconnectUdpProxy() {
|
|
35
|
+
return this.client.disconnectUdpProxy();
|
|
36
|
+
}
|
|
37
|
+
async getConnectionStatus() {
|
|
38
|
+
return this.client.getConnectionStatus();
|
|
39
|
+
}
|
|
40
|
+
// Actor Updates
|
|
41
|
+
async sendActorUpdate(input) {
|
|
42
|
+
return this.client.sendActorUpdate(input);
|
|
43
|
+
}
|
|
44
|
+
// Voxel Updates
|
|
45
|
+
async sendVoxelUpdate(input) {
|
|
46
|
+
return this.client.sendVoxelUpdate(input);
|
|
47
|
+
}
|
|
48
|
+
// Client Packets
|
|
49
|
+
async sendAudioPacket(input) {
|
|
50
|
+
return this.client.sendAudioPacket(input);
|
|
51
|
+
}
|
|
52
|
+
async sendTextPacket(input) {
|
|
53
|
+
return this.client.sendTextPacket(input);
|
|
54
|
+
}
|
|
55
|
+
async sendClientEvent(input) {
|
|
56
|
+
return this.client.sendClientEvent(input);
|
|
57
|
+
}
|
|
58
|
+
// Type-specific subscription handlers
|
|
59
|
+
onActorUpdate(handler) {
|
|
60
|
+
return this.subscriptions.onActorUpdate(handler);
|
|
61
|
+
}
|
|
62
|
+
onActorUpdateResponse(handler) {
|
|
63
|
+
return this.subscriptions.onActorUpdateResponse(handler);
|
|
64
|
+
}
|
|
65
|
+
onVoxelUpdate(handler) {
|
|
66
|
+
return this.subscriptions.onVoxelUpdate(handler);
|
|
67
|
+
}
|
|
68
|
+
onVoxelUpdateResponse(handler) {
|
|
69
|
+
return this.subscriptions.onVoxelUpdateResponse(handler);
|
|
70
|
+
}
|
|
71
|
+
onClientAudio(handler) {
|
|
72
|
+
return this.subscriptions.onClientAudio(handler);
|
|
73
|
+
}
|
|
74
|
+
onClientText(handler) {
|
|
75
|
+
return this.subscriptions.onClientText(handler);
|
|
76
|
+
}
|
|
77
|
+
onClientEvent(handler) {
|
|
78
|
+
return this.subscriptions.onClientEvent(handler);
|
|
79
|
+
}
|
|
80
|
+
onServerEvent(handler) {
|
|
81
|
+
return this.subscriptions.onServerEvent(handler);
|
|
82
|
+
}
|
|
83
|
+
onGenericError(handler) {
|
|
84
|
+
return this.subscriptions.onGenericError(handler);
|
|
85
|
+
}
|
|
86
|
+
// Cleanup
|
|
87
|
+
close() {
|
|
88
|
+
this.subscriptions.close();
|
|
89
|
+
this.client.setAuthToken(null);
|
|
90
|
+
}
|
|
91
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CrowdyJS SDK - Client SDK for Crowded Kingdoms GraphQL API
|
|
3
|
+
*/
|
|
4
|
+
export { CrowdyClient } from './crowdy-client.js';
|
|
5
|
+
export type { CrowdyClientConfig, BigInt, ChunkCoordinates, ChunkCoordinatesInput, VoxelCoordinates, VoxelCoordinatesInput, UdpErrorCode, User, AuthResponse, UdpProxyConnectionStatus, ActorUpdateRequestInput, VoxelUpdateRequestInput, ClientAudioPacketInput, ClientTextPacketInput, ClientEventNotificationInput, ActorUpdateNotification, ActorUpdateResponse, VoxelUpdateNotification, VoxelUpdateResponse, ClientAudioNotification, ClientTextNotification, ClientEventNotification, ServerEventNotification, GenericErrorResponse, UdpNotification, ActorUpdateHandler, ActorUpdateResponseHandler, VoxelUpdateHandler, VoxelUpdateResponseHandler, ClientAudioHandler, ClientTextHandler, ClientEventHandler, ServerEventHandler, GenericErrorHandler, UnsubscribeFn, } from './types.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAEV,kBAAkB,EAElB,MAAM,EACN,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,wBAAwB,EAExB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,EAE5B,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EAEf,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,GACd,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED