@crowdedkingdomstudios/crowdyjs 1.0.7 → 2.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/README.md +439 -12
- package/dist/auth-state.d.ts +21 -0
- package/dist/auth-state.d.ts.map +1 -0
- package/dist/auth-state.js +30 -0
- package/dist/client.d.ts +27 -21
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +27 -196
- package/dist/crowdy-client.d.ts +44 -24
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +42 -81
- package/dist/domains/actors.d.ts +22 -0
- package/dist/domains/actors.d.ts.map +1 -0
- package/dist/domains/actors.js +42 -0
- package/dist/domains/appAccess.d.ts +23 -0
- package/dist/domains/appAccess.d.ts.map +1 -0
- package/dist/domains/appAccess.js +42 -0
- package/dist/domains/apps.d.ts +27 -0
- package/dist/domains/apps.d.ts.map +1 -0
- package/dist/domains/apps.js +49 -0
- package/dist/domains/auth.d.ts +32 -0
- package/dist/domains/auth.d.ts.map +1 -0
- package/dist/domains/auth.js +70 -0
- package/dist/domains/billing.d.ts +17 -0
- package/dist/domains/billing.d.ts.map +1 -0
- package/dist/domains/billing.js +31 -0
- package/dist/domains/chunks.d.ts +20 -0
- package/dist/domains/chunks.d.ts.map +1 -0
- package/dist/domains/chunks.js +40 -0
- package/dist/domains/organizations.d.ts +33 -0
- package/dist/domains/organizations.d.ts.map +1 -0
- package/dist/domains/organizations.js +90 -0
- package/dist/domains/payments.d.ts +20 -0
- package/dist/domains/payments.d.ts.map +1 -0
- package/dist/domains/payments.js +28 -0
- package/dist/domains/quotas.d.ts +20 -0
- package/dist/domains/quotas.d.ts.map +1 -0
- package/dist/domains/quotas.js +34 -0
- package/dist/domains/serverStatus.d.ts +21 -0
- package/dist/domains/serverStatus.d.ts.map +1 -0
- package/dist/domains/serverStatus.js +32 -0
- package/dist/domains/state.d.ts +16 -0
- package/dist/domains/state.d.ts.map +1 -0
- package/dist/domains/state.js +27 -0
- package/dist/domains/teleport.d.ts +13 -0
- package/dist/domains/teleport.d.ts.map +1 -0
- package/dist/domains/teleport.js +15 -0
- package/dist/domains/udp.d.ts +32 -0
- package/dist/domains/udp.d.ts.map +1 -0
- package/dist/domains/udp.js +55 -0
- package/dist/domains/users.d.ts +24 -0
- package/dist/domains/users.d.ts.map +1 -0
- package/dist/domains/users.js +53 -0
- package/dist/domains/voxels.d.ts +17 -0
- package/dist/domains/voxels.d.ts.map +1 -0
- package/dist/domains/voxels.js +31 -0
- package/dist/generated/graphql.d.ts +3571 -0
- package/dist/generated/graphql.d.ts.map +1 -0
- package/dist/generated/graphql.js +181 -0
- package/dist/index.d.ts +33 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -1
- package/dist/subscriptions.d.ts +36 -18
- package/dist/subscriptions.d.ts.map +1 -1
- package/dist/subscriptions.js +95 -181
- package/dist/types.d.ts +20 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -3
- package/package.json +12 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CrowdyJS SDK - Client SDK for Crowded Kingdoms GraphQL API
|
|
2
|
+
* CrowdyJS SDK - Client SDK for Crowded Kingdoms GraphQL API.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
*
|
|
6
|
+
* import { CrowdyClient } from '@crowdedkingdomstudios/crowdyjs';
|
|
7
|
+
*
|
|
8
|
+
* const client = new CrowdyClient({ graphqlEndpoint, wsEndpoint });
|
|
9
|
+
* const { token } = await client.auth.login({ email, password });
|
|
10
|
+
* const me = await client.users.me();
|
|
11
|
+
* const myOrgs = await client.orgs.myOrganizations();
|
|
12
|
+
* const checkout = await client.payments.createCheckout({ ... });
|
|
13
|
+
* const unsub = client.udp.subscribe({ onActorUpdate: (n) => { ... } });
|
|
3
14
|
*/
|
|
4
15
|
declare const VERSION: string;
|
|
5
16
|
export { VERSION };
|
|
6
|
-
export { CrowdyClient } from './crowdy-client.js';
|
|
7
|
-
export type {
|
|
17
|
+
export { CrowdyClient, type CrowdyClientConfig } from './crowdy-client.js';
|
|
18
|
+
export type { BigInt, ChunkCoordinates, VoxelCoordinates, ActorUpdateNotification, ActorUpdateResponse, VoxelUpdateNotification, VoxelUpdateResponse, ClientAudioNotification, ClientTextNotification, ClientEventNotification, ServerEventNotification, GenericErrorResponse, UdpNotification, ActorUpdateHandler, ActorUpdateResponseHandler, VoxelUpdateHandler, VoxelUpdateResponseHandler, ClientAudioHandler, ClientTextHandler, ClientEventHandler, ServerEventHandler, GenericErrorHandler, UnsubscribeFn, } from './types.js';
|
|
19
|
+
export { UdpErrorCode } from './types.js';
|
|
20
|
+
export type { UdpNotificationHandlers } from './subscriptions.js';
|
|
21
|
+
export { AuthAPI } from './domains/auth.js';
|
|
22
|
+
export { UsersAPI } from './domains/users.js';
|
|
23
|
+
export { OrganizationsAPI } from './domains/organizations.js';
|
|
24
|
+
export { AppsAPI } from './domains/apps.js';
|
|
25
|
+
export { AppAccessAPI } from './domains/appAccess.js';
|
|
26
|
+
export { BillingAPI } from './domains/billing.js';
|
|
27
|
+
export { QuotasAPI } from './domains/quotas.js';
|
|
28
|
+
export { PaymentsAPI } from './domains/payments.js';
|
|
29
|
+
export { ChunksAPI } from './domains/chunks.js';
|
|
30
|
+
export { VoxelsAPI } from './domains/voxels.js';
|
|
31
|
+
export { ActorsAPI } from './domains/actors.js';
|
|
32
|
+
export { TeleportAPI } from './domains/teleport.js';
|
|
33
|
+
export { StateAPI } from './domains/state.js';
|
|
34
|
+
export { ServerStatusAPI } from './domains/serverStatus.js';
|
|
35
|
+
export { UdpAPI } from './domains/udp.js';
|
|
36
|
+
export type { ChunkCoordinatesInput, VoxelCoordinatesInput, ActorUpdateRequestInput, VoxelUpdateRequestInput, ClientAudioPacketInput, ClientTextPacketInput, ClientEventNotificationInput, UdpProxyConnectionStatus, LoginUserInput, RegisterUserInput, ResetPasswordInput, CreateOrganizationInput, CreateOrgTokenInput, UpdateOrgTokenInput, CreateOrgRoleInput, UpdateOrgRoleInput, InviteOrgMemberInput, CreateAppInput, UpdateAppInput, AppMarketplaceFilterInput, CreateAccessTierInput, UpdateAccessTierInput, GrantAppAccessInput, CreateCheckoutInput, CheckoutFilterInput, SetQuotaInput, CreateActorInput, UpdateActorInput, ActorFilterInput, BatchActorLookupInput, CreateUserAppStateInput, UpdateUserStateInput, UpdateAvatarStateInput, UpdateActorStateInput, UpdateGamertagInput, UpdateChunkStateInput, UpdateChunkLodsInput, ChunkUpdateInput, UpdateVoxelInput, RollbackVoxelUpdatesInput, GetChunkInput, GetChunkLodsInput, GetChunksByDistanceInput, GetVoxelListInput, ListVoxelsInput, ListVoxelUpdatesByDistanceInput, TeleportRequestInput, LodDataInput, VoxelStateInput, Organization, OrgMember, OrgRole, OrgToken, OrgPermission, OrgMembership, App, AppsPage, AppAccessTier, AppUserAccess, AppBudget, OrgWallet, WalletTransaction, Checkout, CheckoutsPage, ServiceQuota, Chunk, ChunkLodsResponse, ChunksByDistanceResponse, ChunkVoxelResponse, ChunkVoxelUpdatesResponse, Voxel, VoxelUpdatesByDistanceResponse, VoxelUpdateHistoryEvent, RollbackVoxelEventResult, Actor, Avatar, AvatarDto, TeleportResponse, UserAppState, ServerStatus, GraphQlServer, ServerVersionInfo, VersionInfo, PageInfo, UsersPage, Scalars, } from './generated/graphql.js';
|
|
37
|
+
export { PaymentProvider, CheckoutPurpose, CheckoutStatus, AppVisibility, AppStatus, ServerState, } from './generated/graphql.js';
|
|
8
38
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CrowdyJS SDK - Client SDK for Crowded Kingdoms GraphQL API
|
|
2
|
+
* CrowdyJS SDK - Client SDK for Crowded Kingdoms GraphQL API.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
*
|
|
6
|
+
* import { CrowdyClient } from '@crowdedkingdomstudios/crowdyjs';
|
|
7
|
+
*
|
|
8
|
+
* const client = new CrowdyClient({ graphqlEndpoint, wsEndpoint });
|
|
9
|
+
* const { token } = await client.auth.login({ email, password });
|
|
10
|
+
* const me = await client.users.me();
|
|
11
|
+
* const myOrgs = await client.orgs.myOrganizations();
|
|
12
|
+
* const checkout = await client.payments.createCheckout({ ... });
|
|
13
|
+
* const unsub = client.udp.subscribe({ onActorUpdate: (n) => { ... } });
|
|
3
14
|
*/
|
|
4
15
|
import { createRequire } from 'node:module';
|
|
5
16
|
const require = createRequire(import.meta.url);
|
|
@@ -7,3 +18,25 @@ const { version: VERSION } = require('../package.json');
|
|
|
7
18
|
export { VERSION };
|
|
8
19
|
console.log(`CrowdyJS v${VERSION}`);
|
|
9
20
|
export { CrowdyClient } from './crowdy-client.js';
|
|
21
|
+
export { UdpErrorCode } from './types.js';
|
|
22
|
+
// -----------------------------------------------------------------------------
|
|
23
|
+
// Domain wrappers (exported so consumers can reference the API surface in
|
|
24
|
+
// their own type annotations).
|
|
25
|
+
// -----------------------------------------------------------------------------
|
|
26
|
+
export { AuthAPI } from './domains/auth.js';
|
|
27
|
+
export { UsersAPI } from './domains/users.js';
|
|
28
|
+
export { OrganizationsAPI } from './domains/organizations.js';
|
|
29
|
+
export { AppsAPI } from './domains/apps.js';
|
|
30
|
+
export { AppAccessAPI } from './domains/appAccess.js';
|
|
31
|
+
export { BillingAPI } from './domains/billing.js';
|
|
32
|
+
export { QuotasAPI } from './domains/quotas.js';
|
|
33
|
+
export { PaymentsAPI } from './domains/payments.js';
|
|
34
|
+
export { ChunksAPI } from './domains/chunks.js';
|
|
35
|
+
export { VoxelsAPI } from './domains/voxels.js';
|
|
36
|
+
export { ActorsAPI } from './domains/actors.js';
|
|
37
|
+
export { TeleportAPI } from './domains/teleport.js';
|
|
38
|
+
export { StateAPI } from './domains/state.js';
|
|
39
|
+
export { ServerStatusAPI } from './domains/serverStatus.js';
|
|
40
|
+
export { UdpAPI } from './domains/udp.js';
|
|
41
|
+
// Re-export schema enums as values (so consumers can switch on them).
|
|
42
|
+
export { PaymentProvider, CheckoutPurpose, CheckoutStatus, AppVisibility, AppStatus, ServerState, } from './generated/graphql.js';
|
package/dist/subscriptions.d.ts
CHANGED
|
@@ -1,30 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WebSocket subscription manager
|
|
2
|
+
* WebSocket subscription manager for the udpNotifications stream.
|
|
3
|
+
*
|
|
4
|
+
* Owns one shared `graphql-transport-ws` socket and dispatches incoming
|
|
5
|
+
* `udpNotifications` payloads to per-typename handler arrays. Reads its
|
|
6
|
+
* bearer token from `AuthState` so HTTP and WS auth can never drift.
|
|
7
|
+
*
|
|
8
|
+
* Public API is now `subscribe(handlers)` which returns an unsubscribe
|
|
9
|
+
* function; the per-handler `onActorUpdate` etc. shims are gone.
|
|
3
10
|
*/
|
|
11
|
+
import { AuthState } from './auth-state.js';
|
|
4
12
|
import type { ActorUpdateHandler, ActorUpdateResponseHandler, VoxelUpdateHandler, VoxelUpdateResponseHandler, ClientAudioHandler, ClientTextHandler, ClientEventHandler, ServerEventHandler, GenericErrorHandler, UnsubscribeFn } from './types.js';
|
|
13
|
+
export interface UdpNotificationHandlers {
|
|
14
|
+
onActorUpdate?: ActorUpdateHandler;
|
|
15
|
+
onActorUpdateResponse?: ActorUpdateResponseHandler;
|
|
16
|
+
onVoxelUpdate?: VoxelUpdateHandler;
|
|
17
|
+
onVoxelUpdateResponse?: VoxelUpdateResponseHandler;
|
|
18
|
+
onClientAudio?: ClientAudioHandler;
|
|
19
|
+
onClientText?: ClientTextHandler;
|
|
20
|
+
onClientEvent?: ClientEventHandler;
|
|
21
|
+
onServerEvent?: ServerEventHandler;
|
|
22
|
+
onGenericError?: GenericErrorHandler;
|
|
23
|
+
}
|
|
24
|
+
export interface SubscriptionManagerConfig {
|
|
25
|
+
wsEndpoint?: string;
|
|
26
|
+
}
|
|
5
27
|
export declare class SubscriptionManager {
|
|
6
|
-
private
|
|
28
|
+
private readonly wsEndpoint;
|
|
29
|
+
private readonly authState;
|
|
7
30
|
private wsClient;
|
|
8
31
|
private wsUnsubscribe;
|
|
9
32
|
private subscriptionId;
|
|
10
|
-
private
|
|
11
|
-
private
|
|
12
|
-
constructor(config
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
33
|
+
private subscribers;
|
|
34
|
+
private nextSubscriberId;
|
|
35
|
+
constructor(config: SubscriptionManagerConfig | undefined, authState: AuthState);
|
|
36
|
+
/**
|
|
37
|
+
* Register handlers for the udpNotifications stream. The first call opens
|
|
38
|
+
* the shared socket (provided we have a token); subsequent calls reuse it.
|
|
39
|
+
* The returned function detaches just this set of handlers and closes the
|
|
40
|
+
* socket once the last subscriber leaves.
|
|
41
|
+
*/
|
|
42
|
+
subscribe(handlers: UdpNotificationHandlers): UnsubscribeFn;
|
|
16
43
|
private ensureSubscription;
|
|
17
44
|
private startSubscription;
|
|
18
|
-
private
|
|
19
|
-
onActorUpdate(handler: ActorUpdateHandler): UnsubscribeFn;
|
|
20
|
-
onActorUpdateResponse(handler: ActorUpdateResponseHandler): UnsubscribeFn;
|
|
21
|
-
onVoxelUpdate(handler: VoxelUpdateHandler): UnsubscribeFn;
|
|
22
|
-
onVoxelUpdateResponse(handler: VoxelUpdateResponseHandler): UnsubscribeFn;
|
|
23
|
-
onClientAudio(handler: ClientAudioHandler): UnsubscribeFn;
|
|
24
|
-
onClientText(handler: ClientTextHandler): UnsubscribeFn;
|
|
25
|
-
onClientEvent(handler: ClientEventHandler): UnsubscribeFn;
|
|
26
|
-
onServerEvent(handler: ServerEventHandler): UnsubscribeFn;
|
|
27
|
-
onGenericError(handler: GenericErrorHandler): UnsubscribeFn;
|
|
45
|
+
private dispatch;
|
|
28
46
|
private checkIfShouldUnsubscribe;
|
|
29
47
|
close(): void;
|
|
30
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,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;AAEpB,MAAM,WAAW,uBAAuB;IACtC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,qBAAqB,CAAC,EAAE,0BAA0B,CAAC;IACnD,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,qBAAqB,CAAC,EAAE,0BAA0B,CAAC;IACnD,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,cAAc,CAAC,EAAE,mBAAmB,CAAC;CACtC;AAOD,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,WAAW,CAA6C;IAChE,OAAO,CAAC,gBAAgB,CAAK;gBAEjB,MAAM,EAAE,yBAAyB,YAAK,EAAE,SAAS,EAAE,SAAS;IAKxE;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,uBAAuB,GAAG,aAAa;IAU3D,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,iBAAiB;IAsFzB,OAAO,CAAC,QAAQ;IA6ChB,OAAO,CAAC,wBAAwB;IAOhC,KAAK,IAAI,IAAI;CAMd"}
|
package/dist/subscriptions.js
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WebSocket subscription manager
|
|
2
|
+
* WebSocket subscription manager for the udpNotifications stream.
|
|
3
|
+
*
|
|
4
|
+
* Owns one shared `graphql-transport-ws` socket and dispatches incoming
|
|
5
|
+
* `udpNotifications` payloads to per-typename handler arrays. Reads its
|
|
6
|
+
* bearer token from `AuthState` so HTTP and WS auth can never drift.
|
|
7
|
+
*
|
|
8
|
+
* Public API is now `subscribe(handlers)` which returns an unsubscribe
|
|
9
|
+
* function; the per-handler `onActorUpdate` etc. shims are gone.
|
|
3
10
|
*/
|
|
4
11
|
export class SubscriptionManager {
|
|
5
|
-
constructor(config = {}) {
|
|
6
|
-
this.handlers = {
|
|
7
|
-
ActorUpdateNotification: [],
|
|
8
|
-
ActorUpdateResponse: [],
|
|
9
|
-
VoxelUpdateNotification: [],
|
|
10
|
-
VoxelUpdateResponse: [],
|
|
11
|
-
ClientAudioNotification: [],
|
|
12
|
-
ClientTextNotification: [],
|
|
13
|
-
ClientEventNotification: [],
|
|
14
|
-
ServerEventNotification: [],
|
|
15
|
-
GenericErrorResponse: [],
|
|
16
|
-
};
|
|
12
|
+
constructor(config = {}, authState) {
|
|
17
13
|
this.wsClient = null;
|
|
18
14
|
this.wsUnsubscribe = null;
|
|
19
15
|
this.subscriptionId = null;
|
|
20
|
-
this.
|
|
16
|
+
this.subscribers = new Map();
|
|
17
|
+
this.nextSubscriberId = 1;
|
|
21
18
|
this.wsEndpoint = config.wsEndpoint || 'ws://localhost:3000/graphql';
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
this.authState = authState;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register handlers for the udpNotifications stream. The first call opens
|
|
23
|
+
* the shared socket (provided we have a token); subsequent calls reuse it.
|
|
24
|
+
* The returned function detaches just this set of handlers and closes the
|
|
25
|
+
* socket once the last subscriber leaves.
|
|
26
|
+
*/
|
|
27
|
+
subscribe(handlers) {
|
|
28
|
+
const id = `s${this.nextSubscriberId++}`;
|
|
29
|
+
this.subscribers.set(id, { id, handlers });
|
|
30
|
+
this.ensureSubscription();
|
|
31
|
+
return () => {
|
|
32
|
+
this.subscribers.delete(id);
|
|
33
|
+
this.checkIfShouldUnsubscribe();
|
|
34
|
+
};
|
|
25
35
|
}
|
|
26
36
|
ensureSubscription() {
|
|
27
37
|
if (!this.wsClient ||
|
|
@@ -31,23 +41,18 @@ export class SubscriptionManager {
|
|
|
31
41
|
}
|
|
32
42
|
}
|
|
33
43
|
startSubscription() {
|
|
34
|
-
|
|
44
|
+
const token = this.authState.getToken();
|
|
45
|
+
if (!token) {
|
|
35
46
|
throw new Error('Must be authenticated to subscribe');
|
|
36
47
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.wsClient.readyState === WebSocket.CONNECTING)) {
|
|
40
|
-
return; // Already connected or connecting
|
|
41
|
-
}
|
|
42
|
-
const wsUrl = this.wsEndpoint;
|
|
43
|
-
this.subscriptionId = 'udp-notifications-' + Date.now();
|
|
44
|
-
const ws = new WebSocket(wsUrl, 'graphql-transport-ws');
|
|
48
|
+
this.subscriptionId = `udp-notifications-${Date.now()}`;
|
|
49
|
+
const ws = new WebSocket(this.wsEndpoint, 'graphql-transport-ws');
|
|
45
50
|
this.wsClient = ws;
|
|
46
51
|
ws.onopen = () => {
|
|
47
52
|
ws.send(JSON.stringify({
|
|
48
53
|
type: 'connection_init',
|
|
49
54
|
payload: {
|
|
50
|
-
Authorization: `Bearer ${
|
|
55
|
+
Authorization: `Bearer ${token}`,
|
|
51
56
|
},
|
|
52
57
|
}));
|
|
53
58
|
};
|
|
@@ -55,55 +60,30 @@ export class SubscriptionManager {
|
|
|
55
60
|
try {
|
|
56
61
|
const message = JSON.parse(typeof event.data === 'string' ? event.data : '');
|
|
57
62
|
if (message.type === 'connection_ack') {
|
|
58
|
-
|
|
63
|
+
ws.send(JSON.stringify({
|
|
59
64
|
id: this.subscriptionId,
|
|
60
65
|
type: 'subscribe',
|
|
61
|
-
payload: {
|
|
62
|
-
|
|
63
|
-
udpNotifications {
|
|
64
|
-
__typename
|
|
65
|
-
... on ActorUpdateNotification { mapId chunkX chunkY chunkZ distance decayRate uuid state sequenceNumber epochMillis }
|
|
66
|
-
... on VoxelUpdateNotification { mapId chunkX chunkY chunkZ distance decayRate uuid voxelX voxelY voxelZ voxelType voxelState sequenceNumber epochMillis }
|
|
67
|
-
... on GenericErrorResponse { sequenceNumber errorCode }
|
|
68
|
-
... on ActorUpdateResponse { mapId chunkX chunkY chunkZ distance decayRate uuid sequenceNumber epochMillis }
|
|
69
|
-
... on VoxelUpdateResponse { mapId chunkX chunkY chunkZ distance decayRate uuid sequenceNumber epochMillis }
|
|
70
|
-
... on ClientAudioNotification { mapId chunkX chunkY chunkZ distance decayRate uuid audioData sequenceNumber epochMillis }
|
|
71
|
-
... on ClientTextNotification { mapId chunkX chunkY chunkZ distance decayRate uuid text sequenceNumber epochMillis }
|
|
72
|
-
... on ClientEventNotification { mapId chunkX chunkY chunkZ distance decayRate uuid eventType state sequenceNumber epochMillis }
|
|
73
|
-
... on ServerEventNotification { mapId chunkX chunkY chunkZ distance decayRate uuid eventType state sequenceNumber epochMillis }
|
|
74
|
-
}
|
|
75
|
-
}`,
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
ws.send(JSON.stringify(subscribeMessage));
|
|
66
|
+
payload: { query: UDP_NOTIFICATIONS_QUERY },
|
|
67
|
+
}));
|
|
79
68
|
}
|
|
80
69
|
else if (message.type === 'next') {
|
|
81
|
-
if (message.payload?.data?.udpNotifications === null)
|
|
70
|
+
if (message.payload?.data?.udpNotifications === null)
|
|
82
71
|
return;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
this.
|
|
72
|
+
const notification = message.payload?.data
|
|
73
|
+
?.udpNotifications;
|
|
74
|
+
if (notification) {
|
|
75
|
+
this.dispatch(notification);
|
|
87
76
|
}
|
|
88
77
|
else if (message.payload?.errors) {
|
|
89
78
|
console.error('Subscription errors:', message.payload.errors);
|
|
90
|
-
const firstError = message.payload.errors[0];
|
|
91
|
-
const errorMsg = firstError?.message
|
|
92
|
-
? Array.isArray(firstError.message)
|
|
93
|
-
? firstError.message.join(', ')
|
|
94
|
-
: String(firstError.message)
|
|
95
|
-
: firstError?.extensions?.message || 'Unknown subscription error';
|
|
96
|
-
console.error('Subscription error:', errorMsg);
|
|
97
79
|
}
|
|
98
80
|
}
|
|
99
81
|
else if (message.type === 'error') {
|
|
100
82
|
console.error('Subscription error:', message.payload);
|
|
101
83
|
}
|
|
102
84
|
else if (message.type === 'complete') {
|
|
103
|
-
|
|
104
|
-
if (this.wsClient === ws) {
|
|
85
|
+
if (this.wsClient === ws)
|
|
105
86
|
this.wsClient = null;
|
|
106
|
-
}
|
|
107
87
|
}
|
|
108
88
|
else if (message.type === 'ping') {
|
|
109
89
|
ws.send(JSON.stringify({ type: 'pong' }));
|
|
@@ -120,9 +100,8 @@ export class SubscriptionManager {
|
|
|
120
100
|
if (event.code !== 1000) {
|
|
121
101
|
console.warn(`WebSocket closed unexpectedly: ${event.reason || event.code}`);
|
|
122
102
|
}
|
|
123
|
-
if (this.wsClient === ws)
|
|
103
|
+
if (this.wsClient === ws)
|
|
124
104
|
this.wsClient = null;
|
|
125
|
-
}
|
|
126
105
|
};
|
|
127
106
|
this.wsUnsubscribe = () => {
|
|
128
107
|
if (ws.readyState === WebSocket.OPEN) {
|
|
@@ -134,145 +113,80 @@ export class SubscriptionManager {
|
|
|
134
113
|
}
|
|
135
114
|
ws.close();
|
|
136
115
|
}
|
|
137
|
-
if (this.wsClient === ws)
|
|
116
|
+
if (this.wsClient === ws)
|
|
138
117
|
this.wsClient = null;
|
|
139
|
-
}
|
|
140
118
|
this.wsUnsubscribe = null;
|
|
141
119
|
};
|
|
142
120
|
}
|
|
143
|
-
|
|
121
|
+
dispatch(notification) {
|
|
144
122
|
const type = notification.__typename;
|
|
145
123
|
if (!type) {
|
|
146
124
|
console.warn('Received notification without __typename:', notification);
|
|
147
125
|
return;
|
|
148
126
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
127
|
+
// Snapshot the subscribers list so handlers that mutate the registry
|
|
128
|
+
// (e.g. by calling close()) don't affect this dispatch loop.
|
|
129
|
+
for (const sub of [...this.subscribers.values()]) {
|
|
130
|
+
try {
|
|
131
|
+
switch (type) {
|
|
132
|
+
case 'ActorUpdateNotification':
|
|
133
|
+
sub.handlers.onActorUpdate?.(notification);
|
|
134
|
+
break;
|
|
135
|
+
case 'ActorUpdateResponse':
|
|
136
|
+
sub.handlers.onActorUpdateResponse?.(notification);
|
|
137
|
+
break;
|
|
138
|
+
case 'VoxelUpdateNotification':
|
|
139
|
+
sub.handlers.onVoxelUpdate?.(notification);
|
|
140
|
+
break;
|
|
141
|
+
case 'VoxelUpdateResponse':
|
|
142
|
+
sub.handlers.onVoxelUpdateResponse?.(notification);
|
|
143
|
+
break;
|
|
144
|
+
case 'ClientAudioNotification':
|
|
145
|
+
sub.handlers.onClientAudio?.(notification);
|
|
146
|
+
break;
|
|
147
|
+
case 'ClientTextNotification':
|
|
148
|
+
sub.handlers.onClientText?.(notification);
|
|
149
|
+
break;
|
|
150
|
+
case 'ClientEventNotification':
|
|
151
|
+
sub.handlers.onClientEvent?.(notification);
|
|
152
|
+
break;
|
|
153
|
+
case 'ServerEventNotification':
|
|
154
|
+
sub.handlers.onServerEvent?.(notification);
|
|
155
|
+
break;
|
|
156
|
+
case 'GenericErrorResponse':
|
|
157
|
+
sub.handlers.onGenericError?.(notification);
|
|
158
|
+
break;
|
|
157
159
|
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
onActorUpdate(handler) {
|
|
162
|
-
this.handlers.ActorUpdateNotification.push(handler);
|
|
163
|
-
this.ensureSubscription();
|
|
164
|
-
return () => {
|
|
165
|
-
const index = this.handlers.ActorUpdateNotification.indexOf(handler);
|
|
166
|
-
if (index > -1) {
|
|
167
|
-
this.handlers.ActorUpdateNotification.splice(index, 1);
|
|
168
|
-
}
|
|
169
|
-
this.checkIfShouldUnsubscribe();
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
onActorUpdateResponse(handler) {
|
|
173
|
-
this.handlers.ActorUpdateResponse.push(handler);
|
|
174
|
-
this.ensureSubscription();
|
|
175
|
-
return () => {
|
|
176
|
-
const index = this.handlers.ActorUpdateResponse.indexOf(handler);
|
|
177
|
-
if (index > -1) {
|
|
178
|
-
this.handlers.ActorUpdateResponse.splice(index, 1);
|
|
179
|
-
}
|
|
180
|
-
this.checkIfShouldUnsubscribe();
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
onVoxelUpdate(handler) {
|
|
184
|
-
this.handlers.VoxelUpdateNotification.push(handler);
|
|
185
|
-
this.ensureSubscription();
|
|
186
|
-
return () => {
|
|
187
|
-
const index = this.handlers.VoxelUpdateNotification.indexOf(handler);
|
|
188
|
-
if (index > -1) {
|
|
189
|
-
this.handlers.VoxelUpdateNotification.splice(index, 1);
|
|
190
160
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
onVoxelUpdateResponse(handler) {
|
|
195
|
-
this.handlers.VoxelUpdateResponse.push(handler);
|
|
196
|
-
this.ensureSubscription();
|
|
197
|
-
return () => {
|
|
198
|
-
const index = this.handlers.VoxelUpdateResponse.indexOf(handler);
|
|
199
|
-
if (index > -1) {
|
|
200
|
-
this.handlers.VoxelUpdateResponse.splice(index, 1);
|
|
201
|
-
}
|
|
202
|
-
this.checkIfShouldUnsubscribe();
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
onClientAudio(handler) {
|
|
206
|
-
this.handlers.ClientAudioNotification.push(handler);
|
|
207
|
-
this.ensureSubscription();
|
|
208
|
-
return () => {
|
|
209
|
-
const index = this.handlers.ClientAudioNotification.indexOf(handler);
|
|
210
|
-
if (index > -1) {
|
|
211
|
-
this.handlers.ClientAudioNotification.splice(index, 1);
|
|
212
|
-
}
|
|
213
|
-
this.checkIfShouldUnsubscribe();
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
onClientText(handler) {
|
|
217
|
-
this.handlers.ClientTextNotification.push(handler);
|
|
218
|
-
this.ensureSubscription();
|
|
219
|
-
return () => {
|
|
220
|
-
const index = this.handlers.ClientTextNotification.indexOf(handler);
|
|
221
|
-
if (index > -1) {
|
|
222
|
-
this.handlers.ClientTextNotification.splice(index, 1);
|
|
223
|
-
}
|
|
224
|
-
this.checkIfShouldUnsubscribe();
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
onClientEvent(handler) {
|
|
228
|
-
this.handlers.ClientEventNotification.push(handler);
|
|
229
|
-
this.ensureSubscription();
|
|
230
|
-
return () => {
|
|
231
|
-
const index = this.handlers.ClientEventNotification.indexOf(handler);
|
|
232
|
-
if (index > -1) {
|
|
233
|
-
this.handlers.ClientEventNotification.splice(index, 1);
|
|
234
|
-
}
|
|
235
|
-
this.checkIfShouldUnsubscribe();
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
onServerEvent(handler) {
|
|
239
|
-
this.handlers.ServerEventNotification.push(handler);
|
|
240
|
-
this.ensureSubscription();
|
|
241
|
-
return () => {
|
|
242
|
-
const index = this.handlers.ServerEventNotification.indexOf(handler);
|
|
243
|
-
if (index > -1) {
|
|
244
|
-
this.handlers.ServerEventNotification.splice(index, 1);
|
|
245
|
-
}
|
|
246
|
-
this.checkIfShouldUnsubscribe();
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
onGenericError(handler) {
|
|
250
|
-
this.handlers.GenericErrorResponse.push(handler);
|
|
251
|
-
this.ensureSubscription();
|
|
252
|
-
return () => {
|
|
253
|
-
const index = this.handlers.GenericErrorResponse.indexOf(handler);
|
|
254
|
-
if (index > -1) {
|
|
255
|
-
this.handlers.GenericErrorResponse.splice(index, 1);
|
|
161
|
+
catch (error) {
|
|
162
|
+
console.error(`Handler for ${type} threw:`, error);
|
|
256
163
|
}
|
|
257
|
-
|
|
258
|
-
};
|
|
164
|
+
}
|
|
259
165
|
}
|
|
260
166
|
checkIfShouldUnsubscribe() {
|
|
261
|
-
|
|
262
|
-
const hasHandlers = Object.values(this.handlers).some((handlers) => handlers.length > 0);
|
|
263
|
-
if (!hasHandlers && this.wsUnsubscribe) {
|
|
167
|
+
if (this.subscribers.size === 0 && this.wsUnsubscribe) {
|
|
264
168
|
this.wsUnsubscribe();
|
|
265
169
|
this.wsUnsubscribe = null;
|
|
266
170
|
}
|
|
267
171
|
}
|
|
268
172
|
close() {
|
|
269
|
-
|
|
270
|
-
Object.keys(this.handlers).forEach((key) => {
|
|
271
|
-
this.handlers[key] = [];
|
|
272
|
-
});
|
|
273
|
-
// Close WebSocket if open
|
|
173
|
+
this.subscribers.clear();
|
|
274
174
|
if (this.wsUnsubscribe) {
|
|
275
175
|
this.wsUnsubscribe();
|
|
276
176
|
}
|
|
277
177
|
}
|
|
278
178
|
}
|
|
179
|
+
const UDP_NOTIFICATIONS_QUERY = `subscription {
|
|
180
|
+
udpNotifications {
|
|
181
|
+
__typename
|
|
182
|
+
... on ActorUpdateNotification { appId chunkX chunkY chunkZ distance decayRate uuid state sequenceNumber epochMillis }
|
|
183
|
+
... on VoxelUpdateNotification { appId chunkX chunkY chunkZ distance decayRate uuid voxelX voxelY voxelZ voxelType voxelState sequenceNumber epochMillis }
|
|
184
|
+
... on GenericErrorResponse { sequenceNumber errorCode }
|
|
185
|
+
... on ActorUpdateResponse { appId chunkX chunkY chunkZ distance decayRate uuid sequenceNumber epochMillis }
|
|
186
|
+
... on VoxelUpdateResponse { appId chunkX chunkY chunkZ distance decayRate uuid sequenceNumber epochMillis }
|
|
187
|
+
... on ClientAudioNotification { appId chunkX chunkY chunkZ distance decayRate uuid audioData sequenceNumber epochMillis }
|
|
188
|
+
... on ClientTextNotification { appId chunkX chunkY chunkZ distance decayRate uuid text sequenceNumber epochMillis }
|
|
189
|
+
... on ClientEventNotification { appId chunkX chunkY chunkZ distance decayRate uuid eventType state sequenceNumber epochMillis }
|
|
190
|
+
... on ServerEventNotification { appId chunkX chunkY chunkZ distance decayRate uuid eventType state sequenceNumber epochMillis }
|
|
191
|
+
}
|
|
192
|
+
}`;
|