@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/README.md ADDED
@@ -0,0 +1,352 @@
1
+ <h1 align="center">@edge-base/web</h1>
2
+
3
+ <p align="center">
4
+ <b>Browser SDK for EdgeBase</b><br>
5
+ Auth, database, realtime, storage, functions, analytics, and rooms for modern web apps
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="https://www.npmjs.com/package/@edge-base/web"><img src="https://img.shields.io/npm/v/%40edge-base%2Fweb?color=brightgreen" alt="npm"></a>&nbsp;
10
+ <a href="https://edgebase.fun/docs/database/client-sdk"><img src="https://img.shields.io/badge/docs-client_sdk-blue" alt="Docs"></a>&nbsp;
11
+ <a href="https://github.com/edge-base/edgebase/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ React · Next.js · Vite · Vanilla TS · PWAs
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://edgebase.fun/docs/getting-started/quickstart"><b>Quickstart</b></a> ·
20
+ <a href="https://edgebase.fun/docs/database/client-sdk"><b>Client SDK Docs</b></a> ·
21
+ <a href="https://edgebase.fun/docs/database/subscriptions"><b>Database Live</b></a> ·
22
+ <a href="https://edgebase.fun/docs/room/client-sdk"><b>Room Docs</b></a>
23
+ </p>
24
+
25
+ ---
26
+
27
+ `@edge-base/web` is the main client SDK for browser environments.
28
+
29
+ It is designed for apps that need:
30
+
31
+ - user authentication with session persistence
32
+ - direct database access from the client through access rules
33
+ - live updates with `onSnapshot()`
34
+ - multiplayer and presence flows with rooms
35
+ - storage uploads and file URLs
36
+ - client-side function calls, analytics, and web push
37
+
38
+ If you need privileged or server-only access, use [`@edge-base/admin`](https://www.npmjs.com/package/@edge-base/admin) instead.
39
+
40
+ > Beta: the package is already usable, but some APIs may still evolve before general availability.
41
+
42
+ ## Documentation Map
43
+
44
+ Use this README for the fast overview, then jump into the docs when you need depth:
45
+
46
+ - [Quickstart](https://edgebase.fun/docs/getting-started/quickstart)
47
+ Create a project and run EdgeBase locally
48
+ - [Client SDK](https://edgebase.fun/docs/database/client-sdk)
49
+ Full browser SDK reference and query patterns
50
+ - [Database Subscriptions](https://edgebase.fun/docs/database/subscriptions)
51
+ Live queries and `onSnapshot()` patterns
52
+ - [Authentication](https://edgebase.fun/docs/authentication)
53
+ Email/password, OAuth, MFA, sessions, passkeys
54
+ - [Room Client SDK](https://edgebase.fun/docs/room/client-sdk)
55
+ Presence, state, members, signals, and media
56
+ - [Functions Client SDK](https://edgebase.fun/docs/functions/client-sdk)
57
+ Calling EdgeBase functions from the browser
58
+ - [Analytics Client SDK](https://edgebase.fun/docs/analytics/client-sdk)
59
+ Event tracking from web clients
60
+ - [Push Client SDK](https://edgebase.fun/docs/push/client-sdk)
61
+ Web push registration and client-side handling
62
+
63
+ ## For AI Coding Assistants
64
+
65
+ This package ships with an `llms.txt` file for AI-assisted development.
66
+
67
+ Use it when you want an agent or code assistant to:
68
+
69
+ - avoid common API mistakes
70
+ - use the correct method signatures
71
+ - choose the right database and auth patterns
72
+ - prefer the documented EdgeBase flow instead of guessing
73
+
74
+ You can find it:
75
+
76
+ - in this package after install: `node_modules/@edge-base/web/llms.txt`
77
+ - in the repository: [llms.txt](https://github.com/edge-base/edgebase/blob/main/packages/sdk/js/packages/web/llms.txt)
78
+
79
+ For deeper behavioral details, pair `llms.txt` with the docs linked above.
80
+
81
+ ## Why This Package
82
+
83
+ Most browser SDKs stop at auth + CRUD.
84
+
85
+ `@edge-base/web` is meant to be the single browser entry point for the whole EdgeBase app surface:
86
+
87
+ | Capability | Included |
88
+ |---|---|
89
+ | Auth | Email/password, OAuth, sessions, auth state |
90
+ | Database | Query, insert, update, delete |
91
+ | Database Live | `onSnapshot()` subscriptions |
92
+ | Rooms | Presence, room state, signals, media-ready client surface |
93
+ | Storage | Uploads, bucket access, file URLs |
94
+ | Functions | Call EdgeBase functions from the browser |
95
+ | Analytics | Client-side analytics helpers |
96
+ | Push | Web push registration and message handling |
97
+
98
+ ## Installation
99
+
100
+ ```bash
101
+ npm install @edge-base/web
102
+ ```
103
+
104
+ Starting a brand new project?
105
+
106
+ ```bash
107
+ npm create edge-base@latest my-app
108
+ ```
109
+
110
+ That scaffold creates a full EdgeBase app and wires in the local CLI for development and deployment.
111
+
112
+ Read more: [Quickstart](https://edgebase.fun/docs/getting-started/quickstart)
113
+
114
+ ## Recommended Project Layout
115
+
116
+ If you already have a frontend app, a good default is to create EdgeBase inside that project as a dedicated subdirectory:
117
+
118
+ ```bash
119
+ cd your-frontend-project
120
+ npm create edge-base@latest edgebase
121
+ ```
122
+
123
+ That gives you a layout like:
124
+
125
+ ```text
126
+ your-frontend-project/
127
+ src/
128
+ app/
129
+ package.json
130
+ edgebase/
131
+ edgebase.config.ts
132
+ functions/
133
+ package.json
134
+ ```
135
+
136
+ This is only a recommendation, not a requirement.
137
+
138
+ You can also:
139
+
140
+ - create EdgeBase as a completely separate project
141
+ - keep frontend and backend in different repos
142
+ - use a different subdirectory name if that fits your monorepo better
143
+
144
+ The main thing we recommend is avoiding scaffolding directly into an existing app root unless that is intentionally how you want to organize the repo.
145
+
146
+ ## Quick Start
147
+
148
+ ```ts
149
+ import { createClient } from '@edge-base/web';
150
+
151
+ const client = createClient('https://your-project.edgebase.fun');
152
+
153
+ await client.auth.signIn({
154
+ email: 'june@example.com',
155
+ password: 'pass1234',
156
+ });
157
+
158
+ const posts = await client
159
+ .db('app')
160
+ .table('posts')
161
+ .where('published', '==', true)
162
+ .orderBy('createdAt', 'desc')
163
+ .limit(10)
164
+ .getList();
165
+
166
+ const health = await client.functions.get('health');
167
+
168
+ console.log(posts.items, health);
169
+ ```
170
+
171
+ `app` in the example above is your database block name from `edgebase.config.ts`.
172
+
173
+ For instance databases, pass both a namespace and an id:
174
+
175
+ ```ts
176
+ client.db('workspace', 'ws-123');
177
+ client.db('user', 'user-123');
178
+ ```
179
+
180
+ Read more: [Client SDK](https://edgebase.fun/docs/database/client-sdk)
181
+
182
+ ## Core API
183
+
184
+ Once you create a client, these are the main surfaces you will use:
185
+
186
+ - `client.auth`
187
+ Sign up, sign in, sign out, OAuth, MFA flows, and auth state listeners
188
+ - `client.db(namespace, id?)`
189
+ Query tables, mutate records, and subscribe to live changes
190
+ - `client.storage`
191
+ Upload files and resolve bucket URLs
192
+ - `client.functions`
193
+ Call app functions from the browser
194
+ - `client.room(namespace, roomId)`
195
+ Join realtime rooms for presence, state sync, and signals
196
+ - `client.analytics`
197
+ Send analytics data from the client
198
+ - `client.push`
199
+ Register and manage web push flows
200
+
201
+ ## Auth
202
+
203
+ ### Email and password
204
+
205
+ ```ts
206
+ await client.auth.signUp({
207
+ email: 'june@example.com',
208
+ password: 'pass1234',
209
+ data: {
210
+ displayName: 'June',
211
+ },
212
+ });
213
+
214
+ await client.auth.signIn({
215
+ email: 'june@example.com',
216
+ password: 'pass1234',
217
+ });
218
+
219
+ client.auth.onAuthStateChange((user) => {
220
+ console.log('auth changed:', user);
221
+ });
222
+ ```
223
+
224
+ ### OAuth
225
+
226
+ ```ts
227
+ await client.auth.signInWithOAuth('google');
228
+
229
+ const result = await client.auth.handleOAuthCallback();
230
+ if (result) {
231
+ console.log('signed in with OAuth:', result.user);
232
+ }
233
+ ```
234
+
235
+ By default, the browser SDK uses `/auth/callback` on the current origin as the redirect target.
236
+
237
+ Read more: [Authentication Docs](https://edgebase.fun/docs/authentication)
238
+
239
+ ## Database Queries
240
+
241
+ ```ts
242
+ type Post = {
243
+ id: string;
244
+ title: string;
245
+ published: boolean;
246
+ createdAt: string;
247
+ };
248
+
249
+ const posts = client.db('app').table<Post>('posts');
250
+
251
+ const latest = await posts
252
+ .where('published', '==', true)
253
+ .orderBy('createdAt', 'desc')
254
+ .limit(20)
255
+ .getList();
256
+
257
+ await posts.insert({
258
+ title: 'Hello EdgeBase',
259
+ published: true,
260
+ });
261
+ ```
262
+
263
+ Read more: [Database Client SDK](https://edgebase.fun/docs/database/client-sdk)
264
+
265
+ ## Database Live
266
+
267
+ ```ts
268
+ const unsubscribe = client
269
+ .db('app')
270
+ .table('posts')
271
+ .onSnapshot((change) => {
272
+ console.log(change.changeType, change.data);
273
+ });
274
+
275
+ // later
276
+ unsubscribe();
277
+ ```
278
+
279
+ Use this for feeds, counters, collaborative UIs, moderation dashboards, or any UI that should react instantly to server-side changes.
280
+
281
+ Read more: [Database Subscriptions](https://edgebase.fun/docs/database/subscriptions)
282
+
283
+ ## Storage
284
+
285
+ ```ts
286
+ const bucket = client.storage.bucket('avatars');
287
+
288
+ await bucket.upload('me.jpg', file);
289
+
290
+ const publicUrl = bucket.getUrl('me.jpg');
291
+ console.log(publicUrl);
292
+ ```
293
+
294
+ Read more: [Storage Docs](https://edgebase.fun/docs/storage)
295
+
296
+ ## Functions
297
+
298
+ ```ts
299
+ const result = await client.functions.post('contact/send', {
300
+ email: 'june@example.com',
301
+ message: 'Hello from the web SDK',
302
+ });
303
+
304
+ console.log(result);
305
+ ```
306
+
307
+ Read more: [Functions Client SDK](https://edgebase.fun/docs/functions/client-sdk)
308
+
309
+ ## Rooms
310
+
311
+ ```ts
312
+ const room = client.room('game', 'lobby-1');
313
+
314
+ await room.join();
315
+
316
+ room.leave();
317
+ ```
318
+
319
+ Use rooms when you need:
320
+
321
+ - presence
322
+ - room state
323
+ - peer signals
324
+ - multiplayer coordination
325
+ - media/session-style realtime flows
326
+
327
+ Read more: [Room Client SDK](https://edgebase.fun/docs/room/client-sdk)
328
+
329
+ ## Which EdgeBase Package Should You Use?
330
+
331
+ | Package | Use it when |
332
+ |---|---|
333
+ | `@edge-base/web` | You are in the browser or another untrusted client runtime |
334
+ | `@edge-base/admin` | You need trusted server/admin access |
335
+ | `@edge-base/ssr` | You want cookie-based SSR helpers for frameworks like Next.js |
336
+ | `@edge-base/auth-ui-react` | You want headless React auth UI built on top of the web SDK |
337
+ | `@edge-base/react-native` | You are building a React Native app |
338
+
339
+ ## Docs
340
+
341
+ - [Quickstart](https://edgebase.fun/docs/getting-started/quickstart)
342
+ - [Client SDK](https://edgebase.fun/docs/database/client-sdk)
343
+ - [Database Live](https://edgebase.fun/docs/database/subscriptions)
344
+ - [Room Client SDK](https://edgebase.fun/docs/room/client-sdk)
345
+ - [Authentication Docs](https://edgebase.fun/docs/authentication)
346
+ - [Functions Client SDK](https://edgebase.fun/docs/functions/client-sdk)
347
+ - [Analytics Client SDK](https://edgebase.fun/docs/analytics/client-sdk)
348
+ - [Push Client SDK](https://edgebase.fun/docs/push/client-sdk)
349
+
350
+ ## License
351
+
352
+ MIT
@@ -0,0 +1,60 @@
1
+ /**
2
+ * ClientAnalytics — Browser-side custom event tracking for Client SDK
3
+ *
4
+ * Optimized for browser:
5
+ * - Batches events in memory (max 20 or 5s timer, whichever comes first)
6
+ * - Uses sendBeacon on page unload to avoid losing events
7
+ * - Auto-retries failed flushes once by re-queuing
8
+ *
9
+ * Usage:
10
+ * const client = createClient('https://my-app.edgebase.fun');
11
+ * client.analytics.track('page_view', { path: '/pricing' });
12
+ * client.analytics.track('button_click', { id: 'signup-cta', variant: 'A' });
13
+ *
14
+ * // Manual flush if needed
15
+ * await client.analytics.flush();
16
+ */
17
+ import { type HttpClient, type GeneratedDbApi } from '@edge-base/core';
18
+ export declare class ClientAnalytics {
19
+ private httpClient;
20
+ private baseUrl;
21
+ private core?;
22
+ private queue;
23
+ private timer;
24
+ private readonly FLUSH_INTERVAL;
25
+ private readonly MAX_BATCH;
26
+ private boundVisibilityHandler;
27
+ private boundPageHideHandler;
28
+ constructor(httpClient: HttpClient, baseUrl: string, core?: GeneratedDbApi | undefined);
29
+ /**
30
+ * Track a custom event. Events are batched and sent automatically.
31
+ *
32
+ * @param name Event name (e.g. 'page_view', 'button_click', 'purchase')
33
+ * @param properties Optional key-value data (max 50 keys, max 4KB total)
34
+ *
35
+ * @example
36
+ * client.analytics.track('page_view', { path: '/pricing' });
37
+ * client.analytics.track('purchase', { plan: 'pro', amount: 29.99 });
38
+ */
39
+ track(name: string, properties?: Record<string, string | number | boolean>): void;
40
+ /**
41
+ * Manually flush all queued events to the server.
42
+ * Automatically called on timer expiry, batch size reached, or page unload.
43
+ */
44
+ flush(): Promise<void>;
45
+ /**
46
+ * Send remaining events via navigator.sendBeacon (used on page unload).
47
+ * sendBeacon cannot send Authorization headers, so these events arrive
48
+ * without JWT auth — protected by rate limiting only.
49
+ *
50
+ * NOTE: Direct HTTP — sendBeacon requires a raw URL + Blob. Cannot use
51
+ * generated core because sendBeacon bypasses normal fetch/XHR entirely.
52
+ */
53
+ private sendBeacon;
54
+ /**
55
+ * Destroy the analytics client. Flushes remaining events and removes
56
+ * event listeners. Call this when unmounting the SDK.
57
+ */
58
+ destroy(): void;
59
+ }
60
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAY,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAQjF,qBAAa,eAAe;IAUxB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,IAAI,CAAC;IAXf,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAM;IAEhC,OAAO,CAAC,sBAAsB,CAA6B;IAC3D,OAAO,CAAC,oBAAoB,CAA6B;gBAG/C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,cAAc,YAAA;IAc/B;;;;;;;;;OASG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI;IAUjF;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC5B;;;;;;;OAOG;IACH,OAAO,CAAC,UAAU;IAoBlB;;;OAGG;IACH,OAAO,IAAI,IAAI;CAiBhB"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * ClientAnalytics — Browser-side custom event tracking for Client SDK
3
+ *
4
+ * Optimized for browser:
5
+ * - Batches events in memory (max 20 or 5s timer, whichever comes first)
6
+ * - Uses sendBeacon on page unload to avoid losing events
7
+ * - Auto-retries failed flushes once by re-queuing
8
+ *
9
+ * Usage:
10
+ * const client = createClient('https://my-app.edgebase.fun');
11
+ * client.analytics.track('page_view', { path: '/pricing' });
12
+ * client.analytics.track('button_click', { id: 'signup-cta', variant: 'A' });
13
+ *
14
+ * // Manual flush if needed
15
+ * await client.analytics.flush();
16
+ */
17
+ import { ApiPaths } from '@edge-base/core';
18
+ export class ClientAnalytics {
19
+ httpClient;
20
+ baseUrl;
21
+ core;
22
+ queue = [];
23
+ timer = null;
24
+ FLUSH_INTERVAL = 5_000; // 5 seconds
25
+ MAX_BATCH = 20; // 20 events per batch
26
+ boundVisibilityHandler = null;
27
+ boundPageHideHandler = null;
28
+ constructor(httpClient, baseUrl, core) {
29
+ this.httpClient = httpClient;
30
+ this.baseUrl = baseUrl;
31
+ this.core = core;
32
+ // Send remaining events on page unload
33
+ if (typeof window !== 'undefined') {
34
+ this.boundVisibilityHandler = () => {
35
+ if (document.visibilityState === 'hidden')
36
+ this.sendBeacon();
37
+ };
38
+ this.boundPageHideHandler = () => this.sendBeacon();
39
+ window.addEventListener('visibilitychange', this.boundVisibilityHandler);
40
+ window.addEventListener('pagehide', this.boundPageHideHandler);
41
+ }
42
+ }
43
+ /**
44
+ * Track a custom event. Events are batched and sent automatically.
45
+ *
46
+ * @param name Event name (e.g. 'page_view', 'button_click', 'purchase')
47
+ * @param properties Optional key-value data (max 50 keys, max 4KB total)
48
+ *
49
+ * @example
50
+ * client.analytics.track('page_view', { path: '/pricing' });
51
+ * client.analytics.track('purchase', { plan: 'pro', amount: 29.99 });
52
+ */
53
+ track(name, properties) {
54
+ this.queue.push({ name, properties, timestamp: Date.now() });
55
+ if (this.queue.length >= this.MAX_BATCH) {
56
+ void this.flush();
57
+ }
58
+ else if (!this.timer) {
59
+ this.timer = setTimeout(() => void this.flush(), this.FLUSH_INTERVAL);
60
+ }
61
+ }
62
+ /**
63
+ * Manually flush all queued events to the server.
64
+ * Automatically called on timer expiry, batch size reached, or page unload.
65
+ */
66
+ async flush() {
67
+ if (this.timer) {
68
+ clearTimeout(this.timer);
69
+ this.timer = null;
70
+ }
71
+ if (!this.queue.length)
72
+ return;
73
+ const batch = this.queue.splice(0, this.MAX_BATCH);
74
+ try {
75
+ const payload = {
76
+ events: batch.map(e => ({
77
+ name: e.name,
78
+ properties: e.properties,
79
+ timestamp: e.timestamp,
80
+ })),
81
+ };
82
+ if (this.core) {
83
+ await this.core.trackEvents(payload);
84
+ }
85
+ else {
86
+ await this.httpClient.post(ApiPaths.TRACK_EVENTS, payload);
87
+ }
88
+ }
89
+ catch {
90
+ // Failed — re-queue for one retry (don't retry infinitely)
91
+ this.queue.unshift(...batch);
92
+ }
93
+ // If there are still events in the queue, schedule another flush
94
+ if (this.queue.length > 0 && !this.timer) {
95
+ this.timer = setTimeout(() => void this.flush(), this.FLUSH_INTERVAL);
96
+ }
97
+ }
98
+ /**
99
+ * Send remaining events via navigator.sendBeacon (used on page unload).
100
+ * sendBeacon cannot send Authorization headers, so these events arrive
101
+ * without JWT auth — protected by rate limiting only.
102
+ *
103
+ * NOTE: Direct HTTP — sendBeacon requires a raw URL + Blob. Cannot use
104
+ * generated core because sendBeacon bypasses normal fetch/XHR entirely.
105
+ */
106
+ sendBeacon() {
107
+ if (!this.queue.length)
108
+ return;
109
+ const batch = this.queue.splice(0);
110
+ const url = `${this.baseUrl}${ApiPaths.TRACK_EVENTS}`;
111
+ const body = JSON.stringify({
112
+ events: batch.map(e => ({
113
+ name: e.name,
114
+ properties: e.properties,
115
+ timestamp: e.timestamp,
116
+ })),
117
+ });
118
+ try {
119
+ navigator.sendBeacon(url, new Blob([body], { type: 'application/json' }));
120
+ }
121
+ catch {
122
+ // sendBeacon failed — page is unloading, nothing we can do
123
+ }
124
+ }
125
+ /**
126
+ * Destroy the analytics client. Flushes remaining events and removes
127
+ * event listeners. Call this when unmounting the SDK.
128
+ */
129
+ destroy() {
130
+ if (this.timer) {
131
+ clearTimeout(this.timer);
132
+ this.timer = null;
133
+ }
134
+ this.sendBeacon();
135
+ // Remove event listeners
136
+ if (typeof window !== 'undefined') {
137
+ if (this.boundVisibilityHandler) {
138
+ window.removeEventListener('visibilitychange', this.boundVisibilityHandler);
139
+ }
140
+ if (this.boundPageHideHandler) {
141
+ window.removeEventListener('pagehide', this.boundPageHideHandler);
142
+ }
143
+ }
144
+ }
145
+ }
146
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function refreshAccessToken(baseUrl: string, refreshToken: string): Promise<{
2
+ accessToken: string;
3
+ refreshToken: string;
4
+ }>;
5
+ //# sourceMappingURL=auth-refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-refresh.d.ts","sourceRoot":"","sources":["../src/auth-refresh.ts"],"names":[],"mappings":"AAQA,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IACvF,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC,CAgCD"}
@@ -0,0 +1,26 @@
1
+ import { EdgeBaseError } from '@edge-base/core';
2
+ export async function refreshAccessToken(baseUrl, refreshToken) {
3
+ let response;
4
+ try {
5
+ response = await fetch(`${baseUrl.replace(/\/$/, '')}/api/auth/refresh`, {
6
+ method: 'POST',
7
+ headers: { 'Content-Type': 'application/json' },
8
+ body: JSON.stringify({ refreshToken }),
9
+ });
10
+ }
11
+ catch (error) {
12
+ throw new EdgeBaseError(0, `Network error: ${error instanceof Error ? error.message : 'Failed to refresh access token.'}`);
13
+ }
14
+ const body = await response.json().catch(() => null);
15
+ if (!response.ok) {
16
+ throw new EdgeBaseError(response.status, typeof body?.message === 'string' ? body.message : 'Failed to refresh access token.');
17
+ }
18
+ if (!body?.accessToken || !body?.refreshToken) {
19
+ throw new EdgeBaseError(500, 'Invalid auth refresh response.');
20
+ }
21
+ return {
22
+ accessToken: body.accessToken,
23
+ refreshToken: body.refreshToken,
24
+ };
25
+ }
26
+ //# sourceMappingURL=auth-refresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-refresh.js","sourceRoot":"","sources":["../src/auth-refresh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAQhD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAe,EAAE,YAAoB;IAI5E,IAAI,QAAkB,CAAC;IAEvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,EAAE;YACvE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;SACvC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,aAAa,CACrB,CAAC,EACD,kBAAkB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC,EAAE,CAC/F,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAA2B,CAAC;IAC/E,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,aAAa,CACrB,QAAQ,CAAC,MAAM,EACf,OAAO,IAAI,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC,CACrF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;QAC9C,MAAM,IAAI,aAAa,CAAC,GAAG,EAAE,gCAAgC,CAAC,CAAC;IACjE,CAAC;IAED,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;KAChC,CAAC;AACJ,CAAC"}