@leonardssh/use-lanyard
Version:
🚀 Lanyard with Composition API for Vue
234 lines (221 loc) • 7.97 kB
JavaScript
var LeonardsshUseLanyard = (function (exports, vueDemi) {
'use strict';
const API_URL = 'https://api.lanyard.rest/v1';
const WEBSOCKET_URL = 'wss://api.lanyard.rest/socket';
const isClient = typeof window !== 'undefined';
/**
* Call onUnmounted() if it's inside a component lifecycle, if not, do nothing
*
* @param fn
*/
function tryOnUnmounted(fn) {
if (vueDemi.getCurrentInstance())
vueDemi.onUnmounted(fn);
}
/**
* Wrapper for `setInterval` with controls
*
* @param cb
* @param interval
* @param options
*/
function useIntervalFn(cb, interval = 1000, options = {}) {
const { immediate = true, immediateCallback = false, } = options;
let timer = null;
const isActive = vueDemi.ref(false);
function clean() {
if (timer) {
clearInterval(timer);
timer = null;
}
}
function pause() {
isActive.value = false;
clean();
}
function resume() {
if (interval <= 0)
return;
isActive.value = true;
if (immediateCallback)
cb();
clean();
timer = setInterval(cb, interval);
}
if (immediate && isClient)
resume();
tryOnUnmounted(pause);
return {
isActive,
pause,
resume,
};
}
isClient ? window : undefined;
isClient ? window.document : undefined;
isClient ? window.navigator : undefined;
var SwipeDirection;
(function (SwipeDirection) {
SwipeDirection["UP"] = "UP";
SwipeDirection["RIGHT"] = "RIGHT";
SwipeDirection["DOWN"] = "DOWN";
SwipeDirection["LEFT"] = "LEFT";
SwipeDirection["NONE"] = "NONE";
})(SwipeDirection || (SwipeDirection = {}));
function resolveNestedOptions(options) {
if (options === true)
return {};
return options;
}
/**
* Reactive WebSocket client.
*
* @see https://vueuse.org/useWebSocket
* @param url
*/
function useWebSocket(url, options = {}) {
const { onConnected, onDisconnected, onError, onMessage, immediate = true, } = options;
const data = vueDemi.ref(null);
const status = vueDemi.ref('CONNECTING');
const wsRef = vueDemi.ref();
let heartbeatPause;
let heartbeatResume;
let explicitlyClosed = false;
let retried = 0;
let bufferedData = [];
const close = (code, reason) => {
if (!wsRef.value)
return;
explicitlyClosed = true;
heartbeatPause === null || heartbeatPause === void 0 ? void 0 : heartbeatPause();
wsRef.value.close(code, reason);
};
const _sendBuffer = () => {
if (bufferedData.length && wsRef.value && status.value === 'OPEN') {
for (const buffer of bufferedData)
wsRef.value.send(buffer);
bufferedData = [];
}
};
const send = (data, useBuffer = true) => {
if (!wsRef.value || status.value !== 'OPEN') {
if (useBuffer)
bufferedData.push(data);
return false;
}
_sendBuffer();
wsRef.value.send(data);
return true;
};
const _init = () => {
const ws = new WebSocket(url);
wsRef.value = ws;
status.value = 'CONNECTING';
explicitlyClosed = false;
ws.onopen = () => {
status.value = 'OPEN';
onConnected === null || onConnected === void 0 ? void 0 : onConnected(ws);
heartbeatResume === null || heartbeatResume === void 0 ? void 0 : heartbeatResume();
_sendBuffer();
};
ws.onclose = (ev) => {
status.value = 'CLOSED';
wsRef.value = undefined;
onDisconnected === null || onDisconnected === void 0 ? void 0 : onDisconnected(ws, ev);
if (!explicitlyClosed && options.autoReconnect) {
const { retries = -1, delay = 1000, onFailed, } = resolveNestedOptions(options.autoReconnect);
retried += 1;
if (retries < 0 || retried < retries)
setTimeout(_init, delay);
else
onFailed === null || onFailed === void 0 ? void 0 : onFailed();
}
};
ws.onerror = (e) => {
onError === null || onError === void 0 ? void 0 : onError(ws, e);
};
ws.onmessage = (e) => {
data.value = e.data;
onMessage === null || onMessage === void 0 ? void 0 : onMessage(ws, e);
};
};
if (options.heartbeat) {
const { message = 'ping', interval = 1000, } = resolveNestedOptions(options.heartbeat);
const { pause, resume } = useIntervalFn(() => send(message, false), interval, { immediate: false });
heartbeatPause = pause;
heartbeatResume = resume;
}
if (immediate)
_init();
const open = () => {
close();
retried = 0;
_init();
};
tryOnUnmounted(close);
return {
data,
status,
close,
send,
open,
ws: wsRef,
};
}
async function useLanyard(options) {
if (Reflect.has(options, 'socket')) {
const { socket, onPresenceUpdate } = options;
const supportsWebSockets = 'WebSocket' in window || 'MozWebSocket' in window;
if (socket && !supportsWebSockets) {
throw new Error("Browser doesn't support WebSocket connections.");
}
const subscription = typeof options.userId === 'object'
? 'subscribe_to_ids'
: 'subscribe_to_id';
useWebSocket(WEBSOCKET_URL, {
heartbeat: {
interval: 30 * 1000,
message: JSON.stringify({ op: 3 })
},
onMessage(_, e) {
const { t, d } = JSON.parse(e.data);
if (t === 'INIT_STATE' || t === 'PRESENCE_UPDATE') {
onPresenceUpdate?.(d || {});
}
},
onConnected(ws) {
ws.send(JSON.stringify({
op: 2,
d: {
[subscription]: options.userId
}
}));
}
});
return;
}
if (typeof options.userId === 'string') {
const req = await fetch(`${API_URL}/users/${options.userId}`);
const body = (await req.json());
if (body.error) {
throw new Error(body.error.message);
}
return body;
}
const responseArray = [];
for (const id of options.userId) {
const req = await fetch(`${API_URL}/users/${id}`);
const body = (await req.json());
if (body.error) {
throw new Error(body.error.message);
}
responseArray.push(body);
}
return responseArray;
}
exports.API_URL = API_URL;
exports.WEBSOCKET_URL = WEBSOCKET_URL;
exports.useLanyard = useLanyard;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
}({}, VueDemi));