@rebasepro/client 0.9.1-canary.09aaf62 → 0.9.1-canary.0fce67c
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/dist/index.d.ts +0 -2
- package/dist/index.es.js +1 -237
- package/dist/index.es.js.map +1 -1
- package/dist/websocket.d.ts +1 -11
- package/package.json +4 -4
- package/src/index.ts +0 -33
- package/src/websocket.ts +1 -44
- package/dist/realtime-channel.d.ts +0 -89
- package/src/realtime-channel.test.ts +0 -241
- package/src/realtime-channel.ts +0 -238
package/dist/index.d.ts
CHANGED
|
@@ -27,8 +27,6 @@ export type { CreateBackupsOptions } from "./backups";
|
|
|
27
27
|
export type { ApiKeyMasked, ApiKeyPermission, ApiKeyWithSecret, CreateApiKeyRequest, CreateApiKeysOptions, UpdateApiKeyRequest } from "./api-keys";
|
|
28
28
|
export type { FunctionInvokeOptions, FunctionsClient } from "./functions";
|
|
29
29
|
export { RebaseWebSocketClient } from "./websocket";
|
|
30
|
-
export { RebaseRealtimeChannel } from "./realtime-channel";
|
|
31
|
-
export type { PresenceState, PresenceDiff, BroadcastEvent, ChannelTransport } from "./realtime-channel";
|
|
32
30
|
export interface CreateRebaseClientOptions extends RebaseClientConfig {
|
|
33
31
|
auth?: CreateAuthOptions;
|
|
34
32
|
admin?: CreateAdminOptions;
|
package/dist/index.es.js
CHANGED
|
@@ -1419,23 +1419,6 @@ var RebaseWebSocketClient = class {
|
|
|
1419
1419
|
getAuthToken;
|
|
1420
1420
|
subscriptions = /* @__PURE__ */ new Map();
|
|
1421
1421
|
listeners = /* @__PURE__ */ new Map();
|
|
1422
|
-
/** Channel-name → handlers, for broadcast and presence frames. */
|
|
1423
|
-
channelHandlers = /* @__PURE__ */ new Map();
|
|
1424
|
-
/** Subscribe to broadcast/presence frames for one channel. */
|
|
1425
|
-
onChannelMessage(channel, handler) {
|
|
1426
|
-
if (!this.channelHandlers.has(channel)) this.channelHandlers.set(channel, /* @__PURE__ */ new Set());
|
|
1427
|
-
this.channelHandlers.get(channel).add(handler);
|
|
1428
|
-
return () => {
|
|
1429
|
-
const handlers = this.channelHandlers.get(channel);
|
|
1430
|
-
if (!handlers) return;
|
|
1431
|
-
handlers.delete(handler);
|
|
1432
|
-
if (handlers.size === 0) this.channelHandlers.delete(channel);
|
|
1433
|
-
};
|
|
1434
|
-
}
|
|
1435
|
-
/** Notified after the socket comes back, so channels can re-join. */
|
|
1436
|
-
onReconnect(handler) {
|
|
1437
|
-
return this.on("reconnect", handler);
|
|
1438
|
-
}
|
|
1439
1422
|
on(event, cb) {
|
|
1440
1423
|
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
1441
1424
|
this.listeners.get(event).add(cb);
|
|
@@ -1702,15 +1685,6 @@ var RebaseWebSocketClient = class {
|
|
|
1702
1685
|
}
|
|
1703
1686
|
return;
|
|
1704
1687
|
}
|
|
1705
|
-
if (typeof message.channel === "string" && (type === "broadcast" || type === "presence_state" || type === "presence_diff")) {
|
|
1706
|
-
const handlers = this.channelHandlers.get(message.channel);
|
|
1707
|
-
if (handlers) for (const handler of [...handlers]) try {
|
|
1708
|
-
handler(message);
|
|
1709
|
-
} catch (error) {
|
|
1710
|
-
console.error("Error in channel handler:", error);
|
|
1711
|
-
}
|
|
1712
|
-
return;
|
|
1713
|
-
}
|
|
1714
1688
|
if (subscriptionId && type === "collection_update") {
|
|
1715
1689
|
const subscriptionKey = this.backendToCollectionKey.get(subscriptionId);
|
|
1716
1690
|
if (subscriptionKey) {
|
|
@@ -1899,10 +1873,6 @@ var RebaseWebSocketClient = class {
|
|
|
1899
1873
|
throw error;
|
|
1900
1874
|
}
|
|
1901
1875
|
}
|
|
1902
|
-
/**
|
|
1903
|
-
* Public because `RebaseRealtimeChannel` sends channel frames through it.
|
|
1904
|
-
* Not part of the stable surface — prefer `client.realtime.channel(name)`.
|
|
1905
|
-
*/
|
|
1906
1876
|
sendMessage(message) {
|
|
1907
1877
|
const queuedMsg = message;
|
|
1908
1878
|
if (queuedMsg._queuedResolve && queuedMsg._queuedReject) return this.doSendMessage(message, queuedMsg._queuedResolve, queuedMsg._queuedReject);
|
|
@@ -2483,190 +2453,6 @@ var RebaseWebSocketClient = class {
|
|
|
2483
2453
|
}
|
|
2484
2454
|
};
|
|
2485
2455
|
//#endregion
|
|
2486
|
-
//#region src/realtime-channel.ts
|
|
2487
|
-
/**
|
|
2488
|
-
* Re-send presence comfortably inside the server's 30s expiry.
|
|
2489
|
-
*
|
|
2490
|
-
* Two-thirds of the window: one lost heartbeat still leaves time for the next
|
|
2491
|
-
* before the entry is reaped, so a single dropped frame is not a disappearance.
|
|
2492
|
-
*/
|
|
2493
|
-
var PRESENCE_HEARTBEAT_MS = 2e4;
|
|
2494
|
-
var RebaseRealtimeChannel = class {
|
|
2495
|
-
name;
|
|
2496
|
-
transport;
|
|
2497
|
-
presenceHandlers = /* @__PURE__ */ new Set();
|
|
2498
|
-
broadcastHandlers = /* @__PURE__ */ new Set();
|
|
2499
|
-
unsubscribers = [];
|
|
2500
|
-
/** Last known roster, kept so handlers always get a full picture. */
|
|
2501
|
-
presences = {};
|
|
2502
|
-
/** What this client last tracked, replayed on reconnect and heartbeat. */
|
|
2503
|
-
trackedState = null;
|
|
2504
|
-
heartbeat = null;
|
|
2505
|
-
joined = false;
|
|
2506
|
-
constructor(name, transport) {
|
|
2507
|
-
this.name = name;
|
|
2508
|
-
this.transport = transport;
|
|
2509
|
-
}
|
|
2510
|
-
/**
|
|
2511
|
-
* Join the channel and ask for the current roster.
|
|
2512
|
-
*
|
|
2513
|
-
* Called automatically by `track`, `broadcast`, `onPresence` and
|
|
2514
|
-
* `onBroadcast`; calling it directly is only needed to start receiving
|
|
2515
|
-
* before there is anything to send.
|
|
2516
|
-
*/
|
|
2517
|
-
async join() {
|
|
2518
|
-
if (this.joined) return;
|
|
2519
|
-
this.joined = true;
|
|
2520
|
-
this.unsubscribers.push(this.transport.onChannelMessage(this.name, (message) => this.handle(message)));
|
|
2521
|
-
this.unsubscribers.push(this.transport.onReconnect(() => {
|
|
2522
|
-
this.rejoin();
|
|
2523
|
-
}));
|
|
2524
|
-
await this.transport.sendMessage({
|
|
2525
|
-
type: "join_channel",
|
|
2526
|
-
channel: this.name
|
|
2527
|
-
});
|
|
2528
|
-
await this.transport.sendMessage({
|
|
2529
|
-
type: "presence_state",
|
|
2530
|
-
channel: this.name
|
|
2531
|
-
});
|
|
2532
|
-
}
|
|
2533
|
-
async rejoin() {
|
|
2534
|
-
try {
|
|
2535
|
-
await this.transport.sendMessage({
|
|
2536
|
-
type: "join_channel",
|
|
2537
|
-
channel: this.name
|
|
2538
|
-
});
|
|
2539
|
-
await this.transport.sendMessage({
|
|
2540
|
-
type: "presence_state",
|
|
2541
|
-
channel: this.name
|
|
2542
|
-
});
|
|
2543
|
-
if (this.trackedState) await this.transport.sendMessage({
|
|
2544
|
-
type: "presence_track",
|
|
2545
|
-
channel: this.name,
|
|
2546
|
-
state: this.trackedState
|
|
2547
|
-
});
|
|
2548
|
-
} catch {}
|
|
2549
|
-
}
|
|
2550
|
-
/**
|
|
2551
|
-
* Publish this client's presence state, and keep publishing it.
|
|
2552
|
-
*
|
|
2553
|
-
* Calling `track` again replaces the state (and restarts the heartbeat),
|
|
2554
|
-
* which is how you update e.g. a cursor position.
|
|
2555
|
-
*/
|
|
2556
|
-
async track(state) {
|
|
2557
|
-
await this.join();
|
|
2558
|
-
this.trackedState = state;
|
|
2559
|
-
await this.transport.sendMessage({
|
|
2560
|
-
type: "presence_track",
|
|
2561
|
-
channel: this.name,
|
|
2562
|
-
state
|
|
2563
|
-
});
|
|
2564
|
-
if (!this.heartbeat) {
|
|
2565
|
-
this.heartbeat = setInterval(() => {
|
|
2566
|
-
if (!this.trackedState) return;
|
|
2567
|
-
this.transport.sendMessage({
|
|
2568
|
-
type: "presence_track",
|
|
2569
|
-
channel: this.name,
|
|
2570
|
-
state: this.trackedState
|
|
2571
|
-
}).catch(() => {});
|
|
2572
|
-
}, PRESENCE_HEARTBEAT_MS);
|
|
2573
|
-
this.heartbeat.unref?.();
|
|
2574
|
-
}
|
|
2575
|
-
}
|
|
2576
|
-
/** Stop publishing presence, without leaving the channel. */
|
|
2577
|
-
async untrack() {
|
|
2578
|
-
this.stopHeartbeat();
|
|
2579
|
-
this.trackedState = null;
|
|
2580
|
-
if (this.joined) await this.transport.sendMessage({
|
|
2581
|
-
type: "presence_untrack",
|
|
2582
|
-
channel: this.name
|
|
2583
|
-
});
|
|
2584
|
-
}
|
|
2585
|
-
/**
|
|
2586
|
-
* Observe the roster. The handler fires immediately with what is already
|
|
2587
|
-
* known, then on every change.
|
|
2588
|
-
*/
|
|
2589
|
-
onPresence(handler) {
|
|
2590
|
-
this.presenceHandlers.add(handler);
|
|
2591
|
-
this.join();
|
|
2592
|
-
if (Object.keys(this.presences).length > 0) handler({ ...this.presences });
|
|
2593
|
-
return () => this.presenceHandlers.delete(handler);
|
|
2594
|
-
}
|
|
2595
|
-
/** Send a broadcast. The sender does not receive its own message. */
|
|
2596
|
-
async broadcast(event, payload) {
|
|
2597
|
-
await this.join();
|
|
2598
|
-
await this.transport.sendMessage({
|
|
2599
|
-
type: "broadcast",
|
|
2600
|
-
channel: this.name,
|
|
2601
|
-
event,
|
|
2602
|
-
payload
|
|
2603
|
-
});
|
|
2604
|
-
}
|
|
2605
|
-
onBroadcast(eventOrHandler, maybeHandler) {
|
|
2606
|
-
const wrapped = typeof eventOrHandler === "string" ? (e) => {
|
|
2607
|
-
if (e.event === eventOrHandler) maybeHandler(e.payload);
|
|
2608
|
-
} : eventOrHandler;
|
|
2609
|
-
this.broadcastHandlers.add(wrapped);
|
|
2610
|
-
this.join();
|
|
2611
|
-
return () => this.broadcastHandlers.delete(wrapped);
|
|
2612
|
-
}
|
|
2613
|
-
/** Leave the channel and release every listener and timer. */
|
|
2614
|
-
async leave() {
|
|
2615
|
-
this.stopHeartbeat();
|
|
2616
|
-
this.trackedState = null;
|
|
2617
|
-
this.presences = {};
|
|
2618
|
-
this.presenceHandlers.clear();
|
|
2619
|
-
this.broadcastHandlers.clear();
|
|
2620
|
-
for (const off of this.unsubscribers) off();
|
|
2621
|
-
this.unsubscribers = [];
|
|
2622
|
-
if (this.joined) {
|
|
2623
|
-
this.joined = false;
|
|
2624
|
-
await this.transport.sendMessage({
|
|
2625
|
-
type: "leave_channel",
|
|
2626
|
-
channel: this.name
|
|
2627
|
-
});
|
|
2628
|
-
}
|
|
2629
|
-
}
|
|
2630
|
-
stopHeartbeat() {
|
|
2631
|
-
if (this.heartbeat) {
|
|
2632
|
-
clearInterval(this.heartbeat);
|
|
2633
|
-
this.heartbeat = null;
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
|
-
/** Fold an incoming frame into the roster and fan it out. */
|
|
2637
|
-
handle(message) {
|
|
2638
|
-
switch (message.type) {
|
|
2639
|
-
case "presence_state":
|
|
2640
|
-
this.presences = message.presences ?? {};
|
|
2641
|
-
this.emitPresence();
|
|
2642
|
-
break;
|
|
2643
|
-
case "presence_diff": {
|
|
2644
|
-
const joins = message.joins ?? {};
|
|
2645
|
-
const leaves = message.leaves ?? {};
|
|
2646
|
-
for (const [id, state] of Object.entries(joins)) this.presences[id] = state;
|
|
2647
|
-
for (const id of Object.keys(leaves)) delete this.presences[id];
|
|
2648
|
-
this.emitPresence({
|
|
2649
|
-
joins,
|
|
2650
|
-
leaves
|
|
2651
|
-
});
|
|
2652
|
-
break;
|
|
2653
|
-
}
|
|
2654
|
-
case "broadcast": {
|
|
2655
|
-
const event = {
|
|
2656
|
-
event: message.event,
|
|
2657
|
-
payload: message.payload
|
|
2658
|
-
};
|
|
2659
|
-
for (const handler of this.broadcastHandlers) handler(event);
|
|
2660
|
-
break;
|
|
2661
|
-
}
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
emitPresence(diff) {
|
|
2665
|
-
const snapshot = { ...this.presences };
|
|
2666
|
-
for (const handler of this.presenceHandlers) handler(snapshot, diff);
|
|
2667
|
-
}
|
|
2668
|
-
};
|
|
2669
|
-
//#endregion
|
|
2670
2456
|
//#region src/index.ts
|
|
2671
2457
|
/**
|
|
2672
2458
|
* Derive a WebSocket URL from an HTTP base URL.
|
|
@@ -2717,8 +2503,6 @@ function createRebaseClient(options) {
|
|
|
2717
2503
|
};
|
|
2718
2504
|
const resolvedWsUrl = options.realtime !== false ? options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl) : void 0;
|
|
2719
2505
|
let ws;
|
|
2720
|
-
/** One channel object per name — see `realtime.channel`. */
|
|
2721
|
-
const realtimeChannels = /* @__PURE__ */ new Map();
|
|
2722
2506
|
if (resolvedWsUrl) {
|
|
2723
2507
|
ws = new RebaseWebSocketClient({
|
|
2724
2508
|
websocketUrl: resolvedWsUrl,
|
|
@@ -2829,24 +2613,6 @@ function createRebaseClient(options) {
|
|
|
2829
2613
|
createStorageSource,
|
|
2830
2614
|
fetchStorageSources,
|
|
2831
2615
|
ws,
|
|
2832
|
-
realtime: {
|
|
2833
|
-
/**
|
|
2834
|
-
* Join a broadcast/presence channel.
|
|
2835
|
-
*
|
|
2836
|
-
* Repeated calls with the same name return the same channel, so
|
|
2837
|
-
* separate components can attach handlers without each opening its
|
|
2838
|
-
* own membership — and `leave()` from one would otherwise silently
|
|
2839
|
-
* cut off the others.
|
|
2840
|
-
*/
|
|
2841
|
-
channel: (name) => {
|
|
2842
|
-
if (!ws) throw new RebaseClientError("Realtime is disabled on this client (realtime: false), so channels are unavailable.");
|
|
2843
|
-
let existing = realtimeChannels.get(name);
|
|
2844
|
-
if (!existing) {
|
|
2845
|
-
existing = new RebaseRealtimeChannel(name, ws);
|
|
2846
|
-
realtimeChannels.set(name, existing);
|
|
2847
|
-
}
|
|
2848
|
-
return existing;
|
|
2849
|
-
} },
|
|
2850
2616
|
/**
|
|
2851
2617
|
* Release the realtime socket and its reconnect timer.
|
|
2852
2618
|
*
|
|
@@ -2855,8 +2621,6 @@ channel: (name) => {
|
|
|
2855
2621
|
* was never started, and safe to call twice.
|
|
2856
2622
|
*/
|
|
2857
2623
|
close: () => {
|
|
2858
|
-
for (const channel of realtimeChannels.values()) channel.leave();
|
|
2859
|
-
realtimeChannels.clear();
|
|
2860
2624
|
ws?.disconnect();
|
|
2861
2625
|
},
|
|
2862
2626
|
setToken: transport.setToken,
|
|
@@ -2877,6 +2641,6 @@ channel: (name) => {
|
|
|
2877
2641
|
};
|
|
2878
2642
|
}
|
|
2879
2643
|
//#endregion
|
|
2880
|
-
export { QueryBuilder, RebaseApiError, RebaseClientError,
|
|
2644
|
+
export { QueryBuilder, RebaseApiError, RebaseClientError, RebaseWebSocketClient, and, cond, createBackups, createCookieStorage, createMemoryStorage, createRebaseClient, or };
|
|
2881
2645
|
|
|
2882
2646
|
//# sourceMappingURL=index.es.js.map
|