@dcl/sdk 7.20.2-22169778016.commit-030cbfe → 7.20.2-22231111352.commit-d2f6f0a

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 (63) hide show
  1. package/network/binary-message-bus.d.ts +3 -6
  2. package/network/binary-message-bus.js +5 -9
  3. package/network/index.d.ts +2 -8
  4. package/network/index.js +3 -16
  5. package/network/message-bus-sync.d.ts +1 -14
  6. package/network/message-bus-sync.js +103 -166
  7. package/network/state.js +5 -3
  8. package/package.json +6 -6
  9. package/src/network/binary-message-bus.ts +4 -9
  10. package/src/network/index.ts +3 -40
  11. package/src/network/message-bus-sync.ts +110 -180
  12. package/src/network/state.ts +4 -3
  13. package/atom.d.ts +0 -19
  14. package/atom.js +0 -83
  15. package/future.d.ts +0 -8
  16. package/future.js +0 -26
  17. package/network/chunking.d.ts +0 -5
  18. package/network/chunking.js +0 -38
  19. package/network/events/implementation.d.ts +0 -93
  20. package/network/events/implementation.js +0 -230
  21. package/network/events/index.d.ts +0 -42
  22. package/network/events/index.js +0 -43
  23. package/network/events/protocol.d.ts +0 -27
  24. package/network/events/protocol.js +0 -66
  25. package/network/events/registry.d.ts +0 -8
  26. package/network/events/registry.js +0 -3
  27. package/network/server/index.d.ts +0 -14
  28. package/network/server/index.js +0 -219
  29. package/network/server/utils.d.ts +0 -18
  30. package/network/server/utils.js +0 -135
  31. package/server/env-var.d.ts +0 -15
  32. package/server/env-var.js +0 -31
  33. package/server/index.d.ts +0 -2
  34. package/server/index.js +0 -3
  35. package/server/storage/constants.d.ts +0 -23
  36. package/server/storage/constants.js +0 -2
  37. package/server/storage/index.d.ts +0 -22
  38. package/server/storage/index.js +0 -29
  39. package/server/storage/player.d.ts +0 -43
  40. package/server/storage/player.js +0 -92
  41. package/server/storage/scene.d.ts +0 -38
  42. package/server/storage/scene.js +0 -90
  43. package/server/storage-url.d.ts +0 -10
  44. package/server/storage-url.js +0 -29
  45. package/server/utils.d.ts +0 -35
  46. package/server/utils.js +0 -56
  47. package/src/atom.ts +0 -98
  48. package/src/future.ts +0 -38
  49. package/src/network/chunking.ts +0 -45
  50. package/src/network/events/implementation.ts +0 -286
  51. package/src/network/events/index.ts +0 -48
  52. package/src/network/events/protocol.ts +0 -94
  53. package/src/network/events/registry.ts +0 -18
  54. package/src/network/server/index.ts +0 -301
  55. package/src/network/server/utils.ts +0 -189
  56. package/src/server/env-var.ts +0 -36
  57. package/src/server/index.ts +0 -2
  58. package/src/server/storage/constants.ts +0 -22
  59. package/src/server/storage/index.ts +0 -44
  60. package/src/server/storage/player.ts +0 -156
  61. package/src/server/storage/scene.ts +0 -149
  62. package/src/server/storage-url.ts +0 -34
  63. package/src/server/utils.ts +0 -73
package/src/future.ts DELETED
@@ -1,38 +0,0 @@
1
- export type IFuture<T> = Promise<T> & {
2
- resolve: (x: T) => void
3
- reject: (x: Error) => void
4
- finally: (fn: () => void) => void
5
- isPending: boolean
6
- }
7
-
8
- export function future<T = any>(): IFuture<T> {
9
- let resolver: (x: T) => void
10
- let rejecter: (x: Error) => void
11
-
12
- const promise: any = new Promise((ok, err) => {
13
- resolver = (x: T) => {
14
- ok(x)
15
- promise.isPending = false
16
- }
17
- rejecter = (x: Error) => {
18
- err(x)
19
- promise.isPending = false
20
- }
21
- }).catch((e) => Promise.reject(e))
22
-
23
- promise.resolve = resolver!
24
- promise.reject = rejecter!
25
-
26
- if (!('finally' in promise)) {
27
- promise.finally = (fn: any) => {
28
- promise.then(fn)
29
- promise.catch(fn)
30
- }
31
- }
32
-
33
- promise.isPending = true
34
-
35
- return promise as IFuture<T>
36
- }
37
-
38
- export default future
@@ -1,45 +0,0 @@
1
- import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer'
2
- import { readMessages } from './server/utils'
3
-
4
- /**
5
- * Chunks CRDT messages from a Uint8Array buffer, respecting message boundaries
6
- * Uses the comprehensive readMessages function that handles all message types
7
- */
8
- export function chunkCrdtMessages(data: Uint8Array, maxSizeKB: number = 12): Uint8Array[] {
9
- if (data.length === 0) {
10
- return []
11
- }
12
-
13
- const networkBuffer = new ReadWriteByteBuffer()
14
- const chunks: Uint8Array[] = []
15
-
16
- for (const message of readMessages(data)) {
17
- // Check if adding this message would exceed the size limit
18
- const currentBufferSize = networkBuffer.toBinary().byteLength
19
- const messageSize = message.messageBuffer.byteLength
20
-
21
- if ((currentBufferSize + messageSize) / 1024 > maxSizeKB) {
22
- // If the current buffer has content, save it as a chunk
23
- if (currentBufferSize > 0) {
24
- chunks.push(networkBuffer.toCopiedBinary())
25
- networkBuffer.resetBuffer()
26
- }
27
-
28
- // If the message itself is larger than the limit, skip it
29
- if (messageSize / 1024 > maxSizeKB) {
30
- console.error(`Message too large (${messageSize} bytes), skipping CRDT message`)
31
- continue
32
- }
33
- }
34
-
35
- // Add message to current buffer
36
- networkBuffer.writeBuffer(message.messageBuffer, false)
37
- }
38
-
39
- // Add any remaining data as the final chunk
40
- if (networkBuffer.currentWriteOffset() > 0) {
41
- chunks.push(networkBuffer.toBinary())
42
- }
43
-
44
- return chunks
45
- }
@@ -1,286 +0,0 @@
1
- import { IEngine } from '@dcl/ecs'
2
- import { CommsMessage } from '../binary-message-bus'
3
- import { AUTH_SERVER_PEER_ID } from '../message-bus-sync'
4
- import { EventTypes, EventSchemaRegistry } from './registry'
5
- import { encodeEvent, decodeEvent } from './protocol'
6
- import { Atom } from '../../atom'
7
- import { future, IFuture } from '../../future'
8
-
9
- // Context provided to server-side event handlers
10
- export type EventContext = {
11
- from: string
12
- }
13
-
14
- // Event callback type - server gets context, client doesn't
15
- export type EventCallback<T> = (data: T, context?: EventContext) => void
16
-
17
- // Options for sending events
18
- export type SendOptions = {
19
- to?: string[] // Target specific peers (server only)
20
- }
21
-
22
- /**
23
- * Room provides type-safe communication between clients and server
24
- * Uses binary serialization with Schema definitions for efficiency
25
- */
26
- type QueuedMessage<T extends EventSchemaRegistry = EventSchemaRegistry> = {
27
- [K in keyof T]: {
28
- eventType: K
29
- data: EventTypes<T>[K]
30
- options?: SendOptions
31
- }
32
- }[keyof T]
33
-
34
- export class Room<T extends EventSchemaRegistry = EventSchemaRegistry> {
35
- private listeners = new Map<keyof T, Set<EventCallback<any>>>()
36
- private binaryMessageBus: any
37
- private isServerFuture: IFuture<boolean> = future()
38
- private isRoomReadyAtom: Atom<boolean>
39
- private messageQueue: QueuedMessage<T>[] = []
40
- private isProcessingQueue = false
41
-
42
- constructor(_engine: IEngine, binaryMessageBus: any, isServerFn: Atom<boolean>, isRoomReadyAtom: Atom<boolean>) {
43
- void isServerFn.deref().then(($) => this.isServerFuture.resolve($))
44
-
45
- this.binaryMessageBus = binaryMessageBus
46
- this.isRoomReadyAtom = isRoomReadyAtom
47
-
48
- // Subscribe to room readiness changes to flush queue
49
- this.isRoomReadyAtom.observable.add((isReady) => {
50
- if (isReady && this.messageQueue.length > 0) {
51
- void this.flushMessageQueue()
52
- }
53
- })
54
- // Listen for CUSTOM_EVENT messages
55
- binaryMessageBus.on(CommsMessage.CUSTOM_EVENT, (data: Uint8Array, sender: string) => {
56
- try {
57
- const { eventType, payload } = decodeEvent(data, globalEventRegistry)
58
- const callbacks = this.listeners.get(eventType)
59
-
60
- if (callbacks) {
61
- callbacks.forEach(async (cb) => {
62
- if (await this.isServerFuture) {
63
- // Server handlers receive sender context
64
- cb(payload, { from: sender })
65
- } else if (sender === AUTH_SERVER_PEER_ID) {
66
- // Client only processes events from authoritative server
67
- cb(payload)
68
- }
69
- })
70
- }
71
- } catch (error) {
72
- console.error('[EventBus] Failed to decode event:', error)
73
- }
74
- })
75
- }
76
-
77
- /**
78
- * Flush queued messages when room becomes ready
79
- */
80
- private async flushMessageQueue(): Promise<void> {
81
- if (this.isProcessingQueue || this.messageQueue.length === 0) return
82
-
83
- this.isProcessingQueue = true
84
-
85
- // Copy and clear the queue to avoid mutation during iteration
86
- const messages = [...this.messageQueue]
87
- this.messageQueue.length = 0
88
-
89
- // Re-send all queued messages
90
- for (const message of messages) {
91
- await this.send(message.eventType, message.data, message.options)
92
- }
93
-
94
- this.isProcessingQueue = false
95
- }
96
-
97
- /**
98
- * Send an event
99
- * @param eventType - The type of event from the registry
100
- * @param data - The event data matching the schema
101
- * @param options - Optional send options (server only)
102
- *
103
- * Messages are automatically queued if the room is not ready and sent once connected.
104
- */
105
- async send<K extends keyof T>(eventType: K, data: EventTypes<T>[K], options?: SendOptions): Promise<void> {
106
- try {
107
- const isRoomReady = this.isRoomReadyAtom.getOrNull() ?? false
108
-
109
- // If room is not ready, queue the message with original params
110
- if (!isRoomReady) {
111
- this.messageQueue.push({
112
- eventType,
113
- data,
114
- options
115
- })
116
- return
117
- }
118
-
119
- // Room is ready, send immediately
120
- const buffer = encodeEvent(eventType as string, data, globalEventRegistry)
121
-
122
- if (await this.isServerFuture) {
123
- // Server can send to specific clients or broadcast
124
- this.binaryMessageBus.emit(CommsMessage.CUSTOM_EVENT, buffer, options?.to)
125
- } else {
126
- // Client always sends to authoritative server
127
- this.binaryMessageBus.emit(CommsMessage.CUSTOM_EVENT, buffer)
128
- }
129
- } catch (error) {
130
- console.error(`[EventBus] Failed to send event '${String(eventType)}':`, error)
131
- }
132
- }
133
-
134
- /**
135
- * Listen for an event
136
- * @param eventType - The type of event to listen for
137
- * @param callback - Callback to handle the event
138
- * @returns Unsubscribe function
139
- */
140
- onMessage<K extends keyof T>(eventType: K, callback: EventCallback<EventTypes<T>[K]>): () => void {
141
- if (!this.listeners.has(eventType)) {
142
- this.listeners.set(eventType, new Set())
143
- }
144
-
145
- const callbacks = this.listeners.get(eventType)!
146
- callbacks.add(callback)
147
-
148
- // Return unsubscribe function
149
- return () => {
150
- callbacks.delete(callback)
151
- if (callbacks.size === 0) {
152
- this.listeners.delete(eventType)
153
- }
154
- }
155
- }
156
-
157
- /**
158
- * Remove all listeners for a specific event type
159
- * @param eventType - The type of event to clear listeners for
160
- */
161
- clear<K extends keyof T>(eventType?: K): void {
162
- if (eventType) {
163
- this.listeners.delete(eventType)
164
- } else {
165
- this.listeners.clear()
166
- }
167
- }
168
-
169
- /**
170
- * Get the number of listeners for an event type
171
- * @param eventType - The type of event to check
172
- * @returns Number of registered listeners
173
- */
174
- listenerCount<K extends keyof T>(eventType: K): number {
175
- return this.listeners.get(eventType)?.size ?? 0
176
- }
177
-
178
- /**
179
- * Check if the room is ready to send messages
180
- * @returns true if messages will be sent immediately, false if they will be queued
181
- */
182
- isReady(): boolean {
183
- return this.isRoomReadyAtom.getOrNull() ?? false
184
- }
185
-
186
- /**
187
- * Subscribe to room readiness changes
188
- * @param callback - Called when room becomes ready or disconnected
189
- * @returns Unsubscribe function
190
- *
191
- * @example
192
- * ```ts
193
- * const unsubscribe = room.onReady((isReady) => {
194
- * if (isReady) {
195
- * console.log('Room connected!')
196
- * } else {
197
- * console.log('Room disconnected')
198
- * }
199
- * })
200
- *
201
- * // Later: unsubscribe()
202
- * ```
203
- */
204
- onReady(callback: (isReady: boolean) => void): () => void {
205
- const observer = this.isRoomReadyAtom.observable.add((isReady) => {
206
- callback(isReady)
207
- })
208
-
209
- return () => {
210
- if (observer) {
211
- this.isRoomReadyAtom.observable.remove(observer)
212
- }
213
- }
214
- }
215
- }
216
-
217
- // Global registry for user-defined events
218
- const globalEventRegistry: EventSchemaRegistry = {}
219
-
220
- /**
221
- * Get the global event registry (internal use)
222
- * @internal
223
- */
224
- export function getEventRegistry(): EventSchemaRegistry {
225
- return globalEventRegistry
226
- }
227
-
228
- // Global room instance (created by addSyncTransport)
229
- let globalRoom: Room | null = null
230
-
231
- /**
232
- * Set the global room instance (internal use)
233
- * @internal
234
- */
235
- export function setGlobalRoom(roomInstance: Room): void {
236
- globalRoom = roomInstance
237
- }
238
-
239
- /**
240
- * Register message schemas for use with the room
241
- * Call this before main() to define your custom messages
242
- * @param messages - Object containing your message schemas
243
- * @returns Typed room instance for your registered messages
244
- */
245
- export function registerMessages<T extends EventSchemaRegistry>(messages: T): Room<T> {
246
- Object.assign(globalEventRegistry, messages)
247
- if (!globalRoom) {
248
- throw new Error('Room not initialized. Make sure the SDK network transport is initialized.')
249
- }
250
- // Update the room registry
251
- ;(globalRoom as any).registry = globalEventRegistry
252
- return globalRoom as unknown as Room<T>
253
- }
254
-
255
- /**
256
- * Get a typed version of the global room
257
- * Use this when you want the room with your specific message types
258
- *
259
- * @example
260
- * ```typescript
261
- * const MyMessages = { ... }
262
- * registerMessages(MyMessages) // Register first
263
- * const room = getRoom<typeof MyMessages>() // Then get typed version
264
- * ```
265
- */
266
- export function getRoom<T extends EventSchemaRegistry>(): Room<T> {
267
- if (!globalRoom) {
268
- throw new Error('Room not initialized. Make sure the SDK network transport is initialized.')
269
- }
270
- return globalRoom as unknown as Room<T>
271
- }
272
-
273
- /**
274
- * Create a typed room with custom message schemas (internal use)
275
- * @param registry - Your custom message schema registry
276
- * @returns Room instance with your custom types
277
- * @internal
278
- */
279
- export function createRoom<T extends EventSchemaRegistry>(
280
- engine: IEngine,
281
- binaryMessageBus: any,
282
- isServerFn: Atom<boolean>,
283
- isRoomReadyAtom: Atom<boolean>
284
- ): Room<T> {
285
- return new Room(engine, binaryMessageBus, isServerFn, isRoomReadyAtom)
286
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * Room - Multiplayer messaging for SDK7
3
- *
4
- * Simple room-based communication system for multiplayer scenes.
5
- *
6
- * @example Basic usage:
7
- * ```typescript
8
- * import { registerMessages, getRoom, isServer } from '@dcl/sdk/network/events'
9
- *
10
- * const MyMessages = {
11
- * playerJump: Schemas.Map({ playerId: Schemas.String, position: Schemas.Vector3 }),
12
- * gameUpdate: Schemas.Map({ message: Schemas.String })
13
- * }
14
- *
15
- * // Option 1: Register and get typed room
16
- * const room = registerMessages(MyMessages)
17
- *
18
- * // Option 2: Register first, then get typed room
19
- * // registerMessages(MyMessages)
20
- * // const room = getRoom<typeof MyMessages>()
21
- *
22
- * export function main() {
23
- * if (isServer()) {
24
- * room.onMessage('playerJump', (data, context) => {
25
- * console.log(`Player ${context?.from} jumped`)
26
- * room.send('gameUpdate', { message: 'Player jumped!' })
27
- * })
28
- * } else {
29
- * room.send('playerJump', { playerId: 'me', position: { x: 1, y: 2, z: 3 } })
30
- * room.onMessage('gameUpdate', (data) => {
31
- * console.log('Server says:', data.message)
32
- * })
33
- * }
34
- * }
35
- * ```
36
- *
37
- * @packageDocumentation
38
- */
39
-
40
- // Import public API and types
41
- import { registerMessages, getRoom, EventContext } from './implementation'
42
- import { EventSchemaRegistry } from './registry'
43
-
44
- // Re-export public API - only what users need
45
- export { registerMessages, getRoom }
46
-
47
- // Re-export types that users need
48
- export type { EventContext, EventSchemaRegistry }
@@ -1,94 +0,0 @@
1
- import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer'
2
- import { Schemas } from '@dcl/ecs'
3
- import { EventSchemas, EventTypes, EventSchemaRegistry } from './registry'
4
-
5
- // Event envelope that wraps all events with metadata
6
- const EventEnvelope = Schemas.Map({
7
- eventType: Schemas.String,
8
- timestamp: Schemas.Int64
9
- })
10
-
11
- /**
12
- * Encode an event into a binary buffer
13
- * @param eventType - The type of event from the registry
14
- * @param data - The event data matching the schema
15
- * @param registry - Optional custom registry (defaults to EventSchemas)
16
- * @returns Binary buffer containing the encoded event
17
- */
18
- export function encodeEvent<T extends EventSchemaRegistry = typeof EventSchemas, K extends keyof T = keyof T>(
19
- eventType: K,
20
- data: EventTypes<T>[K],
21
- registry: T = EventSchemas as T
22
- ): Uint8Array {
23
- const buffer = new ReadWriteByteBuffer()
24
-
25
- // Write envelope with event type and timestamp
26
- EventEnvelope.serialize(
27
- {
28
- eventType: eventType as string,
29
- timestamp: Date.now()
30
- },
31
- buffer
32
- )
33
-
34
- // Get the schema for this event type
35
- const schema = registry[eventType]
36
- if (!schema) {
37
- throw new Error(`Unknown event type: ${String(eventType)}`)
38
- }
39
-
40
- // Write the typed payload
41
- schema.serialize(data, buffer)
42
-
43
- return buffer.toBinary()
44
- }
45
-
46
- /**
47
- * Decode a binary buffer into an event
48
- * @param data - Binary buffer containing the encoded event
49
- * @param registry - Optional custom registry (defaults to EventSchemas)
50
- * @returns Decoded event with type, payload, and timestamp
51
- */
52
- export function decodeEvent<T extends EventSchemaRegistry = typeof EventSchemas>(
53
- data: Uint8Array,
54
- registry: T = EventSchemas as T
55
- ): {
56
- eventType: keyof T
57
- payload: EventTypes<T>[keyof T]
58
- timestamp: number
59
- } {
60
- const buffer = new ReadWriteByteBuffer()
61
- buffer.writeBuffer(data, false)
62
-
63
- // Read envelope
64
- const envelope = EventEnvelope.deserialize(buffer)
65
- const eventType = envelope.eventType as keyof T
66
-
67
- // Get the schema for this event type
68
- const schema = registry[eventType]
69
- if (!schema) {
70
- throw new Error(`Unknown event type: ${String(eventType)}`)
71
- }
72
-
73
- // Read the typed payload
74
- const payload = schema.deserialize(buffer)
75
-
76
- return {
77
- eventType,
78
- payload,
79
- timestamp: envelope.timestamp
80
- }
81
- }
82
-
83
- /**
84
- * Validate if an event type exists in the registry
85
- * @param eventType - The event type to check
86
- * @param registry - Optional custom registry (defaults to EventSchemas)
87
- * @returns True if the event type exists
88
- */
89
- export function isValidEventType<T extends EventSchemaRegistry = typeof EventSchemas>(
90
- eventType: string,
91
- registry: T = EventSchemas as T
92
- ): eventType is Extract<keyof T, string> {
93
- return eventType in registry
94
- }
@@ -1,18 +0,0 @@
1
- import { ISchema } from '@dcl/ecs'
2
-
3
- // Base type for event schema registry
4
- export type EventSchemaRegistry = Record<string, ISchema>
5
-
6
- // Type extraction from schemas
7
- export type EventTypes<T extends EventSchemaRegistry = EventSchemaRegistry> = {
8
- [K in keyof T]: T[K] extends ISchema<infer U> ? U : never
9
- }
10
-
11
- // Global interface that users can augment with their own events
12
- export type RegisteredEvents = EventSchemaRegistry
13
-
14
- // Default empty registry
15
- export const EventSchemas = {} as RegisteredEvents
16
-
17
- // Helper to ensure user events conform to the registry type
18
- export type ValidateEventRegistry<T extends EventSchemaRegistry> = T