nuxt4, and some changes on packages

This commit is contained in:
2025-08-19 21:38:30 +03:30
parent 61fee6c3da
commit 5b6f1a1cdf
900 changed files with 11139 additions and 15161 deletions
+11 -1
View File
@@ -13,6 +13,7 @@ var __rest = (this && this.__rest) || function (s, e) {
Object.defineProperty(exports, "__esModule", { value: true });
const fetch_1 = require("./lib/fetch");
const helpers_1 = require("./lib/helpers");
const types_1 = require("./lib/types");
const errors_1 = require("./lib/errors");
class GoTrueAdminApi {
constructor({ url = '', headers = {}, fetch, }) {
@@ -29,7 +30,10 @@ class GoTrueAdminApi {
* @param jwt A valid, logged-in JWT.
* @param scope The logout sope.
*/
async signOut(jwt, scope = 'global') {
async signOut(jwt, scope = types_1.SIGN_OUT_SCOPES[0]) {
if (types_1.SIGN_OUT_SCOPES.indexOf(scope) < 0) {
throw new Error(`@supabase/auth-js: Parameter scope must be one of ${types_1.SIGN_OUT_SCOPES.join(', ')}`);
}
try {
await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/logout?scope=${scope}`, {
headers: this.headers,
@@ -171,6 +175,7 @@ class GoTrueAdminApi {
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
async getUserById(uid) {
(0, helpers_1.validateUUID)(uid);
try {
return await (0, fetch_1._request)(this.fetch, 'GET', `${this.url}/admin/users/${uid}`, {
headers: this.headers,
@@ -192,6 +197,7 @@ class GoTrueAdminApi {
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
async updateUserById(uid, attributes) {
(0, helpers_1.validateUUID)(uid);
try {
return await (0, fetch_1._request)(this.fetch, 'PUT', `${this.url}/admin/users/${uid}`, {
body: attributes,
@@ -216,6 +222,7 @@ class GoTrueAdminApi {
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
async deleteUser(id, shouldSoftDelete = false) {
(0, helpers_1.validateUUID)(id);
try {
return await (0, fetch_1._request)(this.fetch, 'DELETE', `${this.url}/admin/users/${id}`, {
headers: this.headers,
@@ -233,6 +240,7 @@ class GoTrueAdminApi {
}
}
async _listFactors(params) {
(0, helpers_1.validateUUID)(params.userId);
try {
const { data, error } = await (0, fetch_1._request)(this.fetch, 'GET', `${this.url}/admin/users/${params.userId}/factors`, {
headers: this.headers,
@@ -250,6 +258,8 @@ class GoTrueAdminApi {
}
}
async _deleteFactor(params) {
(0, helpers_1.validateUUID)(params.userId);
(0, helpers_1.validateUUID)(params.id);
try {
const data = await (0, fetch_1._request)(this.fetch, 'DELETE', `${this.url}/admin/users/${params.userId}/factors/${params.id}`, {
headers: this.headers,
+316 -21
View File
@@ -13,6 +13,7 @@ const polyfills_1 = require("./lib/polyfills");
const version_1 = require("./lib/version");
const locks_1 = require("./lib/locks");
const base64url_1 = require("./lib/base64url");
const helpers_2 = require("./lib/helpers");
(0, polyfills_1.polyfillGlobalThis)(); // Make "globalThis" available
const DEFAULT_OPTIONS = {
url: constants_1.GOTRUE_URL,
@@ -28,12 +29,25 @@ const DEFAULT_OPTIONS = {
async function lockNoOp(name, acquireTimeout, fn) {
return await fn();
}
/**
* Caches JWKS values for all clients created in the same environment. This is
* especially useful for shared-memory execution environments such as Vercel's
* Fluid Compute, AWS Lambda or Supabase's Edge Functions. Regardless of how
* many clients are created, if they share the same storage key they will use
* the same JWKS cache, significantly speeding up getClaims() with asymmetric
* JWTs.
*/
const GLOBAL_JWKS = {};
class GoTrueClient {
/**
* Create a new client for use in the browser.
*/
constructor(options) {
var _a, _b;
/**
* @experimental
*/
this.userStorage = null;
this.memoryStorage = null;
this.stateChangeEmitters = new Map();
this.autoRefreshTicker = null;
@@ -90,8 +104,10 @@ class GoTrueClient {
else {
this.lock = lockNoOp;
}
this.jwks = { keys: [] };
this.jwks_cached_at = Number.MIN_SAFE_INTEGER;
if (!this.jwks) {
this.jwks = { keys: [] };
this.jwks_cached_at = Number.MIN_SAFE_INTEGER;
}
this.mfa = {
verify: this._verify.bind(this),
enroll: this._enroll.bind(this),
@@ -107,13 +123,16 @@ class GoTrueClient {
}
else {
if ((0, helpers_1.supportsLocalStorage)()) {
this.storage = local_storage_1.localStorageAdapter;
this.storage = globalThis.localStorage;
}
else {
this.memoryStorage = {};
this.storage = (0, local_storage_1.memoryLocalStorageAdapter)(this.memoryStorage);
}
}
if (settings.userStorage) {
this.userStorage = settings.userStorage;
}
}
else {
this.memoryStorage = {};
@@ -133,6 +152,23 @@ class GoTrueClient {
}
this.initialize();
}
/**
* The JWKS used for verifying asymmetric JWTs
*/
get jwks() {
var _a, _b;
return (_b = (_a = GLOBAL_JWKS[this.storageKey]) === null || _a === void 0 ? void 0 : _a.jwks) !== null && _b !== void 0 ? _b : { keys: [] };
}
set jwks(value) {
GLOBAL_JWKS[this.storageKey] = Object.assign(Object.assign({}, GLOBAL_JWKS[this.storageKey]), { jwks: value });
}
get jwks_cached_at() {
var _a, _b;
return (_b = (_a = GLOBAL_JWKS[this.storageKey]) === null || _a === void 0 ? void 0 : _a.cachedAt) !== null && _b !== void 0 ? _b : Number.MIN_SAFE_INTEGER;
}
set jwks_cached_at(value) {
GLOBAL_JWKS[this.storageKey] = Object.assign(Object.assign({}, GLOBAL_JWKS[this.storageKey]), { cachedAt: value });
}
_debug(...args) {
if (this.logDebugMessages) {
this.logger(`GoTrueClient@${this.instanceID} (${version_1.version}) ${new Date().toISOString()}`, ...args);
@@ -415,6 +451,157 @@ class GoTrueClient {
return this._exchangeCodeForSession(authCode);
});
}
/**
* Signs in a user by verifying a message signed by the user's private key.
* Only Solana supported at this time, using the Sign in with Solana standard.
*/
async signInWithWeb3(credentials) {
const { chain } = credentials;
if (chain === 'solana') {
return await this.signInWithSolana(credentials);
}
throw new Error(`@supabase/auth-js: Unsupported chain "${chain}"`);
}
async signInWithSolana(credentials) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
let message;
let signature;
if ('message' in credentials) {
message = credentials.message;
signature = credentials.signature;
}
else {
const { chain, wallet, statement, options } = credentials;
let resolvedWallet;
if (!(0, helpers_1.isBrowser)()) {
if (typeof wallet !== 'object' || !(options === null || options === void 0 ? void 0 : options.url)) {
throw new Error('@supabase/auth-js: Both wallet and url must be specified in non-browser environments.');
}
resolvedWallet = wallet;
}
else if (typeof wallet === 'object') {
resolvedWallet = wallet;
}
else {
const windowAny = window;
if ('solana' in windowAny &&
typeof windowAny.solana === 'object' &&
(('signIn' in windowAny.solana && typeof windowAny.solana.signIn === 'function') ||
('signMessage' in windowAny.solana &&
typeof windowAny.solana.signMessage === 'function'))) {
resolvedWallet = windowAny.solana;
}
else {
throw new Error(`@supabase/auth-js: No compatible Solana wallet interface on the window object (window.solana) detected. Make sure the user already has a wallet installed and connected for this app. Prefer passing the wallet interface object directly to signInWithWeb3({ chain: 'solana', wallet: resolvedUserWallet }) instead.`);
}
}
const url = new URL((_a = options === null || options === void 0 ? void 0 : options.url) !== null && _a !== void 0 ? _a : window.location.href);
if ('signIn' in resolvedWallet && resolvedWallet.signIn) {
const output = await resolvedWallet.signIn(Object.assign(Object.assign(Object.assign({ issuedAt: new Date().toISOString() }, options === null || options === void 0 ? void 0 : options.signInWithSolana), {
// non-overridable properties
version: '1', domain: url.host, uri: url.href }), (statement ? { statement } : null)));
let outputToProcess;
if (Array.isArray(output) && output[0] && typeof output[0] === 'object') {
outputToProcess = output[0];
}
else if (output &&
typeof output === 'object' &&
'signedMessage' in output &&
'signature' in output) {
outputToProcess = output;
}
else {
throw new Error('@supabase/auth-js: Wallet method signIn() returned unrecognized value');
}
if ('signedMessage' in outputToProcess &&
'signature' in outputToProcess &&
(typeof outputToProcess.signedMessage === 'string' ||
outputToProcess.signedMessage instanceof Uint8Array) &&
outputToProcess.signature instanceof Uint8Array) {
message =
typeof outputToProcess.signedMessage === 'string'
? outputToProcess.signedMessage
: new TextDecoder().decode(outputToProcess.signedMessage);
signature = outputToProcess.signature;
}
else {
throw new Error('@supabase/auth-js: Wallet method signIn() API returned object without signedMessage and signature fields');
}
}
else {
if (!('signMessage' in resolvedWallet) ||
typeof resolvedWallet.signMessage !== 'function' ||
!('publicKey' in resolvedWallet) ||
typeof resolvedWallet !== 'object' ||
!resolvedWallet.publicKey ||
!('toBase58' in resolvedWallet.publicKey) ||
typeof resolvedWallet.publicKey.toBase58 !== 'function') {
throw new Error('@supabase/auth-js: Wallet does not have a compatible signMessage() and publicKey.toBase58() API');
}
message = [
`${url.host} wants you to sign in with your Solana account:`,
resolvedWallet.publicKey.toBase58(),
...(statement ? ['', statement, ''] : ['']),
'Version: 1',
`URI: ${url.href}`,
`Issued At: ${(_c = (_b = options === null || options === void 0 ? void 0 : options.signInWithSolana) === null || _b === void 0 ? void 0 : _b.issuedAt) !== null && _c !== void 0 ? _c : new Date().toISOString()}`,
...(((_d = options === null || options === void 0 ? void 0 : options.signInWithSolana) === null || _d === void 0 ? void 0 : _d.notBefore)
? [`Not Before: ${options.signInWithSolana.notBefore}`]
: []),
...(((_e = options === null || options === void 0 ? void 0 : options.signInWithSolana) === null || _e === void 0 ? void 0 : _e.expirationTime)
? [`Expiration Time: ${options.signInWithSolana.expirationTime}`]
: []),
...(((_f = options === null || options === void 0 ? void 0 : options.signInWithSolana) === null || _f === void 0 ? void 0 : _f.chainId)
? [`Chain ID: ${options.signInWithSolana.chainId}`]
: []),
...(((_g = options === null || options === void 0 ? void 0 : options.signInWithSolana) === null || _g === void 0 ? void 0 : _g.nonce) ? [`Nonce: ${options.signInWithSolana.nonce}`] : []),
...(((_h = options === null || options === void 0 ? void 0 : options.signInWithSolana) === null || _h === void 0 ? void 0 : _h.requestId)
? [`Request ID: ${options.signInWithSolana.requestId}`]
: []),
...(((_k = (_j = options === null || options === void 0 ? void 0 : options.signInWithSolana) === null || _j === void 0 ? void 0 : _j.resources) === null || _k === void 0 ? void 0 : _k.length)
? [
'Resources',
...options.signInWithSolana.resources.map((resource) => `- ${resource}`),
]
: []),
].join('\n');
const maybeSignature = await resolvedWallet.signMessage(new TextEncoder().encode(message), 'utf8');
if (!maybeSignature || !(maybeSignature instanceof Uint8Array)) {
throw new Error('@supabase/auth-js: Wallet signMessage() API returned an recognized value');
}
signature = maybeSignature;
}
}
try {
const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=web3`, {
headers: this.headers,
body: Object.assign({ chain: 'solana', message, signature: (0, base64url_1.bytesToBase64URL)(signature) }, (((_l = credentials.options) === null || _l === void 0 ? void 0 : _l.captchaToken)
? { gotrue_meta_security: { captcha_token: (_m = credentials.options) === null || _m === void 0 ? void 0 : _m.captchaToken } }
: null)),
xform: fetch_1._sessionResponse,
});
if (error) {
throw error;
}
if (!data || !data.session || !data.user) {
return {
data: { user: null, session: null },
error: new errors_1.AuthInvalidTokenResponseError(),
};
}
if (data.session) {
await this._saveSession(data.session);
await this._notifyAllSubscribers('SIGNED_IN', data.session);
}
return { data: Object.assign({}, data), error };
}
catch (error) {
if ((0, errors_1.isAuthError)(error)) {
return { data: { user: null, session: null }, error };
}
throw error;
}
}
async _exchangeCodeForSession(authCode) {
const storageItem = await (0, helpers_1.getItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
const [codeVerifier, redirectType] = (storageItem !== null && storageItem !== void 0 ? storageItem : '').split('/');
@@ -834,7 +1021,16 @@ class GoTrueClient {
: false;
this._debug('#__loadSession()', `session has${hasExpired ? '' : ' not'} expired`, 'expires_at', currentSession.expires_at);
if (!hasExpired) {
if (this.storage.isServer) {
if (this.userStorage) {
const maybeUser = (await (0, helpers_1.getItemAsync)(this.userStorage, this.storageKey + '-user'));
if (maybeUser === null || maybeUser === void 0 ? void 0 : maybeUser.user) {
currentSession.user = maybeUser.user;
}
else {
currentSession.user = (0, helpers_1.userNotAvailableProxy)();
}
}
if (this.storage.isServer && currentSession.user) {
let suppressWarning = this.suppressGetSessionWarning;
const proxySession = new Proxy(currentSession, {
get: (target, prop, receiver) => {
@@ -1430,11 +1626,39 @@ class GoTrueClient {
* Note: this method is async to accommodate for AsyncStorage e.g. in React native.
*/
async _recoverAndRefresh() {
var _a;
var _a, _b;
const debugName = '#_recoverAndRefresh()';
this._debug(debugName, 'begin');
try {
const currentSession = await (0, helpers_1.getItemAsync)(this.storage, this.storageKey);
const currentSession = (await (0, helpers_1.getItemAsync)(this.storage, this.storageKey));
if (currentSession && this.userStorage) {
let maybeUser = (await (0, helpers_1.getItemAsync)(this.userStorage, this.storageKey + '-user'));
if (!this.storage.isServer && Object.is(this.storage, this.userStorage) && !maybeUser) {
// storage and userStorage are the same storage medium, for example
// window.localStorage if userStorage does not have the user from
// storage stored, store it first thereby migrating the user object
// from storage -> userStorage
maybeUser = { user: currentSession.user };
await (0, helpers_1.setItemAsync)(this.userStorage, this.storageKey + '-user', maybeUser);
}
currentSession.user = (_a = maybeUser === null || maybeUser === void 0 ? void 0 : maybeUser.user) !== null && _a !== void 0 ? _a : (0, helpers_1.userNotAvailableProxy)();
}
else if (currentSession && !currentSession.user) {
// user storage is not set, let's check if it was previously enabled so
// we bring back the storage as it should be
if (!currentSession.user) {
// test if userStorage was previously enabled and the storage medium was the same, to move the user back under the same key
const separateUser = (await (0, helpers_1.getItemAsync)(this.storage, this.storageKey + '-user'));
if (separateUser && (separateUser === null || separateUser === void 0 ? void 0 : separateUser.user)) {
currentSession.user = separateUser.user;
await (0, helpers_1.removeItemAsync)(this.storage, this.storageKey + '-user');
await (0, helpers_1.setItemAsync)(this.storage, this.storageKey, currentSession);
}
else {
currentSession.user = (0, helpers_1.userNotAvailableProxy)();
}
}
}
this._debug(debugName, 'session from storage', currentSession);
if (!this._isValidSession(currentSession)) {
this._debug(debugName, 'session is not valid');
@@ -1443,7 +1667,7 @@ class GoTrueClient {
}
return;
}
const expiresWithMargin = ((_a = currentSession.expires_at) !== null && _a !== void 0 ? _a : Infinity) * 1000 - Date.now() < constants_1.EXPIRY_MARGIN_MS;
const expiresWithMargin = ((_b = currentSession.expires_at) !== null && _b !== void 0 ? _b : Infinity) * 1000 - Date.now() < constants_1.EXPIRY_MARGIN_MS;
this._debug(debugName, `session has${expiresWithMargin ? '' : ' not'} expired with margin of ${constants_1.EXPIRY_MARGIN_MS}s`);
if (expiresWithMargin) {
if (this.autoRefreshToken && currentSession.refresh_token) {
@@ -1457,6 +1681,25 @@ class GoTrueClient {
}
}
}
else if (currentSession.user &&
currentSession.user.__isUserNotAvailableProxy === true) {
// If we have a proxy user, try to get the real user data
try {
const { data, error: userError } = await this._getUser(currentSession.access_token);
if (!userError && (data === null || data === void 0 ? void 0 : data.user)) {
currentSession.user = data.user;
await this._saveSession(currentSession);
await this._notifyAllSubscribers('SIGNED_IN', currentSession);
}
else {
this._debug(debugName, 'could not get user data, skipping SIGNED_IN notification');
}
}
catch (getUserError) {
console.error('Error getting user data:', getUserError);
this._debug(debugName, 'error getting user data, skipping SIGNED_IN notification', getUserError);
}
}
else {
// no need to persist currentSession again, as we just loaded it from
// local storage; persisting it again may overwrite a value saved by
@@ -1552,11 +1795,45 @@ class GoTrueClient {
// _saveSession is always called whenever a new session has been acquired
// so we can safely suppress the warning returned by future getSession calls
this.suppressGetSessionWarning = true;
await (0, helpers_1.setItemAsync)(this.storage, this.storageKey, session);
// Create a shallow copy to work with, to avoid mutating the original session object if it's used elsewhere
const sessionToProcess = Object.assign({}, session);
const userIsProxy = sessionToProcess.user && sessionToProcess.user.__isUserNotAvailableProxy === true;
if (this.userStorage) {
if (!userIsProxy && sessionToProcess.user) {
// If it's a real user object, save it to userStorage.
await (0, helpers_1.setItemAsync)(this.userStorage, this.storageKey + '-user', {
user: sessionToProcess.user,
});
}
else if (userIsProxy) {
// If it's the proxy, it means user was not found in userStorage.
// We should ensure no stale user data for this key exists in userStorage if we were to save null,
// or simply not save the proxy. For now, we don't save the proxy here.
// If there's a need to clear userStorage if user becomes proxy, that logic would go here.
}
// Prepare the main session data for primary storage: remove the user property before cloning
// This is important because the original session.user might be the proxy
const mainSessionData = Object.assign({}, sessionToProcess);
delete mainSessionData.user; // Remove user (real or proxy) before cloning for main storage
const clonedMainSessionData = (0, helpers_2.deepClone)(mainSessionData);
await (0, helpers_1.setItemAsync)(this.storage, this.storageKey, clonedMainSessionData);
}
else {
// No userStorage is configured.
// In this case, session.user should ideally not be a proxy.
// If it were, structuredClone would fail. This implies an issue elsewhere if user is a proxy here
const clonedSession = (0, helpers_2.deepClone)(sessionToProcess); // sessionToProcess still has its original user property
await (0, helpers_1.setItemAsync)(this.storage, this.storageKey, clonedSession);
}
}
async _removeSession() {
this._debug('#_removeSession()');
await (0, helpers_1.removeItemAsync)(this.storage, this.storageKey);
await (0, helpers_1.removeItemAsync)(this.storage, this.storageKey + '-code-verifier');
await (0, helpers_1.removeItemAsync)(this.storage, this.storageKey + '-user');
if (this.userStorage) {
await (0, helpers_1.removeItemAsync)(this.userStorage, this.storageKey + '-user');
}
await this._notifyAllSubscribers('SIGNED_OUT', null);
}
/**
@@ -1982,10 +2259,11 @@ class GoTrueClient {
if (jwk) {
return jwk;
}
const now = Date.now();
// try fetching from cache
jwk = this.jwks.keys.find((key) => key.kid === kid);
// jwk exists and jwks isn't stale
if (jwk && this.jwks_cached_at + constants_1.JWKS_TTL > Date.now()) {
if (jwk && this.jwks_cached_at + constants_1.JWKS_TTL > now) {
return jwk;
}
// jwk isn't cached in memory so we need to fetch it from the well-known endpoint
@@ -1996,22 +2274,34 @@ class GoTrueClient {
throw error;
}
if (!data.keys || data.keys.length === 0) {
throw new errors_1.AuthInvalidJwtError('JWKS is empty');
return null;
}
this.jwks = data;
this.jwks_cached_at = Date.now();
this.jwks_cached_at = now;
// Find the signing key
jwk = data.keys.find((key) => key.kid === kid);
if (!jwk) {
throw new errors_1.AuthInvalidJwtError('No matching signing key found in JWKS');
return null;
}
return jwk;
}
/**
* @experimental This method may change in future versions.
* @description Gets the claims from a JWT. If the JWT is symmetric JWTs, it will call getUser() to verify against the server. If the JWT is asymmetric, it will be verified against the JWKS using the WebCrypto API.
* Extracts the JWT claims present in the access token by first verifying the
* JWT against the server's JSON Web Key Set endpoint
* `/.well-known/jwks.json` which is often cached, resulting in significantly
* faster responses. Prefer this method over {@link #getUser} which always
* sends a request to the Auth server for each JWT.
*
* If the project is not using an asymmetric JWT signing key (like ECC or
* RSA) it always sends a request to the Auth server (similar to {@link
* #getUser}) to verify the JWT.
*
* @param jwt An optional specific JWT you wish to verify, not the one you
* can obtain from {@link #getSession}.
* @param options Various additional options that allow you to customize the
* behavior of this method.
*/
async getClaims(jwt, jwks = { keys: [] }) {
async getClaims(jwt, options = {}) {
try {
let token = jwt;
if (!token) {
@@ -2022,12 +2312,18 @@ class GoTrueClient {
token = data.session.access_token;
}
const { header, payload, signature, raw: { header: rawHeader, payload: rawPayload }, } = (0, helpers_1.decodeJWT)(token);
// Reject expired JWTs
(0, helpers_1.validateExp)(payload.exp);
if (!(options === null || options === void 0 ? void 0 : options.allowExpired)) {
// Reject expired JWTs should only happen if jwt argument was passed
(0, helpers_1.validateExp)(payload.exp);
}
const signingKey = !header.alg ||
header.alg.startsWith('HS') ||
!header.kid ||
!('crypto' in globalThis && 'subtle' in globalThis.crypto)
? null
: await this.fetchJwk(header.kid, (options === null || options === void 0 ? void 0 : options.keys) ? { keys: options.keys } : options === null || options === void 0 ? void 0 : options.jwks);
// If symmetric algorithm or WebCrypto API is unavailable, fallback to getUser()
if (!header.kid ||
header.alg === 'HS256' ||
!('crypto' in globalThis && 'subtle' in globalThis.crypto)) {
if (!signingKey) {
const { error } = await this.getUser(token);
if (error) {
throw error;
@@ -2043,7 +2339,6 @@ class GoTrueClient {
};
}
const algorithm = (0, helpers_1.getAlgorithm)(header.alg);
const signingKey = await this.fetchJwk(header.kid, jwks);
// Convert JWK to CryptoKey
const publicKey = await crypto.subtle.importKey('jwk', signingKey, algorithm, true, [
'verify',
+2 -1
View File
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.lockInternals = exports.NavigatorLockAcquireTimeoutError = exports.navigatorLock = exports.AuthClient = exports.AuthAdminApi = exports.GoTrueClient = exports.GoTrueAdminApi = void 0;
exports.processLock = exports.lockInternals = exports.NavigatorLockAcquireTimeoutError = exports.navigatorLock = exports.AuthClient = exports.AuthAdminApi = exports.GoTrueClient = exports.GoTrueAdminApi = void 0;
const GoTrueAdminApi_1 = __importDefault(require("./GoTrueAdminApi"));
exports.GoTrueAdminApi = GoTrueAdminApi_1.default;
const GoTrueClient_1 = __importDefault(require("./GoTrueClient"));
@@ -32,4 +32,5 @@ var locks_1 = require("./lib/locks");
Object.defineProperty(exports, "navigatorLock", { enumerable: true, get: function () { return locks_1.navigatorLock; } });
Object.defineProperty(exports, "NavigatorLockAcquireTimeoutError", { enumerable: true, get: function () { return locks_1.NavigatorLockAcquireTimeoutError; } });
Object.defineProperty(exports, "lockInternals", { enumerable: true, get: function () { return locks_1.internals; } });
Object.defineProperty(exports, "processLock", { enumerable: true, get: function () { return locks_1.processLock; } });
//# sourceMappingURL=index.js.map
+13 -1
View File
@@ -5,7 +5,7 @@
* that repo!
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringToUint8Array = exports.base64UrlToUint8Array = exports.stringFromUTF8 = exports.stringToUTF8 = exports.codepointToUTF8 = exports.stringFromBase64URL = exports.stringToBase64URL = exports.byteFromBase64URL = exports.byteToBase64URL = void 0;
exports.bytesToBase64URL = exports.stringToUint8Array = exports.base64UrlToUint8Array = exports.stringFromUTF8 = exports.stringToUTF8 = exports.codepointToUTF8 = exports.stringFromBase64URL = exports.stringToBase64URL = exports.byteFromBase64URL = exports.byteToBase64URL = void 0;
/**
* An array of characters that encode 6 bits into a Base64-URL alphabet
* character.
@@ -255,4 +255,16 @@ function stringToUint8Array(str) {
return new Uint8Array(result);
}
exports.stringToUint8Array = stringToUint8Array;
function bytesToBase64URL(bytes) {
const result = [];
const state = { queue: 0, queuedBits: 0 };
const onChar = (char) => {
result.push(char);
};
bytes.forEach((byte) => byteToBase64URL(byte, state, onChar));
// always call with `null` after processing all bytes
byteToBase64URL(null, state, onChar);
return result.join('');
}
exports.bytesToBase64URL = bytesToBase64URL;
//# sourceMappingURL=base64url.js.map
+1 -1
View File
@@ -27,5 +27,5 @@ exports.API_VERSIONS = {
},
};
exports.BASE64URL_REGEX = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$/i;
exports.JWKS_TTL = 600000; // 10 minutes
exports.JWKS_TTL = 10 * 60 * 1000; // 10 minutes
//# sourceMappingURL=constants.js.map
+45 -1
View File
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAlgorithm = exports.validateExp = exports.parseResponseAPIVersion = exports.getCodeChallengeAndMethod = exports.generatePKCEChallenge = exports.generatePKCEVerifier = exports.retryable = exports.sleep = exports.decodeJWT = exports.Deferred = exports.removeItemAsync = exports.getItemAsync = exports.setItemAsync = exports.looksLikeFetchResponse = exports.resolveFetch = exports.parseParametersFromURL = exports.supportsLocalStorage = exports.isBrowser = exports.uuid = exports.expiresAt = void 0;
exports.deepClone = exports.userNotAvailableProxy = exports.validateUUID = exports.getAlgorithm = exports.validateExp = exports.parseResponseAPIVersion = exports.getCodeChallengeAndMethod = exports.generatePKCEChallenge = exports.generatePKCEVerifier = exports.retryable = exports.sleep = exports.decodeJWT = exports.Deferred = exports.removeItemAsync = exports.getItemAsync = exports.setItemAsync = exports.looksLikeFetchResponse = exports.resolveFetch = exports.parseParametersFromURL = exports.supportsLocalStorage = exports.isBrowser = exports.uuid = exports.expiresAt = void 0;
const constants_1 = require("./constants");
const errors_1 = require("./errors");
const base64url_1 = require("./base64url");
@@ -331,4 +331,48 @@ function getAlgorithm(alg) {
}
}
exports.getAlgorithm = getAlgorithm;
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
function validateUUID(str) {
if (!UUID_REGEX.test(str)) {
throw new Error('@supabase/auth-js: Expected parameter to be UUID but is not');
}
}
exports.validateUUID = validateUUID;
function userNotAvailableProxy() {
const proxyTarget = {};
return new Proxy(proxyTarget, {
get: (target, prop) => {
if (prop === '__isUserNotAvailableProxy') {
return true;
}
// Preventative check for common problematic symbols during cloning/inspection
// These symbols might be accessed by structuredClone or other internal mechanisms.
if (typeof prop === 'symbol') {
const sProp = prop.toString();
if (sProp === 'Symbol(Symbol.toPrimitive)' ||
sProp === 'Symbol(Symbol.toStringTag)' ||
sProp === 'Symbol(util.inspect.custom)') {
// Node.js util.inspect
return undefined;
}
}
throw new Error(`@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Accessing the "${prop}" property of the session object is not supported. Please use getUser() instead.`);
},
set: (_target, prop) => {
throw new Error(`@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Setting the "${prop}" property of the session object is not supported. Please use getUser() to fetch a user object you can manipulate.`);
},
deleteProperty: (_target, prop) => {
throw new Error(`@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Deleting the "${prop}" property of the session object is not supported. Please use getUser() to fetch a user object you can manipulate.`);
},
});
}
exports.userNotAvailableProxy = userNotAvailableProxy;
/**
* Deep clones a JSON-serializable object using JSON.parse(JSON.stringify(obj)).
* Note: Only works for JSON-safe data.
*/
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
exports.deepClone = deepClone;
//# sourceMappingURL=helpers.js.map
@@ -1,30 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.memoryLocalStorageAdapter = exports.localStorageAdapter = void 0;
const helpers_1 = require("./helpers");
/**
* Provides safe access to the globalThis.localStorage property.
*/
exports.localStorageAdapter = {
getItem: (key) => {
if (!(0, helpers_1.supportsLocalStorage)()) {
return null;
}
return globalThis.localStorage.getItem(key);
},
setItem: (key, value) => {
if (!(0, helpers_1.supportsLocalStorage)()) {
return;
}
globalThis.localStorage.setItem(key, value);
},
removeItem: (key) => {
if (!(0, helpers_1.supportsLocalStorage)()) {
return;
}
globalThis.localStorage.removeItem(key);
},
};
exports.memoryLocalStorageAdapter = void 0;
/**
* Returns a localStorage-like object that stores the key-value pairs in
* memory.
+2
View File
@@ -1,3 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SIGN_OUT_SCOPES = void 0;
exports.SIGN_OUT_SCOPES = ['global', 'local', 'others'];
//# sourceMappingURL=types.js.map
+1 -1
View File
@@ -1,5 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
exports.version = '2.69.1';
exports.version = '2.71.1';
//# sourceMappingURL=version.js.map
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@supabase/auth-js",
"version": "2.69.1",
"version": "2.71.1",
"private": false,
"description": "Official client library for Supabase Auth",
"keywords": [
@@ -30,7 +30,7 @@
"build:module": "tsc -p tsconfig.module.json",
"lint": "eslint ./src/**/* test/**/*.test.ts",
"test": "run-s test:clean test:infra test:suite test:clean",
"test:suite": "jest --runInBand --coverage",
"test:suite": "npm --prefix ./test run test",
"test:infra": "cd infra && docker compose down && docker compose pull && docker compose up -d && sleep 30",
"test:clean": "cd infra && docker compose down",
"docs": "typedoc src/index.ts --out docs/v2 --excludePrivate --excludeProtected",
@@ -41,8 +41,11 @@ class FunctionsClient {
if (!region) {
region = this.region;
}
// Add region as query parameter using URL API
const url = new URL(`${this.url}/${functionName}`);
if (region && region !== 'any') {
_headers['x-region'] = region;
url.searchParams.set('forceFunctionRegion', region);
}
let body;
if (functionArgs &&
@@ -70,7 +73,7 @@ class FunctionsClient {
body = JSON.stringify(functionArgs);
}
}
const response = yield this.fetch(`${this.url}/${functionName}`, {
const response = yield this.fetch(url.toString(), {
method: method || 'POST',
// headers priority is (high to low):
// 1. invoke-level headers
@@ -106,10 +109,16 @@ class FunctionsClient {
// default to text
data = yield response.text();
}
return { data, error: null };
return { data, error: null, response };
}
catch (error) {
return { data: null, error };
return {
data: null,
error,
response: error instanceof types_1.FunctionsHttpError || error instanceof types_1.FunctionsRelayError
? error.context
: undefined,
};
}
});
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@supabase/functions-js",
"version": "2.4.4",
"version": "2.4.5",
"description": "JS Client library to interact with Supabase Functions.",
"main": "dist/main/index.js",
"module": "dist/module/index.js",
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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 };
};
@@ -39,21 +49,21 @@ var REALTIME_POSTGRES_CHANGES_LISTEN_EVENT;
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 || (exports.REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = {}));
})(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 || (exports.REALTIME_LISTEN_TYPES = {}));
})(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 || (exports.REALTIME_SUBSCRIBE_STATES = {}));
})(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.
@@ -74,7 +84,7 @@ class RealtimeChannel {
this.subTopic = topic.replace(/^realtime:/i, '');
this.params.config = Object.assign({
broadcast: { ack: false, self: false },
presence: { key: '' },
presence: { key: '', enabled: false },
private: false,
}, params.config);
this.timeout = this.socket.timeout;
@@ -108,12 +118,19 @@ class RealtimeChannel {
this.state = constants_1.CHANNEL_STATES.errored;
this.rejoinTimer.scheduleTimeout();
});
this.joinPush.receive('error', (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._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.broadcastEndpointURL = (0, transformers_1.httpEndpointURL)(this.socket.endPoint);
this.private = this.params.config.private || false;
}
/** Subscribe registers your client with the server */
@@ -122,23 +139,23 @@ class RealtimeChannel {
if (!this.socket.isConnected()) {
this.socket.connect();
}
if (this.joinedOnce) {
throw `tried to subscribe multiple times. 'subscribe' can only be called a single time per channel instance`;
}
else {
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 postgres_changes = (_b = (_a = this.bindings.postgres_changes) === null || _a === void 0 ? void 0 : _a.map((r) => r.filter)) !== null && _b !== void 0 ? _b : [];
const presence_enabled = !!this.bindings[REALTIME_LISTEN_TYPES.PRESENCE] &&
this.bindings[REALTIME_LISTEN_TYPES.PRESENCE].length > 0;
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 : [],
presence: Object.assign(Object.assign({}, presence), { enabled: presence_enabled }),
postgres_changes,
private: isPrivate,
};
if (this.socket.accessTokenValue) {
accessTokenPayload.access_token = this.socket.accessTokenValue;
}
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));
this.updateJoinPayload(Object.assign({ config }, accessTokenPayload));
this.joinedOnce = true;
this._rejoin(timeout);
@@ -167,6 +184,7 @@ class RealtimeChannel {
}
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;
}
@@ -177,6 +195,7 @@ class RealtimeChannel {
}
})
.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;
})
@@ -204,6 +223,11 @@ class RealtimeChannel {
}, opts);
}
on(type, filter, callback) {
if (this.state === constants_1.CHANNEL_STATES.joined &&
type === REALTIME_LISTEN_TYPES.PRESENCE) {
this.socket.log('channel', `resubscribe to ${this.topic} due to change in presence callbacks on joined channel`);
this.unsubscribe().then(() => this.subscribe());
}
return this._on(type, filter, callback);
}
/**
@@ -285,11 +309,10 @@ class RealtimeChannel {
this.socket.log('channel', `leave ${this.topic}`);
this._trigger(constants_1.CHANNEL_EVENTS.close, 'leave', this._joinRef());
};
this.rejoinTimer.reset();
// Destroy joinPush to avoid connection timeouts during unscription phase
this.joinPush.destroy();
let leavePush = null;
return new Promise((resolve) => {
const leavePush = new push_1.default(this, constants_1.CHANNEL_EVENTS.leave, {}, timeout);
leavePush = new push_1.default(this, constants_1.CHANNEL_EVENTS.leave, {}, timeout);
leavePush
.receive('ok', () => {
onClose();
@@ -306,8 +329,23 @@ class RealtimeChannel {
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.pushBuffer = [];
this.rejoinTimer.reset();
this.joinPush.destroy();
this.state = constants_1.CHANNEL_STATES.closed;
this.bindings = {};
}
/** @internal */
async _fetchWithTimeout(url, options, timeout) {
const controller = new AbortController();
@@ -326,11 +364,23 @@ class RealtimeChannel {
pushEvent.send();
}
else {
pushEvent.startTimeout();
this.pushBuffer.push(pushEvent);
this._addToPushBuffer(pushEvent);
}
return pushEvent;
}
/** @internal */
_addToPushBuffer(pushEvent) {
pushEvent.startTimeout();
this.pushBuffer.push(pushEvent);
// Enforce buffer size limit
if (this.pushBuffer.length > constants_1.MAX_PUSH_BUFFER_SIZE) {
const removedPush = this.pushBuffer.shift();
if (removedPush) {
removedPush.destroy();
this.socket.log('channel', `discarded push due to buffer overflow: ${removedPush.event}`, removedPush.payload);
}
}
}
/**
* Overridable message hook
*
@@ -450,11 +500,13 @@ class RealtimeChannel {
/** @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));
});
if (this.bindings[typeLower]) {
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 */
+411 -188
View File
@@ -15,24 +15,42 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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 websocket_factory_1 = __importDefault(require("./lib/websocket-factory"));
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 NATIVE_WEBSOCKET_AVAILABLE = typeof WebSocket !== 'undefined';
// Connection-related constants
const CONNECTION_TIMEOUTS = {
HEARTBEAT_INTERVAL: 25000,
RECONNECT_DELAY: 10,
HEARTBEAT_TIMEOUT_FALLBACK: 100,
};
const RECONNECT_INTERVALS = [1000, 2000, 5000, 10000];
const DEFAULT_RECONNECT_FALLBACK = 10000;
const WORKER_SCRIPT = `
addEventListener("message", (e) => {
if (e.data.event === "start") {
@@ -45,12 +63,13 @@ class RealtimeClient {
*
* @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.
* @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 The optional headers 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.
@@ -61,16 +80,20 @@ class RealtimeClient {
var _a;
this.accessTokenValue = null;
this.apiKey = null;
this.channels = [];
this.channels = new Array();
this.endPoint = '';
this.httpEndpoint = '';
this.headers = constants_1.DEFAULT_HEADERS;
/** @deprecated headers cannot be set on websocket connections */
this.headers = {};
this.params = {};
this.timeout = constants_1.DEFAULT_TIMEOUT;
this.heartbeatIntervalMs = 30000;
this.transport = null;
this.heartbeatIntervalMs = CONNECTION_TIMEOUTS.HEARTBEAT_INTERVAL;
this.heartbeatTimer = undefined;
this.pendingHeartbeatRef = null;
this.heartbeatCallback = noop;
this.ref = 0;
this.reconnectTimer = null;
this.logger = noop;
this.conn = null;
this.sendBuffer = [];
@@ -82,6 +105,9 @@ class RealtimeClient {
message: [],
};
this.accessToken = null;
this._connectionState = 'disconnected';
this._wasManualDisconnect = false;
this._authPromise = null;
/**
* Use either custom fetch, if provided, or default fetch to make HTTP requests
*
@@ -93,92 +119,72 @@ class RealtimeClient {
_fetch = customFetch;
}
else if (typeof fetch === 'undefined') {
_fetch = (...args) => Promise.resolve().then(() => __importStar(require('@supabase/node-fetch'))).then(({ default: fetch }) => fetch(...args));
// Node.js environment without native fetch
_fetch = (...args) => Promise.resolve(`${'@supabase/node-fetch'}`).then(s => __importStar(require(s))).then(({ default: fetch }) => fetch(...args))
.catch((error) => {
throw new Error(`Failed to load @supabase/node-fetch: ${error.message}. ` +
`This is required for HTTP requests in Node.js environments without native fetch.`);
});
}
else {
_fetch = fetch;
}
return (...args) => _fetch(...args);
};
// Validate required parameters
if (!((_a = options === null || options === void 0 ? void 0 : options.params) === null || _a === void 0 ? void 0 : _a.apikey)) {
throw new Error('API key is required to connect to Realtime');
}
this.apiKey = options.params.apikey;
// Initialize endpoint URLs
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.headers)
this.headers = Object.assign(Object.assign({}, this.headers), options.headers);
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.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._initializeOptions(options);
this._setupReconnectionTimer();
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) {
// Skip if already connecting, disconnecting, or connected
if (this.isConnecting() ||
this.isDisconnecting() ||
(this.conn !== null && this.isConnected())) {
return;
}
this._setConnectionState('connecting');
this._setAuthSafely('connect');
// Establish WebSocket connection
if (this.transport) {
this.conn = new this.transport(this.endpointURL(), undefined, {
headers: this.headers,
});
return;
// Use custom transport if provided
this.conn = new this.transport(this.endpointURL());
}
if (NATIVE_WEBSOCKET_AVAILABLE) {
this.conn = new WebSocket(this.endpointURL());
this.setupConnection();
return;
else {
// Try to use native WebSocket
try {
this.conn = websocket_factory_1.default.createWebSocket(this.endpointURL());
}
catch (error) {
this._setConnectionState('disconnected');
const errorMessage = error.message;
// Provide helpful error message based on environment
if (errorMessage.includes('Node.js')) {
throw new Error(`${errorMessage}\n\n` +
'To use Realtime in Node.js, you need to provide a WebSocket implementation:\n\n' +
'Option 1: Use Node.js 22+ which has native WebSocket support\n' +
'Option 2: Install and provide the "ws" package:\n\n' +
' npm install ws\n\n' +
' import ws from "ws"\n' +
' const client = new RealtimeClient(url, {\n' +
' ...options,\n' +
' transport: ws\n' +
' })');
}
throw new Error(`WebSocket not available: ${errorMessage}`);
}
}
this.conn = new WSWebSocketDummy(this.endpointURL(), undefined, {
close: () => {
this.conn = null;
},
});
Promise.resolve().then(() => __importStar(require('ws'))).then(({ default: WS }) => {
this.conn = new WS(this.endpointURL(), undefined, {
headers: this.headers,
});
this.setupConnection();
});
this._setupConnectionHandlers();
}
/**
* Returns the URL of the websocket.
@@ -194,18 +200,30 @@ class RealtimeClient {
* @param reason A custom reason for the disconnect.
*/
disconnect(code, reason) {
if (this.isDisconnecting()) {
return;
}
this._setConnectionState('disconnecting', true);
if (this.conn) {
this.conn.onclose = function () { }; // noop
// Setup fallback timer to prevent hanging in disconnecting state
const fallbackTimer = setTimeout(() => {
this._setConnectionState('disconnected');
}, 100);
this.conn.onclose = () => {
clearTimeout(fallbackTimer);
this._setConnectionState('disconnected');
};
// Close the WebSocket connection
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._teardownConnection();
}
else {
this._setConnectionState('disconnected');
}
}
/**
@@ -230,6 +248,7 @@ class RealtimeClient {
*/
async removeAllChannels() {
const values_1 = await Promise.all(this.channels.map((channel) => channel.unsubscribe()));
this.channels = [];
this.disconnect();
return values_1;
}
@@ -262,10 +281,29 @@ class RealtimeClient {
isConnected() {
return this.connectionState() === constants_1.CONNECTION_STATE.Open;
}
/**
* Returns `true` if the connection is currently connecting.
*/
isConnecting() {
return this._connectionState === 'connecting';
}
/**
* Returns `true` if the connection is currently disconnecting.
*/
isDisconnecting() {
return this._connectionState === 'disconnecting';
}
channel(topic, params = { config: {} }) {
const chan = new RealtimeChannel_1.default(`realtime:${topic}`, params, this);
this.channels.push(chan);
return chan;
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.
@@ -298,32 +336,12 @@ class RealtimeClient {
* @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 (tokenToSend) {
let parsed = null;
try {
parsed = JSON.parse(atob(tokenToSend.split('.')[1]));
}
catch (_error) { }
if (parsed && parsed.exp) {
let now = Math.floor(Date.now() / 1000);
let valid = now - parsed.exp < 0;
if (!valid) {
this.log('auth', `InvalidJWTToken: Invalid value for JWT claim "exp" with value ${parsed.exp}`);
return Promise.reject(`InvalidJWTToken: Invalid value for JWT claim "exp" with value ${parsed.exp}`);
}
}
this.accessTokenValue = tokenToSend;
this.channels.forEach((channel) => {
tokenToSend && channel.updateJoinPayload({ access_token: tokenToSend });
if (channel.joinedOnce && channel._isJoined()) {
channel._push(constants_1.CHANNEL_EVENTS.access_token, {
access_token: tokenToSend,
});
}
});
this._authPromise = this._performAuth(token);
try {
await this._authPromise;
}
finally {
this._authPromise = null;
}
}
/**
@@ -332,14 +350,26 @@ class RealtimeClient {
async sendHeartbeat() {
var _a;
if (!this.isConnected()) {
this.heartbeatCallback('disconnected');
return;
}
// Handle heartbeat timeout and force reconnection if needed
if (this.pendingHeartbeatRef) {
this.pendingHeartbeatRef = null;
this.log('transport', 'heartbeat timeout. Attempting to re-establish connection');
(_a = this.conn) === null || _a === void 0 ? void 0 : _a.close(constants_1.WS_CLOSE_NORMAL, 'hearbeat timeout');
this.heartbeatCallback('timeout');
// Force reconnection after heartbeat timeout
this._wasManualDisconnect = false;
(_a = this.conn) === null || _a === void 0 ? void 0 : _a.close(constants_1.WS_CLOSE_NORMAL, 'heartbeat timeout');
setTimeout(() => {
var _a;
if (!this.isConnected()) {
(_a = this.reconnectTimer) === null || _a === void 0 ? void 0 : _a.scheduleTimeout();
}
}, CONNECTION_TIMEOUTS.HEARTBEAT_TIMEOUT_FALLBACK);
return;
}
// Send heartbeat message to server
this.pendingHeartbeatRef = this._makeRef();
this.push({
topic: 'phoenix',
@@ -347,7 +377,11 @@ class RealtimeClient {
payload: {},
ref: this.pendingHeartbeatRef,
});
this.setAuth();
this.heartbeatCallback('sent');
this._setAuthSafely('heartbeat');
}
onHeartbeat(callback) {
this.heartbeatCallback = callback;
}
/**
* Flushes send buffer
@@ -393,83 +427,149 @@ class RealtimeClient {
* @internal
*/
_remove(channel) {
this.channels = this.channels.filter((c) => c._joinRef() !== channel._joinRef());
}
/**
* 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);
}
this.channels = this.channels.filter((c) => c.topic !== channel.topic);
}
/** @internal */
_onConnMessage(rawMessage) {
this.decode(rawMessage.data, (msg) => {
let { topic, event, payload, ref } = msg;
if (ref && ref === this.pendingHeartbeatRef) {
// Handle heartbeat responses
if (msg.topic === 'phoenix' && msg.event === 'phx_reply') {
this.heartbeatCallback(msg.payload.status === 'ok' ? 'ok' : 'error');
}
// Handle pending heartbeat reference cleanup
if (msg.ref && msg.ref === this.pendingHeartbeatRef) {
this.pendingHeartbeatRef = null;
}
this.log('receive', `${payload.status || ''} ${topic} ${event} ${(ref && '(' + ref + ')') || ''}`, payload);
// Log incoming message
const { topic, event, payload, ref } = msg;
const refString = ref ? `(${ref})` : '';
const status = payload.status || '';
this.log('receive', `${status} ${topic} ${event} ${refString}`.trim(), payload);
// Route message to appropriate channels
this.channels
.filter((channel) => channel._isMember(topic))
.forEach((channel) => channel._trigger(event, payload, ref));
this.stateChangeCallbacks.message.forEach((callback) => callback(msg));
this._triggerStateCallbacks('message', msg);
});
}
/**
* Clear specific timer
* @internal
*/
_clearTimer(timer) {
var _a;
if (timer === 'heartbeat' && this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = undefined;
}
else if (timer === 'reconnect') {
(_a = this.reconnectTimer) === null || _a === void 0 ? void 0 : _a.reset();
}
}
/**
* Clear all timers
* @internal
*/
_clearAllTimers() {
this._clearTimer('heartbeat');
this._clearTimer('reconnect');
}
/**
* Setup connection handlers for WebSocket events
* @internal
*/
_setupConnectionHandlers() {
if (!this.conn)
return;
// Set binary type if supported (browsers and most WebSocket implementations)
if ('binaryType' in 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);
}
/**
* Teardown connection and cleanup resources
* @internal
*/
_teardownConnection() {
if (this.conn) {
this.conn.onopen = null;
this.conn.onerror = null;
this.conn.onmessage = null;
this.conn.onclose = null;
this.conn = null;
}
this._clearAllTimers();
this.channels.forEach((channel) => channel.teardown());
}
/** @internal */
_onConnOpen() {
this._setConnectionState('connected');
this.log('transport', `connected to ${this.endpointURL()}`);
this.flushSendBuffer();
this._clearTimer('reconnect');
if (!this.worker) {
this._startHeartbeat();
}
else {
if (!this.workerRef) {
this._startWorkerHeartbeat();
}
}
this._triggerStateCallbacks('open');
}
/** @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 */
async _onConnOpen() {
this.log('transport', `connected to ${this.endpointURL()}`);
this.flushSendBuffer();
this.reconnectTimer.reset();
if (!this.worker) {
this.heartbeatTimer && clearInterval(this.heartbeatTimer);
this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), this.heartbeatIntervalMs);
}
else {
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,
});
}
this.stateChangeCallbacks.open.forEach((callback) => callback());
}
/** @internal */
_onConnClose(event) {
var _a;
this._setConnectionState('disconnected');
this.log('transport', 'close', event);
this._triggerChanError();
this.heartbeatTimer && clearInterval(this.heartbeatTimer);
this.reconnectTimer.scheduleTimeout();
this.stateChangeCallbacks.close.forEach((callback) => callback(event));
this._clearTimer('heartbeat');
// Only schedule reconnection if it wasn't a manual disconnect
if (!this._wasManualDisconnect) {
(_a = this.reconnectTimer) === null || _a === void 0 ? void 0 : _a.scheduleTimeout();
}
this._triggerStateCallbacks('close', event);
}
/** @internal */
_onConnError(error) {
this.log('transport', error.message);
this._setConnectionState('disconnected');
this.log('transport', `${error}`);
this._triggerChanError();
this.stateChangeCallbacks.error.forEach((callback) => callback(error));
this._triggerStateCallbacks('error', error);
}
/** @internal */
_triggerChanError() {
@@ -495,20 +595,143 @@ class RealtimeClient {
}
return result_url;
}
}
exports.default = RealtimeClient;
class WSWebSocketDummy {
constructor(address, _protocols, options) {
this.binaryType = 'arraybuffer';
this.onclose = () => { };
this.onerror = () => { };
this.onmessage = () => { };
this.onopen = () => { };
this.readyState = constants_1.SOCKET_STATES.connecting;
this.send = () => { };
this.url = null;
this.url = address;
this.close = options.close;
/**
* Set connection state with proper state management
* @internal
*/
_setConnectionState(state, manual = false) {
this._connectionState = state;
if (state === 'connecting') {
this._wasManualDisconnect = false;
}
else if (state === 'disconnecting') {
this._wasManualDisconnect = manual;
}
}
/**
* Perform the actual auth operation
* @internal
*/
async _performAuth(token = null) {
let tokenToSend;
if (token) {
tokenToSend = token;
}
else if (this.accessToken) {
// Always call the accessToken callback to get fresh token
tokenToSend = await this.accessToken();
}
else {
tokenToSend = 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,
});
}
});
}
}
/**
* Wait for any in-flight auth operations to complete
* @internal
*/
async _waitForAuthIfNeeded() {
if (this._authPromise) {
await this._authPromise;
}
}
/**
* Safely call setAuth with standardized error handling
* @internal
*/
_setAuthSafely(context = 'general') {
this.setAuth().catch((e) => {
this.log('error', `error setting auth in ${context}`, e);
});
}
/**
* Trigger state change callbacks with proper error handling
* @internal
*/
_triggerStateCallbacks(event, data) {
try {
this.stateChangeCallbacks[event].forEach((callback) => {
try {
callback(data);
}
catch (e) {
this.log('error', `error in ${event} callback`, e);
}
});
}
catch (e) {
this.log('error', `error triggering ${event} callbacks`, e);
}
}
/**
* Setup reconnection timer with proper configuration
* @internal
*/
_setupReconnectionTimer() {
this.reconnectTimer = new timer_1.default(async () => {
setTimeout(async () => {
await this._waitForAuthIfNeeded();
if (!this.isConnected()) {
this.connect();
}
}, CONNECTION_TIMEOUTS.RECONNECT_DELAY);
}, this.reconnectAfterMs);
}
/**
* Initialize client options with defaults
* @internal
*/
_initializeOptions(options) {
var _a, _b, _c, _d, _e, _f, _g, _h;
// Set defaults
this.transport = (_a = options === null || options === void 0 ? void 0 : options.transport) !== null && _a !== void 0 ? _a : null;
this.timeout = (_b = options === null || options === void 0 ? void 0 : options.timeout) !== null && _b !== void 0 ? _b : constants_1.DEFAULT_TIMEOUT;
this.heartbeatIntervalMs =
(_c = options === null || options === void 0 ? void 0 : options.heartbeatIntervalMs) !== null && _c !== void 0 ? _c : CONNECTION_TIMEOUTS.HEARTBEAT_INTERVAL;
this.worker = (_d = options === null || options === void 0 ? void 0 : options.worker) !== null && _d !== void 0 ? _d : false;
this.accessToken = (_e = options === null || options === void 0 ? void 0 : options.accessToken) !== null && _e !== void 0 ? _e : null;
// Handle special cases
if (options === null || options === void 0 ? void 0 : options.params)
this.params = options.params;
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 });
}
// Set up functions with defaults
this.reconnectAfterMs =
(_f = options === null || options === void 0 ? void 0 : options.reconnectAfterMs) !== null && _f !== void 0 ? _f : ((tries) => {
return RECONNECT_INTERVALS[tries - 1] || DEFAULT_RECONNECT_FALLBACK;
});
this.encode =
(_g = options === null || options === void 0 ? void 0 : options.encode) !== null && _g !== void 0 ? _g : ((payload, callback) => {
return callback(JSON.stringify(payload));
});
this.decode =
(_h = options === null || options === void 0 ? void 0 : options.decode) !== null && _h !== void 0 ? _h : this.serializer.decode.bind(this.serializer);
// Handle worker setup
if (this.worker) {
if (typeof window !== 'undefined' && !window.Worker) {
throw new Error('Web Worker is not supported');
}
this.workerUrl = options === null || options === void 0 ? void 0 : options.workerUrl;
}
}
}
exports.default = RealtimeClient;
//# sourceMappingURL=RealtimeClient.js.map
@@ -10,7 +10,7 @@ var 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 || (exports.REALTIME_PRESENCE_LISTEN_EVENTS = {}));
})(REALTIME_PRESENCE_LISTEN_EVENTS || (exports.REALTIME_PRESENCE_LISTEN_EVENTS = REALTIME_PRESENCE_LISTEN_EVENTS = {}));
class RealtimePresence {
/**
* Initializes the Presence.
@@ -24,6 +24,7 @@ class RealtimePresence {
this.state = {};
this.pendingDiffs = [];
this.joinRef = null;
this.enabled = false;
this.caller = {
onJoin: () => { },
onLeave: () => { },
+20 -8
View File
@@ -15,18 +15,28 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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;
exports.WebSocketFactory = 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"));
@@ -38,4 +48,6 @@ Object.defineProperty(exports, "REALTIME_CHANNEL_STATES", { enumerable: true, ge
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; } });
const websocket_factory_1 = __importDefault(require("./lib/websocket-factory"));
exports.WebSocketFactory = websocket_factory_1.default;
//# sourceMappingURL=index.js.map
@@ -1,18 +1,20 @@
"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.VSN = exports.DEFAULT_HEADERS = void 0;
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.VSN = exports.DEFAULT_VERSION = void 0;
const version_1 = require("./version");
exports.DEFAULT_HEADERS = { 'X-Client-Info': `realtime-js/${version_1.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;
exports.MAX_PUSH_BUFFER_SIZE = 100;
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 || (exports.SOCKET_STATES = {}));
})(SOCKET_STATES || (exports.SOCKET_STATES = SOCKET_STATES = {}));
var CHANNEL_STATES;
(function (CHANNEL_STATES) {
CHANNEL_STATES["closed"] = "closed";
@@ -20,7 +22,7 @@ var CHANNEL_STATES;
CHANNEL_STATES["joined"] = "joined";
CHANNEL_STATES["joining"] = "joining";
CHANNEL_STATES["leaving"] = "leaving";
})(CHANNEL_STATES = exports.CHANNEL_STATES || (exports.CHANNEL_STATES = {}));
})(CHANNEL_STATES || (exports.CHANNEL_STATES = CHANNEL_STATES = {}));
var CHANNEL_EVENTS;
(function (CHANNEL_EVENTS) {
CHANNEL_EVENTS["close"] = "phx_close";
@@ -29,16 +31,16 @@ var CHANNEL_EVENTS;
CHANNEL_EVENTS["reply"] = "phx_reply";
CHANNEL_EVENTS["leave"] = "phx_leave";
CHANNEL_EVENTS["access_token"] = "access_token";
})(CHANNEL_EVENTS = exports.CHANNEL_EVENTS || (exports.CHANNEL_EVENTS = {}));
})(CHANNEL_EVENTS || (exports.CHANNEL_EVENTS = CHANNEL_EVENTS = {}));
var TRANSPORTS;
(function (TRANSPORTS) {
TRANSPORTS["websocket"] = "websocket";
})(TRANSPORTS = exports.TRANSPORTS || (exports.TRANSPORTS = {}));
})(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 || (exports.CONNECTION_STATE = {}));
})(CONNECTION_STATE || (exports.CONNECTION_STATE = CONNECTION_STATE = {}));
//# sourceMappingURL=constants.js.map
@@ -24,6 +24,7 @@ class Timer {
reset() {
this.tries = 0;
clearTimeout(this.timer);
this.timer = undefined;
}
// Cancels any previous scheduleTimeout and schedules callback
scheduleTimeout() {
@@ -32,7 +32,7 @@ var PostgresTypes;
PostgresTypes["timetz"] = "timetz";
PostgresTypes["tsrange"] = "tsrange";
PostgresTypes["tstzrange"] = "tstzrange";
})(PostgresTypes = exports.PostgresTypes || (exports.PostgresTypes = {}));
})(PostgresTypes || (exports.PostgresTypes = PostgresTypes = {}));
/**
* Takes an array of columns and an object of string values then converts each string value
* to its mapped type.
@@ -223,7 +223,7 @@ const httpEndpointURL = (socketUrl) => {
let url = socketUrl;
url = url.replace(/^ws/i, 'http');
url = url.replace(/(\/socket\/websocket|\/socket|\/websocket)\/?$/i, '');
return url.replace(/\/+$/, '');
return url.replace(/\/+$/, '') + '/api/broadcast';
};
exports.httpEndpointURL = httpEndpointURL;
//# sourceMappingURL=transformers.js.map
@@ -1,5 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
exports.version = '2.11.2';
exports.version = '2.15.1';
//# sourceMappingURL=version.js.map
@@ -0,0 +1,95 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocketFactory = void 0;
class WebSocketFactory {
static detectEnvironment() {
var _a;
if (typeof WebSocket !== 'undefined') {
return { type: 'native', constructor: WebSocket };
}
if (typeof globalThis !== 'undefined' &&
typeof globalThis.WebSocket !== 'undefined') {
return { type: 'native', constructor: globalThis.WebSocket };
}
if (typeof global !== 'undefined' &&
typeof global.WebSocket !== 'undefined') {
return { type: 'native', constructor: global.WebSocket };
}
if (typeof globalThis !== 'undefined' &&
typeof globalThis.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' && globalThis.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.',
};
}
if (typeof process !== 'undefined' &&
process.versions &&
process.versions.node) {
const nodeVersion = parseInt(process.versions.node.split('.')[0]);
// Node.js 22+ should have native WebSocket
if (nodeVersion >= 22) {
// Check if native WebSocket is available (should be in Node.js 22+)
if (typeof globalThis.WebSocket !== 'undefined') {
return { type: 'native', constructor: globalThis.WebSocket };
}
// If not available, user needs to provide it
return {
type: 'unsupported',
error: `Node.js ${nodeVersion} detected but native WebSocket not found.`,
workaround: 'Provide a WebSocket implementation via the transport option.',
};
}
// Node.js < 22 doesn't have native WebSocket
return {
type: 'unsupported',
error: `Node.js ${nodeVersion} detected without native WebSocket support.`,
workaround: 'For Node.js < 22, install "ws" package and provide it via the transport option:\n' +
'import ws from "ws"\n' +
'new RealtimeClient(url, { transport: ws })',
};
}
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.",
};
}
static getWebSocketConstructor() {
const env = this.detectEnvironment();
if (env.constructor) {
return env.constructor;
}
let errorMessage = env.error || 'WebSocket not supported in this environment.';
if (env.workaround) {
errorMessage += `\n\nSuggested solution: ${env.workaround}`;
}
throw new Error(errorMessage);
}
static createWebSocket(url, protocols) {
const WS = this.getWebSocketConstructor();
return new WS(url, protocols);
}
static isWebSocketSupported() {
try {
const env = this.detectEnvironment();
return env.type === 'native' || env.type === 'ws';
}
catch (_a) {
return false;
}
}
}
exports.WebSocketFactory = WebSocketFactory;
exports.default = WebSocketFactory;
//# sourceMappingURL=websocket-factory.js.map
+13 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@supabase/realtime-js",
"version": "2.11.2",
"version": "2.15.1",
"description": "Listen to realtime updates to your PostgreSQL database",
"keywords": [
"realtime",
@@ -32,22 +32,22 @@
"test": "vitest run",
"test:watch": "vitest",
"coverage": "vitest run --coverage",
"coverage:text": "vitest run --coverage.enabled true --coverage.reporter=text",
"docs": "typedoc src/index.ts --out docs/v2",
"docs:json": "typedoc --json docs/v2/spec.json --excludeExternals src/index.ts",
"check-exports": "attw --pack .",
"ci": "run-s test coverage"
},
"dependencies": {
"@supabase/node-fetch": "^2.6.14",
"@types/phoenix": "^1.5.4",
"@types/ws": "^8.5.10",
"ws": "^8.18.0"
"@supabase/node-fetch": "^2.6.13",
"@types/phoenix": "^1.6.6",
"ws": "^8.18.2",
"@types/ws": "^8.18.1"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.16.2",
"@types/sinon": "^17.0.3",
"@vitest/coverage-v8": "^2.0.5",
"eslint": "^7.0.0",
"@arethetypeswrong/cli": "^0.16.4",
"@vitest/coverage-v8": "^3.1.4",
"eslint": "^9.27.0",
"esm": "^3.2.25",
"jsdom": "^16.7.0",
"jsdom-global": "3.0.0",
@@ -55,12 +55,11 @@
"mock-socket": "^9.3.1",
"npm-run-all": "^4.1.5",
"nyc": "^15.1.0",
"prettier": "^2.1.2",
"prettier": "^2.8.8",
"semantic-release-plugin-update-version-in-files": "^1.1.0",
"sinon": "^18.0.0",
"typedoc": "^0.22.16",
"typescript": "^4.0.3",
"vitest": "^2.0.5",
"typedoc": "^0.27.9",
"typescript": "^5.8.3",
"vitest": "^3.1.4",
"web-worker": "1.2.0"
}
}
@@ -7,8 +7,8 @@ exports.StorageClient = void 0;
const StorageFileApi_1 = __importDefault(require("./packages/StorageFileApi"));
const StorageBucketApi_1 = __importDefault(require("./packages/StorageBucketApi"));
class StorageClient extends StorageBucketApi_1.default {
constructor(url, headers = {}, fetch) {
super(url, headers, fetch);
constructor(url, headers = {}, fetch, opts) {
super(url, headers, fetch, opts);
}
/**
* Perform file operation in a bucket.
+3 -1
View File
@@ -14,16 +14,18 @@ function isStorageError(error) {
}
exports.isStorageError = isStorageError;
class StorageApiError extends StorageError {
constructor(message, status) {
constructor(message, status, statusCode) {
super(message);
this.name = 'StorageApiError';
this.status = status;
this.statusCode = statusCode;
}
toJSON() {
return {
name: this.name,
message: this.message,
status: this.status,
statusCode: this.statusCode,
};
}
}
+12 -4
View File
@@ -19,7 +19,9 @@ const handleError = (error, reject, options) => __awaiter(void 0, void 0, void 0
error
.json()
.then((err) => {
reject(new errors_1.StorageApiError(_getErrorMessage(err), error.status || 500));
const status = error.status || 500;
const statusCode = (err === null || err === void 0 ? void 0 : err.statusCode) || status + '';
reject(new errors_1.StorageApiError(_getErrorMessage(err), status, statusCode));
})
.catch((err) => {
reject(new errors_1.StorageUnknownError(_getErrorMessage(err), err));
@@ -31,13 +33,19 @@ const handleError = (error, reject, options) => __awaiter(void 0, void 0, void 0
});
const _getRequestParams = (method, options, parameters, body) => {
const params = { method, headers: (options === null || options === void 0 ? void 0 : options.headers) || {} };
if (method === 'GET') {
if (method === 'GET' || !body) {
return params;
}
params.headers = Object.assign({ 'Content-Type': 'application/json' }, options === null || options === void 0 ? void 0 : options.headers);
if (body) {
if ((0, helpers_1.isPlainObject)(body)) {
params.headers = Object.assign({ 'Content-Type': 'application/json' }, options === null || options === void 0 ? void 0 : options.headers);
params.body = JSON.stringify(body);
}
else {
params.body = body;
}
if (options === null || options === void 0 ? void 0 : options.duplex) {
params.duplex = options.duplex;
}
return Object.assign(Object.assign({}, params), parameters);
};
function _handleRequest(fetcher, method, url, options, parameters, body) {
+18 -1
View File
@@ -32,7 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.recursiveToCamel = exports.resolveResponse = exports.resolveFetch = void 0;
exports.isPlainObject = exports.recursiveToCamel = exports.resolveResponse = exports.resolveFetch = void 0;
const resolveFetch = (customFetch) => {
let _fetch;
if (customFetch) {
@@ -70,4 +70,21 @@ const recursiveToCamel = (item) => {
return result;
};
exports.recursiveToCamel = recursiveToCamel;
/**
* Determine if input is a plain object
* An object is plain if it's created by either {}, new Object(), or Object.create(null)
* source: https://github.com/sindresorhus/is-plain-obj
*/
const isPlainObject = (value) => {
if (typeof value !== 'object' || value === null) {
return false;
}
const prototype = Object.getPrototypeOf(value);
return ((prototype === null ||
prototype === Object.prototype ||
Object.getPrototypeOf(prototype) === null) &&
!(Symbol.toStringTag in value) &&
!(Symbol.iterator in value));
};
exports.isPlainObject = isPlainObject;
//# sourceMappingURL=helpers.js.map
+1 -1
View File
@@ -2,5 +2,5 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
// generated by genversion
exports.version = '2.7.1';
exports.version = '2.11.0';
//# sourceMappingURL=version.js.map
@@ -14,8 +14,17 @@ const errors_1 = require("../lib/errors");
const fetch_1 = require("../lib/fetch");
const helpers_1 = require("../lib/helpers");
class StorageBucketApi {
constructor(url, headers = {}, fetch) {
this.url = url;
constructor(url, headers = {}, fetch, opts) {
const baseUrl = new URL(url);
// if legacy uri is used, replace with new storage host (disables request buffering to allow > 50GB uploads)
// "project-ref.supabase.co" becomes "project-ref.storage.supabase.co"
if (opts === null || opts === void 0 ? void 0 : opts.useNewHostname) {
const isSupabaseHost = /supabase\.(co|in|red)$/.test(baseUrl.hostname);
if (isSupabaseHost && !baseUrl.hostname.includes('storage.supabase.')) {
baseUrl.hostname = baseUrl.hostname.replace('supabase.', 'storage.supabase.');
}
}
this.url = baseUrl.href;
this.headers = Object.assign(Object.assign({}, constants_1.DEFAULT_HEADERS), headers);
this.fetch = (0, helpers_1.resolveFetch)(fetch);
}
@@ -67,6 +76,8 @@ class StorageBucketApi {
* The default value is null, which allows files with all mime types to be uploaded.
* Each mime type specified can be a wildcard, e.g. image/*, or a specific mime type, e.g. image/png.
* @returns newly created bucket id
* @param options.type (private-beta) specifies the bucket type. see `BucketType` for more details.
* - default bucket type is `STANDARD`
*/
createBucket(id, options = {
public: false,
@@ -76,6 +87,7 @@ class StorageBucketApi {
const data = yield (0, fetch_1.post)(this.fetch, `${this.url}/bucket`, {
id,
name: id,
type: options.type,
public: options.public,
file_size_limit: options.fileSizeLimit,
allowed_mime_types: options.allowedMimeTypes,
@@ -74,18 +74,11 @@ class StorageFileApi {
}
const cleanPath = this._removeEmptyFolders(path);
const _path = this._getFinalPath(cleanPath);
const res = yield this.fetch(`${this.url}/object/${_path}`, Object.assign({ method, body: body, headers }, ((options === null || options === void 0 ? void 0 : options.duplex) ? { duplex: options.duplex } : {})));
const data = yield res.json();
if (res.ok) {
return {
data: { path: cleanPath, id: data.Id, fullPath: data.Key },
error: null,
};
}
else {
const error = data;
return { data: null, error };
}
const data = yield (method == 'PUT' ? fetch_1.put : fetch_1.post)(this.fetch, `${this.url}/object/${_path}`, body, Object.assign({ headers }, ((options === null || options === void 0 ? void 0 : options.duplex) ? { duplex: options.duplex } : {})));
return {
data: { path: cleanPath, id: data.Id, fullPath: data.Key },
error: null,
};
}
catch (error) {
if ((0, errors_1.isStorageError)(error)) {
@@ -136,22 +129,11 @@ class StorageFileApi {
headers['cache-control'] = `max-age=${options.cacheControl}`;
headers['content-type'] = options.contentType;
}
const res = yield this.fetch(url.toString(), {
method: 'PUT',
body: body,
headers,
});
const data = yield res.json();
if (res.ok) {
return {
data: { path: cleanPath, fullPath: data.Key },
error: null,
};
}
else {
const error = data;
return { data: null, error };
}
const data = yield (0, fetch_1.put)(this.fetch, url.toString(), body, { headers });
return {
data: { path: cleanPath, fullPath: data.Key },
error: null,
};
}
catch (error) {
if ((0, errors_1.isStorageError)(error)) {
@@ -498,6 +480,7 @@ class StorageFileApi {
/**
* Lists all the files within a bucket.
* @param path The folder path.
* @param options Search options including limit (defaults to 100), offset, sortBy, and search
*/
list(path, options, parameters) {
return __awaiter(this, void 0, void 0, function* () {
@@ -514,6 +497,26 @@ class StorageFileApi {
}
});
}
/**
* @experimental this method signature might change in the future
* @param options search options
* @param parameters
*/
listV2(options, parameters) {
return __awaiter(this, void 0, void 0, function* () {
try {
const body = Object.assign({}, options);
const data = yield (0, fetch_1.post)(this.fetch, `${this.url}/object/list-v2/${this.bucketId}`, body, { headers: this.headers }, parameters);
return { data, error: null };
}
catch (error) {
if ((0, errors_1.isStorageError)(error)) {
return { data: null, error };
}
throw error;
}
});
}
encodeMetadata(metadata) {
return JSON.stringify(metadata);
}
@@ -524,7 +527,7 @@ class StorageFileApi {
return btoa(data);
}
_getFinalPath(path) {
return `${this.bucketId}/${path}`;
return `${this.bucketId}/${path.replace(/^\/+/, '')}`;
}
_removeEmptyFolders(path) {
return path.replace(/^\/|\/$/g, '').replace(/\/+/g, '/');
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@supabase/storage-js",
"version": "2.7.1",
"version": "2.11.0",
"description": "Isomorphic storage client for Supabase.",
"keywords": [
"javascript",
@@ -29,7 +29,7 @@
"build:umd": "webpack",
"types-generate": "dts-gen -m '@supabase/storage-js' -s",
"test": "run-s test:clean test:infra test:suite test:clean",
"test:suite": "jest --runInBand",
"test:suite": "jest --runInBand --coverage",
"test:infra": "cd infra && docker compose down && docker compose up -d --build && sleep 10",
"test:clean": "cd infra && docker compose down --remove-orphans",
"docs": "typedoc --entryPoints src/index.ts --out docs/v2 --entryPoints src/packages/* --excludePrivate --excludeProtected",
@@ -32,6 +32,7 @@ class SupabaseClient {
* @param options.auth.persistSession Set to "true" if you want to automatically save the user session into local storage.
* @param options.auth.detectSessionInUrl Set to "true" if you want to automatically detects OAuth grants in the URL and signs in the user.
* @param options.realtime Options passed along to realtime-js constructor.
* @param options.storage Options passed along to the storage-js constructor.
* @param options.global.fetch A custom fetch implementation.
* @param options.global.headers Any additional headers to send with each network request.
*/
@@ -79,6 +80,7 @@ class SupabaseClient {
schema: settings.db.schema,
fetch: this.fetch,
});
this.storage = new storage_js_1.StorageClient(this.storageUrl.href, this.headers, this.fetch, options === null || options === void 0 ? void 0 : options.storage);
if (!settings.accessToken) {
this._listenForAuthEvents();
}
@@ -92,12 +94,6 @@ class SupabaseClient {
customFetch: this.fetch,
});
}
/**
* Supabase Storage allows you to manage user-generated content, such as photos or videos.
*/
get storage() {
return new storage_js_1.StorageClient(this.storageUrl.href, this.headers, this.fetch);
}
/**
* Perform a query on a table or a view.
*
@@ -182,7 +178,7 @@ class SupabaseClient {
return yield this.accessToken();
}
const { data } = yield this.auth.getSession();
return (_b = (_a = data.session) === null || _a === void 0 ? void 0 : _a.access_token) !== null && _b !== void 0 ? _b : null;
return (_b = (_a = data.session) === null || _a === void 0 ? void 0 : _a.access_token) !== null && _b !== void 0 ? _b : this.supabaseKey;
});
}
_initSupabaseAuthClient({ autoRefreshToken, persistSession, detectSessionInUrl, storage, storageKey, flowType, lock, debug, }, headers, fetch) {
+27
View File
@@ -38,4 +38,31 @@ const createClient = (supabaseUrl, supabaseKey, options) => {
return new SupabaseClient_1.default(supabaseUrl, supabaseKey, options);
};
exports.createClient = createClient;
// Check for Node.js <= 18 deprecation
function shouldShowDeprecationWarning() {
// Skip in browser environments
if (typeof window !== 'undefined') {
return false;
}
// Skip if process is not available (e.g., Edge Runtime)
if (typeof process === 'undefined') {
return false;
}
// Use dynamic property access to avoid Next.js Edge Runtime static analysis warnings
const processVersion = process['version'];
if (processVersion === undefined || processVersion === null) {
return false;
}
const versionMatch = processVersion.match(/^v(\d+)\./);
if (!versionMatch) {
return false;
}
const majorVersion = parseInt(versionMatch[1], 10);
return majorVersion <= 18;
}
if (shouldShowDeprecationWarning()) {
console.warn(`⚠️ Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. ` +
`Please upgrade to Node.js 20 or later. ` +
`For more information, visit: https://github.com/orgs/supabase/discussions/37217`);
}
//# sourceMappingURL=index.js.map
@@ -31,6 +31,7 @@ function applySettingDefaults(options, defaults) {
db: Object.assign(Object.assign({}, DEFAULT_DB_OPTIONS), dbOptions),
auth: Object.assign(Object.assign({}, DEFAULT_AUTH_OPTIONS), authOptions),
realtime: Object.assign(Object.assign({}, DEFAULT_REALTIME_OPTIONS), realtimeOptions),
storage: {},
global: Object.assign(Object.assign(Object.assign({}, DEFAULT_GLOBAL_OPTIONS), globalOptions), { headers: Object.assign(Object.assign({}, ((_a = DEFAULT_GLOBAL_OPTIONS === null || DEFAULT_GLOBAL_OPTIONS === void 0 ? void 0 : DEFAULT_GLOBAL_OPTIONS.headers) !== null && _a !== void 0 ? _a : {})), ((_b = globalOptions === null || globalOptions === void 0 ? void 0 : globalOptions.headers) !== null && _b !== void 0 ? _b : {})) }),
accessToken: () => __awaiter(this, void 0, void 0, function* () { return ''; }),
};
@@ -1,5 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
exports.version = '2.49.8';
exports.version = '2.55.0';
//# sourceMappingURL=version.js.map
+26 -13
View File
@@ -1,6 +1,6 @@
{
"name": "@supabase/supabase-js",
"version": "2.49.8",
"version": "2.55.0",
"description": "Isomorphic Javascript client for Supabase",
"keywords": [
"javascript",
@@ -26,35 +26,48 @@
"build": "run-s clean format build:*",
"build:main": "tsc -p tsconfig.json",
"build:module": "tsc -p tsconfig.module.json",
"build:umd": "webpack",
"build:umd": "webpack --env mode=production",
"types-generate": "dts-gen -m '@supabase/supabase-js' -s",
"test": "run-s test:types test:run",
"test:run": "jest --runInBand",
"test:coverage": "jest --runInBand --coverage",
"test:db": "cd infra/db && docker-compose down && docker-compose up -d && sleep 5",
"test:all": "run-s test:types test:run test:integration test:integration:browser",
"test:run": "jest --runInBand --detectOpenHandles",
"test:unit": "jest --runInBand --detectOpenHandles test/unit",
"test:coverage": "jest --runInBand --coverage --testPathIgnorePatterns=\"test/integration|test/deno\"",
"test:integration": "jest --runInBand --detectOpenHandles test/integration.test.ts",
"test:integration:browser": "deno test --allow-all test/integration.browser.test.ts",
"test:edge-functions": "deno test --allow-all --no-check test/deno/edge-functions-integration.test.ts",
"test:watch": "jest --watch --verbose false --silent false",
"test:clean": "cd infra/db && docker-compose down",
"test:types": "run-s build:module && tsd --files test/*.test-d.ts",
"test:node:playwright": "cd test/integration/node-browser && npm install && cp ../../../dist/umd/supabase.js . && npm run test",
"test:bun": "cd test/integration/bun && bun install && bun test",
"test:types": "run-s build:module && tsd --files test/types/*.test-d.ts && jsr publish --dry-run",
"docs": "typedoc --entryPoints src/index.ts --out docs/v2 --includes src/**/*.ts",
"docs:json": "typedoc --entryPoints src/index.ts --includes src/**/*.ts --json docs/v2/spec.json --excludeExternals",
"serve:coverage": "npm run test:coverage && serve test/coverage"
"serve:coverage": "npm run test:coverage && serve test/coverage",
"update:test-deps": "npm run build && npm pack && cp supabase-supabase-js-*.tgz test/integration/expo/supabase-supabase-js-0.0.0-automated.tgz && cp supabase-supabase-js-*.tgz test/integration/next/supabase-supabase-js-0.0.0-automated.tgz && cp supabase-supabase-js-*.tgz test/deno/supabase-supabase-js-0.0.0-automated.tgz && cp supabase-supabase-js-*.tgz test/integration/bun/supabase-supabase-js-0.0.0-automated.tgz && cd test/integration/expo && npm install && cd ../next && npm install --legacy-peer-deps && cd ../../deno && npm install && cd ../integration/bun && bun install",
"update:test-deps:expo": "npm run build && npm pack && cp supabase-supabase-js-*.tgz test/integration/expo/supabase-supabase-js-0.0.0-automated.tgz && cd test/integration/expo && npm install",
"update:test-deps:next": "npm run build && npm pack && cp supabase-supabase-js-*.tgz test/integration/next/supabase-supabase-js-0.0.0-automated.tgz && cd test/integration/next && npm install --legacy-peer-deps",
"update:test-deps:deno": "npm run build && npm pack && cp supabase-supabase-js-*.tgz test/deno/supabase-supabase-js-0.0.0-automated.tgz && cd test/deno && npm install",
"update:test-deps:bun": "npm run build && npm pack && cp supabase-supabase-js-*.tgz test/integration/bun/supabase-supabase-js-0.0.0-automated.tgz && cd test/integration/bun && bun install"
},
"dependencies": {
"@supabase/auth-js": "2.69.1",
"@supabase/functions-js": "2.4.4",
"@supabase/auth-js": "2.71.1",
"@supabase/functions-js": "2.4.5",
"@supabase/node-fetch": "2.6.15",
"@supabase/postgrest-js": "1.19.4",
"@supabase/realtime-js": "2.11.2",
"@supabase/storage-js": "2.7.1"
"@supabase/realtime-js": "2.15.1",
"@supabase/storage-js": "^2.10.4"
},
"devDependencies": {
"@sebbo2002/semantic-release-jsr": "^1.0.0",
"@solana/wallet-standard-features": "^1.3.0",
"@types/jest": "^29.2.5",
"husky": "^4.3.0",
"husky": "^4.3.8",
"jest": "^29.3.1",
"jsr": "^0.13.5",
"npm-run-all": "^4.1.5",
"prettier": "^2.5.1",
"pretty-quick": "^3.1.3",
"puppeteer": "^24.9.0",
"rimraf": "^3.0.2",
"semantic-release-plugin-update-version-in-files": "^1.1.0",
"serve": "^14.2.1",