connectbase-client 0.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 ADDED
@@ -0,0 +1,565 @@
1
+ # @connect-base/client
2
+
3
+ Connect Base JavaScript/TypeScript SDK for building real-time multiplayer games and applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @connect-base/client
9
+ # or
10
+ pnpm add @connect-base/client
11
+ # or
12
+ yarn add @connect-base/client
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { ConnectBase } from '@connect-base/client'
19
+
20
+ // Initialize the SDK
21
+ const cb = new ConnectBase({
22
+ apiKey: 'your-api-key'
23
+ })
24
+
25
+ // Create a game room client
26
+ const gameClient = cb.game.createClient({
27
+ clientId: 'player-123'
28
+ })
29
+
30
+ // Set up event handlers
31
+ gameClient
32
+ .on('onConnect', () => console.log('Connected!'))
33
+ .on('onStateUpdate', (state) => console.log('State:', state))
34
+ .on('onPlayerJoined', (player) => console.log('Player joined:', player))
35
+ .on('onPlayerLeft', (player) => console.log('Player left:', player))
36
+
37
+ // Connect and create a room
38
+ await gameClient.connect()
39
+ const state = await gameClient.createRoom({
40
+ maxPlayers: 4,
41
+ tickRate: 64
42
+ })
43
+ ```
44
+
45
+ ## Features
46
+
47
+ - **Real-time Game Server**: WebSocket-based multiplayer game state synchronization
48
+ - **Authentication**: OAuth2, email/password, and social login support
49
+ - **Database**: JSON-based NoSQL database with real-time queries
50
+ - **Storage**: File storage with CDN support
51
+ - **Push Notifications**: Cross-platform push notification support
52
+ - **WebRTC**: Real-time audio/video communication
53
+ - **Payments**: Subscription and one-time payment support
54
+
55
+ ## API Reference
56
+
57
+ ### Game Server
58
+
59
+ #### GameRoom
60
+
61
+ The main class for real-time game communication.
62
+
63
+ ```typescript
64
+ const gameClient = cb.game.createClient({
65
+ clientId: 'unique-player-id', // Required: Unique identifier for this player
66
+ gameServerUrl: 'wss://...', // Optional: Custom game server URL
67
+ autoReconnect: true, // Optional: Auto-reconnect on disconnect (default: true)
68
+ maxReconnectAttempts: 5, // Optional: Max reconnect attempts (default: 5)
69
+ reconnectInterval: 1000, // Optional: Base reconnect interval in ms (default: 1000)
70
+ connectionTimeout: 10000, // Optional: Connection timeout in ms (default: 10000)
71
+ })
72
+ ```
73
+
74
+ ##### Properties
75
+
76
+ | Property | Type | Description |
77
+ |----------|------|-------------|
78
+ | `roomId` | `string \| null` | Current room ID |
79
+ | `state` | `GameState \| null` | Current game state |
80
+ | `isConnected` | `boolean` | Connection status |
81
+ | `isOfflineMode` | `boolean` | Offline mode status |
82
+ | `latency` | `number` | Current latency in ms |
83
+ | `connectionState` | `ConnectionState` | Detailed connection state |
84
+
85
+ ##### Methods
86
+
87
+ **connect(roomId?: string): Promise\<void>**
88
+
89
+ Connect to the game server. Optionally specify a room ID to join immediately.
90
+
91
+ ```typescript
92
+ await gameClient.connect()
93
+ // or
94
+ await gameClient.connect('existing-room-id')
95
+ ```
96
+
97
+ **disconnect(): void**
98
+
99
+ Disconnect from the game server.
100
+
101
+ ```typescript
102
+ gameClient.disconnect()
103
+ ```
104
+
105
+ **createRoom(config?: GameRoomConfig): Promise\<GameState>**
106
+
107
+ Create a new game room.
108
+
109
+ ```typescript
110
+ const state = await gameClient.createRoom({
111
+ roomId: 'my-custom-room', // Optional: Custom room ID
112
+ categoryId: 'battle-royale', // Optional: Room category
113
+ maxPlayers: 100, // Optional: Max players (default: 10)
114
+ tickRate: 64, // Optional: Server tick rate (default: 64)
115
+ metadata: { map: 'forest' } // Optional: Custom metadata
116
+ })
117
+ ```
118
+
119
+ **joinRoom(roomId: string, metadata?: Record\<string, string>): Promise\<GameState>**
120
+
121
+ Join an existing room.
122
+
123
+ ```typescript
124
+ const state = await gameClient.joinRoom('room-id', {
125
+ team: 'blue',
126
+ displayName: 'Player1'
127
+ })
128
+ ```
129
+
130
+ **leaveRoom(): Promise\<void>**
131
+
132
+ Leave the current room.
133
+
134
+ ```typescript
135
+ await gameClient.leaveRoom()
136
+ ```
137
+
138
+ **sendAction(action: GameAction): void**
139
+
140
+ Send a game action to the server.
141
+
142
+ ```typescript
143
+ gameClient.sendAction({
144
+ type: 'move',
145
+ data: { x: 100, y: 200 }
146
+ })
147
+
148
+ gameClient.sendAction({
149
+ type: 'attack',
150
+ data: { targetId: 'enemy-1', damage: 50 }
151
+ })
152
+ ```
153
+
154
+ **sendChat(message: string): void**
155
+
156
+ Send a chat message to the room.
157
+
158
+ ```typescript
159
+ gameClient.sendChat('Hello everyone!')
160
+ ```
161
+
162
+ **requestState(): Promise\<GameState>**
163
+
164
+ Request the full current state from the server.
165
+
166
+ ```typescript
167
+ const state = await gameClient.requestState()
168
+ ```
169
+
170
+ **listRooms(): Promise\<GameRoomInfo[]>**
171
+
172
+ List all available rooms.
173
+
174
+ ```typescript
175
+ const rooms = await gameClient.listRooms()
176
+ rooms.forEach(room => {
177
+ console.log(`${room.id}: ${room.playerCount}/${room.maxPlayers}`)
178
+ })
179
+ ```
180
+
181
+ **ping(): Promise\<number>**
182
+
183
+ Measure round-trip time to the server.
184
+
185
+ ```typescript
186
+ const rtt = await gameClient.ping()
187
+ console.log(`Latency: ${rtt}ms`)
188
+ ```
189
+
190
+ ##### Event Handlers
191
+
192
+ ```typescript
193
+ gameClient
194
+ .on('onConnect', () => {
195
+ // Called when connected to the server
196
+ })
197
+ .on('onDisconnect', (event: CloseEvent) => {
198
+ // Called when disconnected
199
+ })
200
+ .on('onStateUpdate', (state: GameState) => {
201
+ // Called when full state is received
202
+ })
203
+ .on('onDelta', (delta: GameDelta) => {
204
+ // Called for incremental state updates
205
+ // Use this for efficient state synchronization
206
+ })
207
+ .on('onPlayerJoined', (player: GamePlayer) => {
208
+ // Called when a player joins the room
209
+ })
210
+ .on('onPlayerLeft', (player: GamePlayer) => {
211
+ // Called when a player leaves the room
212
+ })
213
+ .on('onChat', (message: ChatMessage) => {
214
+ // Called when a chat message is received
215
+ })
216
+ .on('onError', (error: ErrorMessage) => {
217
+ // Called on errors
218
+ })
219
+ .on('onPong', (pong: PongMessage) => {
220
+ // Called when pong is received
221
+ })
222
+ ```
223
+
224
+ #### Offline Mode
225
+
226
+ Test your game logic locally without a server connection.
227
+
228
+ ```typescript
229
+ // Enable offline mode
230
+ gameClient.enableOfflineMode({
231
+ tickRate: 64,
232
+ initialState: {
233
+ players: {},
234
+ objects: []
235
+ },
236
+ simulatedPlayers: [
237
+ { clientId: 'bot-1', joinedAt: Date.now(), metadata: { isBot: 'true' } }
238
+ ]
239
+ })
240
+
241
+ // Update state directly
242
+ gameClient.setOfflineState('players.player-1.position', { x: 100, y: 200 })
243
+
244
+ // Add/remove simulated players
245
+ gameClient.addSimulatedPlayer({
246
+ clientId: 'bot-2',
247
+ joinedAt: Date.now(),
248
+ metadata: {}
249
+ })
250
+ gameClient.removeSimulatedPlayer('bot-2')
251
+
252
+ // Disable offline mode
253
+ gameClient.disableOfflineMode()
254
+ ```
255
+
256
+ ### Authentication
257
+
258
+ ```typescript
259
+ // Email/Password login
260
+ const session = await cb.auth.signIn({
261
+ email: 'user@example.com',
262
+ password: 'password123'
263
+ })
264
+
265
+ // OAuth login
266
+ const oauthUrl = await cb.oauth.getGoogleAuthUrl()
267
+ // Redirect user to oauthUrl
268
+
269
+ // Get current user
270
+ const user = await cb.auth.getCurrentUser()
271
+
272
+ // Sign out
273
+ await cb.auth.signOut()
274
+ ```
275
+
276
+ ### Database
277
+
278
+ ```typescript
279
+ // Query data
280
+ const { data } = await cb.database.from('users').select().where({ active: true }).limit(10)
281
+
282
+ // Insert data
283
+ await cb.database.from('users').insert({
284
+ name: 'John',
285
+ email: 'john@example.com'
286
+ })
287
+
288
+ // Update data
289
+ await cb.database.from('users').update({ active: false }).where({ id: 'user-1' })
290
+
291
+ // Delete data
292
+ await cb.database.from('users').delete().where({ id: 'user-1' })
293
+ ```
294
+
295
+ ### Storage
296
+
297
+ ```typescript
298
+ // Upload file
299
+ const { url } = await cb.storage.upload('avatars/user-1.png', file)
300
+
301
+ // Download file
302
+ const data = await cb.storage.download('avatars/user-1.png')
303
+
304
+ // Delete file
305
+ await cb.storage.delete('avatars/user-1.png')
306
+
307
+ // List files
308
+ const files = await cb.storage.list('avatars/')
309
+ ```
310
+
311
+ ### Realtime
312
+
313
+ ```typescript
314
+ // Subscribe to a channel
315
+ const channel = cb.realtime.channel('chat-room-1')
316
+
317
+ channel.on('message', (data) => {
318
+ console.log('New message:', data)
319
+ })
320
+
321
+ await channel.subscribe()
322
+
323
+ // Publish message
324
+ channel.publish('message', { text: 'Hello!' })
325
+
326
+ // Unsubscribe
327
+ await channel.unsubscribe()
328
+ ```
329
+
330
+ ### Push Notifications
331
+
332
+ ```typescript
333
+ // Register for push notifications
334
+ await cb.push.register({
335
+ token: 'fcm-token-or-apns-token',
336
+ platform: 'android' // or 'ios', 'web'
337
+ })
338
+
339
+ // Subscribe to topics
340
+ await cb.push.subscribeToTopic('news')
341
+
342
+ // Unsubscribe from topic
343
+ await cb.push.unsubscribeFromTopic('news')
344
+ ```
345
+
346
+ ### WebRTC
347
+
348
+ ```typescript
349
+ // Create a broadcast
350
+ const broadcast = cb.webrtc.createBroadcast({
351
+ roomId: 'live-stream-1'
352
+ })
353
+
354
+ await broadcast.start()
355
+
356
+ // Join as viewer
357
+ const viewer = cb.webrtc.createViewer({
358
+ roomId: 'live-stream-1'
359
+ })
360
+
361
+ viewer.on('stream', (stream) => {
362
+ videoElement.srcObject = stream
363
+ })
364
+
365
+ await viewer.join()
366
+ ```
367
+
368
+ ### Payments & Subscriptions
369
+
370
+ ```typescript
371
+ // Create a subscription
372
+ const subscription = await cb.subscription.create({
373
+ planId: 'premium-monthly',
374
+ billingKeyId: 'billing-key-1'
375
+ })
376
+
377
+ // Check subscription status
378
+ const status = await cb.subscription.getStatus()
379
+
380
+ // Cancel subscription
381
+ await cb.subscription.cancel()
382
+ ```
383
+
384
+ ## Types
385
+
386
+ ### GameState
387
+
388
+ ```typescript
389
+ interface GameState {
390
+ roomId: string
391
+ state: Record<string, unknown> // Your game state
392
+ version: number
393
+ serverTime: number
394
+ tickRate: number
395
+ players: GamePlayer[]
396
+ }
397
+ ```
398
+
399
+ ### GameDelta
400
+
401
+ ```typescript
402
+ interface GameDelta {
403
+ fromVersion: number
404
+ toVersion: number
405
+ changes: Array<{
406
+ path: string
407
+ operation: 'set' | 'delete'
408
+ value?: unknown
409
+ }>
410
+ tick: number
411
+ }
412
+ ```
413
+
414
+ ### GamePlayer
415
+
416
+ ```typescript
417
+ interface GamePlayer {
418
+ clientId: string
419
+ joinedAt: number
420
+ metadata?: Record<string, string>
421
+ }
422
+ ```
423
+
424
+ ### ConnectionState
425
+
426
+ ```typescript
427
+ interface ConnectionState {
428
+ status: 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error' | 'offline'
429
+ reconnectAttempt: number
430
+ lastError?: Error
431
+ latency: number
432
+ }
433
+ ```
434
+
435
+ ## Error Handling
436
+
437
+ ```typescript
438
+ try {
439
+ await gameClient.connect()
440
+ } catch (error) {
441
+ if (error instanceof Error) {
442
+ console.error('Connection failed:', error.message)
443
+ }
444
+ }
445
+
446
+ // Or use event handlers
447
+ gameClient.on('onError', (error) => {
448
+ console.error('Game error:', error.message)
449
+ })
450
+ ```
451
+
452
+ ## Best Practices
453
+
454
+ ### State Synchronization
455
+
456
+ Use delta updates for efficient state synchronization:
457
+
458
+ ```typescript
459
+ gameClient.on('onDelta', (delta) => {
460
+ // Apply only the changes instead of replacing entire state
461
+ for (const change of delta.changes) {
462
+ applyChange(localState, change.path, change.operation, change.value)
463
+ }
464
+ })
465
+ ```
466
+
467
+ ### Reconnection Handling
468
+
469
+ ```typescript
470
+ gameClient.on('onDisconnect', (event) => {
471
+ if (event.code !== 1000) {
472
+ // Show reconnecting UI
473
+ showReconnectingMessage()
474
+ }
475
+ })
476
+
477
+ gameClient.on('onConnect', () => {
478
+ // Reconnected - request full state
479
+ gameClient.requestState()
480
+ hideReconnectingMessage()
481
+ })
482
+ ```
483
+
484
+ ### Latency Compensation
485
+
486
+ ```typescript
487
+ // Measure latency periodically
488
+ setInterval(async () => {
489
+ const rtt = await gameClient.ping()
490
+ // Adjust client-side prediction based on latency
491
+ updatePredictionOffset(rtt / 2)
492
+ }, 5000)
493
+ ```
494
+
495
+ ## Examples
496
+
497
+ ### Simple Multiplayer Game
498
+
499
+ ```typescript
500
+ import { ConnectBase } from '@connect-base/client'
501
+
502
+ const cb = new ConnectBase({ apiKey: 'your-api-key' })
503
+ const game = cb.game.createClient({ clientId: `player-${Date.now()}` })
504
+
505
+ // Local player state
506
+ let localPlayer = { x: 0, y: 0 }
507
+
508
+ game
509
+ .on('onConnect', () => console.log('Connected'))
510
+ .on('onStateUpdate', (state) => {
511
+ // Render all players
512
+ renderPlayers(state.state.players)
513
+ })
514
+ .on('onDelta', (delta) => {
515
+ // Efficient incremental updates
516
+ for (const change of delta.changes) {
517
+ updatePlayer(change.path, change.value)
518
+ }
519
+ })
520
+
521
+ // Connect and create room
522
+ await game.connect()
523
+ await game.createRoom({ maxPlayers: 8 })
524
+
525
+ // Game loop
526
+ function gameLoop() {
527
+ // Read input
528
+ const input = getPlayerInput()
529
+
530
+ // Send action
531
+ if (input.moved) {
532
+ game.sendAction({
533
+ type: 'move',
534
+ data: { x: input.x, y: input.y }
535
+ })
536
+ }
537
+
538
+ requestAnimationFrame(gameLoop)
539
+ }
540
+
541
+ gameLoop()
542
+ ```
543
+
544
+ ### Chat Application
545
+
546
+ ```typescript
547
+ const game = cb.game.createClient({ clientId: userId })
548
+
549
+ game.on('onChat', (message) => {
550
+ displayMessage(message.senderId, message.message, message.timestamp)
551
+ })
552
+
553
+ await game.connect()
554
+ await game.joinRoom('general-chat')
555
+
556
+ // Send message
557
+ chatInput.addEventListener('submit', () => {
558
+ game.sendChat(chatInput.value)
559
+ chatInput.value = ''
560
+ })
561
+ ```
562
+
563
+ ## License
564
+
565
+ MIT