@edge-base/web 0.1.1

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 (51) hide show
  1. package/README.md +352 -0
  2. package/dist/analytics.d.ts +60 -0
  3. package/dist/analytics.d.ts.map +1 -0
  4. package/dist/analytics.js +146 -0
  5. package/dist/analytics.js.map +1 -0
  6. package/dist/auth-refresh.d.ts +5 -0
  7. package/dist/auth-refresh.d.ts.map +1 -0
  8. package/dist/auth-refresh.js +26 -0
  9. package/dist/auth-refresh.js.map +1 -0
  10. package/dist/auth.d.ts +314 -0
  11. package/dist/auth.d.ts.map +1 -0
  12. package/dist/auth.js +518 -0
  13. package/dist/auth.js.map +1 -0
  14. package/dist/browser-storage.d.ts +7 -0
  15. package/dist/browser-storage.d.ts.map +1 -0
  16. package/dist/browser-storage.js +43 -0
  17. package/dist/browser-storage.js.map +1 -0
  18. package/dist/client.d.ts +145 -0
  19. package/dist/client.d.ts.map +1 -0
  20. package/dist/client.js +310 -0
  21. package/dist/client.js.map +1 -0
  22. package/dist/database-live.d.ts +65 -0
  23. package/dist/database-live.d.ts.map +1 -0
  24. package/dist/database-live.js +486 -0
  25. package/dist/database-live.js.map +1 -0
  26. package/dist/index.d.ts +21 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +28 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/match-filter.d.ts +30 -0
  31. package/dist/match-filter.d.ts.map +1 -0
  32. package/dist/match-filter.js +86 -0
  33. package/dist/match-filter.js.map +1 -0
  34. package/dist/room-realtime-media.d.ts +96 -0
  35. package/dist/room-realtime-media.d.ts.map +1 -0
  36. package/dist/room-realtime-media.js +418 -0
  37. package/dist/room-realtime-media.js.map +1 -0
  38. package/dist/room.d.ts +450 -0
  39. package/dist/room.d.ts.map +1 -0
  40. package/dist/room.js +1506 -0
  41. package/dist/room.js.map +1 -0
  42. package/dist/token-manager.d.ts +73 -0
  43. package/dist/token-manager.d.ts.map +1 -0
  44. package/dist/token-manager.js +378 -0
  45. package/dist/token-manager.js.map +1 -0
  46. package/dist/turnstile.d.ts +56 -0
  47. package/dist/turnstile.d.ts.map +1 -0
  48. package/dist/turnstile.js +191 -0
  49. package/dist/turnstile.js.map +1 -0
  50. package/llms.txt +549 -0
  51. package/package.json +50 -0
package/llms.txt ADDED
@@ -0,0 +1,549 @@
1
+ # EdgeBase JS Web SDK
2
+
3
+ Use this file as a quick-reference contract for AI coding assistants working with `@edge-base/web`.
4
+
5
+ ## Package Boundary
6
+
7
+ Use `@edge-base/web` for browser and untrusted client environments.
8
+
9
+ Do not use this package for privileged server-side work that needs admin access, raw SQL, or trusted secrets. Use `@edge-base/admin` for that. Use `@edge-base/ssr` when you specifically need SSR cookie helpers.
10
+
11
+ ## Source Of Truth
12
+
13
+ - Package README: https://github.com/edge-base/edgebase/blob/main/packages/sdk/js/packages/web/README.md
14
+ - Quickstart: https://edgebase.fun/docs/getting-started/quickstart
15
+ - Client SDK docs: https://edgebase.fun/docs/database/client-sdk
16
+ - Database subscriptions: https://edgebase.fun/docs/database/subscriptions
17
+ - Authentication: https://edgebase.fun/docs/authentication
18
+ - Room client SDK: https://edgebase.fun/docs/room/client-sdk
19
+ - Functions client SDK: https://edgebase.fun/docs/functions/client-sdk
20
+
21
+ If code examples, docs, and assumptions disagree, prefer the current package API and official docs over guessed patterns.
22
+
23
+ Async methods below are shown with their real `Promise<...>` return types. In example code, `await` them unless the method is explicitly synchronous.
24
+
25
+ ## Recommended Project Layout
26
+
27
+ If adding EdgeBase to an existing frontend project, a good default is:
28
+
29
+ ```text
30
+ your-frontend-project/
31
+ package.json
32
+ src/
33
+ edgebase/
34
+ edgebase.config.ts
35
+ functions/
36
+ package.json
37
+ ```
38
+
39
+ Typical setup:
40
+
41
+ ```bash
42
+ cd your-frontend-project
43
+ npm create edge-base@latest edgebase
44
+ ```
45
+
46
+ This is a recommendation, not a requirement. Separate repos or a different subdirectory name are also valid.
47
+
48
+ ## Canonical Examples
49
+
50
+ ### Create a client
51
+
52
+ ```ts
53
+ import { createClient } from '@edge-base/web';
54
+
55
+ const client = createClient('https://your-project.edgebase.fun');
56
+ ```
57
+
58
+ ### Sign in and react to auth changes
59
+
60
+ ```ts
61
+ await client.auth.signIn({
62
+ email: 'june@example.com',
63
+ password: 'pass1234',
64
+ });
65
+
66
+ const user = client.auth.currentUser;
67
+
68
+ const unsubscribeAuth = client.auth.onAuthStateChange((nextUser) => {
69
+ console.log('auth changed:', nextUser);
70
+ });
71
+ ```
72
+
73
+ ### Query data from a single-instance block
74
+
75
+ ```ts
76
+ type Post = {
77
+ id: string;
78
+ title: string;
79
+ published: boolean;
80
+ };
81
+
82
+ const posts = await client
83
+ .db('app')
84
+ .table<Post>('posts')
85
+ .where('published', '==', true)
86
+ .orderBy('title', 'asc')
87
+ .limit(20)
88
+ .getList();
89
+ ```
90
+
91
+ ### Query data from an instance database
92
+
93
+ ```ts
94
+ const docs = await client
95
+ .db('workspace', 'ws-1')
96
+ .table('docs')
97
+ .getList();
98
+ ```
99
+
100
+ ### Subscribe to live updates
101
+
102
+ ```ts
103
+ const unsubscribe = client
104
+ .db('app')
105
+ .table('posts')
106
+ .onSnapshot((change) => {
107
+ console.log(change.changeType, change.data);
108
+ });
109
+ ```
110
+
111
+ ### Upload a file and create a signed URL
112
+
113
+ ```ts
114
+ const bucket = client.storage.bucket('avatars');
115
+
116
+ await bucket.upload('me.jpg', file);
117
+
118
+ const signedUrl = await bucket.createSignedUrl('me.jpg', {
119
+ expiresIn: '1h',
120
+ });
121
+ ```
122
+
123
+ ### Call a function
124
+
125
+ ```ts
126
+ const result = await client.functions.post('contact/send', {
127
+ email: 'june@example.com',
128
+ message: 'Hello from the browser',
129
+ });
130
+ ```
131
+
132
+ ### Join a room
133
+
134
+ ```ts
135
+ const room = client.room('game', 'lobby-1');
136
+
137
+ await room.join();
138
+
139
+ room.leave();
140
+ ```
141
+
142
+ ### Update special fields
143
+
144
+ ```ts
145
+ import { deleteField, increment } from '@edge-base/web';
146
+
147
+ await client
148
+ .db('app')
149
+ .table('posts')
150
+ .update('post-1', {
151
+ views: increment(1),
152
+ temporaryField: deleteField(),
153
+ });
154
+ ```
155
+
156
+ ## Common Mistakes
157
+
158
+ - `client.auth.currentUser` is a property, not a method
159
+ - `client.auth.onAuthStateChange()` callback receives `(user)`, not `(event, user)`
160
+ - `client.db(namespace, id?)` uses a positional instance id, not a named object
161
+ - database block names like `app`, `shared`, and `workspace` are examples, not reserved keywords
162
+ - `table.get()` returns a list result, not a single document
163
+ - `table.getOne(id)` or `table.doc(id).get()` returns a single document
164
+ - write operations require an authenticated user
165
+ - `requestPasswordReset()` takes the email as the first positional argument
166
+ - `changePassword()` expects `currentPassword`, not `oldPassword`
167
+ - `createSignedUrl()` expects `expiresIn` as a string like `'1h'`, not a number
168
+ - batch updates and deletes are chained from filters, for example `table.where(...).updateMany(...)`
169
+
170
+ ## Quick Reference
171
+
172
+ ```js
173
+ // Initialize
174
+ import { createClient } from '@edge-base/web'
175
+ const client = createClient('https://my-project.edgebase.fun')
176
+
177
+ // Auth — currentUser is a PROPERTY, not a method
178
+ const user = client.auth.currentUser // TokenUser | null
179
+
180
+ // Auth state — callback receives (user), NOT (event, user)
181
+ const unsub = client.auth.onAuthStateChange((user) => { /* user or null */ })
182
+
183
+ // Sign up with profile data
184
+ await client.auth.signUp({ email: 'a@b.com', password: 'pass123', data: { displayName: 'June' } })
185
+
186
+ // Password reset — positional args, NOT object
187
+ await client.auth.requestPasswordReset('user@test.com')
188
+ await client.auth.resetPassword(token, 'newPass123')
189
+
190
+ // Change password — field is currentPassword, NOT oldPassword
191
+ await client.auth.changePassword({ currentPassword: 'old', newPassword: 'new' })
192
+
193
+ // DB access — instanceId is positional, NOT named
194
+ const posts = client.db('shared').table('posts')
195
+ const docs = client.db('workspace', 'ws-1').table('docs')
196
+
197
+ // get() returns ListResult, NOT a single record
198
+ const list = await posts.get() // { items, total, page, perPage, hasMore, cursor }
199
+ const one = await posts.getOne('id-1') // single record
200
+ const one2 = await posts.doc('id-1').get() // same thing
201
+
202
+ // Batch ops — chain where() first, NOT pass filter as arg
203
+ await posts.where('status', '==', 'old').updateMany({ status: 'archived' })
204
+ await posts.where('status', '==', 'old').deleteMany()
205
+
206
+ // Signed URLs — expiresIn is a STRING like '1h', NOT a number
207
+ const url = await bucket.createSignedUrl('file.pdf', { expiresIn: '1h' })
208
+
209
+ // Special field ops
210
+ import { increment, deleteField } from '@edge-base/web'
211
+ await posts.update(id, { views: increment(1), temp: deleteField() })
212
+
213
+ // Write operations require authenticated user
214
+ ```
215
+
216
+ ### createClient
217
+
218
+ ```
219
+ import { createClient } from '@edge-base/web'
220
+ const client = createClient(url, options?: { schema?, databaseLive?: { autoReconnect?, maxReconnectAttempts?, reconnectBaseDelay? } })
221
+ ```
222
+
223
+ ### Client Lifecycle
224
+
225
+ ```
226
+ client.destroy() → void (cleanup all resources, subscriptions, timers)
227
+ ```
228
+
229
+ ### Auth
230
+
231
+ ```
232
+ client.auth.currentUser → TokenUser | null (PROPERTY, not method)
233
+ client.auth.signUp({email, password, data?, locale?, captchaToken?}) → Promise<AuthResult>
234
+ client.auth.signIn({email, password, captchaToken?}) → Promise<AuthResult | {mfaRequired, mfaTicket, factors}>
235
+ client.auth.signInAnonymously({captchaToken?}?) → Promise<AuthResult>
236
+ client.auth.signOut() → Promise<void>
237
+ client.auth.signInWithOAuth(provider, {redirectUrl?, captchaToken?}) → {url}
238
+ client.auth.handleOAuthCallback(url?) → Promise<AuthResult | null>
239
+ client.auth.signInWithMagicLink({email, captchaToken?, redirectUrl?, state?}) → Promise<void>
240
+ client.auth.verifyMagicLink(token) → Promise<AuthResult>
241
+ client.auth.signInWithEmailOtp({email}) → Promise<void>
242
+ client.auth.verifyEmailOtp({email, code}) → Promise<AuthResult>
243
+ client.auth.signInWithPhone({phone, captchaToken?}) → Promise<void>
244
+ client.auth.verifyPhone({phone, code}) → Promise<AuthResult>
245
+ client.auth.requestPasswordReset(email, {captchaToken?, redirectUrl?, state?}?) → Promise<void>
246
+ client.auth.resetPassword(token, newPassword) → Promise<void>
247
+ client.auth.changePassword({currentPassword, newPassword}) → Promise<AuthResult>
248
+ client.auth.changeEmail({newEmail, password, redirectUrl?, state?}) → Promise<void>
249
+ client.auth.verifyEmailChange(token) → Promise<void>
250
+ client.auth.updateProfile({displayName?, avatarUrl?, emailVisibility?, locale?}) → Promise<TokenUser>
251
+ client.auth.updateLocale(locale) → Promise<TokenUser>
252
+ client.auth.refreshSession() → Promise<AuthResult>
253
+ client.auth.listSessions() → Promise<Session[]>
254
+ client.auth.revokeSession(sessionId) → Promise<void>
255
+ client.auth.onAuthStateChange(cb: (user: TokenUser | null) => void) → unsubscribe()
256
+ client.auth.requestEmailVerification({redirectUrl?, state?}?) → Promise<void>
257
+ client.auth.verifyEmail(token) → Promise<void>
258
+ client.auth.listIdentities() → Promise<{identities, methods}>
259
+ client.auth.unlinkIdentity(identityId) → Promise<{identities, methods}>
260
+ client.auth.linkWithEmail({email, password}) → Promise<AuthResult>
261
+ client.auth.linkWithPhone({phone}) → Promise<void>
262
+ client.auth.verifyLinkPhone({phone, code}) → Promise<void>
263
+ client.auth.linkWithOAuth(provider, {redirectUrl?, state?}?) → Promise<{redirectUrl}>
264
+ ```
265
+
266
+ #### MFA
267
+
268
+ ```
269
+ client.auth.mfa.enrollTotp() → Promise<{factorId, secret, qrCodeUri, recoveryCodes}>
270
+ client.auth.mfa.verifyTotpEnrollment(factorId, code) → Promise<{ok: true}>
271
+ client.auth.mfa.verifyTotp(mfaTicket, code) → Promise<AuthResult>
272
+ client.auth.mfa.useRecoveryCode(mfaTicket, code) → Promise<AuthResult>
273
+ client.auth.mfa.disableTotp({password?, code?}?) → Promise<{ok: true}>
274
+ client.auth.mfa.listFactors() → Promise<{factors}>
275
+ ```
276
+
277
+ #### Passkeys
278
+
279
+ ```
280
+ client.auth.passkeysRegisterOptions() → Promise<unknown>
281
+ client.auth.passkeysRegister(credential) → Promise<unknown>
282
+ client.auth.passkeysAuthOptions({email?}?) → Promise<unknown>
283
+ client.auth.passkeysAuthenticate(assertion) → Promise<AuthResult>
284
+ client.auth.passkeysList() → Promise<unknown>
285
+ client.auth.passkeysDelete(credentialId) → Promise<unknown>
286
+ ```
287
+
288
+ ### Database
289
+
290
+ ```
291
+ client.db(namespace: 'shared' | 'workspace' | 'user' | string, instanceId?: string)
292
+ .table(name) → TableRef
293
+ ```
294
+
295
+ #### Read
296
+
297
+ ```
298
+ table.getList() → Promise<{items, total, page, perPage, hasMore, cursor}>
299
+ table.get() → Promise<{items, total, page, perPage, hasMore, cursor}> (NOT get-by-id)
300
+ table.getOne(id) → Promise<record>
301
+ table.doc(id).get() → Promise<record>
302
+ table.getFirst() → Promise<record | null>
303
+ table.count() → Promise<number>
304
+ ```
305
+
306
+ #### Query (immutable chaining)
307
+
308
+ ```
309
+ table.where(field, op, value) → TableRef ops: == != < <= > >= in not-in contains array-contains
310
+ table.or(q => q.where(...).where(...)) → TableRef OR conditions
311
+ table.orderBy(field, 'asc'|'desc') → TableRef
312
+ table.limit(n) → TableRef
313
+ table.offset(n) → TableRef
314
+ table.page(n) → TableRef 1-based
315
+ table.search(query) → TableRef
316
+ table.after(cursor) → TableRef
317
+ table.before(cursor) → TableRef
318
+ ```
319
+
320
+ #### Write (require auth)
321
+
322
+ ```
323
+ table.insert(data) → Promise<record>
324
+ table.insertMany(items[]) → Promise<record[]> auto-chunks at 500
325
+ table.update(id, data) → Promise<record> supports increment(), deleteField()
326
+ table.delete(id) → Promise<void>
327
+ table.upsert(data, {conflictTarget?}?) → Promise<record & {action: 'inserted'|'updated'}>
328
+ table.upsertMany(items[], {conflictTarget?}?) → Promise<record[]>
329
+ table.where(...).updateMany(data) → Promise<{totalProcessed, totalSucceeded, errors}>
330
+ table.where(...).deleteMany() → Promise<{totalProcessed, totalSucceeded, errors}>
331
+ ```
332
+
333
+ #### Special fields
334
+
335
+ ```
336
+ import { increment, deleteField } from '@edge-base/web'
337
+ table.update(id, { views: increment(1), old: deleteField() })
338
+ ```
339
+
340
+ #### Doc ref
341
+
342
+ ```
343
+ table.doc(id).get() → Promise<record>
344
+ table.doc(id).update(data) → Promise<record>
345
+ table.doc(id).delete() → Promise<void>
346
+ table.doc(id).onSnapshot(cb: (data, change) => void) → unsubscribe()
347
+ ```
348
+
349
+ ### Database Live
350
+
351
+ ```
352
+ table.onSnapshot(cb: (snapshot) => void) → unsubscribe()
353
+ table.where(...).onSnapshot(cb) → unsubscribe()
354
+ table.doc(id).onSnapshot(cb: (data, change) => void) → unsubscribe()
355
+
356
+ snapshot = { items: T[], changes: { added: T[], modified: T[], removed: T[] } }
357
+ change = { changeType: 'added'|'modified'|'removed', data, docId }
358
+ ```
359
+
360
+ ### Storage
361
+
362
+ ```
363
+ client.storage.bucket(name) → StorageBucket
364
+ ```
365
+
366
+ #### Operations
367
+
368
+ ```
369
+ bucket.upload(key, File|Blob|ArrayBuffer|Uint8Array, {contentType?, customMetadata?, onProgress?, signal?}?) → UploadTask<FileInfo>
370
+ bucket.uploadString(key, value, format?: 'raw'|'base64'|'base64url'|'data_url', opts?) → UploadTask<FileInfo>
371
+ bucket.download(key, {as?: 'blob'|'arraybuffer'|'stream'|'text'}?) → Promise<Blob|...>
372
+ bucket.getUrl(key) → string (sync)
373
+ bucket.createSignedUrl(key, {expiresIn?: '1h'|'30m'|'7d'}) → Promise<string> expiresIn is STRING not number
374
+ bucket.createSignedUrls(keys[], {expiresIn?}) → Promise<Array<{key, url, expiresAt}>>
375
+ bucket.createSignedUploadUrl(key, {expiresIn?, maxFileSize?}) → Promise<{url, expiresAt, maxFileSize, uploadedBy}>
376
+ bucket.getMetadata(key) → Promise<FileInfo>
377
+ bucket.updateMetadata(key, {customMetadata?, contentType?}) → Promise<FileInfo>
378
+ bucket.exists(key) → Promise<boolean>
379
+ bucket.list({prefix?, cursor?, limit?}?) → Promise<{files: FileInfo[], cursor, truncated}>
380
+ bucket.delete(key) → Promise<void>
381
+ bucket.deleteMany(keys[]) → Promise<{deleted, failed}>
382
+ bucket.resumeUpload(key, uploadId, data, opts?) → UploadTask<FileInfo>
383
+ bucket.getUploadParts(key, uploadId) → Promise<{uploadId, key, parts: [{partNumber, etag}]}>
384
+
385
+ upload() returns UploadTask (Promise + .cancel() method)
386
+ on resumable upload failure: catch ResumableUploadError {key, uploadId, completedParts, failedPartNumber}
387
+ ```
388
+
389
+ #### Convenience (without bucket ref)
390
+
391
+ ```
392
+ client.storage.upload(bucketName, key, data, opts?) → UploadTask<FileInfo>
393
+ client.storage.delete(bucketName, key) → Promise<void>
394
+ client.storage.getUrl(bucketName, key) → string
395
+ ```
396
+
397
+ ### Room
398
+
399
+ ```
400
+ const room = client.room(namespace, roomId, {autoReconnect?, maxReconnectAttempts?, reconnectBaseDelay?, sendTimeout?}?)
401
+ room.join() → Promise<void>
402
+ room.leave() → void
403
+ ```
404
+
405
+ #### Members
406
+
407
+ ```
408
+ room.members.list() → RoomMember[]
409
+ room.members.onSync(cb) → Subscription (.unsubscribe())
410
+ room.members.onJoin(cb) → Subscription
411
+ room.members.onLeave(cb: (member, reason: 'leave'|'timeout'|'kicked') => void) → Subscription
412
+ room.members.setState(state) → Promise<void>
413
+ room.members.clearState() → Promise<void>
414
+ room.members.onStateChange(cb) → Subscription
415
+ ```
416
+
417
+ #### State
418
+
419
+ ```
420
+ room.state.getShared() → Record<string, unknown>
421
+ room.state.getMine() → Record<string, unknown>
422
+ room.state.onSharedChange(cb) → Subscription
423
+ room.state.onMineChange(cb) → Subscription
424
+ room.state.send(actionType, payload?) → Promise<response>
425
+ ```
426
+
427
+ #### Signals
428
+
429
+ ```
430
+ room.signals.send(event, payload?, {includeSelf?}?) → Promise<void>
431
+ room.signals.sendTo(memberId, event, payload?) → Promise<void>
432
+ room.signals.on(event, cb: (payload, meta) => void) → Subscription
433
+ room.signals.onAny(cb: (event, payload, meta) => void) → Subscription
434
+ ```
435
+
436
+ #### Media
437
+
438
+ ```
439
+ room.media.audio.enable() / disable() / setMuted(bool) → Promise<void>
440
+ room.media.video.enable() / disable() / setMuted(bool) → Promise<void>
441
+ room.media.screen.start() / stop() → Promise<void>
442
+ room.media.list() → RoomMediaMember[]
443
+ room.media.devices.switch({audioInputId?, videoInputId?}) → Promise<void>
444
+ room.media.onTrack(cb) → Subscription
445
+ room.media.onTrackRemoved(cb) → Subscription
446
+ room.media.onStateChange(cb) → Subscription
447
+ room.media.onDeviceChange(cb) → Subscription
448
+ ```
449
+
450
+ #### Admin (in-room moderation)
451
+
452
+ ```
453
+ room.admin.kick(memberId) → Promise<void>
454
+ room.admin.mute(memberId) → Promise<void>
455
+ room.admin.block(memberId) → Promise<void>
456
+ room.admin.setRole(memberId, role) → Promise<void>
457
+ room.admin.disableVideo(memberId) → Promise<void>
458
+ room.admin.stopScreenShare(memberId) → Promise<void>
459
+ ```
460
+
461
+ #### Meta
462
+
463
+ ```
464
+ room.meta.get() → Promise<Record<string, unknown>>
465
+ ```
466
+
467
+ #### Realtime (WebRTC) — HTTP Wrappers
468
+
469
+ ```
470
+ room.media.realtime.createSession(payload?) → Promise<{sessionId, sessionDescription?}>
471
+ room.media.realtime.getIceServers({ttl?}?) → Promise<{iceServers}>
472
+ room.media.realtime.addTracks({sessionId, tracks, sessionDescription?}) → Promise<{sessionDescription?, tracks?}>
473
+ room.media.realtime.renegotiate({sessionId, sessionDescription}) → Promise<{sessionDescription?, tracks?}>
474
+ room.media.realtime.closeTracks({sessionId, tracks: [{mid}]}) → Promise<{sessionDescription?, tracks?}>
475
+ ```
476
+
477
+ For higher-level WebRTC transport, use the built-in room transport or the `RoomRealtimeMediaTransport` export from `@edge-base/web`:
478
+ ```
479
+ const transport = room.media.realtime.transport({ autoSubscribe: true });
480
+ await transport.connect();
481
+ await transport.enableAudio();
482
+ await transport.enableVideo();
483
+ transport.onRemoteTrack(event => { ... });
484
+ ```
485
+
486
+ #### Session
487
+
488
+ ```
489
+ room.session.onConnectionStateChange(cb: (state: 'idle'|'connecting'|'connected'|'reconnecting'|'disconnected'|'auth_lost'|'kicked') => void) → Subscription
490
+ room.session.onKicked(cb) → Subscription
491
+ room.session.onError(cb) → Subscription
492
+ room.session.onReconnect(cb) → Subscription
493
+ ```
494
+
495
+ ### Functions
496
+
497
+ ```
498
+ client.functions.call(name, {method?, body?, query?}?) → Promise<T>
499
+ client.functions.get(path, query?) → Promise<T>
500
+ client.functions.post(path, body?) → Promise<T>
501
+ client.functions.put(path, body?) → Promise<T>
502
+ client.functions.patch(path, body?) → Promise<T>
503
+ client.functions.delete(path) → Promise<T>
504
+ ```
505
+
506
+ ### Analytics
507
+
508
+ ```
509
+ client.analytics.track(name, properties?: Record<string, string|number|boolean>) → void (batched)
510
+ client.analytics.flush() → Promise<void>
511
+ client.analytics.destroy() → void (flush + cleanup)
512
+ ```
513
+
514
+ ### Push
515
+
516
+ ```
517
+ client.push.setTokenProvider(provider: () => Promise<string>) → void
518
+ client.push.register({metadata?}?) → Promise<void>
519
+ client.push.unregister(deviceId?) → Promise<void>
520
+ client.push.subscribeTopic(topic) → Promise<void>
521
+ client.push.unsubscribeTopic(topic) → Promise<void>
522
+ client.push.onMessage(cb: (msg: {title?, body?, data?}) => void)
523
+ client.push.onMessageOpenedApp(cb: (msg) => void) → void (notification tap opened app)
524
+ client.push.getPermissionStatus() → 'granted'|'denied'|'notDetermined'
525
+ client.push.requestPermission() → Promise<'granted'|'denied'>
526
+ ```
527
+
528
+ ### Errors
529
+
530
+ ```
531
+ import { EdgeBaseError } from '@edge-base/web'
532
+ EdgeBaseError extends Error {
533
+ code: number // HTTP status code (e.g. 400, 401, 404)
534
+ message: string
535
+ slug?: string // machine-readable error identifier
536
+ data?: Record<string, FieldError> // per-field validation errors
537
+ status: number // getter, alias for code
538
+ }
539
+ ```
540
+
541
+ ### Utility
542
+
543
+ ```
544
+ client.setLocale(locale: string | undefined)
545
+ client.getLocale() → string | undefined
546
+ client.setContext(ctx) → void
547
+ client.getContext() → ContextValue
548
+ client.getRoomMetadata(namespace, roomId) → Promise<Record<string, unknown>>
549
+ ```
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@edge-base/web",
3
+ "version": "0.1.1",
4
+ "description": "EdgeBase web SDK — browser client with database-live subscriptions, room, and auth persistence",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/edge-base/edgebase.git",
9
+ "directory": "packages/sdk/js/packages/web"
10
+ },
11
+ "homepage": "https://edgebase.fun",
12
+ "bugs": "https://github.com/edge-base/edgebase/issues",
13
+ "keywords": [
14
+ "edgebase",
15
+ "sdk",
16
+ "web",
17
+ "database-live",
18
+ "baas"
19
+ ],
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js"
27
+ }
28
+ },
29
+ "sideEffects": false,
30
+ "files": [
31
+ "dist",
32
+ "llms.txt"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "dev": "tsc --watch",
40
+ "test": "tsc --noEmit && vitest run test/unit/",
41
+ "prepack": "pnpm run build"
42
+ },
43
+ "dependencies": {
44
+ "@edge-base/core": "workspace:*"
45
+ },
46
+ "devDependencies": {
47
+ "typescript": "^5.7.0",
48
+ "vitest": "^3.0.0"
49
+ }
50
+ }