main repo

This commit is contained in:
Basilosaurusrex
2025-11-24 18:09:40 +01:00
parent b636ee5e70
commit f027651f9b
34146 changed files with 4436636 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
import { CHANNEL_STATES } from './lib/constants';
import Push from './lib/push';
import type RealtimeClient from './RealtimeClient';
import Timer from './lib/timer';
import RealtimePresence, { REALTIME_PRESENCE_LISTEN_EVENTS } from './RealtimePresence';
import type { RealtimePresenceJoinPayload, RealtimePresenceLeavePayload, RealtimePresenceState } from './RealtimePresence';
export type RealtimeChannelOptions = {
config: {
/**
* self option enables client to receive message it broadcast
* ack option instructs server to acknowledge that broadcast message was received
*/
broadcast?: {
self?: boolean;
ack?: boolean;
};
/**
* key option is used to track presence payload across clients
*/
presence?: {
key?: string;
};
/**
* defines if the channel is private or not and if RLS policies will be used to check data
*/
private?: boolean;
};
};
type RealtimePostgresChangesPayloadBase = {
schema: string;
table: string;
commit_timestamp: string;
errors: string[];
};
export type RealtimePostgresInsertPayload<T extends {
[key: string]: any;
}> = RealtimePostgresChangesPayloadBase & {
eventType: `${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.INSERT}`;
new: T;
old: {};
};
export type RealtimePostgresUpdatePayload<T extends {
[key: string]: any;
}> = RealtimePostgresChangesPayloadBase & {
eventType: `${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.UPDATE}`;
new: T;
old: Partial<T>;
};
export type RealtimePostgresDeletePayload<T extends {
[key: string]: any;
}> = RealtimePostgresChangesPayloadBase & {
eventType: `${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.DELETE}`;
new: {};
old: Partial<T>;
};
export type RealtimePostgresChangesPayload<T extends {
[key: string]: any;
}> = RealtimePostgresInsertPayload<T> | RealtimePostgresUpdatePayload<T> | RealtimePostgresDeletePayload<T>;
export type RealtimePostgresChangesFilter<T extends `${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT}`> = {
/**
* The type of database change to listen to.
*/
event: T;
/**
* The database schema to listen to.
*/
schema: string;
/**
* The database table to listen to.
*/
table?: string;
/**
* Receive database changes when filter is matched.
*/
filter?: string;
};
export type RealtimeChannelSendResponse = 'ok' | 'timed out' | 'error';
export declare enum REALTIME_POSTGRES_CHANGES_LISTEN_EVENT {
ALL = "*",
INSERT = "INSERT",
UPDATE = "UPDATE",
DELETE = "DELETE"
}
export declare enum REALTIME_LISTEN_TYPES {
BROADCAST = "broadcast",
PRESENCE = "presence",
POSTGRES_CHANGES = "postgres_changes",
SYSTEM = "system"
}
export declare enum REALTIME_SUBSCRIBE_STATES {
SUBSCRIBED = "SUBSCRIBED",
TIMED_OUT = "TIMED_OUT",
CLOSED = "CLOSED",
CHANNEL_ERROR = "CHANNEL_ERROR"
}
export declare const REALTIME_CHANNEL_STATES: typeof CHANNEL_STATES;
/** A channel is the basic building block of Realtime
* and narrows the scope of data flow to subscribed clients.
* You can think of a channel as a chatroom where participants are able to see who's online
* and send and receive messages.
*/
export default class RealtimeChannel {
/** Topic name can be any string. */
topic: string;
params: RealtimeChannelOptions;
socket: RealtimeClient;
bindings: {
[key: string]: {
type: string;
filter: {
[key: string]: any;
};
callback: Function;
id?: string;
}[];
};
timeout: number;
state: CHANNEL_STATES;
joinedOnce: boolean;
joinPush: Push;
rejoinTimer: Timer;
pushBuffer: Push[];
presence: RealtimePresence;
broadcastEndpointURL: string;
subTopic: string;
private: boolean;
constructor(
/** Topic name can be any string. */
topic: string, params: RealtimeChannelOptions | undefined, socket: RealtimeClient);
/** Subscribe registers your client with the server */
subscribe(callback?: (status: REALTIME_SUBSCRIBE_STATES, err?: Error) => void, timeout?: number): RealtimeChannel;
presenceState<T extends {
[key: string]: any;
} = {}>(): RealtimePresenceState<T>;
track(payload: {
[key: string]: any;
}, opts?: {
[key: string]: any;
}): Promise<RealtimeChannelSendResponse>;
untrack(opts?: {
[key: string]: any;
}): Promise<RealtimeChannelSendResponse>;
/**
* Creates an event handler that listens to changes.
*/
on(type: `${REALTIME_LISTEN_TYPES.PRESENCE}`, filter: {
event: `${REALTIME_PRESENCE_LISTEN_EVENTS.SYNC}`;
}, callback: () => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.PRESENCE}`, filter: {
event: `${REALTIME_PRESENCE_LISTEN_EVENTS.JOIN}`;
}, callback: (payload: RealtimePresenceJoinPayload<T>) => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.PRESENCE}`, filter: {
event: `${REALTIME_PRESENCE_LISTEN_EVENTS.LEAVE}`;
}, callback: (payload: RealtimePresenceLeavePayload<T>) => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.POSTGRES_CHANGES}`, filter: RealtimePostgresChangesFilter<`${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.ALL}`>, callback: (payload: RealtimePostgresChangesPayload<T>) => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.POSTGRES_CHANGES}`, filter: RealtimePostgresChangesFilter<`${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.INSERT}`>, callback: (payload: RealtimePostgresInsertPayload<T>) => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.POSTGRES_CHANGES}`, filter: RealtimePostgresChangesFilter<`${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.UPDATE}`>, callback: (payload: RealtimePostgresUpdatePayload<T>) => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.POSTGRES_CHANGES}`, filter: RealtimePostgresChangesFilter<`${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.DELETE}`>, callback: (payload: RealtimePostgresDeletePayload<T>) => void): RealtimeChannel;
/**
* The following is placed here to display on supabase.com/docs/reference/javascript/subscribe.
* @param type One of "broadcast", "presence", or "postgres_changes".
* @param filter Custom object specific to the Realtime feature detailing which payloads to receive.
* @param callback Function to be invoked when event handler is triggered.
*/
on(type: `${REALTIME_LISTEN_TYPES.BROADCAST}`, filter: {
event: string;
}, callback: (payload: {
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`;
event: string;
[key: string]: any;
}) => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.BROADCAST}`, filter: {
event: string;
}, callback: (payload: {
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`;
event: string;
payload: T;
}) => void): RealtimeChannel;
on<T extends {
[key: string]: any;
}>(type: `${REALTIME_LISTEN_TYPES.SYSTEM}`, filter: {}, callback: (payload: any) => void): RealtimeChannel;
/**
* Sends a message into the channel.
*
* @param args Arguments to send to channel
* @param args.type The type of event to send
* @param args.event The name of the event being sent
* @param args.payload Payload to be sent
* @param opts Options to be used during the send process
*/
send(args: {
type: 'broadcast' | 'presence' | 'postgres_changes';
event: string;
payload?: any;
[key: string]: any;
}, opts?: {
[key: string]: any;
}): Promise<RealtimeChannelSendResponse>;
updateJoinPayload(payload: {
[key: string]: any;
}): void;
/**
* Leaves the channel.
*
* Unsubscribes from server events, and instructs channel to terminate on server.
* Triggers onClose() hooks.
*
* To receive leave acknowledgements, use the a `receive` hook to bind to the server ack, ie:
* channel.unsubscribe().receive("ok", () => alert("left!") )
*/
unsubscribe(timeout?: number): Promise<'ok' | 'timed out' | 'error'>;
/**
* Teardown the channel.
*
* Destroys and stops related timers.
*/
teardown(): void;
}
export {};
//# sourceMappingURL=RealtimeChannel.d.ts.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,548 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.REALTIME_CHANNEL_STATES = exports.REALTIME_SUBSCRIBE_STATES = exports.REALTIME_LISTEN_TYPES = exports.REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = void 0;
const constants_1 = require("./lib/constants");
const push_1 = __importDefault(require("./lib/push"));
const timer_1 = __importDefault(require("./lib/timer"));
const RealtimePresence_1 = __importDefault(require("./RealtimePresence"));
const Transformers = __importStar(require("./lib/transformers"));
const transformers_1 = require("./lib/transformers");
var REALTIME_POSTGRES_CHANGES_LISTEN_EVENT;
(function (REALTIME_POSTGRES_CHANGES_LISTEN_EVENT) {
REALTIME_POSTGRES_CHANGES_LISTEN_EVENT["ALL"] = "*";
REALTIME_POSTGRES_CHANGES_LISTEN_EVENT["INSERT"] = "INSERT";
REALTIME_POSTGRES_CHANGES_LISTEN_EVENT["UPDATE"] = "UPDATE";
REALTIME_POSTGRES_CHANGES_LISTEN_EVENT["DELETE"] = "DELETE";
})(REALTIME_POSTGRES_CHANGES_LISTEN_EVENT || (exports.REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = {}));
var REALTIME_LISTEN_TYPES;
(function (REALTIME_LISTEN_TYPES) {
REALTIME_LISTEN_TYPES["BROADCAST"] = "broadcast";
REALTIME_LISTEN_TYPES["PRESENCE"] = "presence";
REALTIME_LISTEN_TYPES["POSTGRES_CHANGES"] = "postgres_changes";
REALTIME_LISTEN_TYPES["SYSTEM"] = "system";
})(REALTIME_LISTEN_TYPES || (exports.REALTIME_LISTEN_TYPES = REALTIME_LISTEN_TYPES = {}));
var REALTIME_SUBSCRIBE_STATES;
(function (REALTIME_SUBSCRIBE_STATES) {
REALTIME_SUBSCRIBE_STATES["SUBSCRIBED"] = "SUBSCRIBED";
REALTIME_SUBSCRIBE_STATES["TIMED_OUT"] = "TIMED_OUT";
REALTIME_SUBSCRIBE_STATES["CLOSED"] = "CLOSED";
REALTIME_SUBSCRIBE_STATES["CHANNEL_ERROR"] = "CHANNEL_ERROR";
})(REALTIME_SUBSCRIBE_STATES || (exports.REALTIME_SUBSCRIBE_STATES = REALTIME_SUBSCRIBE_STATES = {}));
exports.REALTIME_CHANNEL_STATES = constants_1.CHANNEL_STATES;
/** A channel is the basic building block of Realtime
* and narrows the scope of data flow to subscribed clients.
* You can think of a channel as a chatroom where participants are able to see who's online
* and send and receive messages.
*/
class RealtimeChannel {
constructor(
/** Topic name can be any string. */
topic, params = { config: {} }, socket) {
this.topic = topic;
this.params = params;
this.socket = socket;
this.bindings = {};
this.state = constants_1.CHANNEL_STATES.closed;
this.joinedOnce = false;
this.pushBuffer = [];
this.subTopic = topic.replace(/^realtime:/i, '');
this.params.config = Object.assign({
broadcast: { ack: false, self: false },
presence: { key: '' },
private: false,
}, params.config);
this.timeout = this.socket.timeout;
this.joinPush = new push_1.default(this, constants_1.CHANNEL_EVENTS.join, this.params, this.timeout);
this.rejoinTimer = new timer_1.default(() => this._rejoinUntilConnected(), this.socket.reconnectAfterMs);
this.joinPush.receive('ok', () => {
this.state = constants_1.CHANNEL_STATES.joined;
this.rejoinTimer.reset();
this.pushBuffer.forEach((pushEvent) => pushEvent.send());
this.pushBuffer = [];
});
this._onClose(() => {
this.rejoinTimer.reset();
this.socket.log('channel', `close ${this.topic} ${this._joinRef()}`);
this.state = constants_1.CHANNEL_STATES.closed;
this.socket._remove(this);
});
this._onError((reason) => {
if (this._isLeaving() || this._isClosed()) {
return;
}
this.socket.log('channel', `error ${this.topic}`, reason);
this.state = constants_1.CHANNEL_STATES.errored;
this.rejoinTimer.scheduleTimeout();
});
this.joinPush.receive('timeout', () => {
if (!this._isJoining()) {
return;
}
this.socket.log('channel', `timeout ${this.topic}`, this.joinPush.timeout);
this.state = constants_1.CHANNEL_STATES.errored;
this.rejoinTimer.scheduleTimeout();
});
this._on(constants_1.CHANNEL_EVENTS.reply, {}, (payload, ref) => {
this._trigger(this._replyEventName(ref), payload);
});
this.presence = new RealtimePresence_1.default(this);
this.broadcastEndpointURL =
(0, transformers_1.httpEndpointURL)(this.socket.endPoint) + '/api/broadcast';
this.private = this.params.config.private || false;
}
/** Subscribe registers your client with the server */
subscribe(callback, timeout = this.timeout) {
var _a, _b;
if (!this.socket.isConnected()) {
this.socket.connect();
}
if (this.state == constants_1.CHANNEL_STATES.closed) {
const { config: { broadcast, presence, private: isPrivate }, } = this.params;
this._onError((e) => callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, e));
this._onClose(() => callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CLOSED));
const accessTokenPayload = {};
const config = {
broadcast,
presence,
postgres_changes: (_b = (_a = this.bindings.postgres_changes) === null || _a === void 0 ? void 0 : _a.map((r) => r.filter)) !== null && _b !== void 0 ? _b : [],
private: isPrivate,
};
if (this.socket.accessTokenValue) {
accessTokenPayload.access_token = this.socket.accessTokenValue;
}
this.updateJoinPayload(Object.assign({ config }, accessTokenPayload));
this.joinedOnce = true;
this._rejoin(timeout);
this.joinPush
.receive('ok', async ({ postgres_changes }) => {
var _a;
this.socket.setAuth();
if (postgres_changes === undefined) {
callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED);
return;
}
else {
const clientPostgresBindings = this.bindings.postgres_changes;
const bindingsLen = (_a = clientPostgresBindings === null || clientPostgresBindings === void 0 ? void 0 : clientPostgresBindings.length) !== null && _a !== void 0 ? _a : 0;
const newPostgresBindings = [];
for (let i = 0; i < bindingsLen; i++) {
const clientPostgresBinding = clientPostgresBindings[i];
const { filter: { event, schema, table, filter }, } = clientPostgresBinding;
const serverPostgresFilter = postgres_changes && postgres_changes[i];
if (serverPostgresFilter &&
serverPostgresFilter.event === event &&
serverPostgresFilter.schema === schema &&
serverPostgresFilter.table === table &&
serverPostgresFilter.filter === filter) {
newPostgresBindings.push(Object.assign(Object.assign({}, clientPostgresBinding), { id: serverPostgresFilter.id }));
}
else {
this.unsubscribe();
this.state = constants_1.CHANNEL_STATES.errored;
callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, new Error('mismatch between server and client bindings for postgres changes'));
return;
}
}
this.bindings.postgres_changes = newPostgresBindings;
callback && callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED);
return;
}
})
.receive('error', (error) => {
this.state = constants_1.CHANNEL_STATES.errored;
callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, new Error(JSON.stringify(Object.values(error).join(', ') || 'error')));
return;
})
.receive('timeout', () => {
callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.TIMED_OUT);
return;
});
}
return this;
}
presenceState() {
return this.presence.state;
}
async track(payload, opts = {}) {
return await this.send({
type: 'presence',
event: 'track',
payload,
}, opts.timeout || this.timeout);
}
async untrack(opts = {}) {
return await this.send({
type: 'presence',
event: 'untrack',
}, opts);
}
on(type, filter, callback) {
return this._on(type, filter, callback);
}
/**
* Sends a message into the channel.
*
* @param args Arguments to send to channel
* @param args.type The type of event to send
* @param args.event The name of the event being sent
* @param args.payload Payload to be sent
* @param opts Options to be used during the send process
*/
async send(args, opts = {}) {
var _a, _b;
if (!this._canPush() && args.type === 'broadcast') {
const { event, payload: endpoint_payload } = args;
const authorization = this.socket.accessTokenValue
? `Bearer ${this.socket.accessTokenValue}`
: '';
const options = {
method: 'POST',
headers: {
Authorization: authorization,
apikey: this.socket.apiKey ? this.socket.apiKey : '',
'Content-Type': 'application/json',
},
body: JSON.stringify({
messages: [
{
topic: this.subTopic,
event,
payload: endpoint_payload,
private: this.private,
},
],
}),
};
try {
const response = await this._fetchWithTimeout(this.broadcastEndpointURL, options, (_a = opts.timeout) !== null && _a !== void 0 ? _a : this.timeout);
await ((_b = response.body) === null || _b === void 0 ? void 0 : _b.cancel());
return response.ok ? 'ok' : 'error';
}
catch (error) {
if (error.name === 'AbortError') {
return 'timed out';
}
else {
return 'error';
}
}
}
else {
return new Promise((resolve) => {
var _a, _b, _c;
const push = this._push(args.type, args, opts.timeout || this.timeout);
if (args.type === 'broadcast' && !((_c = (_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
resolve('ok');
}
push.receive('ok', () => resolve('ok'));
push.receive('error', () => resolve('error'));
push.receive('timeout', () => resolve('timed out'));
});
}
}
updateJoinPayload(payload) {
this.joinPush.updatePayload(payload);
}
/**
* Leaves the channel.
*
* Unsubscribes from server events, and instructs channel to terminate on server.
* Triggers onClose() hooks.
*
* To receive leave acknowledgements, use the a `receive` hook to bind to the server ack, ie:
* channel.unsubscribe().receive("ok", () => alert("left!") )
*/
unsubscribe(timeout = this.timeout) {
this.state = constants_1.CHANNEL_STATES.leaving;
const onClose = () => {
this.socket.log('channel', `leave ${this.topic}`);
this._trigger(constants_1.CHANNEL_EVENTS.close, 'leave', this._joinRef());
};
this.joinPush.destroy();
let leavePush = null;
return new Promise((resolve) => {
leavePush = new push_1.default(this, constants_1.CHANNEL_EVENTS.leave, {}, timeout);
leavePush
.receive('ok', () => {
onClose();
resolve('ok');
})
.receive('timeout', () => {
onClose();
resolve('timed out');
})
.receive('error', () => {
resolve('error');
});
leavePush.send();
if (!this._canPush()) {
leavePush.trigger('ok', {});
}
}).finally(() => {
leavePush === null || leavePush === void 0 ? void 0 : leavePush.destroy();
});
}
/**
* Teardown the channel.
*
* Destroys and stops related timers.
*/
teardown() {
this.pushBuffer.forEach((push) => push.destroy());
this.rejoinTimer && clearTimeout(this.rejoinTimer.timer);
this.joinPush.destroy();
}
/** @internal */
async _fetchWithTimeout(url, options, timeout) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
const response = await this.socket.fetch(url, Object.assign(Object.assign({}, options), { signal: controller.signal }));
clearTimeout(id);
return response;
}
/** @internal */
_push(event, payload, timeout = this.timeout) {
if (!this.joinedOnce) {
throw `tried to push '${event}' to '${this.topic}' before joining. Use channel.subscribe() before pushing events`;
}
let pushEvent = new push_1.default(this, event, payload, timeout);
if (this._canPush()) {
pushEvent.send();
}
else {
pushEvent.startTimeout();
this.pushBuffer.push(pushEvent);
}
return pushEvent;
}
/**
* Overridable message hook
*
* Receives all events for specialized message handling before dispatching to the channel callbacks.
* Must return the payload, modified or unmodified.
*
* @internal
*/
_onMessage(_event, payload, _ref) {
return payload;
}
/** @internal */
_isMember(topic) {
return this.topic === topic;
}
/** @internal */
_joinRef() {
return this.joinPush.ref;
}
/** @internal */
_trigger(type, payload, ref) {
var _a, _b;
const typeLower = type.toLocaleLowerCase();
const { close, error, leave, join } = constants_1.CHANNEL_EVENTS;
const events = [close, error, leave, join];
if (ref && events.indexOf(typeLower) >= 0 && ref !== this._joinRef()) {
return;
}
let handledPayload = this._onMessage(typeLower, payload, ref);
if (payload && !handledPayload) {
throw 'channel onMessage callbacks must return the payload, modified or unmodified';
}
if (['insert', 'update', 'delete'].includes(typeLower)) {
(_a = this.bindings.postgres_changes) === null || _a === void 0 ? void 0 : _a.filter((bind) => {
var _a, _b, _c;
return (((_a = bind.filter) === null || _a === void 0 ? void 0 : _a.event) === '*' ||
((_c = (_b = bind.filter) === null || _b === void 0 ? void 0 : _b.event) === null || _c === void 0 ? void 0 : _c.toLocaleLowerCase()) === typeLower);
}).map((bind) => bind.callback(handledPayload, ref));
}
else {
(_b = this.bindings[typeLower]) === null || _b === void 0 ? void 0 : _b.filter((bind) => {
var _a, _b, _c, _d, _e, _f;
if (['broadcast', 'presence', 'postgres_changes'].includes(typeLower)) {
if ('id' in bind) {
const bindId = bind.id;
const bindEvent = (_a = bind.filter) === null || _a === void 0 ? void 0 : _a.event;
return (bindId &&
((_b = payload.ids) === null || _b === void 0 ? void 0 : _b.includes(bindId)) &&
(bindEvent === '*' ||
(bindEvent === null || bindEvent === void 0 ? void 0 : bindEvent.toLocaleLowerCase()) ===
((_c = payload.data) === null || _c === void 0 ? void 0 : _c.type.toLocaleLowerCase())));
}
else {
const bindEvent = (_e = (_d = bind === null || bind === void 0 ? void 0 : bind.filter) === null || _d === void 0 ? void 0 : _d.event) === null || _e === void 0 ? void 0 : _e.toLocaleLowerCase();
return (bindEvent === '*' ||
bindEvent === ((_f = payload === null || payload === void 0 ? void 0 : payload.event) === null || _f === void 0 ? void 0 : _f.toLocaleLowerCase()));
}
}
else {
return bind.type.toLocaleLowerCase() === typeLower;
}
}).map((bind) => {
if (typeof handledPayload === 'object' && 'ids' in handledPayload) {
const postgresChanges = handledPayload.data;
const { schema, table, commit_timestamp, type, errors } = postgresChanges;
const enrichedPayload = {
schema: schema,
table: table,
commit_timestamp: commit_timestamp,
eventType: type,
new: {},
old: {},
errors: errors,
};
handledPayload = Object.assign(Object.assign({}, enrichedPayload), this._getPayloadRecords(postgresChanges));
}
bind.callback(handledPayload, ref);
});
}
}
/** @internal */
_isClosed() {
return this.state === constants_1.CHANNEL_STATES.closed;
}
/** @internal */
_isJoined() {
return this.state === constants_1.CHANNEL_STATES.joined;
}
/** @internal */
_isJoining() {
return this.state === constants_1.CHANNEL_STATES.joining;
}
/** @internal */
_isLeaving() {
return this.state === constants_1.CHANNEL_STATES.leaving;
}
/** @internal */
_replyEventName(ref) {
return `chan_reply_${ref}`;
}
/** @internal */
_on(type, filter, callback) {
const typeLower = type.toLocaleLowerCase();
const binding = {
type: typeLower,
filter: filter,
callback: callback,
};
if (this.bindings[typeLower]) {
this.bindings[typeLower].push(binding);
}
else {
this.bindings[typeLower] = [binding];
}
return this;
}
/** @internal */
_off(type, filter) {
const typeLower = type.toLocaleLowerCase();
this.bindings[typeLower] = this.bindings[typeLower].filter((bind) => {
var _a;
return !(((_a = bind.type) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase()) === typeLower &&
RealtimeChannel.isEqual(bind.filter, filter));
});
return this;
}
/** @internal */
static isEqual(obj1, obj2) {
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
return false;
}
for (const k in obj1) {
if (obj1[k] !== obj2[k]) {
return false;
}
}
return true;
}
/** @internal */
_rejoinUntilConnected() {
this.rejoinTimer.scheduleTimeout();
if (this.socket.isConnected()) {
this._rejoin();
}
}
/**
* Registers a callback that will be executed when the channel closes.
*
* @internal
*/
_onClose(callback) {
this._on(constants_1.CHANNEL_EVENTS.close, {}, callback);
}
/**
* Registers a callback that will be executed when the channel encounteres an error.
*
* @internal
*/
_onError(callback) {
this._on(constants_1.CHANNEL_EVENTS.error, {}, (reason) => callback(reason));
}
/**
* Returns `true` if the socket is connected and the channel has been joined.
*
* @internal
*/
_canPush() {
return this.socket.isConnected() && this._isJoined();
}
/** @internal */
_rejoin(timeout = this.timeout) {
if (this._isLeaving()) {
return;
}
this.socket._leaveOpenTopic(this.topic);
this.state = constants_1.CHANNEL_STATES.joining;
this.joinPush.resend(timeout);
}
/** @internal */
_getPayloadRecords(payload) {
const records = {
new: {},
old: {},
};
if (payload.type === 'INSERT' || payload.type === 'UPDATE') {
records.new = Transformers.convertChangeData(payload.columns, payload.record);
}
if (payload.type === 'UPDATE' || payload.type === 'DELETE') {
records.old = Transformers.convertChangeData(payload.columns, payload.old_record);
}
return records;
}
}
exports.default = RealtimeChannel;
//# sourceMappingURL=RealtimeChannel.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,184 @@
import { CONNECTION_STATE } from './lib/constants';
import Serializer from './lib/serializer';
import Timer from './lib/timer';
import RealtimeChannel from './RealtimeChannel';
import type { RealtimeChannelOptions } from './RealtimeChannel';
type Fetch = typeof fetch;
export type Channel = {
name: string;
inserted_at: string;
updated_at: string;
id: number;
};
export type LogLevel = 'info' | 'warn' | 'error';
export type RealtimeMessage = {
topic: string;
event: string;
payload: any;
ref: string;
join_ref?: string;
};
export type RealtimeRemoveChannelResponse = 'ok' | 'timed out' | 'error';
export type HeartbeatStatus = 'sent' | 'ok' | 'error' | 'timeout' | 'disconnected';
export interface WebSocketLikeConstructor {
new (address: string | URL, subprotocols?: string | string[] | undefined): WebSocketLike;
}
export type WebSocketLike = WebSocket;
export interface WebSocketLikeError {
error: any;
message: string;
type: string;
}
export type RealtimeClientOptions = {
transport?: WebSocketLikeConstructor;
timeout?: number;
heartbeatIntervalMs?: number;
logger?: Function;
encode?: Function;
decode?: Function;
reconnectAfterMs?: Function;
headers?: {
[key: string]: string;
};
params?: {
[key: string]: any;
};
log_level?: LogLevel;
logLevel?: LogLevel;
fetch?: Fetch;
worker?: boolean;
workerUrl?: string;
accessToken?: () => Promise<string | null>;
};
export default class RealtimeClient {
accessTokenValue: string | null;
apiKey: string | null;
channels: RealtimeChannel[];
endPoint: string;
httpEndpoint: string;
/** @deprecated headers cannot be set on websocket connections */
headers?: {
[key: string]: string;
};
params?: {
[key: string]: string;
};
timeout: number;
transport: WebSocketLikeConstructor | null;
heartbeatIntervalMs: number;
heartbeatTimer: ReturnType<typeof setInterval> | undefined;
pendingHeartbeatRef: string | null;
heartbeatCallback: (status: HeartbeatStatus) => void;
ref: number;
reconnectTimer: Timer;
logger: Function;
logLevel?: LogLevel;
encode: Function;
decode: Function;
reconnectAfterMs: Function;
conn: WebSocketLike | null;
sendBuffer: Function[];
serializer: Serializer;
stateChangeCallbacks: {
open: Function[];
close: Function[];
error: Function[];
message: Function[];
};
fetch: Fetch;
accessToken: (() => Promise<string | null>) | null;
worker?: boolean;
workerUrl?: string;
workerRef?: Worker;
/**
* Initializes the Socket.
*
* @param endPoint The string WebSocket endpoint, ie, "ws://example.com/socket", "wss://example.com", "/socket" (inherited host & protocol)
* @param httpEndpoint The string HTTP endpoint, ie, "https://example.com", "/" (inherited host & protocol)
* @param options.transport The Websocket Transport, for example WebSocket. This can be a custom implementation
* @param options.timeout The default timeout in milliseconds to trigger push timeouts.
* @param options.params The optional params to pass when connecting.
* @param options.headers Deprecated: headers cannot be set on websocket connections and this option will be removed in the future.
* @param options.heartbeatIntervalMs The millisec interval to send a heartbeat message.
* @param options.logger The optional function for specialized logging, ie: logger: (kind, msg, data) => { console.log(`${kind}: ${msg}`, data) }
* @param options.logLevel Sets the log level for Realtime
* @param options.encode The function to encode outgoing messages. Defaults to JSON: (payload, callback) => callback(JSON.stringify(payload))
* @param options.decode The function to decode incoming messages. Defaults to Serializer's decode.
* @param options.reconnectAfterMs he optional function that returns the millsec reconnect interval. Defaults to stepped backoff off.
* @param options.worker Use Web Worker to set a side flow. Defaults to false.
* @param options.workerUrl The URL of the worker script. Defaults to https://realtime.supabase.com/worker.js that includes a heartbeat event call to keep the connection alive.
*/
constructor(endPoint: string, options?: RealtimeClientOptions);
/**
* Connects the socket, unless already connected.
*/
connect(): void;
/**
* Returns the URL of the websocket.
* @returns string The URL of the websocket.
*/
endpointURL(): string;
/**
* Disconnects the socket.
*
* @param code A numeric status code to send on disconnect.
* @param reason A custom reason for the disconnect.
*/
disconnect(code?: number, reason?: string): void;
/**
* Returns all created channels
*/
getChannels(): RealtimeChannel[];
/**
* Unsubscribes and removes a single channel
* @param channel A RealtimeChannel instance
*/
removeChannel(channel: RealtimeChannel): Promise<RealtimeRemoveChannelResponse>;
/**
* Unsubscribes and removes all channels
*/
removeAllChannels(): Promise<RealtimeRemoveChannelResponse[]>;
/**
* Logs the message.
*
* For customized logging, `this.logger` can be overridden.
*/
log(kind: string, msg: string, data?: any): void;
/**
* Returns the current state of the socket.
*/
connectionState(): CONNECTION_STATE;
/**
* Returns `true` is the connection is open.
*/
isConnected(): boolean;
channel(topic: string, params?: RealtimeChannelOptions): RealtimeChannel;
/**
* Push out a message if the socket is connected.
*
* If the socket is not connected, the message gets enqueued within a local buffer, and sent out when a connection is next established.
*/
push(data: RealtimeMessage): void;
/**
* Sets the JWT access token used for channel subscription authorization and Realtime RLS.
*
* If param is null it will use the `accessToken` callback function or the token set on the client.
*
* On callback used, it will set the value of the token internal to the client.
*
* @param token A JWT string to override the token set on the client.
*/
setAuth(token?: string | null): Promise<void>;
/**
* Sends a heartbeat message if the socket is connected.
*/
sendHeartbeat(): Promise<void>;
onHeartbeat(callback: (status: HeartbeatStatus) => void): void;
/**
* Flushes send buffer
*/
flushSendBuffer(): void;
private _workerObjectUrl;
}
export {};
//# sourceMappingURL=RealtimeClient.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"RealtimeClient.d.ts","sourceRoot":"","sources":["../../src/RealtimeClient.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,520 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const isows_1 = require("isows");
const constants_1 = require("./lib/constants");
const serializer_1 = __importDefault(require("./lib/serializer"));
const timer_1 = __importDefault(require("./lib/timer"));
const transformers_1 = require("./lib/transformers");
const RealtimeChannel_1 = __importDefault(require("./RealtimeChannel"));
const noop = () => { };
const WORKER_SCRIPT = `
addEventListener("message", (e) => {
if (e.data.event === "start") {
setInterval(() => postMessage({ event: "keepAlive" }), e.data.interval);
}
});`;
class RealtimeClient {
/**
* Initializes the Socket.
*
* @param endPoint The string WebSocket endpoint, ie, "ws://example.com/socket", "wss://example.com", "/socket" (inherited host & protocol)
* @param httpEndpoint The string HTTP endpoint, ie, "https://example.com", "/" (inherited host & protocol)
* @param options.transport The Websocket Transport, for example WebSocket. This can be a custom implementation
* @param options.timeout The default timeout in milliseconds to trigger push timeouts.
* @param options.params The optional params to pass when connecting.
* @param options.headers Deprecated: headers cannot be set on websocket connections and this option will be removed in the future.
* @param options.heartbeatIntervalMs The millisec interval to send a heartbeat message.
* @param options.logger The optional function for specialized logging, ie: logger: (kind, msg, data) => { console.log(`${kind}: ${msg}`, data) }
* @param options.logLevel Sets the log level for Realtime
* @param options.encode The function to encode outgoing messages. Defaults to JSON: (payload, callback) => callback(JSON.stringify(payload))
* @param options.decode The function to decode incoming messages. Defaults to Serializer's decode.
* @param options.reconnectAfterMs he optional function that returns the millsec reconnect interval. Defaults to stepped backoff off.
* @param options.worker Use Web Worker to set a side flow. Defaults to false.
* @param options.workerUrl The URL of the worker script. Defaults to https://realtime.supabase.com/worker.js that includes a heartbeat event call to keep the connection alive.
*/
constructor(endPoint, options) {
var _a;
this.accessTokenValue = null;
this.apiKey = null;
this.channels = new Array();
this.endPoint = '';
this.httpEndpoint = '';
/** @deprecated headers cannot be set on websocket connections */
this.headers = {};
this.params = {};
this.timeout = constants_1.DEFAULT_TIMEOUT;
this.heartbeatIntervalMs = 25000;
this.heartbeatTimer = undefined;
this.pendingHeartbeatRef = null;
this.heartbeatCallback = noop;
this.ref = 0;
this.logger = noop;
this.conn = null;
this.sendBuffer = [];
this.serializer = new serializer_1.default();
this.stateChangeCallbacks = {
open: [],
close: [],
error: [],
message: [],
};
this.accessToken = null;
/**
* Use either custom fetch, if provided, or default fetch to make HTTP requests
*
* @internal
*/
this._resolveFetch = (customFetch) => {
let _fetch;
if (customFetch) {
_fetch = customFetch;
}
else if (typeof fetch === 'undefined') {
_fetch = (...args) => Promise.resolve(`${'@supabase/node-fetch'}`).then(s => __importStar(require(s))).then(({ default: fetch }) => fetch(...args));
}
else {
_fetch = fetch;
}
return (...args) => _fetch(...args);
};
this.endPoint = `${endPoint}/${constants_1.TRANSPORTS.websocket}`;
this.httpEndpoint = (0, transformers_1.httpEndpointURL)(endPoint);
if (options === null || options === void 0 ? void 0 : options.transport) {
this.transport = options.transport;
}
else {
this.transport = null;
}
if (options === null || options === void 0 ? void 0 : options.params)
this.params = options.params;
if (options === null || options === void 0 ? void 0 : options.timeout)
this.timeout = options.timeout;
if (options === null || options === void 0 ? void 0 : options.logger)
this.logger = options.logger;
if ((options === null || options === void 0 ? void 0 : options.logLevel) || (options === null || options === void 0 ? void 0 : options.log_level)) {
this.logLevel = options.logLevel || options.log_level;
this.params = Object.assign(Object.assign({}, this.params), { log_level: this.logLevel });
}
if (options === null || options === void 0 ? void 0 : options.heartbeatIntervalMs)
this.heartbeatIntervalMs = options.heartbeatIntervalMs;
const accessTokenValue = (_a = options === null || options === void 0 ? void 0 : options.params) === null || _a === void 0 ? void 0 : _a.apikey;
if (accessTokenValue) {
this.accessTokenValue = accessTokenValue;
this.apiKey = accessTokenValue;
}
this.reconnectAfterMs = (options === null || options === void 0 ? void 0 : options.reconnectAfterMs)
? options.reconnectAfterMs
: (tries) => {
return [1000, 2000, 5000, 10000][tries - 1] || 10000;
};
this.encode = (options === null || options === void 0 ? void 0 : options.encode)
? options.encode
: (payload, callback) => {
return callback(JSON.stringify(payload));
};
this.decode = (options === null || options === void 0 ? void 0 : options.decode)
? options.decode
: this.serializer.decode.bind(this.serializer);
this.reconnectTimer = new timer_1.default(async () => {
this.disconnect();
this.connect();
}, this.reconnectAfterMs);
this.fetch = this._resolveFetch(options === null || options === void 0 ? void 0 : options.fetch);
if (options === null || options === void 0 ? void 0 : options.worker) {
if (typeof window !== 'undefined' && !window.Worker) {
throw new Error('Web Worker is not supported');
}
this.worker = (options === null || options === void 0 ? void 0 : options.worker) || false;
this.workerUrl = options === null || options === void 0 ? void 0 : options.workerUrl;
}
this.accessToken = (options === null || options === void 0 ? void 0 : options.accessToken) || null;
}
/**
* Connects the socket, unless already connected.
*/
connect() {
if (this.conn) {
return;
}
if (!this.transport) {
this.transport = isows_1.WebSocket;
}
if (!this.transport) {
throw new Error('No transport provided');
}
this.conn = new this.transport(this.endpointURL());
this.setupConnection();
}
/**
* Returns the URL of the websocket.
* @returns string The URL of the websocket.
*/
endpointURL() {
return this._appendParams(this.endPoint, Object.assign({}, this.params, { vsn: constants_1.VSN }));
}
/**
* Disconnects the socket.
*
* @param code A numeric status code to send on disconnect.
* @param reason A custom reason for the disconnect.
*/
disconnect(code, reason) {
if (this.conn) {
this.conn.onclose = function () { }; // noop
if (code) {
this.conn.close(code, reason !== null && reason !== void 0 ? reason : '');
}
else {
this.conn.close();
}
this.conn = null;
// remove open handles
this.heartbeatTimer && clearInterval(this.heartbeatTimer);
this.reconnectTimer.reset();
this.channels.forEach((channel) => channel.teardown());
}
}
/**
* Returns all created channels
*/
getChannels() {
return this.channels;
}
/**
* Unsubscribes and removes a single channel
* @param channel A RealtimeChannel instance
*/
async removeChannel(channel) {
const status = await channel.unsubscribe();
if (this.channels.length === 0) {
this.disconnect();
}
return status;
}
/**
* Unsubscribes and removes all channels
*/
async removeAllChannels() {
const values_1 = await Promise.all(this.channels.map((channel) => channel.unsubscribe()));
this.channels = [];
this.disconnect();
return values_1;
}
/**
* Logs the message.
*
* For customized logging, `this.logger` can be overridden.
*/
log(kind, msg, data) {
this.logger(kind, msg, data);
}
/**
* Returns the current state of the socket.
*/
connectionState() {
switch (this.conn && this.conn.readyState) {
case constants_1.SOCKET_STATES.connecting:
return constants_1.CONNECTION_STATE.Connecting;
case constants_1.SOCKET_STATES.open:
return constants_1.CONNECTION_STATE.Open;
case constants_1.SOCKET_STATES.closing:
return constants_1.CONNECTION_STATE.Closing;
default:
return constants_1.CONNECTION_STATE.Closed;
}
}
/**
* Returns `true` is the connection is open.
*/
isConnected() {
return this.connectionState() === constants_1.CONNECTION_STATE.Open;
}
channel(topic, params = { config: {} }) {
const realtimeTopic = `realtime:${topic}`;
const exists = this.getChannels().find((c) => c.topic === realtimeTopic);
if (!exists) {
const chan = new RealtimeChannel_1.default(`realtime:${topic}`, params, this);
this.channels.push(chan);
return chan;
}
else {
return exists;
}
}
/**
* Push out a message if the socket is connected.
*
* If the socket is not connected, the message gets enqueued within a local buffer, and sent out when a connection is next established.
*/
push(data) {
const { topic, event, payload, ref } = data;
const callback = () => {
this.encode(data, (result) => {
var _a;
(_a = this.conn) === null || _a === void 0 ? void 0 : _a.send(result);
});
};
this.log('push', `${topic} ${event} (${ref})`, payload);
if (this.isConnected()) {
callback();
}
else {
this.sendBuffer.push(callback);
}
}
/**
* Sets the JWT access token used for channel subscription authorization and Realtime RLS.
*
* If param is null it will use the `accessToken` callback function or the token set on the client.
*
* On callback used, it will set the value of the token internal to the client.
*
* @param token A JWT string to override the token set on the client.
*/
async setAuth(token = null) {
let tokenToSend = token ||
(this.accessToken && (await this.accessToken())) ||
this.accessTokenValue;
if (this.accessTokenValue != tokenToSend) {
this.accessTokenValue = tokenToSend;
this.channels.forEach((channel) => {
const payload = {
access_token: tokenToSend,
version: constants_1.DEFAULT_VERSION,
};
tokenToSend && channel.updateJoinPayload(payload);
if (channel.joinedOnce && channel._isJoined()) {
channel._push(constants_1.CHANNEL_EVENTS.access_token, {
access_token: tokenToSend,
});
}
});
}
}
/**
* Sends a heartbeat message if the socket is connected.
*/
async sendHeartbeat() {
var _a;
if (!this.isConnected()) {
this.heartbeatCallback('disconnected');
return;
}
if (this.pendingHeartbeatRef) {
this.pendingHeartbeatRef = null;
this.log('transport', 'heartbeat timeout. Attempting to re-establish connection');
this.heartbeatCallback('timeout');
(_a = this.conn) === null || _a === void 0 ? void 0 : _a.close(constants_1.WS_CLOSE_NORMAL, 'hearbeat timeout');
return;
}
this.pendingHeartbeatRef = this._makeRef();
this.push({
topic: 'phoenix',
event: 'heartbeat',
payload: {},
ref: this.pendingHeartbeatRef,
});
this.heartbeatCallback('sent');
await this.setAuth();
}
onHeartbeat(callback) {
this.heartbeatCallback = callback;
}
/**
* Flushes send buffer
*/
flushSendBuffer() {
if (this.isConnected() && this.sendBuffer.length > 0) {
this.sendBuffer.forEach((callback) => callback());
this.sendBuffer = [];
}
}
/**
* Return the next message ref, accounting for overflows
*
* @internal
*/
_makeRef() {
let newRef = this.ref + 1;
if (newRef === this.ref) {
this.ref = 0;
}
else {
this.ref = newRef;
}
return this.ref.toString();
}
/**
* Unsubscribe from channels with the specified topic.
*
* @internal
*/
_leaveOpenTopic(topic) {
let dupChannel = this.channels.find((c) => c.topic === topic && (c._isJoined() || c._isJoining()));
if (dupChannel) {
this.log('transport', `leaving duplicate topic "${topic}"`);
dupChannel.unsubscribe();
}
}
/**
* Removes a subscription from the socket.
*
* @param channel An open subscription.
*
* @internal
*/
_remove(channel) {
this.channels = this.channels.filter((c) => c.topic !== channel.topic);
}
/**
* Sets up connection handlers.
*
* @internal
*/
setupConnection() {
if (this.conn) {
this.conn.binaryType = 'arraybuffer';
this.conn.onopen = () => this._onConnOpen();
this.conn.onerror = (error) => this._onConnError(error);
this.conn.onmessage = (event) => this._onConnMessage(event);
this.conn.onclose = (event) => this._onConnClose(event);
}
}
/** @internal */
_onConnMessage(rawMessage) {
this.decode(rawMessage.data, (msg) => {
let { topic, event, payload, ref } = msg;
if (topic === 'phoenix' && event === 'phx_reply') {
this.heartbeatCallback(msg.payload.status == 'ok' ? 'ok' : 'error');
}
if (ref && ref === this.pendingHeartbeatRef) {
this.pendingHeartbeatRef = null;
}
this.log('receive', `${payload.status || ''} ${topic} ${event} ${(ref && '(' + ref + ')') || ''}`, payload);
Array.from(this.channels)
.filter((channel) => channel._isMember(topic))
.forEach((channel) => channel._trigger(event, payload, ref));
this.stateChangeCallbacks.message.forEach((callback) => callback(msg));
});
}
/** @internal */
_onConnOpen() {
this.log('transport', `connected to ${this.endpointURL()}`);
this.flushSendBuffer();
this.reconnectTimer.reset();
if (!this.worker) {
this._startHeartbeat();
}
else {
if (!this.workerRef) {
this._startWorkerHeartbeat();
}
}
this.stateChangeCallbacks.open.forEach((callback) => callback());
}
/** @internal */
_startHeartbeat() {
this.heartbeatTimer && clearInterval(this.heartbeatTimer);
this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), this.heartbeatIntervalMs);
}
/** @internal */
_startWorkerHeartbeat() {
if (this.workerUrl) {
this.log('worker', `starting worker for from ${this.workerUrl}`);
}
else {
this.log('worker', `starting default worker`);
}
const objectUrl = this._workerObjectUrl(this.workerUrl);
this.workerRef = new Worker(objectUrl);
this.workerRef.onerror = (error) => {
this.log('worker', 'worker error', error.message);
this.workerRef.terminate();
};
this.workerRef.onmessage = (event) => {
if (event.data.event === 'keepAlive') {
this.sendHeartbeat();
}
};
this.workerRef.postMessage({
event: 'start',
interval: this.heartbeatIntervalMs,
});
}
/** @internal */
_onConnClose(event) {
this.log('transport', 'close', event);
this._triggerChanError();
this.heartbeatTimer && clearInterval(this.heartbeatTimer);
this.reconnectTimer.scheduleTimeout();
this.stateChangeCallbacks.close.forEach((callback) => callback(event));
}
/** @internal */
_onConnError(error) {
this.log('transport', `${error}`);
this._triggerChanError();
this.stateChangeCallbacks.error.forEach((callback) => callback(error));
}
/** @internal */
_triggerChanError() {
this.channels.forEach((channel) => channel._trigger(constants_1.CHANNEL_EVENTS.error));
}
/** @internal */
_appendParams(url, params) {
if (Object.keys(params).length === 0) {
return url;
}
const prefix = url.match(/\?/) ? '&' : '?';
const query = new URLSearchParams(params);
return `${url}${prefix}${query}`;
}
_workerObjectUrl(url) {
let result_url;
if (url) {
result_url = url;
}
else {
const blob = new Blob([WORKER_SCRIPT], { type: 'application/javascript' });
result_url = URL.createObjectURL(blob);
}
return result_url;
}
}
exports.default = RealtimeClient;
//# sourceMappingURL=RealtimeClient.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,67 @@
import type { PresenceOpts, PresenceOnJoinCallback, PresenceOnLeaveCallback } from 'phoenix';
import type RealtimeChannel from './RealtimeChannel';
type Presence<T extends {
[key: string]: any;
} = {}> = {
presence_ref: string;
} & T;
export type RealtimePresenceState<T extends {
[key: string]: any;
} = {}> = {
[key: string]: Presence<T>[];
};
export type RealtimePresenceJoinPayload<T extends {
[key: string]: any;
}> = {
event: `${REALTIME_PRESENCE_LISTEN_EVENTS.JOIN}`;
key: string;
currentPresences: Presence<T>[];
newPresences: Presence<T>[];
};
export type RealtimePresenceLeavePayload<T extends {
[key: string]: any;
}> = {
event: `${REALTIME_PRESENCE_LISTEN_EVENTS.LEAVE}`;
key: string;
currentPresences: Presence<T>[];
leftPresences: Presence<T>[];
};
export declare enum REALTIME_PRESENCE_LISTEN_EVENTS {
SYNC = "sync",
JOIN = "join",
LEAVE = "leave"
}
type RawPresenceState = {
[key: string]: {
metas: {
phx_ref?: string;
phx_ref_prev?: string;
[key: string]: any;
}[];
};
};
type RawPresenceDiff = {
joins: RawPresenceState;
leaves: RawPresenceState;
};
export default class RealtimePresence {
channel: RealtimeChannel;
state: RealtimePresenceState;
pendingDiffs: RawPresenceDiff[];
joinRef: string | null;
caller: {
onJoin: PresenceOnJoinCallback;
onLeave: PresenceOnLeaveCallback;
onSync: () => void;
};
/**
* Initializes the Presence.
*
* @param channel - The RealtimeChannel
* @param opts - The options,
* for example `{events: {state: 'state', diff: 'diff'}}`
*/
constructor(channel: RealtimeChannel, opts?: PresenceOpts);
}
export {};
//# sourceMappingURL=RealtimePresence.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"RealtimePresence.d.ts","sourceRoot":"","sources":["../../src/RealtimePresence.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,YAAY,EACZ,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,eAAe,MAAM,mBAAmB,CAAA;AAEpD,KAAK,QAAQ,CAAC,CAAC,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,EAAE,IAAI;IACrD,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,CAAC,CAAA;AAEL,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,EAAE,IAAI;IACzE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,IAAI;IAC1E,KAAK,EAAE,GAAG,+BAA+B,CAAC,IAAI,EAAE,CAAA;IAChD,GAAG,EAAE,MAAM,CAAA;IACX,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/B,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,4BAA4B,CAAC,CAAC,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,IAAI;IAC3E,KAAK,EAAE,GAAG,+BAA+B,CAAC,KAAK,EAAE,CAAA;IACjD,GAAG,EAAE,MAAM,CAAA;IACX,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/B,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;CAC7B,CAAA;AAED,oBAAY,+BAA+B;IACzC,IAAI,SAAS;IACb,IAAI,SAAS;IACb,KAAK,UAAU;CAChB;AAOD,KAAK,gBAAgB,GAAG;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG;QACb,KAAK,EAAE;YACL,OAAO,CAAC,EAAE,MAAM,CAAA;YAChB,YAAY,CAAC,EAAE,MAAM,CAAA;YACrB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SACnB,EAAE,CAAA;KACJ,CAAA;CACF,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,gBAAgB,CAAA;IACvB,MAAM,EAAE,gBAAgB,CAAA;CACzB,CAAA;AAID,MAAM,CAAC,OAAO,OAAO,gBAAgB;IAqBhB,OAAO,EAAE,eAAe;IApB3C,KAAK,EAAE,qBAAqB,CAAK;IACjC,YAAY,EAAE,eAAe,EAAE,CAAK;IACpC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAO;IAC7B,MAAM,EAAE;QACN,MAAM,EAAE,sBAAsB,CAAA;QAC9B,OAAO,EAAE,uBAAuB,CAAA;QAChC,MAAM,EAAE,MAAM,IAAI,CAAA;KACnB,CAIA;IAED;;;;;;OAMG;gBACgB,OAAO,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,YAAY;CAwRjE"}

View File

@@ -0,0 +1,228 @@
"use strict";
/*
This file draws heavily from https://github.com/phoenixframework/phoenix/blob/d344ec0a732ab4ee204215b31de69cf4be72e3bf/assets/js/phoenix/presence.js
License: https://github.com/phoenixframework/phoenix/blob/d344ec0a732ab4ee204215b31de69cf4be72e3bf/LICENSE.md
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.REALTIME_PRESENCE_LISTEN_EVENTS = void 0;
var REALTIME_PRESENCE_LISTEN_EVENTS;
(function (REALTIME_PRESENCE_LISTEN_EVENTS) {
REALTIME_PRESENCE_LISTEN_EVENTS["SYNC"] = "sync";
REALTIME_PRESENCE_LISTEN_EVENTS["JOIN"] = "join";
REALTIME_PRESENCE_LISTEN_EVENTS["LEAVE"] = "leave";
})(REALTIME_PRESENCE_LISTEN_EVENTS || (exports.REALTIME_PRESENCE_LISTEN_EVENTS = REALTIME_PRESENCE_LISTEN_EVENTS = {}));
class RealtimePresence {
/**
* Initializes the Presence.
*
* @param channel - The RealtimeChannel
* @param opts - The options,
* for example `{events: {state: 'state', diff: 'diff'}}`
*/
constructor(channel, opts) {
this.channel = channel;
this.state = {};
this.pendingDiffs = [];
this.joinRef = null;
this.caller = {
onJoin: () => { },
onLeave: () => { },
onSync: () => { },
};
const events = (opts === null || opts === void 0 ? void 0 : opts.events) || {
state: 'presence_state',
diff: 'presence_diff',
};
this.channel._on(events.state, {}, (newState) => {
const { onJoin, onLeave, onSync } = this.caller;
this.joinRef = this.channel._joinRef();
this.state = RealtimePresence.syncState(this.state, newState, onJoin, onLeave);
this.pendingDiffs.forEach((diff) => {
this.state = RealtimePresence.syncDiff(this.state, diff, onJoin, onLeave);
});
this.pendingDiffs = [];
onSync();
});
this.channel._on(events.diff, {}, (diff) => {
const { onJoin, onLeave, onSync } = this.caller;
if (this.inPendingSyncState()) {
this.pendingDiffs.push(diff);
}
else {
this.state = RealtimePresence.syncDiff(this.state, diff, onJoin, onLeave);
onSync();
}
});
this.onJoin((key, currentPresences, newPresences) => {
this.channel._trigger('presence', {
event: 'join',
key,
currentPresences,
newPresences,
});
});
this.onLeave((key, currentPresences, leftPresences) => {
this.channel._trigger('presence', {
event: 'leave',
key,
currentPresences,
leftPresences,
});
});
this.onSync(() => {
this.channel._trigger('presence', { event: 'sync' });
});
}
/**
* Used to sync the list of presences on the server with the
* client's state.
*
* An optional `onJoin` and `onLeave` callback can be provided to
* react to changes in the client's local presences across
* disconnects and reconnects with the server.
*
* @internal
*/
static syncState(currentState, newState, onJoin, onLeave) {
const state = this.cloneDeep(currentState);
const transformedState = this.transformState(newState);
const joins = {};
const leaves = {};
this.map(state, (key, presences) => {
if (!transformedState[key]) {
leaves[key] = presences;
}
});
this.map(transformedState, (key, newPresences) => {
const currentPresences = state[key];
if (currentPresences) {
const newPresenceRefs = newPresences.map((m) => m.presence_ref);
const curPresenceRefs = currentPresences.map((m) => m.presence_ref);
const joinedPresences = newPresences.filter((m) => curPresenceRefs.indexOf(m.presence_ref) < 0);
const leftPresences = currentPresences.filter((m) => newPresenceRefs.indexOf(m.presence_ref) < 0);
if (joinedPresences.length > 0) {
joins[key] = joinedPresences;
}
if (leftPresences.length > 0) {
leaves[key] = leftPresences;
}
}
else {
joins[key] = newPresences;
}
});
return this.syncDiff(state, { joins, leaves }, onJoin, onLeave);
}
/**
* Used to sync a diff of presence join and leave events from the
* server, as they happen.
*
* Like `syncState`, `syncDiff` accepts optional `onJoin` and
* `onLeave` callbacks to react to a user joining or leaving from a
* device.
*
* @internal
*/
static syncDiff(state, diff, onJoin, onLeave) {
const { joins, leaves } = {
joins: this.transformState(diff.joins),
leaves: this.transformState(diff.leaves),
};
if (!onJoin) {
onJoin = () => { };
}
if (!onLeave) {
onLeave = () => { };
}
this.map(joins, (key, newPresences) => {
var _a;
const currentPresences = (_a = state[key]) !== null && _a !== void 0 ? _a : [];
state[key] = this.cloneDeep(newPresences);
if (currentPresences.length > 0) {
const joinedPresenceRefs = state[key].map((m) => m.presence_ref);
const curPresences = currentPresences.filter((m) => joinedPresenceRefs.indexOf(m.presence_ref) < 0);
state[key].unshift(...curPresences);
}
onJoin(key, currentPresences, newPresences);
});
this.map(leaves, (key, leftPresences) => {
let currentPresences = state[key];
if (!currentPresences)
return;
const presenceRefsToRemove = leftPresences.map((m) => m.presence_ref);
currentPresences = currentPresences.filter((m) => presenceRefsToRemove.indexOf(m.presence_ref) < 0);
state[key] = currentPresences;
onLeave(key, currentPresences, leftPresences);
if (currentPresences.length === 0)
delete state[key];
});
return state;
}
/** @internal */
static map(obj, func) {
return Object.getOwnPropertyNames(obj).map((key) => func(key, obj[key]));
}
/**
* Remove 'metas' key
* Change 'phx_ref' to 'presence_ref'
* Remove 'phx_ref' and 'phx_ref_prev'
*
* @example
* // returns {
* abc123: [
* { presence_ref: '2', user_id: 1 },
* { presence_ref: '3', user_id: 2 }
* ]
* }
* RealtimePresence.transformState({
* abc123: {
* metas: [
* { phx_ref: '2', phx_ref_prev: '1' user_id: 1 },
* { phx_ref: '3', user_id: 2 }
* ]
* }
* })
*
* @internal
*/
static transformState(state) {
state = this.cloneDeep(state);
return Object.getOwnPropertyNames(state).reduce((newState, key) => {
const presences = state[key];
if ('metas' in presences) {
newState[key] = presences.metas.map((presence) => {
presence['presence_ref'] = presence['phx_ref'];
delete presence['phx_ref'];
delete presence['phx_ref_prev'];
return presence;
});
}
else {
newState[key] = presences;
}
return newState;
}, {});
}
/** @internal */
static cloneDeep(obj) {
return JSON.parse(JSON.stringify(obj));
}
/** @internal */
onJoin(callback) {
this.caller.onJoin = callback;
}
/** @internal */
onLeave(callback) {
this.caller.onLeave = callback;
}
/** @internal */
onSync(callback) {
this.caller.onSync = callback;
}
/** @internal */
inPendingSyncState() {
return !this.joinRef || this.joinRef !== this.channel._joinRef();
}
}
exports.default = RealtimePresence;
//# sourceMappingURL=RealtimePresence.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
import RealtimeClient, { RealtimeClientOptions, RealtimeMessage, RealtimeRemoveChannelResponse } from './RealtimeClient';
import RealtimeChannel, { RealtimeChannelOptions, RealtimeChannelSendResponse, RealtimePostgresChangesFilter, RealtimePostgresChangesPayload, RealtimePostgresInsertPayload, RealtimePostgresUpdatePayload, RealtimePostgresDeletePayload, REALTIME_LISTEN_TYPES, REALTIME_POSTGRES_CHANGES_LISTEN_EVENT, REALTIME_SUBSCRIBE_STATES, REALTIME_CHANNEL_STATES } from './RealtimeChannel';
import RealtimePresence, { RealtimePresenceState, RealtimePresenceJoinPayload, RealtimePresenceLeavePayload, REALTIME_PRESENCE_LISTEN_EVENTS } from './RealtimePresence';
export { RealtimePresence, RealtimeChannel, RealtimeChannelOptions, RealtimeChannelSendResponse, RealtimeClient, RealtimeClientOptions, RealtimeMessage, RealtimePostgresChangesFilter, RealtimePostgresChangesPayload, RealtimePostgresInsertPayload, RealtimePostgresUpdatePayload, RealtimePostgresDeletePayload, RealtimePresenceJoinPayload, RealtimePresenceLeavePayload, RealtimePresenceState, RealtimeRemoveChannelResponse, REALTIME_LISTEN_TYPES, REALTIME_POSTGRES_CHANGES_LISTEN_EVENT, REALTIME_PRESENCE_LISTEN_EVENTS, REALTIME_SUBSCRIBE_STATES, REALTIME_CHANNEL_STATES, };
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,EAAE,EACrB,qBAAqB,EACrB,eAAe,EACf,6BAA6B,EAC9B,MAAM,kBAAkB,CAAA;AACzB,OAAO,eAAe,EAAE,EACtB,sBAAsB,EACtB,2BAA2B,EAC3B,6BAA6B,EAC7B,8BAA8B,EAC9B,6BAA6B,EAC7B,6BAA6B,EAC7B,6BAA6B,EAC7B,qBAAqB,EACrB,sCAAsC,EACtC,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,gBAAgB,EAAE,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,4BAA4B,EAC5B,+BAA+B,EAChC,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,6BAA6B,EAC7B,8BAA8B,EAC9B,6BAA6B,EAC7B,6BAA6B,EAC7B,6BAA6B,EAC7B,2BAA2B,EAC3B,4BAA4B,EAC5B,qBAAqB,EACrB,6BAA6B,EAC7B,qBAAqB,EACrB,sCAAsC,EACtC,+BAA+B,EAC/B,yBAAyB,EACzB,uBAAuB,GACxB,CAAA"}

51
node_modules/@supabase/realtime-js/dist/main/index.js generated vendored Normal file
View File

@@ -0,0 +1,51 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.REALTIME_CHANNEL_STATES = exports.REALTIME_SUBSCRIBE_STATES = exports.REALTIME_PRESENCE_LISTEN_EVENTS = exports.REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = exports.REALTIME_LISTEN_TYPES = exports.RealtimeClient = exports.RealtimeChannel = exports.RealtimePresence = void 0;
const RealtimeClient_1 = __importDefault(require("./RealtimeClient"));
exports.RealtimeClient = RealtimeClient_1.default;
const RealtimeChannel_1 = __importStar(require("./RealtimeChannel"));
exports.RealtimeChannel = RealtimeChannel_1.default;
Object.defineProperty(exports, "REALTIME_LISTEN_TYPES", { enumerable: true, get: function () { return RealtimeChannel_1.REALTIME_LISTEN_TYPES; } });
Object.defineProperty(exports, "REALTIME_POSTGRES_CHANGES_LISTEN_EVENT", { enumerable: true, get: function () { return RealtimeChannel_1.REALTIME_POSTGRES_CHANGES_LISTEN_EVENT; } });
Object.defineProperty(exports, "REALTIME_SUBSCRIBE_STATES", { enumerable: true, get: function () { return RealtimeChannel_1.REALTIME_SUBSCRIBE_STATES; } });
Object.defineProperty(exports, "REALTIME_CHANNEL_STATES", { enumerable: true, get: function () { return RealtimeChannel_1.REALTIME_CHANNEL_STATES; } });
const RealtimePresence_1 = __importStar(require("./RealtimePresence"));
exports.RealtimePresence = RealtimePresence_1.default;
Object.defineProperty(exports, "REALTIME_PRESENCE_LISTEN_EVENTS", { enumerable: true, get: function () { return RealtimePresence_1.REALTIME_PRESENCE_LISTEN_EVENTS; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sEAIyB;AA0BvB,yBA9BK,wBAAc,CA8BL;AAzBhB,qEAY0B;AAUxB,0BAtBK,yBAAe,CAsBL;AAef,sGA7BA,uCAAqB,OA6BA;AACrB,uHA7BA,wDAAsC,OA6BA;AAEtC,0GA9BA,2CAAyB,OA8BA;AACzB,wGA9BA,yCAAuB,OA8BA;AA5BzB,uEAK2B;AAGzB,2BARK,0BAAgB,CAQL;AAkBhB,gHAtBA,kDAA+B,OAsBA"}

View File

@@ -0,0 +1,36 @@
export declare const DEFAULT_VERSION = "realtime-js/0.0.0-automated";
export declare const VSN: string;
export declare const VERSION = "0.0.0-automated";
export declare const DEFAULT_TIMEOUT = 10000;
export declare const WS_CLOSE_NORMAL = 1000;
export declare enum SOCKET_STATES {
connecting = 0,
open = 1,
closing = 2,
closed = 3
}
export declare enum CHANNEL_STATES {
closed = "closed",
errored = "errored",
joined = "joined",
joining = "joining",
leaving = "leaving"
}
export declare enum CHANNEL_EVENTS {
close = "phx_close",
error = "phx_error",
join = "phx_join",
reply = "phx_reply",
leave = "phx_leave",
access_token = "access_token"
}
export declare enum TRANSPORTS {
websocket = "websocket"
}
export declare enum CONNECTION_STATE {
Connecting = "connecting",
Open = "open",
Closing = "closing",
Closed = "closed"
}
//# sourceMappingURL=constants.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,gCAA2B,CAAA;AACvD,eAAO,MAAM,GAAG,EAAE,MAAgB,CAAA;AAElC,eAAO,MAAM,OAAO,oBAAU,CAAA;AAE9B,eAAO,MAAM,eAAe,QAAQ,CAAA;AAEpC,eAAO,MAAM,eAAe,OAAO,CAAA;AAEnC,oBAAY,aAAa;IACvB,UAAU,IAAI;IACd,IAAI,IAAI;IACR,OAAO,IAAI;IACX,MAAM,IAAI;CACX;AAED,oBAAY,cAAc;IACxB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED,oBAAY,cAAc;IACxB,KAAK,cAAc;IACnB,KAAK,cAAc;IACnB,IAAI,aAAa;IACjB,KAAK,cAAc;IACnB,KAAK,cAAc;IACnB,YAAY,iBAAiB;CAC9B;AAED,oBAAY,UAAU;IACpB,SAAS,cAAc;CACxB;AAED,oBAAY,gBAAgB;IAC1B,UAAU,eAAe;IACzB,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,MAAM,WAAW;CAClB"}

View File

@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CONNECTION_STATE = exports.TRANSPORTS = exports.CHANNEL_EVENTS = exports.CHANNEL_STATES = exports.SOCKET_STATES = exports.WS_CLOSE_NORMAL = exports.DEFAULT_TIMEOUT = exports.VERSION = exports.VSN = exports.DEFAULT_VERSION = void 0;
const version_1 = require("./version");
exports.DEFAULT_VERSION = `realtime-js/${version_1.version}`;
exports.VSN = '1.0.0';
exports.VERSION = version_1.version;
exports.DEFAULT_TIMEOUT = 10000;
exports.WS_CLOSE_NORMAL = 1000;
var SOCKET_STATES;
(function (SOCKET_STATES) {
SOCKET_STATES[SOCKET_STATES["connecting"] = 0] = "connecting";
SOCKET_STATES[SOCKET_STATES["open"] = 1] = "open";
SOCKET_STATES[SOCKET_STATES["closing"] = 2] = "closing";
SOCKET_STATES[SOCKET_STATES["closed"] = 3] = "closed";
})(SOCKET_STATES || (exports.SOCKET_STATES = SOCKET_STATES = {}));
var CHANNEL_STATES;
(function (CHANNEL_STATES) {
CHANNEL_STATES["closed"] = "closed";
CHANNEL_STATES["errored"] = "errored";
CHANNEL_STATES["joined"] = "joined";
CHANNEL_STATES["joining"] = "joining";
CHANNEL_STATES["leaving"] = "leaving";
})(CHANNEL_STATES || (exports.CHANNEL_STATES = CHANNEL_STATES = {}));
var CHANNEL_EVENTS;
(function (CHANNEL_EVENTS) {
CHANNEL_EVENTS["close"] = "phx_close";
CHANNEL_EVENTS["error"] = "phx_error";
CHANNEL_EVENTS["join"] = "phx_join";
CHANNEL_EVENTS["reply"] = "phx_reply";
CHANNEL_EVENTS["leave"] = "phx_leave";
CHANNEL_EVENTS["access_token"] = "access_token";
})(CHANNEL_EVENTS || (exports.CHANNEL_EVENTS = CHANNEL_EVENTS = {}));
var TRANSPORTS;
(function (TRANSPORTS) {
TRANSPORTS["websocket"] = "websocket";
})(TRANSPORTS || (exports.TRANSPORTS = TRANSPORTS = {}));
var CONNECTION_STATE;
(function (CONNECTION_STATE) {
CONNECTION_STATE["Connecting"] = "connecting";
CONNECTION_STATE["Open"] = "open";
CONNECTION_STATE["Closing"] = "closing";
CONNECTION_STATE["Closed"] = "closed";
})(CONNECTION_STATE || (exports.CONNECTION_STATE = CONNECTION_STATE = {}));
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":";;;AAAA,uCAAmC;AAEtB,QAAA,eAAe,GAAG,eAAe,iBAAO,EAAE,CAAA;AAC1C,QAAA,GAAG,GAAW,OAAO,CAAA;AAErB,QAAA,OAAO,GAAG,iBAAO,CAAA;AAEjB,QAAA,eAAe,GAAG,KAAK,CAAA;AAEvB,QAAA,eAAe,GAAG,IAAI,CAAA;AAEnC,IAAY,aAKX;AALD,WAAY,aAAa;IACvB,6DAAc,CAAA;IACd,iDAAQ,CAAA;IACR,uDAAW,CAAA;IACX,qDAAU,CAAA;AACZ,CAAC,EALW,aAAa,6BAAb,aAAa,QAKxB;AAED,IAAY,cAMX;AAND,WAAY,cAAc;IACxB,mCAAiB,CAAA;IACjB,qCAAmB,CAAA;IACnB,mCAAiB,CAAA;IACjB,qCAAmB,CAAA;IACnB,qCAAmB,CAAA;AACrB,CAAC,EANW,cAAc,8BAAd,cAAc,QAMzB;AAED,IAAY,cAOX;AAPD,WAAY,cAAc;IACxB,qCAAmB,CAAA;IACnB,qCAAmB,CAAA;IACnB,mCAAiB,CAAA;IACjB,qCAAmB,CAAA;IACnB,qCAAmB,CAAA;IACnB,+CAA6B,CAAA;AAC/B,CAAC,EAPW,cAAc,8BAAd,cAAc,QAOzB;AAED,IAAY,UAEX;AAFD,WAAY,UAAU;IACpB,qCAAuB,CAAA;AACzB,CAAC,EAFW,UAAU,0BAAV,UAAU,QAErB;AAED,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC1B,6CAAyB,CAAA;IACzB,iCAAa,CAAA;IACb,uCAAmB,CAAA;IACnB,qCAAiB,CAAA;AACnB,CAAC,EALW,gBAAgB,gCAAhB,gBAAgB,QAK3B"}

View File

@@ -0,0 +1,48 @@
import type RealtimeChannel from '../RealtimeChannel';
export default class Push {
channel: RealtimeChannel;
event: string;
payload: {
[key: string]: any;
};
timeout: number;
sent: boolean;
timeoutTimer: number | undefined;
ref: string;
receivedResp: {
status: string;
response: {
[key: string]: any;
};
} | null;
recHooks: {
status: string;
callback: Function;
}[];
refEvent: string | null;
/**
* Initializes the Push
*
* @param channel The Channel
* @param event The event, for example `"phx_join"`
* @param payload The payload, for example `{user_id: 123}`
* @param timeout The push timeout in milliseconds
*/
constructor(channel: RealtimeChannel, event: string, payload?: {
[key: string]: any;
}, timeout?: number);
resend(timeout: number): void;
send(): void;
updatePayload(payload: {
[key: string]: any;
}): void;
receive(status: string, callback: Function): this;
startTimeout(): void;
trigger(status: string, response: any): void;
destroy(): void;
private _cancelRefEvent;
private _cancelTimeout;
private _matchReceive;
private _hasReceived;
}
//# sourceMappingURL=push.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/lib/push.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,eAAe,MAAM,oBAAoB,CAAA;AAErD,MAAM,CAAC,OAAO,OAAO,IAAI;IAuBd,OAAO,EAAE,eAAe;IACxB,KAAK,EAAE,MAAM;IACb,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE;IAC/B,OAAO,EAAE,MAAM;IAzBxB,IAAI,EAAE,OAAO,CAAQ;IACrB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAY;IAC5C,GAAG,EAAE,MAAM,CAAK;IAChB,YAAY,EAAE;QACZ,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAA;KACjC,GAAG,IAAI,CAAO;IACf,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,QAAQ,CAAA;KACnB,EAAE,CAAK;IACR,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAO;IAE9B;;;;;;;OAOG;gBAEM,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAO,EACpC,OAAO,GAAE,MAAwB;IAG1C,MAAM,CAAC,OAAO,EAAE,MAAM;IAUtB,IAAI;IAeJ,aAAa,CAAC,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAAG,IAAI;IAIpD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ;IAS1C,YAAY;IAqBZ,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG;IAKrC,OAAO;IAKP,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,YAAY;CAGrB"}

View File

@@ -0,0 +1,104 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("../lib/constants");
class Push {
/**
* Initializes the Push
*
* @param channel The Channel
* @param event The event, for example `"phx_join"`
* @param payload The payload, for example `{user_id: 123}`
* @param timeout The push timeout in milliseconds
*/
constructor(channel, event, payload = {}, timeout = constants_1.DEFAULT_TIMEOUT) {
this.channel = channel;
this.event = event;
this.payload = payload;
this.timeout = timeout;
this.sent = false;
this.timeoutTimer = undefined;
this.ref = '';
this.receivedResp = null;
this.recHooks = [];
this.refEvent = null;
}
resend(timeout) {
this.timeout = timeout;
this._cancelRefEvent();
this.ref = '';
this.refEvent = null;
this.receivedResp = null;
this.sent = false;
this.send();
}
send() {
if (this._hasReceived('timeout')) {
return;
}
this.startTimeout();
this.sent = true;
this.channel.socket.push({
topic: this.channel.topic,
event: this.event,
payload: this.payload,
ref: this.ref,
join_ref: this.channel._joinRef(),
});
}
updatePayload(payload) {
this.payload = Object.assign(Object.assign({}, this.payload), payload);
}
receive(status, callback) {
var _a;
if (this._hasReceived(status)) {
callback((_a = this.receivedResp) === null || _a === void 0 ? void 0 : _a.response);
}
this.recHooks.push({ status, callback });
return this;
}
startTimeout() {
if (this.timeoutTimer) {
return;
}
this.ref = this.channel.socket._makeRef();
this.refEvent = this.channel._replyEventName(this.ref);
const callback = (payload) => {
this._cancelRefEvent();
this._cancelTimeout();
this.receivedResp = payload;
this._matchReceive(payload);
};
this.channel._on(this.refEvent, {}, callback);
this.timeoutTimer = setTimeout(() => {
this.trigger('timeout', {});
}, this.timeout);
}
trigger(status, response) {
if (this.refEvent)
this.channel._trigger(this.refEvent, { status, response });
}
destroy() {
this._cancelRefEvent();
this._cancelTimeout();
}
_cancelRefEvent() {
if (!this.refEvent) {
return;
}
this.channel._off(this.refEvent, {});
}
_cancelTimeout() {
clearTimeout(this.timeoutTimer);
this.timeoutTimer = undefined;
}
_matchReceive({ status, response, }) {
this.recHooks
.filter((h) => h.status === status)
.forEach((h) => h.callback(response));
}
_hasReceived(status) {
return this.receivedResp && this.receivedResp.status === status;
}
}
exports.default = Push;
//# sourceMappingURL=push.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../../src/lib/push.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,7 @@
export default class Serializer {
HEADER_LENGTH: number;
decode(rawPayload: ArrayBuffer | string, callback: Function): any;
private _binaryDecode;
private _decodeBroadcast;
}
//# sourceMappingURL=serializer.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../../src/lib/serializer.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,OAAO,UAAU;IAC7B,aAAa,SAAI;IAEjB,MAAM,CAAC,UAAU,EAAE,WAAW,GAAG,MAAM,EAAE,QAAQ,EAAE,QAAQ;IAY3D,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,gBAAgB;CAuBzB"}

View File

@@ -0,0 +1,36 @@
"use strict";
// This file draws heavily from https://github.com/phoenixframework/phoenix/commit/cf098e9cf7a44ee6479d31d911a97d3c7430c6fe
// License: https://github.com/phoenixframework/phoenix/blob/master/LICENSE.md
Object.defineProperty(exports, "__esModule", { value: true });
class Serializer {
constructor() {
this.HEADER_LENGTH = 1;
}
decode(rawPayload, callback) {
if (rawPayload.constructor === ArrayBuffer) {
return callback(this._binaryDecode(rawPayload));
}
if (typeof rawPayload === 'string') {
return callback(JSON.parse(rawPayload));
}
return callback({});
}
_binaryDecode(buffer) {
const view = new DataView(buffer);
const decoder = new TextDecoder();
return this._decodeBroadcast(buffer, view, decoder);
}
_decodeBroadcast(buffer, view, decoder) {
const topicSize = view.getUint8(1);
const eventSize = view.getUint8(2);
let offset = this.HEADER_LENGTH + 2;
const topic = decoder.decode(buffer.slice(offset, offset + topicSize));
offset = offset + topicSize;
const event = decoder.decode(buffer.slice(offset, offset + eventSize));
offset = offset + eventSize;
const data = JSON.parse(decoder.decode(buffer.slice(offset, buffer.byteLength)));
return { ref: null, topic: topic, event: event, payload: data };
}
}
exports.default = Serializer;
//# sourceMappingURL=serializer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"serializer.js","sourceRoot":"","sources":["../../../src/lib/serializer.ts"],"names":[],"mappings":";AAAA,2HAA2H;AAC3H,8EAA8E;;AAE9E,MAAqB,UAAU;IAA/B;QACE,kBAAa,GAAG,CAAC,CAAA;IA4CnB,CAAC;IA1CC,MAAM,CAAC,UAAgC,EAAE,QAAkB;QACzD,IAAI,UAAU,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;YAC3C,OAAO,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAA;QACjD,CAAC;QAED,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;YACnC,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAA;QACzC,CAAC;QAED,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAA;IACrB,CAAC;IAEO,aAAa,CAAC,MAAmB;QACvC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;QACjC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;QAEjC,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IACrD,CAAC;IAEO,gBAAgB,CACtB,MAAmB,EACnB,IAAc,EACd,OAAoB;QAOpB,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QAClC,IAAI,MAAM,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACnC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;QACtE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;QACtE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CACrB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CACxD,CAAA;QAED,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IACjE,CAAC;CACF;AA7CD,6BA6CC"}

View File

@@ -0,0 +1,22 @@
/**
* Creates a timer that accepts a `timerCalc` function to perform calculated timeout retries, such as exponential backoff.
*
* @example
* let reconnectTimer = new Timer(() => this.connect(), function(tries){
* return [1000, 5000, 10000][tries - 1] || 10000
* })
* reconnectTimer.scheduleTimeout() // fires after 1000
* reconnectTimer.scheduleTimeout() // fires after 5000
* reconnectTimer.reset()
* reconnectTimer.scheduleTimeout() // fires after 1000
*/
export default class Timer {
callback: Function;
timerCalc: Function;
timer: number | undefined;
tries: number;
constructor(callback: Function, timerCalc: Function);
reset(): void;
scheduleTimeout(): void;
}
//# sourceMappingURL=timer.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"timer.d.ts","sourceRoot":"","sources":["../../../src/lib/timer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,OAAO,KAAK;IAIL,QAAQ,EAAE,QAAQ;IAAS,SAAS,EAAE,QAAQ;IAHjE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAY;IACrC,KAAK,EAAE,MAAM,CAAI;gBAEE,QAAQ,EAAE,QAAQ,EAAS,SAAS,EAAE,QAAQ;IAKjE,KAAK;IAML,eAAe;CAQhB"}

View File

@@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Creates a timer that accepts a `timerCalc` function to perform calculated timeout retries, such as exponential backoff.
*
* @example
* let reconnectTimer = new Timer(() => this.connect(), function(tries){
* return [1000, 5000, 10000][tries - 1] || 10000
* })
* reconnectTimer.scheduleTimeout() // fires after 1000
* reconnectTimer.scheduleTimeout() // fires after 5000
* reconnectTimer.reset()
* reconnectTimer.scheduleTimeout() // fires after 1000
*/
class Timer {
constructor(callback, timerCalc) {
this.callback = callback;
this.timerCalc = timerCalc;
this.timer = undefined;
this.tries = 0;
this.callback = callback;
this.timerCalc = timerCalc;
}
reset() {
this.tries = 0;
clearTimeout(this.timer);
}
// Cancels any previous scheduleTimeout and schedules callback
scheduleTimeout() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.tries = this.tries + 1;
this.callback();
}, this.timerCalc(this.tries + 1));
}
}
exports.default = Timer;
//# sourceMappingURL=timer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"timer.js","sourceRoot":"","sources":["../../../src/lib/timer.ts"],"names":[],"mappings":";;AAAA;;;;;;;;;;;GAWG;AACH,MAAqB,KAAK;IAIxB,YAAmB,QAAkB,EAAS,SAAmB;QAA9C,aAAQ,GAAR,QAAQ,CAAU;QAAS,cAAS,GAAT,SAAS,CAAU;QAHjE,UAAK,GAAuB,SAAS,CAAA;QACrC,UAAK,GAAW,CAAC,CAAA;QAGf,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;QACd,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,8DAA8D;IAC9D,eAAe;QACb,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAExB,IAAI,CAAC,KAAK,GAAQ,UAAU,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;YAC3B,IAAI,CAAC,QAAQ,EAAE,CAAA;QACjB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAA;IACpC,CAAC;CACF;AAvBD,wBAuBC"}

View File

@@ -0,0 +1,109 @@
/**
* Helpers to convert the change Payload into native JS types.
*/
export declare enum PostgresTypes {
abstime = "abstime",
bool = "bool",
date = "date",
daterange = "daterange",
float4 = "float4",
float8 = "float8",
int2 = "int2",
int4 = "int4",
int4range = "int4range",
int8 = "int8",
int8range = "int8range",
json = "json",
jsonb = "jsonb",
money = "money",
numeric = "numeric",
oid = "oid",
reltime = "reltime",
text = "text",
time = "time",
timestamp = "timestamp",
timestamptz = "timestamptz",
timetz = "timetz",
tsrange = "tsrange",
tstzrange = "tstzrange"
}
type Columns = {
name: string;
type: string;
flags?: string[];
type_modifier?: number;
}[];
type BaseValue = null | string | number | boolean;
type RecordValue = BaseValue | BaseValue[];
type Record = {
[key: string]: RecordValue;
};
/**
* Takes an array of columns and an object of string values then converts each string value
* to its mapped type.
*
* @param {{name: String, type: String}[]} columns
* @param {Object} record
* @param {Object} options The map of various options that can be applied to the mapper
* @param {Array} options.skipTypes The array of types that should not be converted
*
* @example convertChangeData([{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age:'33'}, {})
* //=>{ first_name: 'Paul', age: 33 }
*/
export declare const convertChangeData: (columns: Columns, record: Record, options?: {
skipTypes?: string[];
}) => Record;
/**
* Converts the value of an individual column.
*
* @param {String} columnName The column that you want to convert
* @param {{name: String, type: String}[]} columns All of the columns
* @param {Object} record The map of string values
* @param {Array} skipTypes An array of types that should not be converted
* @return {object} Useless information
*
* @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, [])
* //=> 33
* @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, ['int4'])
* //=> "33"
*/
export declare const convertColumn: (columnName: string, columns: Columns, record: Record, skipTypes: string[]) => RecordValue;
/**
* If the value of the cell is `null`, returns null.
* Otherwise converts the string value to the correct type.
* @param {String} type A postgres column type
* @param {String} value The cell value
*
* @example convertCell('bool', 't')
* //=> true
* @example convertCell('int8', '10')
* //=> 10
* @example convertCell('_int4', '{1,2,3,4}')
* //=> [1,2,3,4]
*/
export declare const convertCell: (type: string, value: RecordValue) => RecordValue;
export declare const toBoolean: (value: RecordValue) => RecordValue;
export declare const toNumber: (value: RecordValue) => RecordValue;
export declare const toJson: (value: RecordValue) => RecordValue;
/**
* Converts a Postgres Array into a native JS array
*
* @example toArray('{}', 'int4')
* //=> []
* @example toArray('{"[2021-01-01,2021-12-31)","(2021-01-01,2021-12-32]"}', 'daterange')
* //=> ['[2021-01-01,2021-12-31)', '(2021-01-01,2021-12-32]']
* @example toArray([1,2,3,4], 'int4')
* //=> [1,2,3,4]
*/
export declare const toArray: (value: RecordValue, type: string) => RecordValue;
/**
* Fixes timestamp to be ISO-8601. Swaps the space between the date and time for a 'T'
* See https://github.com/supabase/supabase/issues/18
*
* @example toTimestampString('2019-09-10 00:00:00')
* //=> '2019-09-10T00:00:00'
*/
export declare const toTimestampString: (value: RecordValue) => RecordValue;
export declare const httpEndpointURL: (socketUrl: string) => string;
export {};
//# sourceMappingURL=transformers.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"transformers.d.ts","sourceRoot":"","sources":["../../../src/lib/transformers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,SAAS,cAAc;CACxB;AAED,KAAK,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,EAAE,CAAA;AAEH,KAAK,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AACjD,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,EAAE,CAAA;AAE1C,KAAK,MAAM,GAAG;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAA;CAC3B,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,OAAO,EAChB,QAAQ,MAAM,EACd,UAAS;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,KACrC,MAOF,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,EAClB,SAAS,OAAO,EAChB,QAAQ,MAAM,EACd,WAAW,MAAM,EAAE,KAClB,WAUF,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,OAAO,WAAW,KAAG,WA0C9D,CAAA;AAKD,eAAO,MAAM,SAAS,GAAI,OAAO,WAAW,KAAG,WAS9C,CAAA;AACD,eAAO,MAAM,QAAQ,GAAI,OAAO,WAAW,KAAG,WAQ7C,CAAA;AACD,eAAO,MAAM,MAAM,GAAI,OAAO,WAAW,KAAG,WAU3C,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,WAAW,EAAE,MAAM,MAAM,KAAG,WA0B1D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,WAAW,KAAG,WAMtD,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,WAAW,MAAM,KAAG,MAKnD,CAAA"}

View File

@@ -0,0 +1,229 @@
"use strict";
/**
* Helpers to convert the change Payload into native JS types.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.httpEndpointURL = exports.toTimestampString = exports.toArray = exports.toJson = exports.toNumber = exports.toBoolean = exports.convertCell = exports.convertColumn = exports.convertChangeData = exports.PostgresTypes = void 0;
// Adapted from epgsql (src/epgsql_binary.erl), this module licensed under
// 3-clause BSD found here: https://raw.githubusercontent.com/epgsql/epgsql/devel/LICENSE
var PostgresTypes;
(function (PostgresTypes) {
PostgresTypes["abstime"] = "abstime";
PostgresTypes["bool"] = "bool";
PostgresTypes["date"] = "date";
PostgresTypes["daterange"] = "daterange";
PostgresTypes["float4"] = "float4";
PostgresTypes["float8"] = "float8";
PostgresTypes["int2"] = "int2";
PostgresTypes["int4"] = "int4";
PostgresTypes["int4range"] = "int4range";
PostgresTypes["int8"] = "int8";
PostgresTypes["int8range"] = "int8range";
PostgresTypes["json"] = "json";
PostgresTypes["jsonb"] = "jsonb";
PostgresTypes["money"] = "money";
PostgresTypes["numeric"] = "numeric";
PostgresTypes["oid"] = "oid";
PostgresTypes["reltime"] = "reltime";
PostgresTypes["text"] = "text";
PostgresTypes["time"] = "time";
PostgresTypes["timestamp"] = "timestamp";
PostgresTypes["timestamptz"] = "timestamptz";
PostgresTypes["timetz"] = "timetz";
PostgresTypes["tsrange"] = "tsrange";
PostgresTypes["tstzrange"] = "tstzrange";
})(PostgresTypes || (exports.PostgresTypes = PostgresTypes = {}));
/**
* Takes an array of columns and an object of string values then converts each string value
* to its mapped type.
*
* @param {{name: String, type: String}[]} columns
* @param {Object} record
* @param {Object} options The map of various options that can be applied to the mapper
* @param {Array} options.skipTypes The array of types that should not be converted
*
* @example convertChangeData([{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age:'33'}, {})
* //=>{ first_name: 'Paul', age: 33 }
*/
const convertChangeData = (columns, record, options = {}) => {
var _a;
const skipTypes = (_a = options.skipTypes) !== null && _a !== void 0 ? _a : [];
return Object.keys(record).reduce((acc, rec_key) => {
acc[rec_key] = (0, exports.convertColumn)(rec_key, columns, record, skipTypes);
return acc;
}, {});
};
exports.convertChangeData = convertChangeData;
/**
* Converts the value of an individual column.
*
* @param {String} columnName The column that you want to convert
* @param {{name: String, type: String}[]} columns All of the columns
* @param {Object} record The map of string values
* @param {Array} skipTypes An array of types that should not be converted
* @return {object} Useless information
*
* @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, [])
* //=> 33
* @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, ['int4'])
* //=> "33"
*/
const convertColumn = (columnName, columns, record, skipTypes) => {
const column = columns.find((x) => x.name === columnName);
const colType = column === null || column === void 0 ? void 0 : column.type;
const value = record[columnName];
if (colType && !skipTypes.includes(colType)) {
return (0, exports.convertCell)(colType, value);
}
return noop(value);
};
exports.convertColumn = convertColumn;
/**
* If the value of the cell is `null`, returns null.
* Otherwise converts the string value to the correct type.
* @param {String} type A postgres column type
* @param {String} value The cell value
*
* @example convertCell('bool', 't')
* //=> true
* @example convertCell('int8', '10')
* //=> 10
* @example convertCell('_int4', '{1,2,3,4}')
* //=> [1,2,3,4]
*/
const convertCell = (type, value) => {
// if data type is an array
if (type.charAt(0) === '_') {
const dataType = type.slice(1, type.length);
return (0, exports.toArray)(value, dataType);
}
// If not null, convert to correct type.
switch (type) {
case PostgresTypes.bool:
return (0, exports.toBoolean)(value);
case PostgresTypes.float4:
case PostgresTypes.float8:
case PostgresTypes.int2:
case PostgresTypes.int4:
case PostgresTypes.int8:
case PostgresTypes.numeric:
case PostgresTypes.oid:
return (0, exports.toNumber)(value);
case PostgresTypes.json:
case PostgresTypes.jsonb:
return (0, exports.toJson)(value);
case PostgresTypes.timestamp:
return (0, exports.toTimestampString)(value); // Format to be consistent with PostgREST
case PostgresTypes.abstime: // To allow users to cast it based on Timezone
case PostgresTypes.date: // To allow users to cast it based on Timezone
case PostgresTypes.daterange:
case PostgresTypes.int4range:
case PostgresTypes.int8range:
case PostgresTypes.money:
case PostgresTypes.reltime: // To allow users to cast it based on Timezone
case PostgresTypes.text:
case PostgresTypes.time: // To allow users to cast it based on Timezone
case PostgresTypes.timestamptz: // To allow users to cast it based on Timezone
case PostgresTypes.timetz: // To allow users to cast it based on Timezone
case PostgresTypes.tsrange:
case PostgresTypes.tstzrange:
return noop(value);
default:
// Return the value for remaining types
return noop(value);
}
};
exports.convertCell = convertCell;
const noop = (value) => {
return value;
};
const toBoolean = (value) => {
switch (value) {
case 't':
return true;
case 'f':
return false;
default:
return value;
}
};
exports.toBoolean = toBoolean;
const toNumber = (value) => {
if (typeof value === 'string') {
const parsedValue = parseFloat(value);
if (!Number.isNaN(parsedValue)) {
return parsedValue;
}
}
return value;
};
exports.toNumber = toNumber;
const toJson = (value) => {
if (typeof value === 'string') {
try {
return JSON.parse(value);
}
catch (error) {
console.log(`JSON parse error: ${error}`);
return value;
}
}
return value;
};
exports.toJson = toJson;
/**
* Converts a Postgres Array into a native JS array
*
* @example toArray('{}', 'int4')
* //=> []
* @example toArray('{"[2021-01-01,2021-12-31)","(2021-01-01,2021-12-32]"}', 'daterange')
* //=> ['[2021-01-01,2021-12-31)', '(2021-01-01,2021-12-32]']
* @example toArray([1,2,3,4], 'int4')
* //=> [1,2,3,4]
*/
const toArray = (value, type) => {
if (typeof value !== 'string') {
return value;
}
const lastIdx = value.length - 1;
const closeBrace = value[lastIdx];
const openBrace = value[0];
// Confirm value is a Postgres array by checking curly brackets
if (openBrace === '{' && closeBrace === '}') {
let arr;
const valTrim = value.slice(1, lastIdx);
// TODO: find a better solution to separate Postgres array data
try {
arr = JSON.parse('[' + valTrim + ']');
}
catch (_) {
// WARNING: splitting on comma does not cover all edge cases
arr = valTrim ? valTrim.split(',') : [];
}
return arr.map((val) => (0, exports.convertCell)(type, val));
}
return value;
};
exports.toArray = toArray;
/**
* Fixes timestamp to be ISO-8601. Swaps the space between the date and time for a 'T'
* See https://github.com/supabase/supabase/issues/18
*
* @example toTimestampString('2019-09-10 00:00:00')
* //=> '2019-09-10T00:00:00'
*/
const toTimestampString = (value) => {
if (typeof value === 'string') {
return value.replace(' ', 'T');
}
return value;
};
exports.toTimestampString = toTimestampString;
const httpEndpointURL = (socketUrl) => {
let url = socketUrl;
url = url.replace(/^ws/i, 'http');
url = url.replace(/(\/socket\/websocket|\/socket|\/websocket)\/?$/i, '');
return url.replace(/\/+$/, '');
};
exports.httpEndpointURL = httpEndpointURL;
//# sourceMappingURL=transformers.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export declare const version = "2.11.15";
//# sourceMappingURL=version.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/lib/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,oBAAoB,CAAA"}

View File

@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
exports.version = '2.11.15';
//# sourceMappingURL=version.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/lib/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,iBAAiB,CAAA"}