Init
This commit is contained in:
+43
@@ -0,0 +1,43 @@
|
||||
import type { SocketState, ChannelState, ChannelEvent as PhoenixChannelEvent, Transport, Vsn } from '../phoenix/types';
|
||||
export type { SocketState, ChannelState, Transport };
|
||||
export declare const DEFAULT_VERSION = "realtime-js/2.110.8";
|
||||
export declare const VSN_1_0_0: Vsn;
|
||||
export declare const VSN_2_0_0: Vsn;
|
||||
export declare const DEFAULT_VSN: Vsn;
|
||||
export declare const VERSION = "2.110.8";
|
||||
export declare const DEFAULT_TIMEOUT = 10000;
|
||||
export declare const WS_CLOSE_NORMAL = 1000;
|
||||
export declare const MAX_PUSH_BUFFER_SIZE = 100;
|
||||
export declare const SOCKET_STATES: {
|
||||
readonly connecting: 0;
|
||||
readonly open: 1;
|
||||
readonly closing: 2;
|
||||
readonly closed: 3;
|
||||
};
|
||||
export declare const CHANNEL_STATES: {
|
||||
readonly closed: "closed";
|
||||
readonly errored: "errored";
|
||||
readonly joined: "joined";
|
||||
readonly joining: "joining";
|
||||
readonly leaving: "leaving";
|
||||
};
|
||||
export type ChannelEvent = PhoenixChannelEvent | 'access_token';
|
||||
export declare const CHANNEL_EVENTS: {
|
||||
readonly close: "phx_close";
|
||||
readonly error: "phx_error";
|
||||
readonly join: "phx_join";
|
||||
readonly reply: "phx_reply";
|
||||
readonly leave: "phx_leave";
|
||||
readonly access_token: "access_token";
|
||||
};
|
||||
export declare const TRANSPORTS: {
|
||||
readonly websocket: "websocket";
|
||||
};
|
||||
export type ConnectionState = 'connecting' | 'open' | 'closing' | 'closed' | (string & {});
|
||||
export declare const CONNECTION_STATE: {
|
||||
readonly connecting: "connecting";
|
||||
readonly open: "open";
|
||||
readonly closing: "closing";
|
||||
readonly closed: "closed";
|
||||
};
|
||||
//# sourceMappingURL=constants.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,YAAY,IAAI,mBAAmB,EACnC,SAAS,EACT,GAAG,EACJ,MAAM,kBAAkB,CAAA;AAEzB,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,CAAA;AAEpD,eAAO,MAAM,eAAe,wBAA2B,CAAA;AAEvD,eAAO,MAAM,SAAS,EAAE,GAAa,CAAA;AACrC,eAAO,MAAM,SAAS,EAAE,GAAa,CAAA;AACrC,eAAO,MAAM,WAAW,EAAE,GAAe,CAAA;AAEzC,eAAO,MAAM,OAAO,YAAU,CAAA;AAE9B,eAAO,MAAM,eAAe,QAAQ,CAAA;AAEpC,eAAO,MAAM,eAAe,OAAO,CAAA;AACnC,eAAO,MAAM,oBAAoB,MAAM,CAAA;AAEvC,eAAO,MAAM,aAAa;;;;;CAKhB,CAAA;AAEV,eAAO,MAAM,cAAc;;;;;;CAMjB,CAAA;AAEV,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,cAAc,CAAA;AAE/D,eAAO,MAAM,cAAc;;;;;;;CAOjB,CAAA;AAEV,eAAO,MAAM,UAAU;;CAEb,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAE1F,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAA"}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CONNECTION_STATE = exports.TRANSPORTS = exports.CHANNEL_EVENTS = exports.CHANNEL_STATES = exports.SOCKET_STATES = exports.MAX_PUSH_BUFFER_SIZE = exports.WS_CLOSE_NORMAL = exports.DEFAULT_TIMEOUT = exports.VERSION = exports.DEFAULT_VSN = exports.VSN_2_0_0 = exports.VSN_1_0_0 = exports.DEFAULT_VERSION = void 0;
|
||||
const version_1 = require("./version");
|
||||
exports.DEFAULT_VERSION = `realtime-js/${version_1.version}`;
|
||||
exports.VSN_1_0_0 = '1.0.0';
|
||||
exports.VSN_2_0_0 = '2.0.0';
|
||||
exports.DEFAULT_VSN = exports.VSN_2_0_0;
|
||||
exports.VERSION = version_1.version;
|
||||
exports.DEFAULT_TIMEOUT = 10000;
|
||||
exports.WS_CLOSE_NORMAL = 1000;
|
||||
exports.MAX_PUSH_BUFFER_SIZE = 100;
|
||||
exports.SOCKET_STATES = {
|
||||
connecting: 0,
|
||||
open: 1,
|
||||
closing: 2,
|
||||
closed: 3,
|
||||
};
|
||||
exports.CHANNEL_STATES = {
|
||||
closed: 'closed',
|
||||
errored: 'errored',
|
||||
joined: 'joined',
|
||||
joining: 'joining',
|
||||
leaving: 'leaving',
|
||||
};
|
||||
exports.CHANNEL_EVENTS = {
|
||||
close: 'phx_close',
|
||||
error: 'phx_error',
|
||||
join: 'phx_join',
|
||||
reply: 'phx_reply',
|
||||
leave: 'phx_leave',
|
||||
access_token: 'access_token',
|
||||
};
|
||||
exports.TRANSPORTS = {
|
||||
websocket: 'websocket',
|
||||
};
|
||||
exports.CONNECTION_STATE = {
|
||||
connecting: 'connecting',
|
||||
open: 'open',
|
||||
closing: 'closing',
|
||||
closed: 'closed',
|
||||
};
|
||||
//# sourceMappingURL=constants.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":";;;AAAA,uCAAmC;AAWtB,QAAA,eAAe,GAAG,eAAe,iBAAO,EAAE,CAAA;AAE1C,QAAA,SAAS,GAAQ,OAAO,CAAA;AACxB,QAAA,SAAS,GAAQ,OAAO,CAAA;AACxB,QAAA,WAAW,GAAQ,iBAAS,CAAA;AAE5B,QAAA,OAAO,GAAG,iBAAO,CAAA;AAEjB,QAAA,eAAe,GAAG,KAAK,CAAA;AAEvB,QAAA,eAAe,GAAG,IAAI,CAAA;AACtB,QAAA,oBAAoB,GAAG,GAAG,CAAA;AAE1B,QAAA,aAAa,GAAG;IAC3B,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,CAAC;CACD,CAAA;AAEG,QAAA,cAAc,GAAG;IAC5B,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACV,CAAA;AAIG,QAAA,cAAc,GAAG;IAC5B,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE,WAAW;IAClB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE,WAAW;IAClB,YAAY,EAAE,cAAc;CACpB,CAAA;AAEG,QAAA,UAAU,GAAG;IACxB,SAAS,EAAE,WAAW;CACd,CAAA;AAIG,QAAA,gBAAgB,GAAG;IAC9B,UAAU,EAAE,YAAY;IACxB,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;CACR,CAAA"}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Normalize the various shapes a channel error reason can take into a real `Error`.
|
||||
*
|
||||
* Transport-level channel errors arrive as a `CloseEvent`, a transport `Event`, an `Error`,
|
||||
* a string, or `undefined` depending on which path in the underlying socket fired. Server-reply
|
||||
* errors arrive as a payload object. This helper produces a consistent `Error` for every case
|
||||
* and preserves the original via `cause` so callers can still inspect the raw event.
|
||||
*/
|
||||
export declare function normalizeChannelError(reason: unknown): Error;
|
||||
//# sourceMappingURL=normalizeChannelError.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"normalizeChannelError.d.ts","sourceRoot":"","sources":["../../../src/lib/normalizeChannelError.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,CAqB5D"}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.normalizeChannelError = normalizeChannelError;
|
||||
/**
|
||||
* Normalize the various shapes a channel error reason can take into a real `Error`.
|
||||
*
|
||||
* Transport-level channel errors arrive as a `CloseEvent`, a transport `Event`, an `Error`,
|
||||
* a string, or `undefined` depending on which path in the underlying socket fired. Server-reply
|
||||
* errors arrive as a payload object. This helper produces a consistent `Error` for every case
|
||||
* and preserves the original via `cause` so callers can still inspect the raw event.
|
||||
*/
|
||||
function normalizeChannelError(reason) {
|
||||
if (reason instanceof Error) {
|
||||
return reason;
|
||||
}
|
||||
if (typeof reason === 'string') {
|
||||
return new Error(reason);
|
||||
}
|
||||
if (reason && typeof reason === 'object') {
|
||||
const obj = reason;
|
||||
if (typeof obj.code === 'number') {
|
||||
const detail = typeof obj.reason === 'string' && obj.reason ? ` (${obj.reason})` : '';
|
||||
return new Error(`socket closed: ${obj.code}${detail}`, { cause: reason });
|
||||
}
|
||||
return new Error('channel error: transport failure', { cause: reason });
|
||||
}
|
||||
return new Error('channel error: connection lost');
|
||||
}
|
||||
//# sourceMappingURL=normalizeChannelError.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"normalizeChannelError.js","sourceRoot":"","sources":["../../../src/lib/normalizeChannelError.ts"],"names":[],"mappings":";;AAQA,sDAqBC;AA7BD;;;;;;;GAOG;AACH,SAAgB,qBAAqB,CAAC,MAAe;IACnD,IAAI,MAAM,YAAY,KAAK,EAAE,CAAC;QAC5B,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,CAAA;IAC1B,CAAC;IAED,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,MAAiC,CAAA;QAE7C,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;YACrF,OAAO,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,IAAI,GAAG,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC5E,CAAC;QAED,OAAO,IAAI,KAAK,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IACzE,CAAC;IAED,OAAO,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;AACpD,CAAC"}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
export type Msg<T> = {
|
||||
join_ref?: string | null;
|
||||
ref?: string | null;
|
||||
topic: string;
|
||||
event: string;
|
||||
payload: T;
|
||||
};
|
||||
export default class Serializer {
|
||||
HEADER_LENGTH: number;
|
||||
USER_BROADCAST_PUSH_META_LENGTH: number;
|
||||
KINDS: {
|
||||
userBroadcastPush: number;
|
||||
userBroadcast: number;
|
||||
};
|
||||
BINARY_ENCODING: number;
|
||||
JSON_ENCODING: number;
|
||||
BROADCAST_EVENT: string;
|
||||
allowedMetadataKeys: string[];
|
||||
constructor(allowedMetadataKeys?: string[] | null);
|
||||
encode(msg: Msg<{
|
||||
[key: string]: any;
|
||||
}>, callback: (result: ArrayBuffer | string) => any): any;
|
||||
private _binaryEncodeUserBroadcastPush;
|
||||
private _encodeBinaryUserBroadcastPush;
|
||||
private _encodeJsonUserBroadcastPush;
|
||||
private _encodeUserBroadcastPush;
|
||||
decode(rawPayload: ArrayBuffer | string, callback: Function): any;
|
||||
private _binaryDecode;
|
||||
private _decodeUserBroadcast;
|
||||
private _isArrayBuffer;
|
||||
private _pick;
|
||||
}
|
||||
//# sourceMappingURL=serializer.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../../src/lib/serializer.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,CAAC,CAAA;CACX,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,UAAU;IAC7B,aAAa,SAAI;IACjB,+BAA+B,SAAI;IACnC,KAAK;;;MAA6C;IAClD,eAAe,SAAI;IACnB,aAAa,SAAI;IACjB,eAAe,SAAc;IAE7B,mBAAmB,EAAE,MAAM,EAAE,CAAK;gBAEtB,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAIjD,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,KAAK,GAAG;IAexF,OAAO,CAAC,8BAA8B;IAQtC,OAAO,CAAC,8BAA8B;IAKtC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,wBAAwB;IA6EhC,MAAM,CAAC,UAAU,EAAE,WAAW,GAAG,MAAM,EAAE,QAAQ,EAAE,QAAQ;IAe3D,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,oBAAoB;IA0C5B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,KAAK;CAMd"}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class Serializer {
|
||||
constructor(allowedMetadataKeys) {
|
||||
this.HEADER_LENGTH = 1;
|
||||
this.USER_BROADCAST_PUSH_META_LENGTH = 6;
|
||||
this.KINDS = { userBroadcastPush: 3, userBroadcast: 4 };
|
||||
this.BINARY_ENCODING = 0;
|
||||
this.JSON_ENCODING = 1;
|
||||
this.BROADCAST_EVENT = 'broadcast';
|
||||
this.allowedMetadataKeys = [];
|
||||
this.allowedMetadataKeys = allowedMetadataKeys !== null && allowedMetadataKeys !== void 0 ? allowedMetadataKeys : [];
|
||||
}
|
||||
encode(msg, callback) {
|
||||
if (msg.event === this.BROADCAST_EVENT &&
|
||||
!(msg.payload instanceof ArrayBuffer) &&
|
||||
typeof msg.payload.event === 'string') {
|
||||
return callback(this._binaryEncodeUserBroadcastPush(msg));
|
||||
}
|
||||
let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload];
|
||||
return callback(JSON.stringify(payload));
|
||||
}
|
||||
_binaryEncodeUserBroadcastPush(message) {
|
||||
var _a;
|
||||
if (this._isArrayBuffer((_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload)) {
|
||||
return this._encodeBinaryUserBroadcastPush(message);
|
||||
}
|
||||
else {
|
||||
return this._encodeJsonUserBroadcastPush(message);
|
||||
}
|
||||
}
|
||||
_encodeBinaryUserBroadcastPush(message) {
|
||||
var _a, _b;
|
||||
const userPayload = (_b = (_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload) !== null && _b !== void 0 ? _b : new ArrayBuffer(0);
|
||||
return this._encodeUserBroadcastPush(message, this.BINARY_ENCODING, userPayload);
|
||||
}
|
||||
_encodeJsonUserBroadcastPush(message) {
|
||||
var _a, _b;
|
||||
const userPayload = (_b = (_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload) !== null && _b !== void 0 ? _b : {};
|
||||
const encoder = new TextEncoder();
|
||||
const encodedUserPayload = encoder.encode(JSON.stringify(userPayload)).buffer;
|
||||
return this._encodeUserBroadcastPush(message, this.JSON_ENCODING, encodedUserPayload);
|
||||
}
|
||||
_encodeUserBroadcastPush(message, encodingType, encodedPayload) {
|
||||
var _a, _b;
|
||||
// Encode each header field as UTF-8. The length prefixes are byte counts and
|
||||
// the decode side uses TextDecoder (UTF-8), so measuring with String.length
|
||||
// and writing with charCodeAt would corrupt any multi-byte character (e.g.
|
||||
// accents or emoji) and desynchronize the buffer.
|
||||
const encoder = new TextEncoder();
|
||||
const topic = encoder.encode(message.topic);
|
||||
const ref = encoder.encode((_a = message.ref) !== null && _a !== void 0 ? _a : '');
|
||||
const joinRef = encoder.encode((_b = message.join_ref) !== null && _b !== void 0 ? _b : '');
|
||||
const userEvent = encoder.encode(message.payload.event);
|
||||
// Filter metadata based on allowed keys
|
||||
const rest = this.allowedMetadataKeys
|
||||
? this._pick(message.payload, this.allowedMetadataKeys)
|
||||
: {};
|
||||
const metadata = encoder.encode(Object.keys(rest).length === 0 ? '' : JSON.stringify(rest));
|
||||
// Validate byte lengths don't exceed uint8 max value (255)
|
||||
if (joinRef.length > 255) {
|
||||
throw new Error(`joinRef length ${joinRef.length} exceeds maximum of 255`);
|
||||
}
|
||||
if (ref.length > 255) {
|
||||
throw new Error(`ref length ${ref.length} exceeds maximum of 255`);
|
||||
}
|
||||
if (topic.length > 255) {
|
||||
throw new Error(`topic length ${topic.length} exceeds maximum of 255`);
|
||||
}
|
||||
if (userEvent.length > 255) {
|
||||
throw new Error(`userEvent length ${userEvent.length} exceeds maximum of 255`);
|
||||
}
|
||||
if (metadata.length > 255) {
|
||||
throw new Error(`metadata length ${metadata.length} exceeds maximum of 255`);
|
||||
}
|
||||
const metaLength = this.USER_BROADCAST_PUSH_META_LENGTH +
|
||||
joinRef.length +
|
||||
ref.length +
|
||||
topic.length +
|
||||
userEvent.length +
|
||||
metadata.length;
|
||||
const header = new ArrayBuffer(this.HEADER_LENGTH + metaLength);
|
||||
const view = new DataView(header);
|
||||
const bytes = new Uint8Array(header);
|
||||
let offset = 0;
|
||||
view.setUint8(offset++, this.KINDS.userBroadcastPush); // kind
|
||||
view.setUint8(offset++, joinRef.length);
|
||||
view.setUint8(offset++, ref.length);
|
||||
view.setUint8(offset++, topic.length);
|
||||
view.setUint8(offset++, userEvent.length);
|
||||
view.setUint8(offset++, metadata.length);
|
||||
view.setUint8(offset++, encodingType);
|
||||
bytes.set(joinRef, offset);
|
||||
offset += joinRef.length;
|
||||
bytes.set(ref, offset);
|
||||
offset += ref.length;
|
||||
bytes.set(topic, offset);
|
||||
offset += topic.length;
|
||||
bytes.set(userEvent, offset);
|
||||
offset += userEvent.length;
|
||||
bytes.set(metadata, offset);
|
||||
offset += metadata.length;
|
||||
var combined = new Uint8Array(header.byteLength + encodedPayload.byteLength);
|
||||
combined.set(new Uint8Array(header), 0);
|
||||
combined.set(new Uint8Array(encodedPayload), header.byteLength);
|
||||
return combined.buffer;
|
||||
}
|
||||
decode(rawPayload, callback) {
|
||||
if (this._isArrayBuffer(rawPayload)) {
|
||||
let result = this._binaryDecode(rawPayload);
|
||||
return callback(result);
|
||||
}
|
||||
if (typeof rawPayload === 'string') {
|
||||
const jsonPayload = JSON.parse(rawPayload);
|
||||
const [join_ref, ref, topic, event, payload] = jsonPayload;
|
||||
return callback({ join_ref, ref, topic, event, payload });
|
||||
}
|
||||
return callback({});
|
||||
}
|
||||
_binaryDecode(buffer) {
|
||||
const view = new DataView(buffer);
|
||||
const kind = view.getUint8(0);
|
||||
const decoder = new TextDecoder();
|
||||
switch (kind) {
|
||||
case this.KINDS.userBroadcast:
|
||||
return this._decodeUserBroadcast(buffer, view, decoder);
|
||||
}
|
||||
}
|
||||
_decodeUserBroadcast(buffer, view, decoder) {
|
||||
const topicSize = view.getUint8(1);
|
||||
const userEventSize = view.getUint8(2);
|
||||
const metadataSize = view.getUint8(3);
|
||||
const payloadEncoding = view.getUint8(4);
|
||||
let offset = this.HEADER_LENGTH + 4;
|
||||
const topic = decoder.decode(buffer.slice(offset, offset + topicSize));
|
||||
offset = offset + topicSize;
|
||||
const userEvent = decoder.decode(buffer.slice(offset, offset + userEventSize));
|
||||
offset = offset + userEventSize;
|
||||
const metadata = decoder.decode(buffer.slice(offset, offset + metadataSize));
|
||||
offset = offset + metadataSize;
|
||||
const payload = buffer.slice(offset, buffer.byteLength);
|
||||
const parsedPayload = payloadEncoding === this.JSON_ENCODING ? JSON.parse(decoder.decode(payload)) : payload;
|
||||
const data = {
|
||||
type: this.BROADCAST_EVENT,
|
||||
event: userEvent,
|
||||
payload: parsedPayload,
|
||||
};
|
||||
// Metadata is optional and always JSON encoded
|
||||
if (metadataSize > 0) {
|
||||
data['meta'] = JSON.parse(metadata);
|
||||
}
|
||||
return { join_ref: null, ref: null, topic: topic, event: this.BROADCAST_EVENT, payload: data };
|
||||
}
|
||||
_isArrayBuffer(buffer) {
|
||||
var _a;
|
||||
return buffer instanceof ArrayBuffer || ((_a = buffer === null || buffer === void 0 ? void 0 : buffer.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'ArrayBuffer';
|
||||
}
|
||||
_pick(obj, keys) {
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
return {};
|
||||
}
|
||||
return Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)));
|
||||
}
|
||||
}
|
||||
exports.default = Serializer;
|
||||
//# sourceMappingURL=serializer.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+109
@@ -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 | null, 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
|
||||
+1
@@ -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,GAAG,IAAI,EACrB,UAAS;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,KACrC,MAWF,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,WAS3C,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,MAkBnD,CAAA"}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
"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 : [];
|
||||
if (!record) {
|
||||
return {};
|
||||
}
|
||||
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 (_a) {
|
||||
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) => {
|
||||
const wsUrl = new URL(socketUrl);
|
||||
wsUrl.protocol = wsUrl.protocol.replace(/^ws/i, 'http');
|
||||
wsUrl.pathname = wsUrl.pathname
|
||||
.replace(/\/+$/, '') // remove all trailing slashes
|
||||
.replace(/\/socket\/websocket$/i, '') // remove the socket/websocket path
|
||||
.replace(/\/socket$/i, '') // remove the socket path
|
||||
.replace(/\/websocket$/i, ''); // remove the websocket path
|
||||
if (wsUrl.pathname === '' || wsUrl.pathname === '/') {
|
||||
wsUrl.pathname = '/api/broadcast';
|
||||
}
|
||||
else {
|
||||
wsUrl.pathname = wsUrl.pathname + '/api/broadcast';
|
||||
}
|
||||
return wsUrl.href;
|
||||
};
|
||||
exports.httpEndpointURL = httpEndpointURL;
|
||||
//# sourceMappingURL=transformers.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+2
@@ -0,0 +1,2 @@
|
||||
export declare const version = "2.110.8";
|
||||
//# sourceMappingURL=version.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/lib/version.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,OAAO,YAAY,CAAA"}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.version = void 0;
|
||||
// Generated automatically during releases by scripts/update-version-files.ts
|
||||
// This file provides runtime access to the package version for:
|
||||
// - HTTP request headers (e.g., X-Client-Info header for API requests)
|
||||
// - Debugging and support (identifying which version is running)
|
||||
// - Telemetry and logging (version reporting in errors/analytics)
|
||||
// - Ensuring build artifacts match the published package version
|
||||
exports.version = '2.110.8';
|
||||
//# sourceMappingURL=version.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/lib/version.ts"],"names":[],"mappings":";;;AAAA,6EAA6E;AAC7E,gEAAgE;AAChE,uEAAuE;AACvE,iEAAiE;AACjE,kEAAkE;AAClE,iEAAiE;AACpD,QAAA,OAAO,GAAG,SAAS,CAAA"}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
export interface WebSocketLike {
|
||||
readonly CONNECTING: number;
|
||||
readonly OPEN: number;
|
||||
readonly CLOSING: number;
|
||||
readonly CLOSED: number;
|
||||
readonly readyState: number;
|
||||
readonly url: string;
|
||||
readonly protocol: string;
|
||||
/**
|
||||
* Closes the socket, optionally providing a close code and reason.
|
||||
*/
|
||||
close(code?: number, reason?: string): void;
|
||||
/**
|
||||
* Sends data through the socket using the underlying implementation.
|
||||
*/
|
||||
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;
|
||||
onopen: ((this: any, ev: Event) => any) | null;
|
||||
onmessage: ((this: any, ev: MessageEvent) => any) | null;
|
||||
onclose: ((this: any, ev: CloseEvent) => any) | null;
|
||||
onerror: ((this: any, ev: Event) => any) | null;
|
||||
/**
|
||||
* Registers an event listener on the socket (compatible with browser WebSocket API).
|
||||
*/
|
||||
addEventListener(type: string, listener: EventListener): void;
|
||||
/**
|
||||
* Removes a previously registered event listener.
|
||||
*/
|
||||
removeEventListener(type: string, listener: EventListener): void;
|
||||
binaryType?: string;
|
||||
bufferedAmount?: number;
|
||||
extensions?: string;
|
||||
dispatchEvent?: (event: Event) => boolean;
|
||||
}
|
||||
export interface WebSocketEnvironment {
|
||||
type: 'native' | 'cloudflare' | 'unsupported';
|
||||
/** WebSocket constructor for this environment, if available. */
|
||||
wsConstructor?: typeof WebSocket;
|
||||
error?: string;
|
||||
workaround?: string;
|
||||
}
|
||||
/**
|
||||
* Utilities for creating WebSocket instances across runtimes.
|
||||
*/
|
||||
export declare class WebSocketFactory {
|
||||
/**
|
||||
* Static-only utility – prevent instantiation.
|
||||
*/
|
||||
private constructor();
|
||||
private static detectEnvironment;
|
||||
/**
|
||||
* Returns the best available WebSocket constructor for the current runtime.
|
||||
*
|
||||
* @category Realtime
|
||||
*
|
||||
* @example Example with error handling
|
||||
* ```ts
|
||||
* try {
|
||||
* const WS = WebSocketFactory.getWebSocketConstructor()
|
||||
* const socket = new WS('wss://example.com/socket')
|
||||
* } catch (error) {
|
||||
* console.error('WebSocket not available in this environment.', error)
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
static getWebSocketConstructor(): typeof WebSocket;
|
||||
/**
|
||||
* Detects whether the runtime can establish WebSocket connections.
|
||||
*
|
||||
* @category Realtime
|
||||
*
|
||||
* @example Example in a Node.js script
|
||||
* ```ts
|
||||
* if (!WebSocketFactory.isWebSocketSupported()) {
|
||||
* console.error('WebSockets are required for this script.')
|
||||
* process.exitCode = 1
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
static isWebSocketSupported(): boolean;
|
||||
}
|
||||
export default WebSocketFactory;
|
||||
//# sourceMappingURL=websocket-factory.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"websocket-factory.d.ts","sourceRoot":"","sources":["../../../src/lib/websocket-factory.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3C;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,GAAG,eAAe,GAAG,IAAI,CAAA;IAEnE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,KAAK,GAAG,CAAC,GAAG,IAAI,CAAA;IAC9C,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,KAAK,GAAG,CAAC,GAAG,IAAI,CAAA;IACxD,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,UAAU,KAAK,GAAG,CAAC,GAAG,IAAI,CAAA;IACpD,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,KAAK,GAAG,CAAC,GAAG,IAAI,CAAA;IAE/C;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAA;IAC7D;;OAEG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAA;IAGhE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;CAC1C;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,QAAQ,GAAG,YAAY,GAAG,aAAa,CAAA;IAC7C,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,SAAS,CAAA;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAYD;;GAEG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,OAAO;IACP,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAqEhC;;;;;;;;;;;;;;OAcG;WACW,uBAAuB,IAAI,OAAO,SAAS;IAYzD;;;;;;;;;;;;OAYG;WACW,oBAAoB,IAAI,OAAO;CAQ9C;AAED,eAAe,gBAAgB,CAAA"}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WebSocketFactory = void 0;
|
||||
/**
|
||||
* Utilities for creating WebSocket instances across runtimes.
|
||||
*/
|
||||
class WebSocketFactory {
|
||||
/**
|
||||
* Static-only utility – prevent instantiation.
|
||||
*/
|
||||
constructor() { }
|
||||
static detectEnvironment() {
|
||||
var _a;
|
||||
if (typeof WebSocket !== 'undefined') {
|
||||
return { type: 'native', wsConstructor: WebSocket };
|
||||
}
|
||||
const gt = globalThis;
|
||||
if (typeof globalThis !== 'undefined' && typeof gt.WebSocket !== 'undefined') {
|
||||
return { type: 'native', wsConstructor: gt.WebSocket };
|
||||
}
|
||||
const gl = typeof global !== 'undefined' ? global : undefined;
|
||||
if (gl && typeof gl.WebSocket !== 'undefined') {
|
||||
return { type: 'native', wsConstructor: gl.WebSocket };
|
||||
}
|
||||
if (typeof globalThis !== 'undefined' &&
|
||||
typeof gt.WebSocketPair !== 'undefined' &&
|
||||
typeof globalThis.WebSocket === 'undefined') {
|
||||
return {
|
||||
type: 'cloudflare',
|
||||
error: 'Cloudflare Workers detected. WebSocket clients are not supported in Cloudflare Workers.',
|
||||
workaround: 'Use Cloudflare Workers WebSocket API for server-side WebSocket handling, or deploy to a different runtime.',
|
||||
};
|
||||
}
|
||||
if ((typeof globalThis !== 'undefined' && gt.EdgeRuntime) ||
|
||||
(typeof navigator !== 'undefined' && ((_a = navigator.userAgent) === null || _a === void 0 ? void 0 : _a.includes('Vercel-Edge')))) {
|
||||
return {
|
||||
type: 'unsupported',
|
||||
error: 'Edge runtime detected (Vercel Edge/Netlify Edge). WebSockets are not supported in edge functions.',
|
||||
workaround: 'Use serverless functions or a different deployment target for WebSocket functionality.',
|
||||
};
|
||||
}
|
||||
// Use dynamic property access to avoid Next.js Edge Runtime static analysis warnings
|
||||
const _process = globalThis['process'];
|
||||
if (_process) {
|
||||
const processVersions = _process['versions'];
|
||||
if (processVersions && processVersions['node']) {
|
||||
// Reaching here means an earlier check did not find a native WebSocket,
|
||||
// so this Node.js process is missing the global WebSocket (Node.js 22+).
|
||||
return {
|
||||
type: 'unsupported',
|
||||
error: 'Node.js detected but native WebSocket not found.',
|
||||
workaround: 'Ensure you are running Node.js 22+ or provide a WebSocket implementation via the transport option.',
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'unsupported',
|
||||
error: 'Unknown JavaScript runtime without WebSocket support.',
|
||||
workaround: "Ensure you're running in a supported environment (browser, Node.js, Deno) or provide a custom WebSocket implementation.",
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Returns the best available WebSocket constructor for the current runtime.
|
||||
*
|
||||
* @category Realtime
|
||||
*
|
||||
* @example Example with error handling
|
||||
* ```ts
|
||||
* try {
|
||||
* const WS = WebSocketFactory.getWebSocketConstructor()
|
||||
* const socket = new WS('wss://example.com/socket')
|
||||
* } catch (error) {
|
||||
* console.error('WebSocket not available in this environment.', error)
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
static getWebSocketConstructor() {
|
||||
const env = this.detectEnvironment();
|
||||
if (env.wsConstructor) {
|
||||
return env.wsConstructor;
|
||||
}
|
||||
let errorMessage = env.error || 'WebSocket not supported in this environment.';
|
||||
if (env.workaround) {
|
||||
errorMessage += `\n\nSuggested solution: ${env.workaround}`;
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
/**
|
||||
* Detects whether the runtime can establish WebSocket connections.
|
||||
*
|
||||
* @category Realtime
|
||||
*
|
||||
* @example Example in a Node.js script
|
||||
* ```ts
|
||||
* if (!WebSocketFactory.isWebSocketSupported()) {
|
||||
* console.error('WebSockets are required for this script.')
|
||||
* process.exitCode = 1
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
static isWebSocketSupported() {
|
||||
try {
|
||||
const env = this.detectEnvironment();
|
||||
return env.type === 'native';
|
||||
}
|
||||
catch (_a) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.WebSocketFactory = WebSocketFactory;
|
||||
exports.default = WebSocketFactory;
|
||||
//# sourceMappingURL=websocket-factory.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"websocket-factory.js","sourceRoot":"","sources":["../../../src/lib/websocket-factory.ts"],"names":[],"mappings":"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"}
|
||||
Reference in New Issue
Block a user