@sesionario/blocks 1.13.0 → 1.14.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/dist/index.cjs +169 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +169 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1123,8 +1123,12 @@ type UseRealtimeChannelOptions = {
|
|
|
1123
1123
|
};
|
|
1124
1124
|
/**
|
|
1125
1125
|
* Subscribe to a realtime-svc channel WebSocket.
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
1126
|
+
* Components on the same channel share one socket (ref-counted; closed when
|
|
1127
|
+
* the last subscriber unmounts). Reconnects with exponential backoff and
|
|
1128
|
+
* refreshes the URL (token) on each attempt; if the URL resolves null the
|
|
1129
|
+
* connection goes idle until the tab becomes visible again.
|
|
1130
|
+
* Treats events as invalidation signals — callers should re-fetch
|
|
1131
|
+
* authoritative data.
|
|
1128
1132
|
*/
|
|
1129
1133
|
declare function useRealtimeChannel({ getWsUrl, onEvent, enabled, reconnectDelayMs, }: UseRealtimeChannelOptions): void;
|
|
1130
1134
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1123,8 +1123,12 @@ type UseRealtimeChannelOptions = {
|
|
|
1123
1123
|
};
|
|
1124
1124
|
/**
|
|
1125
1125
|
* Subscribe to a realtime-svc channel WebSocket.
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
1126
|
+
* Components on the same channel share one socket (ref-counted; closed when
|
|
1127
|
+
* the last subscriber unmounts). Reconnects with exponential backoff and
|
|
1128
|
+
* refreshes the URL (token) on each attempt; if the URL resolves null the
|
|
1129
|
+
* connection goes idle until the tab becomes visible again.
|
|
1130
|
+
* Treats events as invalidation signals — callers should re-fetch
|
|
1131
|
+
* authoritative data.
|
|
1128
1132
|
*/
|
|
1129
1133
|
declare function useRealtimeChannel({ getWsUrl, onEvent, enabled, reconnectDelayMs, }: UseRealtimeChannelOptions): void;
|
|
1130
1134
|
|
package/dist/index.js
CHANGED
|
@@ -6154,7 +6154,7 @@ function MessageScrollerButton({
|
|
|
6154
6154
|
"data-size": size,
|
|
6155
6155
|
direction,
|
|
6156
6156
|
className: cn(
|
|
6157
|
-
"absolute
|
|
6157
|
+
"absolute left-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full data-[direction=start]:[&_svg]:rotate-180",
|
|
6158
6158
|
className
|
|
6159
6159
|
),
|
|
6160
6160
|
render: render ?? /* @__PURE__ */ jsx(Button, { variant, size }),
|
|
@@ -6954,6 +6954,162 @@ function createSupportChatClient(basePath = "/api/chat-svc") {
|
|
|
6954
6954
|
}
|
|
6955
6955
|
var DEFAULT_RECONNECT_MS = 2e3;
|
|
6956
6956
|
var MAX_RECONNECT_MS = 3e4;
|
|
6957
|
+
var HEARTBEAT_MS = 3e4;
|
|
6958
|
+
var registry = /* @__PURE__ */ new Map();
|
|
6959
|
+
function channelKeyFromUrl(url) {
|
|
6960
|
+
const q = url.indexOf("?");
|
|
6961
|
+
return q === -1 ? url : url.slice(0, q);
|
|
6962
|
+
}
|
|
6963
|
+
function stopHeartbeat(shared) {
|
|
6964
|
+
if (shared.heartbeatTimer) {
|
|
6965
|
+
clearInterval(shared.heartbeatTimer);
|
|
6966
|
+
shared.heartbeatTimer = null;
|
|
6967
|
+
}
|
|
6968
|
+
}
|
|
6969
|
+
function startHeartbeat(shared, gen) {
|
|
6970
|
+
stopHeartbeat(shared);
|
|
6971
|
+
shared.heartbeatTimer = setInterval(() => {
|
|
6972
|
+
if (gen !== shared.gen) return;
|
|
6973
|
+
if (shared.ws?.readyState === WebSocket.OPEN) {
|
|
6974
|
+
try {
|
|
6975
|
+
shared.ws.send("ping");
|
|
6976
|
+
} catch {
|
|
6977
|
+
}
|
|
6978
|
+
}
|
|
6979
|
+
}, HEARTBEAT_MS);
|
|
6980
|
+
}
|
|
6981
|
+
function clearReconnect(shared) {
|
|
6982
|
+
if (shared.reconnectTimer) {
|
|
6983
|
+
clearTimeout(shared.reconnectTimer);
|
|
6984
|
+
shared.reconnectTimer = null;
|
|
6985
|
+
}
|
|
6986
|
+
}
|
|
6987
|
+
function openSocket(shared, url) {
|
|
6988
|
+
const gen = ++shared.gen;
|
|
6989
|
+
clearReconnect(shared);
|
|
6990
|
+
if (shared.ws) {
|
|
6991
|
+
try {
|
|
6992
|
+
shared.ws.close();
|
|
6993
|
+
} catch {
|
|
6994
|
+
}
|
|
6995
|
+
}
|
|
6996
|
+
const ws = new WebSocket(url);
|
|
6997
|
+
shared.ws = ws;
|
|
6998
|
+
ws.onopen = () => {
|
|
6999
|
+
if (gen !== shared.gen) return;
|
|
7000
|
+
shared.attempt = 0;
|
|
7001
|
+
startHeartbeat(shared, gen);
|
|
7002
|
+
};
|
|
7003
|
+
ws.onmessage = (msg) => {
|
|
7004
|
+
if (gen !== shared.gen) return;
|
|
7005
|
+
let data;
|
|
7006
|
+
try {
|
|
7007
|
+
data = JSON.parse(String(msg.data));
|
|
7008
|
+
} catch {
|
|
7009
|
+
return;
|
|
7010
|
+
}
|
|
7011
|
+
if (typeof data?.type !== "string") return;
|
|
7012
|
+
if (data.type === "pong") return;
|
|
7013
|
+
for (const listener of shared.listeners) {
|
|
7014
|
+
listener(data);
|
|
7015
|
+
}
|
|
7016
|
+
};
|
|
7017
|
+
ws.onclose = () => {
|
|
7018
|
+
if (gen !== shared.gen) return;
|
|
7019
|
+
shared.ws = null;
|
|
7020
|
+
stopHeartbeat(shared);
|
|
7021
|
+
scheduleReconnect(shared);
|
|
7022
|
+
};
|
|
7023
|
+
ws.onerror = () => {
|
|
7024
|
+
};
|
|
7025
|
+
}
|
|
7026
|
+
function scheduleReconnect(shared) {
|
|
7027
|
+
if (shared.listeners.size === 0) return;
|
|
7028
|
+
clearReconnect(shared);
|
|
7029
|
+
const delay = Math.min(
|
|
7030
|
+
shared.reconnectDelayMs * 2 ** shared.attempt,
|
|
7031
|
+
MAX_RECONNECT_MS
|
|
7032
|
+
);
|
|
7033
|
+
shared.attempt += 1;
|
|
7034
|
+
shared.reconnectTimer = setTimeout(() => {
|
|
7035
|
+
shared.reconnectTimer = null;
|
|
7036
|
+
void connectShared(shared);
|
|
7037
|
+
}, delay);
|
|
7038
|
+
}
|
|
7039
|
+
async function connectShared(shared) {
|
|
7040
|
+
if (shared.connecting || shared.listeners.size === 0) return;
|
|
7041
|
+
shared.connecting = true;
|
|
7042
|
+
let url = null;
|
|
7043
|
+
try {
|
|
7044
|
+
url = await shared.getWsUrl();
|
|
7045
|
+
} finally {
|
|
7046
|
+
shared.connecting = false;
|
|
7047
|
+
}
|
|
7048
|
+
if (shared.listeners.size === 0) return;
|
|
7049
|
+
if (!url) return;
|
|
7050
|
+
openSocket(shared, url);
|
|
7051
|
+
}
|
|
7052
|
+
function destroyShared(shared) {
|
|
7053
|
+
shared.gen += 1;
|
|
7054
|
+
clearReconnect(shared);
|
|
7055
|
+
stopHeartbeat(shared);
|
|
7056
|
+
if (shared.ws) {
|
|
7057
|
+
try {
|
|
7058
|
+
shared.ws.close();
|
|
7059
|
+
} catch {
|
|
7060
|
+
}
|
|
7061
|
+
shared.ws = null;
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
function joinChannel(key, url, getWsUrl, reconnectDelayMs, listener) {
|
|
7065
|
+
ensureVisibilityHook();
|
|
7066
|
+
let shared = registry.get(key);
|
|
7067
|
+
if (!shared) {
|
|
7068
|
+
shared = {
|
|
7069
|
+
key,
|
|
7070
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
7071
|
+
getWsUrl,
|
|
7072
|
+
reconnectDelayMs,
|
|
7073
|
+
ws: null,
|
|
7074
|
+
attempt: 0,
|
|
7075
|
+
reconnectTimer: null,
|
|
7076
|
+
heartbeatTimer: null,
|
|
7077
|
+
connecting: false,
|
|
7078
|
+
gen: 0
|
|
7079
|
+
};
|
|
7080
|
+
registry.set(key, shared);
|
|
7081
|
+
shared.listeners.add(listener);
|
|
7082
|
+
openSocket(shared, url);
|
|
7083
|
+
return;
|
|
7084
|
+
}
|
|
7085
|
+
shared.getWsUrl = getWsUrl;
|
|
7086
|
+
shared.listeners.add(listener);
|
|
7087
|
+
if (!shared.ws && !shared.connecting && !shared.reconnectTimer) {
|
|
7088
|
+
openSocket(shared, url);
|
|
7089
|
+
}
|
|
7090
|
+
}
|
|
7091
|
+
function leaveChannel(key, listener) {
|
|
7092
|
+
const shared = registry.get(key);
|
|
7093
|
+
if (!shared) return;
|
|
7094
|
+
shared.listeners.delete(listener);
|
|
7095
|
+
if (shared.listeners.size === 0) {
|
|
7096
|
+
destroyShared(shared);
|
|
7097
|
+
registry.delete(key);
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
var visibilityHooked = false;
|
|
7101
|
+
function ensureVisibilityHook() {
|
|
7102
|
+
if (visibilityHooked || typeof document === "undefined") return;
|
|
7103
|
+
visibilityHooked = true;
|
|
7104
|
+
document.addEventListener("visibilitychange", () => {
|
|
7105
|
+
if (document.visibilityState !== "visible") return;
|
|
7106
|
+
for (const shared of registry.values()) {
|
|
7107
|
+
if (!shared.ws && !shared.reconnectTimer && !shared.connecting) {
|
|
7108
|
+
void connectShared(shared);
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
});
|
|
7112
|
+
}
|
|
6957
7113
|
function useRealtimeChannel({
|
|
6958
7114
|
getWsUrl,
|
|
6959
7115
|
onEvent,
|
|
@@ -6967,87 +7123,26 @@ function useRealtimeChannel({
|
|
|
6967
7123
|
useEffect(() => {
|
|
6968
7124
|
if (!enabled) return;
|
|
6969
7125
|
let cancelled = false;
|
|
6970
|
-
let
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
const
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
};
|
|
6980
|
-
const scheduleReconnect = () => {
|
|
6981
|
-
if (cancelled) return;
|
|
6982
|
-
clearReconnect();
|
|
6983
|
-
const delay = Math.min(reconnectDelayMs * 2 ** attempt, MAX_RECONNECT_MS);
|
|
6984
|
-
attempt += 1;
|
|
6985
|
-
reconnectTimer = setTimeout(() => {
|
|
6986
|
-
void connect();
|
|
6987
|
-
}, delay);
|
|
6988
|
-
};
|
|
6989
|
-
const connect = async () => {
|
|
6990
|
-
const gen = ++connectGen.current;
|
|
6991
|
-
clearReconnect();
|
|
6992
|
-
const url = await getWsUrlRef.current();
|
|
6993
|
-
if (cancelled || gen !== connectGen.current) return;
|
|
6994
|
-
if (!url) {
|
|
6995
|
-
scheduleReconnect();
|
|
6996
|
-
return;
|
|
6997
|
-
}
|
|
6998
|
-
if (socket) {
|
|
6999
|
-
try {
|
|
7000
|
-
socket.close();
|
|
7001
|
-
} catch {
|
|
7002
|
-
}
|
|
7003
|
-
socket = null;
|
|
7004
|
-
}
|
|
7005
|
-
const ws = new WebSocket(url);
|
|
7006
|
-
socket = ws;
|
|
7007
|
-
ws.onopen = () => {
|
|
7008
|
-
if (cancelled || gen !== connectGen.current) return;
|
|
7009
|
-
attempt = 0;
|
|
7010
|
-
};
|
|
7011
|
-
ws.onmessage = (msg) => {
|
|
7012
|
-
if (cancelled || gen !== connectGen.current) return;
|
|
7013
|
-
let data;
|
|
7014
|
-
try {
|
|
7015
|
-
data = JSON.parse(String(msg.data));
|
|
7016
|
-
} catch {
|
|
7017
|
-
return;
|
|
7018
|
-
}
|
|
7019
|
-
if (typeof data?.type !== "string") return;
|
|
7020
|
-
if (data.type === "pong") return;
|
|
7021
|
-
onEventRef.current(data);
|
|
7022
|
-
};
|
|
7023
|
-
ws.onclose = () => {
|
|
7024
|
-
if (cancelled || gen !== connectGen.current) return;
|
|
7025
|
-
socket = null;
|
|
7026
|
-
scheduleReconnect();
|
|
7027
|
-
};
|
|
7028
|
-
ws.onerror = () => {
|
|
7029
|
-
};
|
|
7126
|
+
let joinedKey = null;
|
|
7127
|
+
const listener = (event) => onEventRef.current(event);
|
|
7128
|
+
const resolver = () => getWsUrlRef.current();
|
|
7129
|
+
const join = async () => {
|
|
7130
|
+
if (cancelled || joinedKey) return;
|
|
7131
|
+
const url = await resolver();
|
|
7132
|
+
if (cancelled || !url) return;
|
|
7133
|
+
joinedKey = channelKeyFromUrl(url);
|
|
7134
|
+
joinChannel(joinedKey, url, resolver, reconnectDelayMs, listener);
|
|
7030
7135
|
};
|
|
7031
7136
|
const onVisibility = () => {
|
|
7032
7137
|
if (document.visibilityState !== "visible" || cancelled) return;
|
|
7033
|
-
if (!
|
|
7034
|
-
void connect();
|
|
7035
|
-
}
|
|
7138
|
+
if (!joinedKey) void join();
|
|
7036
7139
|
};
|
|
7037
|
-
void
|
|
7140
|
+
void join();
|
|
7038
7141
|
document.addEventListener("visibilitychange", onVisibility);
|
|
7039
7142
|
return () => {
|
|
7040
7143
|
cancelled = true;
|
|
7041
|
-
connectGen.current += 1;
|
|
7042
|
-
clearReconnect();
|
|
7043
7144
|
document.removeEventListener("visibilitychange", onVisibility);
|
|
7044
|
-
if (
|
|
7045
|
-
try {
|
|
7046
|
-
socket.close();
|
|
7047
|
-
} catch {
|
|
7048
|
-
}
|
|
7049
|
-
socket = null;
|
|
7050
|
-
}
|
|
7145
|
+
if (joinedKey) leaveChannel(joinedKey, listener);
|
|
7051
7146
|
};
|
|
7052
7147
|
}, [enabled, reconnectDelayMs]);
|
|
7053
7148
|
}
|