@pooflabs/web 0.0.90 → 0.0.92-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/hooks/useAuth.d.ts +2 -1
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/providers/offchain-auth-provider.d.ts +1 -0
- package/dist/auth/providers/phantom-wallet-provider.d.ts +10 -0
- package/dist/{index-C65AsRIA.esm.js → index-8ttHwD7w.esm.js} +14 -364
- package/dist/index-8ttHwD7w.esm.js.map +1 -0
- package/dist/index-B41m9KgX.esm.js +6 -0
- package/dist/index-B41m9KgX.esm.js.map +1 -0
- package/dist/{index-DOYZMq5N.esm.js → index-B8EmyNEY.esm.js} +13 -363
- package/dist/index-B8EmyNEY.esm.js.map +1 -0
- package/dist/{index-CzVM_hix.esm.js → index-DOAgc25g.esm.js} +1050 -42
- package/dist/index-DOAgc25g.esm.js.map +1 -0
- package/dist/{index-lt7AQ69U.js → index-DYlgQ5eM.js} +14 -364
- package/dist/index-DYlgQ5eM.js.map +1 -0
- package/dist/{index-BZ_W-sR0.js → index-Db6dsdHn.js} +2 -2
- package/dist/index-Db6dsdHn.js.map +1 -0
- package/dist/{index-Eb2uyla3.js → index-Qooqzt4n.js} +1052 -41
- package/dist/index-Qooqzt4n.js.map +1 -0
- package/dist/{index-CqpErQap.js → index-YWtjwOnI.js} +13 -363
- package/dist/index-YWtjwOnI.js.map +1 -0
- package/dist/{index.browser-D1uNEi4e.esm.js → index.browser-BAtXWf8k.esm.js} +2 -2
- package/dist/{index.browser-D1uNEi4e.esm.js.map → index.browser-BAtXWf8k.esm.js.map} +1 -1
- package/dist/{index.browser-C81ODkjH.js → index.browser-BtqDgoVf.js} +2 -2
- package/dist/{index.browser-C81ODkjH.js.map → index.browser-BtqDgoVf.js.map} +1 -1
- package/dist/{index.browser-zlnKOqcR.esm.js → index.browser-Cmz2nG0U.esm.js} +2 -2
- package/dist/{index.browser-zlnKOqcR.esm.js.map → index.browser-Cmz2nG0U.esm.js.map} +1 -1
- package/dist/{index.browser-BltIkY00.js → index.browser-DC1jUfJf.js} +2 -2
- package/dist/{index.browser-BltIkY00.js.map → index.browser-DC1jUfJf.js.map} +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/{index.native-Czk4F68O.esm.js → index.native-BbmtowC0.esm.js} +955 -30
- package/dist/index.native-BbmtowC0.esm.js.map +1 -0
- package/dist/{index.native-DYddSSgT.js → index.native-DoznXdQe.js} +957 -29
- package/dist/index.native-DoznXdQe.js.map +1 -0
- package/dist/index.native.esm.js +1 -1
- package/dist/index.native.js +4 -1
- package/dist/index.native.js.map +1 -1
- package/dist/{phantom-wallet-provider-0tX0Zs72.esm.js → phantom-wallet-provider-BZwDaCQQ.esm.js} +99 -16
- package/dist/phantom-wallet-provider-BZwDaCQQ.esm.js.map +1 -0
- package/dist/{phantom-wallet-provider-DR5qAGcS.js → phantom-wallet-provider-CNrBhCG1.js} +99 -16
- package/dist/phantom-wallet-provider-CNrBhCG1.js.map +1 -0
- package/dist/{privy-wallet-provider-BqTsdJPZ.js → privy-wallet-provider-BjiWbKiy.js} +3 -3
- package/dist/privy-wallet-provider-BjiWbKiy.js.map +1 -0
- package/dist/{privy-wallet-provider-ChMUFAEp.esm.js → privy-wallet-provider-CFa78z1Z.esm.js} +3 -3
- package/dist/privy-wallet-provider-CFa78z1Z.esm.js.map +1 -0
- package/dist/{solana-mobile-wallet-provider-Cq2H4eoW.esm.js → solana-mobile-wallet-provider-P6brXW6S.esm.js} +4 -4
- package/dist/{solana-mobile-wallet-provider-Cq2H4eoW.esm.js.map → solana-mobile-wallet-provider-P6brXW6S.esm.js.map} +1 -1
- package/dist/{solana-mobile-wallet-provider-DiXPSf8n.js → solana-mobile-wallet-provider-yETC7TqO.js} +4 -4
- package/dist/{solana-mobile-wallet-provider-DiXPSf8n.js.map → solana-mobile-wallet-provider-yETC7TqO.js.map} +1 -1
- package/package.json +2 -2
- package/dist/index-BZ_W-sR0.js.map +0 -1
- package/dist/index-C65AsRIA.esm.js.map +0 -1
- package/dist/index-CqpErQap.js.map +0 -1
- package/dist/index-CzVM_hix.esm.js.map +0 -1
- package/dist/index-D72o3sHT.esm.js +0 -6
- package/dist/index-D72o3sHT.esm.js.map +0 -1
- package/dist/index-DOYZMq5N.esm.js.map +0 -1
- package/dist/index-Eb2uyla3.js.map +0 -1
- package/dist/index-lt7AQ69U.js.map +0 -1
- package/dist/index.native-Czk4F68O.esm.js.map +0 -1
- package/dist/index.native-DYddSSgT.js.map +0 -1
- package/dist/phantom-wallet-provider-0tX0Zs72.esm.js.map +0 -1
- package/dist/phantom-wallet-provider-DR5qAGcS.js.map +0 -1
- package/dist/privy-wallet-provider-BqTsdJPZ.js.map +0 -1
- package/dist/privy-wallet-provider-ChMUFAEp.esm.js.map +0 -1
|
@@ -10362,9 +10362,40 @@ async function get(path, opts = {}) {
|
|
|
10362
10362
|
}
|
|
10363
10363
|
// Create a new request promise and store it
|
|
10364
10364
|
const requestPromise = (async () => {
|
|
10365
|
+
var _a;
|
|
10365
10366
|
try {
|
|
10366
|
-
//
|
|
10367
|
+
// For realtime chains, prefer WebSocket reads (lower latency, already connected)
|
|
10368
|
+
const config = await getConfig();
|
|
10367
10369
|
const pathIsDocument = normalizedPath.split("/").length % 2 === 0;
|
|
10370
|
+
if (((_a = config.chain) === null || _a === void 0 ? void 0 : _a.startsWith('realtime_')) && !config.isServer && !opts.prompt && !opts.shape && !opts.cursor) {
|
|
10371
|
+
try {
|
|
10372
|
+
const { wsGet, wsQuery, hasActiveConnection } = await Promise.resolve().then(function () { return subscriptionV2; });
|
|
10373
|
+
if (hasActiveConnection()) {
|
|
10374
|
+
if (pathIsDocument) {
|
|
10375
|
+
const wsResult = await wsGet(normalizedPath);
|
|
10376
|
+
const responseData = wsResult;
|
|
10377
|
+
if (!opts.bypassCache) {
|
|
10378
|
+
getCache[cacheKey] = { data: responseData, expiresAt: now + GET_CACHE_TTL };
|
|
10379
|
+
}
|
|
10380
|
+
return responseData;
|
|
10381
|
+
}
|
|
10382
|
+
else if (!opts.limit) {
|
|
10383
|
+
const wsResult = await wsQuery(normalizedPath, {
|
|
10384
|
+
filter: undefined,
|
|
10385
|
+
sort: undefined,
|
|
10386
|
+
includeSubPaths: opts.includeSubPaths,
|
|
10387
|
+
});
|
|
10388
|
+
const responseData = wsResult;
|
|
10389
|
+
if (!opts.bypassCache) {
|
|
10390
|
+
getCache[cacheKey] = { data: responseData, expiresAt: now + GET_CACHE_TTL };
|
|
10391
|
+
}
|
|
10392
|
+
return responseData;
|
|
10393
|
+
}
|
|
10394
|
+
}
|
|
10395
|
+
}
|
|
10396
|
+
catch ( /* fall through to HTTP */_b) { /* fall through to HTTP */ }
|
|
10397
|
+
}
|
|
10398
|
+
// Cache miss or bypass - proceed with HTTP API request
|
|
10368
10399
|
let response;
|
|
10369
10400
|
// Build common query params
|
|
10370
10401
|
const includeSubPathsParam = opts.includeSubPaths ? '&includeSubPaths=true' : '';
|
|
@@ -10373,7 +10404,6 @@ async function get(path, opts = {}) {
|
|
|
10373
10404
|
const cursorParam = opts.cursor ? `&cursor=${encodeURIComponent(opts.cursor)}` : '';
|
|
10374
10405
|
if (pathIsDocument) {
|
|
10375
10406
|
const itemId = encodeURIComponent(normalizedPath);
|
|
10376
|
-
// For documents, query params go after the path
|
|
10377
10407
|
const queryParams = [includeSubPathsParam, shapeParam].filter(p => p).join('');
|
|
10378
10408
|
const apiPath = queryParams ? `items/${itemId}?${queryParams.substring(1)}` : `items/${itemId}`;
|
|
10379
10409
|
response = await makeApiRequest('GET', apiPath, null, opts._overrides);
|
|
@@ -10568,7 +10598,7 @@ async function set(path, document, options) {
|
|
|
10568
10598
|
return result;
|
|
10569
10599
|
}
|
|
10570
10600
|
async function setMany(many, options) {
|
|
10571
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
10601
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
10572
10602
|
// Returns the data that was set, or undefined if the document was already set.
|
|
10573
10603
|
try {
|
|
10574
10604
|
const config = await getConfig();
|
|
@@ -10605,13 +10635,28 @@ async function setMany(many, options) {
|
|
|
10605
10635
|
}
|
|
10606
10636
|
let setResponse;
|
|
10607
10637
|
try {
|
|
10608
|
-
|
|
10638
|
+
// For realtime chains, prefer WebSocket if a connection is active (lower latency)
|
|
10639
|
+
const useWs = ((_c = config.chain) === null || _c === void 0 ? void 0 : _c.startsWith('realtime_')) && !config.isServer;
|
|
10640
|
+
if (useWs) {
|
|
10641
|
+
try {
|
|
10642
|
+
const { wsSet, hasActiveConnection } = await Promise.resolve().then(function () { return subscriptionV2; });
|
|
10643
|
+
if (hasActiveConnection()) {
|
|
10644
|
+
const wsResult = await wsSet(documents);
|
|
10645
|
+
// Normalize to same shape as HTTP 200 response so downstream handling is identical
|
|
10646
|
+
setResponse = { data: wsResult, status: 200 };
|
|
10647
|
+
}
|
|
10648
|
+
}
|
|
10649
|
+
catch ( /* fall through to HTTP */_j) { /* fall through to HTTP */ }
|
|
10650
|
+
}
|
|
10651
|
+
if (!setResponse) {
|
|
10652
|
+
setResponse = await makeApiRequest('PUT', `items`, { documents }, options === null || options === void 0 ? void 0 : options._overrides);
|
|
10653
|
+
}
|
|
10609
10654
|
}
|
|
10610
10655
|
catch (error) {
|
|
10611
10656
|
if ((error === null || error === void 0 ? void 0 : error.statusCode) === 402 && (error === null || error === void 0 ? void 0 : error.error) === 'INSUFFICIENT_BALANCE') {
|
|
10612
|
-
const deficitLamports = Number((
|
|
10613
|
-
const deficitSol = Number((
|
|
10614
|
-
throw new InsufficientBalanceError(String((
|
|
10657
|
+
const deficitLamports = Number((_d = error.deficitLamports) !== null && _d !== void 0 ? _d : 0);
|
|
10658
|
+
const deficitSol = Number((_e = error.deficitSol) !== null && _e !== void 0 ? _e : deficitLamports / 1000000000);
|
|
10659
|
+
throw new InsufficientBalanceError(String((_f = error.address) !== null && _f !== void 0 ? _f : ''), Number((_g = error.balanceLamports) !== null && _g !== void 0 ? _g : 0), Number((_h = error.estimatedCostLamports) !== null && _h !== void 0 ? _h : 0), deficitLamports, deficitSol);
|
|
10615
10660
|
}
|
|
10616
10661
|
throw error;
|
|
10617
10662
|
}
|
|
@@ -10655,7 +10700,7 @@ async function setMany(many, options) {
|
|
|
10655
10700
|
else if (setResponse.data &&
|
|
10656
10701
|
typeof setResponse.data === 'object' &&
|
|
10657
10702
|
setResponse.data.success === true) {
|
|
10658
|
-
const
|
|
10703
|
+
const _k = setResponse.data, { success: _success } = _k, rest = __rest(_k, ["success"]);
|
|
10659
10704
|
return Object.assign(Object.assign(Object.assign({}, documents.map(d => d.document)), rest), { transactionId: null });
|
|
10660
10705
|
}
|
|
10661
10706
|
else {
|
|
@@ -11702,6 +11747,21 @@ async function wsGetMany(paths) {
|
|
|
11702
11747
|
}));
|
|
11703
11748
|
}
|
|
11704
11749
|
|
|
11750
|
+
var subscriptionV2 = /*#__PURE__*/Object.freeze({
|
|
11751
|
+
__proto__: null,
|
|
11752
|
+
clearCacheV2: clearCacheV2,
|
|
11753
|
+
closeAllSubscriptionsV2: closeAllSubscriptionsV2,
|
|
11754
|
+
getCachedDataV2: getCachedDataV2,
|
|
11755
|
+
hasActiveConnection: hasActiveConnection,
|
|
11756
|
+
reconnectWithNewAuthV2: reconnectWithNewAuthV2,
|
|
11757
|
+
subscribeV2: subscribeV2,
|
|
11758
|
+
wsDelete: wsDelete,
|
|
11759
|
+
wsGet: wsGet,
|
|
11760
|
+
wsGetMany: wsGetMany,
|
|
11761
|
+
wsQuery: wsQuery,
|
|
11762
|
+
wsSet: wsSet
|
|
11763
|
+
});
|
|
11764
|
+
|
|
11705
11765
|
/**
|
|
11706
11766
|
* WebSocket Subscription Module
|
|
11707
11767
|
*
|
|
@@ -11955,6 +12015,786 @@ class ReactNativeSessionManager {
|
|
|
11955
12015
|
}
|
|
11956
12016
|
ReactNativeSessionManager.TAROBASE_SESSION_STORAGE_KEY = "tarobase_session_storage";
|
|
11957
12017
|
|
|
12018
|
+
// ---------------------------------------------------------------------------
|
|
12019
|
+
// realtime-store.ts — Client-side state manager for realtime apps.
|
|
12020
|
+
//
|
|
12021
|
+
// Manages: WS connection, in-memory state, IDB persistence, optimistic
|
|
12022
|
+
// writes, delta accumulation, loading states, ephemeral/durable tiers.
|
|
12023
|
+
// ---------------------------------------------------------------------------
|
|
12024
|
+
// ---------------------------------------------------------------------------
|
|
12025
|
+
// IDB helpers (lazy-loaded, non-blocking)
|
|
12026
|
+
// ---------------------------------------------------------------------------
|
|
12027
|
+
const IDB_NAME = 'tarobase-realtime';
|
|
12028
|
+
const IDB_STORE = 'subscriptions';
|
|
12029
|
+
const IDB_VERSION = 1;
|
|
12030
|
+
let idbPromise = null;
|
|
12031
|
+
function getIDB() {
|
|
12032
|
+
if (idbPromise)
|
|
12033
|
+
return idbPromise;
|
|
12034
|
+
if (typeof indexedDB === 'undefined') {
|
|
12035
|
+
return Promise.reject(new Error('IndexedDB not available'));
|
|
12036
|
+
}
|
|
12037
|
+
idbPromise = new Promise((resolve, reject) => {
|
|
12038
|
+
const req = indexedDB.open(IDB_NAME, IDB_VERSION);
|
|
12039
|
+
req.onupgradeneeded = () => {
|
|
12040
|
+
const db = req.result;
|
|
12041
|
+
if (!db.objectStoreNames.contains(IDB_STORE)) {
|
|
12042
|
+
db.createObjectStore(IDB_STORE);
|
|
12043
|
+
}
|
|
12044
|
+
};
|
|
12045
|
+
req.onsuccess = () => resolve(req.result);
|
|
12046
|
+
req.onerror = () => reject(req.error);
|
|
12047
|
+
});
|
|
12048
|
+
return idbPromise;
|
|
12049
|
+
}
|
|
12050
|
+
async function idbGet(key) {
|
|
12051
|
+
try {
|
|
12052
|
+
const db = await getIDB();
|
|
12053
|
+
return new Promise((resolve) => {
|
|
12054
|
+
const tx = db.transaction(IDB_STORE, 'readonly');
|
|
12055
|
+
const store = tx.objectStore(IDB_STORE);
|
|
12056
|
+
const req = store.get(key);
|
|
12057
|
+
req.onsuccess = () => { var _a; return resolve((_a = req.result) !== null && _a !== void 0 ? _a : null); };
|
|
12058
|
+
req.onerror = () => resolve(null);
|
|
12059
|
+
});
|
|
12060
|
+
}
|
|
12061
|
+
catch (_a) {
|
|
12062
|
+
return null;
|
|
12063
|
+
}
|
|
12064
|
+
}
|
|
12065
|
+
async function idbSet(key, value) {
|
|
12066
|
+
try {
|
|
12067
|
+
const db = await getIDB();
|
|
12068
|
+
return new Promise((resolve) => {
|
|
12069
|
+
const tx = db.transaction(IDB_STORE, 'readwrite');
|
|
12070
|
+
const store = tx.objectStore(IDB_STORE);
|
|
12071
|
+
store.put(value, key);
|
|
12072
|
+
tx.oncomplete = () => resolve();
|
|
12073
|
+
tx.onerror = () => resolve();
|
|
12074
|
+
});
|
|
12075
|
+
}
|
|
12076
|
+
catch (_a) {
|
|
12077
|
+
// Best-effort persistence
|
|
12078
|
+
}
|
|
12079
|
+
}
|
|
12080
|
+
// ---------------------------------------------------------------------------
|
|
12081
|
+
// RealtimeStore
|
|
12082
|
+
// ---------------------------------------------------------------------------
|
|
12083
|
+
let nextRequestId = 1;
|
|
12084
|
+
class RealtimeStore {
|
|
12085
|
+
constructor() {
|
|
12086
|
+
this.ws = null;
|
|
12087
|
+
this.wsUrl = '';
|
|
12088
|
+
this.appId = '';
|
|
12089
|
+
this.subscriptions = new Map();
|
|
12090
|
+
this.pendingRequests = new Map();
|
|
12091
|
+
this.connectPromise = null;
|
|
12092
|
+
this.reconnectTimer = null;
|
|
12093
|
+
this.reconnectDelay = 1000;
|
|
12094
|
+
this.maxReconnectDelay = 30000;
|
|
12095
|
+
this.idbFlushTimer = null;
|
|
12096
|
+
this.idbDirtyKeys = new Set();
|
|
12097
|
+
this.closed = false;
|
|
12098
|
+
this.authToken = null;
|
|
12099
|
+
}
|
|
12100
|
+
// -----------------------------------------------------------------------
|
|
12101
|
+
// Initialization
|
|
12102
|
+
// -----------------------------------------------------------------------
|
|
12103
|
+
async init() {
|
|
12104
|
+
var _a, _b;
|
|
12105
|
+
const config = await getConfig();
|
|
12106
|
+
this.appId = config.appId;
|
|
12107
|
+
this.wsUrl = config.wsApiUrl;
|
|
12108
|
+
if (config.authProvider) {
|
|
12109
|
+
try {
|
|
12110
|
+
const headers = await ((_b = (_a = config.authProvider).getAuthHeaders) === null || _b === void 0 ? void 0 : _b.call(_a));
|
|
12111
|
+
if (headers === null || headers === void 0 ? void 0 : headers.Authorization) {
|
|
12112
|
+
this.authToken = headers.Authorization.replace('Bearer ', '');
|
|
12113
|
+
}
|
|
12114
|
+
}
|
|
12115
|
+
catch ( /* no auth */_c) { /* no auth */ }
|
|
12116
|
+
}
|
|
12117
|
+
}
|
|
12118
|
+
// -----------------------------------------------------------------------
|
|
12119
|
+
// WebSocket connection
|
|
12120
|
+
// -----------------------------------------------------------------------
|
|
12121
|
+
async ensureConnected() {
|
|
12122
|
+
var _a;
|
|
12123
|
+
if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN)
|
|
12124
|
+
return;
|
|
12125
|
+
if (this.connectPromise)
|
|
12126
|
+
return this.connectPromise;
|
|
12127
|
+
this.connectPromise = this.connect();
|
|
12128
|
+
return this.connectPromise;
|
|
12129
|
+
}
|
|
12130
|
+
connect() {
|
|
12131
|
+
return new Promise((resolve, reject) => {
|
|
12132
|
+
if (this.closed) {
|
|
12133
|
+
reject(new Error('Store closed'));
|
|
12134
|
+
return;
|
|
12135
|
+
}
|
|
12136
|
+
const params = new URLSearchParams();
|
|
12137
|
+
params.set('apiKey', this.appId);
|
|
12138
|
+
// Auth token sent via subprotocol to avoid leaking in URL/logs
|
|
12139
|
+
const url = `${this.wsUrl}?${params.toString()}`;
|
|
12140
|
+
const protocols = this.authToken ? [`bearer-${this.authToken}`] : undefined;
|
|
12141
|
+
const ws = protocols ? new WebSocket(url, protocols) : new WebSocket(url);
|
|
12142
|
+
this.ws = ws;
|
|
12143
|
+
const onOpen = () => {
|
|
12144
|
+
ws.removeEventListener('error', onError);
|
|
12145
|
+
this.reconnectDelay = 1000;
|
|
12146
|
+
this.connectPromise = null;
|
|
12147
|
+
this.resubscribeAll();
|
|
12148
|
+
resolve();
|
|
12149
|
+
};
|
|
12150
|
+
const onError = (e) => {
|
|
12151
|
+
ws.removeEventListener('open', onOpen);
|
|
12152
|
+
this.connectPromise = null;
|
|
12153
|
+
reject(new Error('WebSocket connection failed'));
|
|
12154
|
+
};
|
|
12155
|
+
ws.addEventListener('open', onOpen, { once: true });
|
|
12156
|
+
ws.addEventListener('error', onError, { once: true });
|
|
12157
|
+
ws.addEventListener('message', (event) => {
|
|
12158
|
+
this.handleMessage(event.data);
|
|
12159
|
+
});
|
|
12160
|
+
ws.addEventListener('close', () => {
|
|
12161
|
+
this.ws = null;
|
|
12162
|
+
this.connectPromise = null;
|
|
12163
|
+
this.rejectAllPending('WebSocket closed');
|
|
12164
|
+
this.setAllSubscriptionStatus('reconnecting');
|
|
12165
|
+
this.scheduleReconnect();
|
|
12166
|
+
});
|
|
12167
|
+
});
|
|
12168
|
+
}
|
|
12169
|
+
scheduleReconnect() {
|
|
12170
|
+
if (this.closed)
|
|
12171
|
+
return;
|
|
12172
|
+
if (this.reconnectTimer)
|
|
12173
|
+
clearTimeout(this.reconnectTimer);
|
|
12174
|
+
this.reconnectTimer = setTimeout(() => {
|
|
12175
|
+
this.ensureConnected().catch(() => {
|
|
12176
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
|
|
12177
|
+
this.scheduleReconnect();
|
|
12178
|
+
});
|
|
12179
|
+
}, this.reconnectDelay);
|
|
12180
|
+
}
|
|
12181
|
+
resubscribeAll() {
|
|
12182
|
+
for (const sub of this.subscriptions.values()) {
|
|
12183
|
+
this.sendSubscribe(sub);
|
|
12184
|
+
}
|
|
12185
|
+
}
|
|
12186
|
+
// -----------------------------------------------------------------------
|
|
12187
|
+
// Message handling
|
|
12188
|
+
// -----------------------------------------------------------------------
|
|
12189
|
+
handleMessage(raw) {
|
|
12190
|
+
const text = typeof raw === 'string' ? raw : new TextDecoder().decode(raw);
|
|
12191
|
+
let msg;
|
|
12192
|
+
try {
|
|
12193
|
+
msg = JSON.parse(text);
|
|
12194
|
+
}
|
|
12195
|
+
catch (_a) {
|
|
12196
|
+
return;
|
|
12197
|
+
}
|
|
12198
|
+
switch (msg.type) {
|
|
12199
|
+
case 'snapshot':
|
|
12200
|
+
this.handleSnapshot(msg);
|
|
12201
|
+
break;
|
|
12202
|
+
case 'delta':
|
|
12203
|
+
this.handleDelta(msg);
|
|
12204
|
+
break;
|
|
12205
|
+
case 'result':
|
|
12206
|
+
this.handleResult(msg);
|
|
12207
|
+
break;
|
|
12208
|
+
case 'error':
|
|
12209
|
+
this.handleError(msg);
|
|
12210
|
+
break;
|
|
12211
|
+
case 'pong':
|
|
12212
|
+
break;
|
|
12213
|
+
// v1 compat: handle legacy message types during transition
|
|
12214
|
+
case 'subscribed':
|
|
12215
|
+
this.handleSnapshot(Object.assign(Object.assign({}, msg), { type: 'snapshot', docs: msg.data }));
|
|
12216
|
+
break;
|
|
12217
|
+
case 'data':
|
|
12218
|
+
// Legacy full-snapshot delta — treat as snapshot replacement
|
|
12219
|
+
this.handleLegacyData(msg);
|
|
12220
|
+
break;
|
|
12221
|
+
case 'response':
|
|
12222
|
+
this.handleResult(Object.assign(Object.assign({}, msg), { type: 'result', ok: msg.status === 200, doc: msg.data }));
|
|
12223
|
+
break;
|
|
12224
|
+
}
|
|
12225
|
+
}
|
|
12226
|
+
handleSnapshot(msg) {
|
|
12227
|
+
var _a, _b, _c;
|
|
12228
|
+
const subId = (_a = msg.id) !== null && _a !== void 0 ? _a : msg.subscriptionId;
|
|
12229
|
+
if (!subId)
|
|
12230
|
+
return;
|
|
12231
|
+
const sub = this.findSubscriptionById(subId);
|
|
12232
|
+
if (!sub)
|
|
12233
|
+
return;
|
|
12234
|
+
const docs = (_c = (_b = msg.docs) !== null && _b !== void 0 ? _b : msg.data) !== null && _c !== void 0 ? _c : [];
|
|
12235
|
+
const docsArray = Array.isArray(docs) ? docs : [docs];
|
|
12236
|
+
sub.docs.clear();
|
|
12237
|
+
for (const doc of docsArray) {
|
|
12238
|
+
if (doc && doc._id) {
|
|
12239
|
+
sub.docs.set(doc._id, doc);
|
|
12240
|
+
}
|
|
12241
|
+
}
|
|
12242
|
+
sub.ref.current = sub.docs;
|
|
12243
|
+
sub.status = 'live';
|
|
12244
|
+
sub.isStale = false;
|
|
12245
|
+
sub.error = null;
|
|
12246
|
+
this.notifySubscription(sub);
|
|
12247
|
+
this.markIdbDirty(sub.path);
|
|
12248
|
+
}
|
|
12249
|
+
handleDelta(msg) {
|
|
12250
|
+
var _a, _b;
|
|
12251
|
+
const subId = (_a = msg.id) !== null && _a !== void 0 ? _a : msg.subscriptionId;
|
|
12252
|
+
if (!subId)
|
|
12253
|
+
return;
|
|
12254
|
+
const sub = this.findSubscriptionById(subId);
|
|
12255
|
+
if (!sub)
|
|
12256
|
+
return;
|
|
12257
|
+
if (sub.tier === 'ephemeral') {
|
|
12258
|
+
// Ephemeral: just overwrite, no accumulation logic
|
|
12259
|
+
if (msg.change === 'removed' && msg.docId) {
|
|
12260
|
+
sub.docs.delete(msg.docId);
|
|
12261
|
+
}
|
|
12262
|
+
else if (msg.doc && msg.doc._id) {
|
|
12263
|
+
sub.docs.set(msg.doc._id, msg.doc);
|
|
12264
|
+
}
|
|
12265
|
+
sub.ref.current = sub.docs;
|
|
12266
|
+
if (sub.options.mode !== 'ref') {
|
|
12267
|
+
this.notifySubscription(sub);
|
|
12268
|
+
}
|
|
12269
|
+
return;
|
|
12270
|
+
}
|
|
12271
|
+
// Durable/checkpointed: full delta handling
|
|
12272
|
+
switch (msg.change) {
|
|
12273
|
+
case 'added':
|
|
12274
|
+
case 'modified':
|
|
12275
|
+
if (msg.doc && msg.doc._id) {
|
|
12276
|
+
sub.docs.set(msg.doc._id, msg.doc);
|
|
12277
|
+
}
|
|
12278
|
+
break;
|
|
12279
|
+
case 'removed':
|
|
12280
|
+
if (msg.docId) {
|
|
12281
|
+
sub.docs.delete(msg.docId);
|
|
12282
|
+
}
|
|
12283
|
+
else if ((_b = msg.doc) === null || _b === void 0 ? void 0 : _b._id) {
|
|
12284
|
+
sub.docs.delete(msg.doc._id);
|
|
12285
|
+
}
|
|
12286
|
+
break;
|
|
12287
|
+
}
|
|
12288
|
+
sub.ref.current = sub.docs;
|
|
12289
|
+
this.notifySubscription(sub);
|
|
12290
|
+
this.markIdbDirty(sub.path);
|
|
12291
|
+
}
|
|
12292
|
+
handleLegacyData(msg) {
|
|
12293
|
+
// Legacy v1 format: 'data' message with full snapshot or single doc
|
|
12294
|
+
const subId = msg.subscriptionId;
|
|
12295
|
+
if (!subId)
|
|
12296
|
+
return;
|
|
12297
|
+
const sub = this.findSubscriptionById(subId);
|
|
12298
|
+
if (!sub)
|
|
12299
|
+
return;
|
|
12300
|
+
if (Array.isArray(msg.data)) {
|
|
12301
|
+
// Full snapshot replacement
|
|
12302
|
+
sub.docs.clear();
|
|
12303
|
+
for (const doc of msg.data) {
|
|
12304
|
+
if (doc && doc._id)
|
|
12305
|
+
sub.docs.set(doc._id, doc);
|
|
12306
|
+
}
|
|
12307
|
+
}
|
|
12308
|
+
else if (msg.data && msg.data._id) {
|
|
12309
|
+
// Single doc update
|
|
12310
|
+
sub.docs.set(msg.data._id, msg.data);
|
|
12311
|
+
}
|
|
12312
|
+
else if (msg.data === null) ;
|
|
12313
|
+
sub.ref.current = sub.docs;
|
|
12314
|
+
sub.status = 'live';
|
|
12315
|
+
sub.isStale = false;
|
|
12316
|
+
this.notifySubscription(sub);
|
|
12317
|
+
this.markIdbDirty(sub.path);
|
|
12318
|
+
}
|
|
12319
|
+
handleResult(msg) {
|
|
12320
|
+
var _a, _b, _c, _d;
|
|
12321
|
+
const requestId = msg.requestId;
|
|
12322
|
+
if (!requestId)
|
|
12323
|
+
return;
|
|
12324
|
+
const pending = this.pendingRequests.get(requestId);
|
|
12325
|
+
if (!pending)
|
|
12326
|
+
return;
|
|
12327
|
+
this.pendingRequests.delete(requestId);
|
|
12328
|
+
clearTimeout(pending.timeout);
|
|
12329
|
+
const ok = (_a = msg.ok) !== null && _a !== void 0 ? _a : (msg.status === 200);
|
|
12330
|
+
if (ok) {
|
|
12331
|
+
pending.resolve((_c = (_b = msg.doc) !== null && _b !== void 0 ? _b : msg.data) !== null && _c !== void 0 ? _c : true);
|
|
12332
|
+
}
|
|
12333
|
+
else {
|
|
12334
|
+
pending.reject(new Error((_d = msg.error) !== null && _d !== void 0 ? _d : 'Operation failed'));
|
|
12335
|
+
}
|
|
12336
|
+
}
|
|
12337
|
+
handleError(msg) {
|
|
12338
|
+
var _a;
|
|
12339
|
+
const requestId = msg.requestId;
|
|
12340
|
+
if (requestId) {
|
|
12341
|
+
const pending = this.pendingRequests.get(requestId);
|
|
12342
|
+
if (pending) {
|
|
12343
|
+
this.pendingRequests.delete(requestId);
|
|
12344
|
+
clearTimeout(pending.timeout);
|
|
12345
|
+
pending.reject(new Error((_a = msg.message) !== null && _a !== void 0 ? _a : 'Server error'));
|
|
12346
|
+
}
|
|
12347
|
+
}
|
|
12348
|
+
}
|
|
12349
|
+
// -----------------------------------------------------------------------
|
|
12350
|
+
// Subscribe
|
|
12351
|
+
// -----------------------------------------------------------------------
|
|
12352
|
+
async subscribe(path, opts = {}) {
|
|
12353
|
+
var _a;
|
|
12354
|
+
const tier = (_a = opts.tier) !== null && _a !== void 0 ? _a : 'durable';
|
|
12355
|
+
const subKey = this.getSubKey(path, opts);
|
|
12356
|
+
let sub = this.subscriptions.get(subKey);
|
|
12357
|
+
if (sub) {
|
|
12358
|
+
// Existing subscription — add callback
|
|
12359
|
+
if (opts.onData)
|
|
12360
|
+
sub.callbacks.add(opts.onData);
|
|
12361
|
+
if (opts.onState)
|
|
12362
|
+
sub.stateCallbacks.add(opts.onState);
|
|
12363
|
+
// Immediately deliver current state
|
|
12364
|
+
if (opts.onData && sub.docs.size > 0) {
|
|
12365
|
+
opts.onData(this.docsToArray(sub));
|
|
12366
|
+
}
|
|
12367
|
+
if (opts.onState) {
|
|
12368
|
+
opts.onState(this.getState(sub));
|
|
12369
|
+
}
|
|
12370
|
+
return this.createUnsubscribe(subKey, opts.onData, opts.onState);
|
|
12371
|
+
}
|
|
12372
|
+
// New subscription
|
|
12373
|
+
const subId = `sub_${nextRequestId++}`;
|
|
12374
|
+
sub = {
|
|
12375
|
+
id: subId,
|
|
12376
|
+
path,
|
|
12377
|
+
tier,
|
|
12378
|
+
options: opts,
|
|
12379
|
+
docs: new Map(),
|
|
12380
|
+
status: 'idle',
|
|
12381
|
+
isStale: false,
|
|
12382
|
+
error: null,
|
|
12383
|
+
callbacks: new Set(opts.onData ? [opts.onData] : []),
|
|
12384
|
+
stateCallbacks: new Set(opts.onState ? [opts.onState] : []),
|
|
12385
|
+
ref: { current: new Map() },
|
|
12386
|
+
};
|
|
12387
|
+
this.subscriptions.set(subKey, sub);
|
|
12388
|
+
// Step 1: Load from IDB (durable/checkpointed only)
|
|
12389
|
+
if (tier !== 'ephemeral') {
|
|
12390
|
+
const cached = await idbGet(this.idbKey(path));
|
|
12391
|
+
if (cached && Array.isArray(cached)) {
|
|
12392
|
+
for (const doc of cached) {
|
|
12393
|
+
if (doc && doc._id)
|
|
12394
|
+
sub.docs.set(doc._id, doc);
|
|
12395
|
+
}
|
|
12396
|
+
sub.ref.current = sub.docs;
|
|
12397
|
+
sub.status = 'cached';
|
|
12398
|
+
sub.isStale = true;
|
|
12399
|
+
this.notifySubscription(sub);
|
|
12400
|
+
}
|
|
12401
|
+
}
|
|
12402
|
+
// Step 2: Connect and subscribe via WS
|
|
12403
|
+
sub.status = sub.docs.size > 0 ? 'cached' : 'loading';
|
|
12404
|
+
this.notifyState(sub);
|
|
12405
|
+
try {
|
|
12406
|
+
await this.ensureConnected();
|
|
12407
|
+
this.sendSubscribe(sub);
|
|
12408
|
+
}
|
|
12409
|
+
catch (_b) {
|
|
12410
|
+
sub.status = 'error';
|
|
12411
|
+
sub.error = new Error('Connection failed');
|
|
12412
|
+
this.notifyState(sub);
|
|
12413
|
+
}
|
|
12414
|
+
return this.createUnsubscribe(subKey, opts.onData, opts.onState);
|
|
12415
|
+
}
|
|
12416
|
+
getRef(path, opts = {}) {
|
|
12417
|
+
var _a;
|
|
12418
|
+
const subKey = this.getSubKey(path, opts);
|
|
12419
|
+
const sub = this.subscriptions.get(subKey);
|
|
12420
|
+
if (sub)
|
|
12421
|
+
return sub.ref;
|
|
12422
|
+
// Auto-subscribe in ref mode
|
|
12423
|
+
const ref = { current: new Map() };
|
|
12424
|
+
this.subscribe(path, Object.assign(Object.assign({}, opts), { mode: 'ref', tier: 'ephemeral' })).catch(() => { });
|
|
12425
|
+
const newSub = this.subscriptions.get(this.getSubKey(path, Object.assign(Object.assign({}, opts), { tier: 'ephemeral' })));
|
|
12426
|
+
return (_a = newSub === null || newSub === void 0 ? void 0 : newSub.ref) !== null && _a !== void 0 ? _a : ref;
|
|
12427
|
+
}
|
|
12428
|
+
// -----------------------------------------------------------------------
|
|
12429
|
+
// CRUD operations
|
|
12430
|
+
// -----------------------------------------------------------------------
|
|
12431
|
+
async set(path, doc) {
|
|
12432
|
+
var _a;
|
|
12433
|
+
await this.ensureConnected();
|
|
12434
|
+
// Resolve operations (Increment, Time.Now) client-side for optimistic update
|
|
12435
|
+
const resolvedDoc = this.resolveOperations(doc, path);
|
|
12436
|
+
// Optimistic update: apply to local state immediately
|
|
12437
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
12438
|
+
const collectionPath = this.getCollectionPath(normalizedPath);
|
|
12439
|
+
const optimisticDoc = Object.assign(Object.assign({ _id: normalizedPath, pathId: normalizedPath }, resolvedDoc), { tarobase_updated_at: Date.now() });
|
|
12440
|
+
const sub = this.findSubscriptionByPath(collectionPath);
|
|
12441
|
+
let prevDoc = null;
|
|
12442
|
+
if (sub) {
|
|
12443
|
+
prevDoc = (_a = sub.docs.get(normalizedPath)) !== null && _a !== void 0 ? _a : null;
|
|
12444
|
+
sub.docs.set(normalizedPath, optimisticDoc);
|
|
12445
|
+
sub.ref.current = sub.docs;
|
|
12446
|
+
this.notifySubscription(sub);
|
|
12447
|
+
}
|
|
12448
|
+
// Send to server
|
|
12449
|
+
const requestId = `r_${nextRequestId++}`;
|
|
12450
|
+
try {
|
|
12451
|
+
const result = await this.sendRequest(requestId, {
|
|
12452
|
+
type: 'set',
|
|
12453
|
+
requestId,
|
|
12454
|
+
documents: [{ destinationPath: normalizedPath, document: doc }],
|
|
12455
|
+
});
|
|
12456
|
+
// Replace optimistic doc with server-confirmed version
|
|
12457
|
+
if (sub && result && typeof result === 'object') {
|
|
12458
|
+
const serverDoc = Array.isArray(result) ? result[0] : result;
|
|
12459
|
+
if (serverDoc && serverDoc._id) {
|
|
12460
|
+
sub.docs.set(serverDoc._id, serverDoc);
|
|
12461
|
+
sub.ref.current = sub.docs;
|
|
12462
|
+
this.notifySubscription(sub);
|
|
12463
|
+
this.markIdbDirty(collectionPath);
|
|
12464
|
+
}
|
|
12465
|
+
}
|
|
12466
|
+
return Array.isArray(result) ? result[0] : result;
|
|
12467
|
+
}
|
|
12468
|
+
catch (err) {
|
|
12469
|
+
// Revert optimistic update
|
|
12470
|
+
if (sub) {
|
|
12471
|
+
if (prevDoc) {
|
|
12472
|
+
sub.docs.set(normalizedPath, prevDoc);
|
|
12473
|
+
}
|
|
12474
|
+
else {
|
|
12475
|
+
sub.docs.delete(normalizedPath);
|
|
12476
|
+
}
|
|
12477
|
+
sub.ref.current = sub.docs;
|
|
12478
|
+
this.notifySubscription(sub);
|
|
12479
|
+
}
|
|
12480
|
+
throw err;
|
|
12481
|
+
}
|
|
12482
|
+
}
|
|
12483
|
+
async get(path) {
|
|
12484
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
12485
|
+
// Check local subscriptions first
|
|
12486
|
+
const collectionPath = this.getCollectionPath(normalizedPath);
|
|
12487
|
+
const sub = this.findSubscriptionByPath(collectionPath);
|
|
12488
|
+
if (sub && sub.status === 'live') {
|
|
12489
|
+
const doc = sub.docs.get(normalizedPath);
|
|
12490
|
+
return doc !== null && doc !== void 0 ? doc : null;
|
|
12491
|
+
}
|
|
12492
|
+
// One-shot WS fetch
|
|
12493
|
+
await this.ensureConnected();
|
|
12494
|
+
const requestId = `r_${nextRequestId++}`;
|
|
12495
|
+
return this.sendRequest(requestId, {
|
|
12496
|
+
type: 'get',
|
|
12497
|
+
requestId,
|
|
12498
|
+
path: normalizedPath,
|
|
12499
|
+
});
|
|
12500
|
+
}
|
|
12501
|
+
async getMany(paths) {
|
|
12502
|
+
await this.ensureConnected();
|
|
12503
|
+
const normalizedPaths = paths.map(p => p.startsWith('/') ? p.slice(1) : p);
|
|
12504
|
+
const requestId = `r_${nextRequestId++}`;
|
|
12505
|
+
return this.sendRequest(requestId, {
|
|
12506
|
+
type: 'getMany',
|
|
12507
|
+
requestId,
|
|
12508
|
+
paths: normalizedPaths,
|
|
12509
|
+
});
|
|
12510
|
+
}
|
|
12511
|
+
async delete(path) {
|
|
12512
|
+
var _a;
|
|
12513
|
+
await this.ensureConnected();
|
|
12514
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
12515
|
+
// Optimistic: remove from local state
|
|
12516
|
+
const collectionPath = this.getCollectionPath(normalizedPath);
|
|
12517
|
+
const sub = this.findSubscriptionByPath(collectionPath);
|
|
12518
|
+
let prevDoc = null;
|
|
12519
|
+
if (sub) {
|
|
12520
|
+
prevDoc = (_a = sub.docs.get(normalizedPath)) !== null && _a !== void 0 ? _a : null;
|
|
12521
|
+
sub.docs.delete(normalizedPath);
|
|
12522
|
+
sub.ref.current = sub.docs;
|
|
12523
|
+
this.notifySubscription(sub);
|
|
12524
|
+
}
|
|
12525
|
+
const requestId = `r_${nextRequestId++}`;
|
|
12526
|
+
try {
|
|
12527
|
+
await this.sendRequest(requestId, {
|
|
12528
|
+
type: 'delete',
|
|
12529
|
+
requestId,
|
|
12530
|
+
path: normalizedPath,
|
|
12531
|
+
});
|
|
12532
|
+
if (sub)
|
|
12533
|
+
this.markIdbDirty(collectionPath);
|
|
12534
|
+
}
|
|
12535
|
+
catch (err) {
|
|
12536
|
+
// Revert
|
|
12537
|
+
if (sub && prevDoc) {
|
|
12538
|
+
sub.docs.set(normalizedPath, prevDoc);
|
|
12539
|
+
sub.ref.current = sub.docs;
|
|
12540
|
+
this.notifySubscription(sub);
|
|
12541
|
+
}
|
|
12542
|
+
throw err;
|
|
12543
|
+
}
|
|
12544
|
+
}
|
|
12545
|
+
async query(path, opts) {
|
|
12546
|
+
await this.ensureConnected();
|
|
12547
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
12548
|
+
const requestId = `r_${nextRequestId++}`;
|
|
12549
|
+
return this.sendRequest(requestId, Object.assign(Object.assign(Object.assign(Object.assign({ type: 'query', requestId, path: normalizedPath }, ((opts === null || opts === void 0 ? void 0 : opts.filter) ? { filter: opts.filter } : {})), ((opts === null || opts === void 0 ? void 0 : opts.sort) ? { sort: opts.sort } : {})), ((opts === null || opts === void 0 ? void 0 : opts.limit) !== undefined ? { limit: opts.limit } : {})), ((opts === null || opts === void 0 ? void 0 : opts.includeSubPaths) ? { includeSubPaths: true } : {})));
|
|
12550
|
+
}
|
|
12551
|
+
async count(path) {
|
|
12552
|
+
var _a;
|
|
12553
|
+
await this.ensureConnected();
|
|
12554
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
12555
|
+
const requestId = `r_${nextRequestId++}`;
|
|
12556
|
+
const result = await this.sendRequest(requestId, {
|
|
12557
|
+
type: 'count',
|
|
12558
|
+
requestId,
|
|
12559
|
+
path: normalizedPath,
|
|
12560
|
+
});
|
|
12561
|
+
return typeof result === 'number' ? result : ((_a = result === null || result === void 0 ? void 0 : result.value) !== null && _a !== void 0 ? _a : 0);
|
|
12562
|
+
}
|
|
12563
|
+
async aggregate(path, operation, opts) {
|
|
12564
|
+
await this.ensureConnected();
|
|
12565
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
12566
|
+
const requestId = `r_${nextRequestId++}`;
|
|
12567
|
+
return this.sendRequest(requestId, Object.assign({ type: 'aggregate', requestId, path: normalizedPath, operation }, ((opts === null || opts === void 0 ? void 0 : opts.field) ? { field: opts.field } : {})));
|
|
12568
|
+
}
|
|
12569
|
+
// -----------------------------------------------------------------------
|
|
12570
|
+
// Helpers
|
|
12571
|
+
// -----------------------------------------------------------------------
|
|
12572
|
+
sendSubscribe(sub) {
|
|
12573
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
12574
|
+
return;
|
|
12575
|
+
const msg = {
|
|
12576
|
+
type: 'subscribe',
|
|
12577
|
+
subscriptionId: sub.id,
|
|
12578
|
+
path: sub.path,
|
|
12579
|
+
};
|
|
12580
|
+
if (sub.options.filter)
|
|
12581
|
+
msg.filter = sub.options.filter;
|
|
12582
|
+
if (sub.options.includeSubPaths)
|
|
12583
|
+
msg.includeSubPaths = true;
|
|
12584
|
+
if (sub.options.limit)
|
|
12585
|
+
msg.limit = sub.options.limit;
|
|
12586
|
+
if (sub.options.prompt)
|
|
12587
|
+
msg.prompt = sub.options.prompt;
|
|
12588
|
+
this.ws.send(JSON.stringify(msg));
|
|
12589
|
+
}
|
|
12590
|
+
sendRequest(requestId, msg) {
|
|
12591
|
+
return new Promise((resolve, reject) => {
|
|
12592
|
+
const timeout = setTimeout(() => {
|
|
12593
|
+
this.pendingRequests.delete(requestId);
|
|
12594
|
+
reject(new Error('Request timed out'));
|
|
12595
|
+
}, 30000);
|
|
12596
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeout });
|
|
12597
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
12598
|
+
this.ws.send(JSON.stringify(msg));
|
|
12599
|
+
}
|
|
12600
|
+
else {
|
|
12601
|
+
this.pendingRequests.delete(requestId);
|
|
12602
|
+
clearTimeout(timeout);
|
|
12603
|
+
reject(new Error('WebSocket not connected'));
|
|
12604
|
+
}
|
|
12605
|
+
});
|
|
12606
|
+
}
|
|
12607
|
+
notifySubscription(sub) {
|
|
12608
|
+
const data = this.docsToArray(sub);
|
|
12609
|
+
const callbacks = Array.from(sub.callbacks);
|
|
12610
|
+
for (const cb of callbacks) {
|
|
12611
|
+
try {
|
|
12612
|
+
cb(data);
|
|
12613
|
+
}
|
|
12614
|
+
catch ( /* swallow callback errors */_a) { /* swallow callback errors */ }
|
|
12615
|
+
}
|
|
12616
|
+
this.notifyState(sub);
|
|
12617
|
+
}
|
|
12618
|
+
notifyState(sub) {
|
|
12619
|
+
const state = this.getState(sub);
|
|
12620
|
+
const callbacks = Array.from(sub.stateCallbacks);
|
|
12621
|
+
for (const cb of callbacks) {
|
|
12622
|
+
try {
|
|
12623
|
+
cb(state);
|
|
12624
|
+
}
|
|
12625
|
+
catch ( /* swallow */_a) { /* swallow */ }
|
|
12626
|
+
}
|
|
12627
|
+
}
|
|
12628
|
+
getState(sub) {
|
|
12629
|
+
return {
|
|
12630
|
+
data: this.docsToArray(sub),
|
|
12631
|
+
status: sub.status,
|
|
12632
|
+
isStale: sub.isStale,
|
|
12633
|
+
error: sub.error,
|
|
12634
|
+
};
|
|
12635
|
+
}
|
|
12636
|
+
docsToArray(sub) {
|
|
12637
|
+
return Array.from(sub.docs.values());
|
|
12638
|
+
}
|
|
12639
|
+
findSubscriptionById(id) {
|
|
12640
|
+
for (const sub of this.subscriptions.values()) {
|
|
12641
|
+
if (sub.id === id)
|
|
12642
|
+
return sub;
|
|
12643
|
+
}
|
|
12644
|
+
return undefined;
|
|
12645
|
+
}
|
|
12646
|
+
findSubscriptionByPath(collectionPath) {
|
|
12647
|
+
for (const sub of this.subscriptions.values()) {
|
|
12648
|
+
const subPath = sub.path.startsWith('/') ? sub.path.slice(1) : sub.path;
|
|
12649
|
+
if (subPath === collectionPath)
|
|
12650
|
+
return sub;
|
|
12651
|
+
if (collectionPath.startsWith(subPath + '/'))
|
|
12652
|
+
return sub;
|
|
12653
|
+
}
|
|
12654
|
+
return undefined;
|
|
12655
|
+
}
|
|
12656
|
+
getCollectionPath(docPath) {
|
|
12657
|
+
const segments = docPath.split('/');
|
|
12658
|
+
if (segments.length % 2 === 0) {
|
|
12659
|
+
return segments.slice(0, -1).join('/');
|
|
12660
|
+
}
|
|
12661
|
+
return docPath;
|
|
12662
|
+
}
|
|
12663
|
+
getSubKey(path, opts) {
|
|
12664
|
+
const parts = [path];
|
|
12665
|
+
if (opts.filter)
|
|
12666
|
+
parts.push(JSON.stringify(opts.filter));
|
|
12667
|
+
if (opts.prompt)
|
|
12668
|
+
parts.push(opts.prompt);
|
|
12669
|
+
if (opts.tier)
|
|
12670
|
+
parts.push(opts.tier);
|
|
12671
|
+
return parts.join('::');
|
|
12672
|
+
}
|
|
12673
|
+
idbKey(path) {
|
|
12674
|
+
return `${this.appId}:${path}`;
|
|
12675
|
+
}
|
|
12676
|
+
markIdbDirty(path) {
|
|
12677
|
+
const sub = this.findSubscriptionByPath(path);
|
|
12678
|
+
if (sub && sub.tier === 'ephemeral')
|
|
12679
|
+
return;
|
|
12680
|
+
this.idbDirtyKeys.add(path);
|
|
12681
|
+
if (!this.idbFlushTimer) {
|
|
12682
|
+
this.idbFlushTimer = setTimeout(() => {
|
|
12683
|
+
this.flushIdb();
|
|
12684
|
+
this.idbFlushTimer = null;
|
|
12685
|
+
}, 500);
|
|
12686
|
+
}
|
|
12687
|
+
}
|
|
12688
|
+
async flushIdb() {
|
|
12689
|
+
const keys = Array.from(this.idbDirtyKeys);
|
|
12690
|
+
this.idbDirtyKeys.clear();
|
|
12691
|
+
for (const path of keys) {
|
|
12692
|
+
const sub = this.findSubscriptionByPath(path);
|
|
12693
|
+
if (sub && sub.tier !== 'ephemeral') {
|
|
12694
|
+
const docs = this.docsToArray(sub);
|
|
12695
|
+
await idbSet(this.idbKey(path), docs);
|
|
12696
|
+
}
|
|
12697
|
+
}
|
|
12698
|
+
}
|
|
12699
|
+
createUnsubscribe(subKey, onData, onState) {
|
|
12700
|
+
return async () => {
|
|
12701
|
+
const sub = this.subscriptions.get(subKey);
|
|
12702
|
+
if (!sub)
|
|
12703
|
+
return;
|
|
12704
|
+
if (onData)
|
|
12705
|
+
sub.callbacks.delete(onData);
|
|
12706
|
+
if (onState)
|
|
12707
|
+
sub.stateCallbacks.delete(onState);
|
|
12708
|
+
// If no more callbacks, unsubscribe entirely
|
|
12709
|
+
if (sub.callbacks.size === 0 && sub.stateCallbacks.size === 0) {
|
|
12710
|
+
this.subscriptions.delete(subKey);
|
|
12711
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
12712
|
+
this.ws.send(JSON.stringify({
|
|
12713
|
+
type: 'unsubscribe',
|
|
12714
|
+
subscriptionId: sub.id,
|
|
12715
|
+
}));
|
|
12716
|
+
}
|
|
12717
|
+
}
|
|
12718
|
+
};
|
|
12719
|
+
}
|
|
12720
|
+
resolveOperations(doc, path) {
|
|
12721
|
+
var _a;
|
|
12722
|
+
if (!doc || typeof doc !== 'object')
|
|
12723
|
+
return doc;
|
|
12724
|
+
const resolved = {};
|
|
12725
|
+
for (const [key, value] of Object.entries(doc)) {
|
|
12726
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && value.operation) {
|
|
12727
|
+
const op = value;
|
|
12728
|
+
if (op.operation === 'time' && op.value === 'now') {
|
|
12729
|
+
resolved[key] = Math.floor(Date.now() / 1000);
|
|
12730
|
+
}
|
|
12731
|
+
else if (op.operation === 'increment') {
|
|
12732
|
+
// For optimistic: get current value and add
|
|
12733
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
12734
|
+
const collectionPath = this.getCollectionPath(normalizedPath);
|
|
12735
|
+
const sub = this.findSubscriptionByPath(collectionPath);
|
|
12736
|
+
const existing = sub === null || sub === void 0 ? void 0 : sub.docs.get(normalizedPath);
|
|
12737
|
+
const current = (_a = existing === null || existing === void 0 ? void 0 : existing[key]) !== null && _a !== void 0 ? _a : 0;
|
|
12738
|
+
resolved[key] = (typeof current === 'number' ? current : 0) + op.value;
|
|
12739
|
+
}
|
|
12740
|
+
else {
|
|
12741
|
+
resolved[key] = value;
|
|
12742
|
+
}
|
|
12743
|
+
}
|
|
12744
|
+
else {
|
|
12745
|
+
resolved[key] = value;
|
|
12746
|
+
}
|
|
12747
|
+
}
|
|
12748
|
+
return resolved;
|
|
12749
|
+
}
|
|
12750
|
+
rejectAllPending(reason) {
|
|
12751
|
+
for (const [requestId, pending] of this.pendingRequests) {
|
|
12752
|
+
clearTimeout(pending.timeout);
|
|
12753
|
+
pending.reject(new Error(reason));
|
|
12754
|
+
}
|
|
12755
|
+
this.pendingRequests.clear();
|
|
12756
|
+
}
|
|
12757
|
+
setAllSubscriptionStatus(status) {
|
|
12758
|
+
for (const sub of this.subscriptions.values()) {
|
|
12759
|
+
sub.status = status;
|
|
12760
|
+
this.notifyState(sub);
|
|
12761
|
+
}
|
|
12762
|
+
}
|
|
12763
|
+
// -----------------------------------------------------------------------
|
|
12764
|
+
// Lifecycle
|
|
12765
|
+
// -----------------------------------------------------------------------
|
|
12766
|
+
close() {
|
|
12767
|
+
this.closed = true;
|
|
12768
|
+
if (this.reconnectTimer)
|
|
12769
|
+
clearTimeout(this.reconnectTimer);
|
|
12770
|
+
if (this.idbFlushTimer)
|
|
12771
|
+
clearTimeout(this.idbFlushTimer);
|
|
12772
|
+
this.flushIdb();
|
|
12773
|
+
if (this.ws) {
|
|
12774
|
+
this.ws.close(1000, 'Store closed');
|
|
12775
|
+
this.ws = null;
|
|
12776
|
+
}
|
|
12777
|
+
this.rejectAllPending('Store closed');
|
|
12778
|
+
this.subscriptions.clear();
|
|
12779
|
+
}
|
|
12780
|
+
}
|
|
12781
|
+
// ---------------------------------------------------------------------------
|
|
12782
|
+
// Singleton instance
|
|
12783
|
+
// ---------------------------------------------------------------------------
|
|
12784
|
+
let storeInstance = null;
|
|
12785
|
+
function getRealtimeStore() {
|
|
12786
|
+
if (!storeInstance) {
|
|
12787
|
+
storeInstance = new RealtimeStore();
|
|
12788
|
+
}
|
|
12789
|
+
return storeInstance;
|
|
12790
|
+
}
|
|
12791
|
+
function resetRealtimeStore() {
|
|
12792
|
+
if (storeInstance) {
|
|
12793
|
+
storeInstance.close();
|
|
12794
|
+
storeInstance = null;
|
|
12795
|
+
}
|
|
12796
|
+
}
|
|
12797
|
+
|
|
11958
12798
|
/**
|
|
11959
12799
|
* Platform abstraction layer for React Native compatibility.
|
|
11960
12800
|
*
|
|
@@ -12260,6 +13100,15 @@ class OffchainAuthProvider {
|
|
|
12260
13100
|
}
|
|
12261
13101
|
return null;
|
|
12262
13102
|
}
|
|
13103
|
+
// Forward per-call login overrides (theme/title/subtitle and the `method`
|
|
13104
|
+
// directive) to the wrapped provider. Without this, the top-level login()
|
|
13105
|
+
// forwarder (which duck-types `setLoginOverrides` on the active provider)
|
|
13106
|
+
// skips the wrapper and the override — including `method` — is dropped on
|
|
13107
|
+
// offchain/Poofnet builds.
|
|
13108
|
+
setLoginOverrides(opts) {
|
|
13109
|
+
var _a, _b;
|
|
13110
|
+
(_b = (_a = this.wrappedProvider).setLoginOverrides) === null || _b === void 0 ? void 0 : _b.call(_a, opts);
|
|
13111
|
+
}
|
|
12263
13112
|
async logout() {
|
|
12264
13113
|
await this.wrappedProvider.logout();
|
|
12265
13114
|
}
|
|
@@ -12951,6 +13800,26 @@ class OffchainAuthProvider {
|
|
|
12951
13800
|
let currentAuthProvider = null;
|
|
12952
13801
|
let currentAuthMethod = null;
|
|
12953
13802
|
let initConfig = null;
|
|
13803
|
+
// The effective Phantom provider (offchain-wrapped when chain:"offchain"), captured
|
|
13804
|
+
// when a Phantom-primary app initializes. Used to restore Phantom after a staged
|
|
13805
|
+
// Privy email swap is cancelled/fails, and to route method-specific login() calls
|
|
13806
|
+
// back to Phantom. Null for non-Phantom apps.
|
|
13807
|
+
let savedPhantomProvider = null;
|
|
13808
|
+
/**
|
|
13809
|
+
* Restore the saved Phantom provider as the active auth provider. Used to undo a
|
|
13810
|
+
* staged Privy email swap on cancel/failure and to re-anchor method-specific
|
|
13811
|
+
* login() calls on Phantom. No-op when there is no saved Phantom provider.
|
|
13812
|
+
*/
|
|
13813
|
+
async function restoreSavedPhantomProvider() {
|
|
13814
|
+
if (!savedPhantomProvider)
|
|
13815
|
+
return;
|
|
13816
|
+
currentAuthProvider = savedPhantomProvider;
|
|
13817
|
+
currentAuthMethod = 'phantom';
|
|
13818
|
+
const coreConfig = await getConfig();
|
|
13819
|
+
coreConfig.authProvider = savedPhantomProvider;
|
|
13820
|
+
coreConfig.authMethod = 'phantom';
|
|
13821
|
+
setAuthProviderInstance(savedPhantomProvider);
|
|
13822
|
+
}
|
|
12954
13823
|
// --- localStorage helpers: track which auth method the user last logged in with ---
|
|
12955
13824
|
const STORED_AUTH_METHOD_KEY$1 = 'tarobase_last_auth_method';
|
|
12956
13825
|
function getStoredAuthMethod() {
|
|
@@ -13023,20 +13892,59 @@ async function hotSwapToPrivyProvider(config) {
|
|
|
13023
13892
|
solana: {
|
|
13024
13893
|
createOnLogin: 'users-without-wallets'
|
|
13025
13894
|
}
|
|
13026
|
-
}, appearance: Object.assign(Object.assign({}, (_f = (_e = config.privyConfig) === null || _e === void 0 ? void 0 : _e.config) === null || _f === void 0 ? void 0 : _f.appearance), { walletChainType: 'solana-only', showWalletLoginFirst: false, theme: 'dark', walletList: [] })
|
|
13895
|
+
}, appearance: Object.assign(Object.assign({}, (_f = (_e = config.privyConfig) === null || _e === void 0 ? void 0 : _e.config) === null || _f === void 0 ? void 0 : _f.appearance), { walletChainType: 'solana-only', showWalletLoginFirst: false, theme: 'dark', walletList: [] }),
|
|
13896
|
+
// Explicitly empty external wallets — social-only mode. Setting the
|
|
13897
|
+
// key (with an empty connectors array) keeps useWallets().ready able to
|
|
13898
|
+
// resolve while suppressing the wallet picker, AND prevents the
|
|
13899
|
+
// PrivyWalletProvider constructor from re-injecting the full Solana
|
|
13900
|
+
// connector set when externalWallets is absent (see privy-wallet-provider.ts).
|
|
13901
|
+
externalWallets: { solana: { connectors: [] } } })
|
|
13027
13902
|
};
|
|
13028
13903
|
const privyProvider = new PrivyWalletProvider((_g = config.name) !== null && _g !== void 0 ? _g : null, (_h = config.logoUrl) !== null && _h !== void 0 ? _h : null, fallbackPrivyConfig, rpcUrl);
|
|
13029
13904
|
let provider = privyProvider;
|
|
13030
13905
|
if (config.chain === "offchain") {
|
|
13031
13906
|
provider = new OffchainAuthProvider(privyProvider);
|
|
13032
13907
|
}
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13908
|
+
// STAGED swap: do NOT mutate the module-level auth globals here. The caller (the
|
|
13909
|
+
// Phantom modal's email button / the `method:'email'` bridge) calls `.login()` on
|
|
13910
|
+
// the returned provider separately. If the user cancels, committing up-front would
|
|
13911
|
+
// strand the globals on Privy and break reload/signing. Instead, return a provider
|
|
13912
|
+
// whose `login()` commits the globals to Privy ONLY on success and restores the
|
|
13913
|
+
// saved Phantom provider on cancel/failure.
|
|
13914
|
+
const commitPrivy = async () => {
|
|
13915
|
+
currentAuthProvider = provider;
|
|
13916
|
+
currentAuthMethod = 'privy';
|
|
13917
|
+
const coreConfig = await getConfig();
|
|
13918
|
+
coreConfig.authProvider = provider;
|
|
13919
|
+
coreConfig.authMethod = 'privy';
|
|
13920
|
+
setAuthProviderInstance(provider);
|
|
13921
|
+
};
|
|
13922
|
+
// Proxy intercepts only `login`; every other access delegates to `provider`. The
|
|
13923
|
+
// proxy is used solely for this one `.login()` call — on success the globals are
|
|
13924
|
+
// committed to the inner `provider` (not the proxy), so subsequent calls bypass it.
|
|
13925
|
+
return new Proxy(provider, {
|
|
13926
|
+
get(target, prop, receiver) {
|
|
13927
|
+
if (prop === 'login') {
|
|
13928
|
+
return async (...args) => {
|
|
13929
|
+
try {
|
|
13930
|
+
const user = await target.login(...args);
|
|
13931
|
+
if (user) {
|
|
13932
|
+
await commitPrivy();
|
|
13933
|
+
}
|
|
13934
|
+
else {
|
|
13935
|
+
await restoreSavedPhantomProvider();
|
|
13936
|
+
}
|
|
13937
|
+
return user;
|
|
13938
|
+
}
|
|
13939
|
+
catch (err) {
|
|
13940
|
+
await restoreSavedPhantomProvider();
|
|
13941
|
+
throw err;
|
|
13942
|
+
}
|
|
13943
|
+
};
|
|
13944
|
+
}
|
|
13945
|
+
return Reflect.get(target, prop, receiver);
|
|
13946
|
+
},
|
|
13947
|
+
});
|
|
13040
13948
|
}
|
|
13041
13949
|
async function hotSwapToMWAProvider(config) {
|
|
13042
13950
|
var _a, _b;
|
|
@@ -13067,7 +13975,7 @@ const SOLANA_DEVNET_RPC_URL = "https://idelle-8nxsep-fast-devnet.helius-rpc.com"
|
|
|
13067
13975
|
const SOLANA_MAINNET_RPC_URL = "https://celestia-cegncv-fast-mainnet.helius-rpc.com";
|
|
13068
13976
|
const SURFNET_RPC_URL$2 = "https://surfpool.fly.dev";
|
|
13069
13977
|
async function getAuthProvider(config) {
|
|
13070
|
-
var _a, _b, _c
|
|
13978
|
+
var _a, _b, _c;
|
|
13071
13979
|
if (currentAuthProvider) {
|
|
13072
13980
|
return currentAuthProvider;
|
|
13073
13981
|
}
|
|
@@ -13111,11 +14019,13 @@ async function getAuthProvider(config) {
|
|
|
13111
14019
|
// MWA hot-swap is always available (custom modal shows MWA button on Android)
|
|
13112
14020
|
currentAuthProvider.onSwitchToMWA =
|
|
13113
14021
|
() => hotSwapToMWAProvider(config);
|
|
13114
|
-
// Privy
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
14022
|
+
// Privy email bridge: ALWAYS wired, independent of enablePrivyFallback, so
|
|
14023
|
+
// `login({ method: 'email' })` works even on a custom Phantom app (which
|
|
14024
|
+
// sets enablePrivyFallback:false). enablePrivyFallback now only controls
|
|
14025
|
+
// whether the DEFAULT modal renders its own email button (see
|
|
14026
|
+
// phantom-wallet-provider.ts) — not whether the bridge exists.
|
|
14027
|
+
currentAuthProvider.onSwitchToPrivy =
|
|
14028
|
+
() => hotSwapToPrivyProvider(config);
|
|
13119
14029
|
break;
|
|
13120
14030
|
}
|
|
13121
14031
|
case "privy-expo":
|
|
@@ -13146,6 +14056,13 @@ async function getAuthProvider(config) {
|
|
|
13146
14056
|
console.log("[Offchain] Wrapping auth provider for Poofnet transaction tracking");
|
|
13147
14057
|
currentAuthProvider = new OffchainAuthProvider(currentAuthProvider);
|
|
13148
14058
|
}
|
|
14059
|
+
// Save the EFFECTIVE Phantom provider (post offchain-wrap) so the staged Privy
|
|
14060
|
+
// email swap can restore it on cancel/failure and method-specific login() calls
|
|
14061
|
+
// can re-anchor on Phantom. Captured after the wrap so restore doesn't bypass the
|
|
14062
|
+
// OffchainAuthProvider on Poofnet/preview.
|
|
14063
|
+
if (authMethod === 'phantom') {
|
|
14064
|
+
savedPhantomProvider = currentAuthProvider;
|
|
14065
|
+
}
|
|
13149
14066
|
return currentAuthProvider;
|
|
13150
14067
|
}
|
|
13151
14068
|
async function login$1(options) {
|
|
@@ -13161,6 +14078,14 @@ async function login$1(options) {
|
|
|
13161
14078
|
if (!currentAuthProvider) {
|
|
13162
14079
|
throw new Error("Auth provider not initialized. Please call init() first.");
|
|
13163
14080
|
}
|
|
14081
|
+
// Method-specific login() always operates on the Phantom provider (which then
|
|
14082
|
+
// bridges to Privy for 'email'). If a prior email swap committed Privy, re-anchor
|
|
14083
|
+
// on the saved Phantom provider before delegating so the `method` directive lands
|
|
14084
|
+
// on Phantom. (Cancelled swaps already restore Phantom via the staged proxy; this
|
|
14085
|
+
// covers the post-success case.) No-op for non-Phantom apps (no saved provider).
|
|
14086
|
+
if ((options === null || options === void 0 ? void 0 : options.method) && currentAuthMethod !== 'phantom' && savedPhantomProvider) {
|
|
14087
|
+
await restoreSavedPhantomProvider();
|
|
14088
|
+
}
|
|
13164
14089
|
// Forward per-call overrides to providers that support them (duck-typed to stay
|
|
13165
14090
|
// lazy-load safe — no direct import of PhantomWalletProvider here).
|
|
13166
14091
|
// Always call (even with null) so previous overrides are cleared when this
|
|
@@ -13320,7 +14245,7 @@ function useAuth() {
|
|
|
13320
14245
|
// Provide a fallback so server render doesn't break
|
|
13321
14246
|
if (isSSR) {
|
|
13322
14247
|
return {
|
|
13323
|
-
login: async () => undefined,
|
|
14248
|
+
login: async (_options) => undefined,
|
|
13324
14249
|
logout: async () => undefined,
|
|
13325
14250
|
loading: true,
|
|
13326
14251
|
user: null,
|
|
@@ -13340,10 +14265,10 @@ function useAuth() {
|
|
|
13340
14265
|
return () => {
|
|
13341
14266
|
};
|
|
13342
14267
|
}, []);
|
|
13343
|
-
const login$1 = async () => {
|
|
14268
|
+
const login$1 = async (options) => {
|
|
13344
14269
|
try {
|
|
13345
14270
|
setLoading(true);
|
|
13346
|
-
const user = await login();
|
|
14271
|
+
const user = await login(options);
|
|
13347
14272
|
setUser(user);
|
|
13348
14273
|
}
|
|
13349
14274
|
catch (error) {
|
|
@@ -15880,7 +16805,7 @@ async function loadDependencies() {
|
|
|
15880
16805
|
const [reactModule, reactDomModule, phantomModule] = await Promise.all([
|
|
15881
16806
|
import('react'),
|
|
15882
16807
|
import('react-dom/client'),
|
|
15883
|
-
import('./index-
|
|
16808
|
+
import('./index-B8EmyNEY.esm.js')
|
|
15884
16809
|
]);
|
|
15885
16810
|
// Extract default export from ESM module namespace
|
|
15886
16811
|
// Dynamic import() returns { default: Module, ...exports }, not the module directly
|
|
@@ -15900,7 +16825,15 @@ class PhantomWalletProvider {
|
|
|
15900
16825
|
this.containerElement = null;
|
|
15901
16826
|
this.root = null;
|
|
15902
16827
|
this.phantomMethods = null;
|
|
16828
|
+
// The FULL set registered with the Phantom SDK (so login({ method:'google'|'apple' })
|
|
16829
|
+
// can connect directly even when those buttons are hidden from the default modal).
|
|
15903
16830
|
this.resolvedProviders = ['injected'];
|
|
16831
|
+
// What the DEFAULT chooser modal renders as buttons (social hidden when the Privy
|
|
16832
|
+
// email fallback owns vanilla email). Subset of resolvedProviders.
|
|
16833
|
+
this.modalProviders = ['injected'];
|
|
16834
|
+
// True only while a `login({ method: 'wallet' })` modal is open — suppresses the
|
|
16835
|
+
// social + email buttons so wallet mode shows wallets only.
|
|
16836
|
+
this.modalWalletOnly = false;
|
|
15904
16837
|
this.pendingLogin = null;
|
|
15905
16838
|
this.loginInProgress = false;
|
|
15906
16839
|
this.autoLoginInProgress = false;
|
|
@@ -15957,10 +16890,15 @@ class PhantomWalletProvider {
|
|
|
15957
16890
|
else {
|
|
15958
16891
|
this.resolvedProviders = ['injected'];
|
|
15959
16892
|
}
|
|
15960
|
-
//
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
16893
|
+
// resolvedProviders stays the FULL set (registered with the Phantom SDK), so a
|
|
16894
|
+
// direct login({ method: 'google'|'apple' }) can connect even when the default
|
|
16895
|
+
// modal hides those buttons. modalProviders is what the DEFAULT chooser renders:
|
|
16896
|
+
// when the Privy email fallback owns vanilla email we hide social from the
|
|
16897
|
+
// default modal — but it remains registered above. (Apps with their own auth UI
|
|
16898
|
+
// use login({ method }) and bypass the default modal entirely.)
|
|
16899
|
+
this.modalProviders = this.config.enablePrivyFallback
|
|
16900
|
+
? this.resolvedProviders.filter(p => p !== 'google' && p !== 'apple')
|
|
16901
|
+
: [...this.resolvedProviders];
|
|
15964
16902
|
}
|
|
15965
16903
|
/**
|
|
15966
16904
|
* Patch the Phantom extension's provider to gracefully handle `phantom_getFeatures`
|
|
@@ -16062,6 +17000,52 @@ class PhantomWalletProvider {
|
|
|
16062
17000
|
connectError,
|
|
16063
17001
|
showCustomModal: () => setShowWalletModal(true),
|
|
16064
17002
|
hideCustomModal: () => setShowWalletModal(false),
|
|
17003
|
+
// Per-method login bridge: connect a specific provider directly
|
|
17004
|
+
// (no modal). The connection-success effect resolves the pending
|
|
17005
|
+
// login. Used for login({ method: 'google' | 'apple' }).
|
|
17006
|
+
connectWithProvider: async (provider) => {
|
|
17007
|
+
walletClickedRef.current = true;
|
|
17008
|
+
setShowWalletModal(false);
|
|
17009
|
+
try {
|
|
17010
|
+
await connect({ provider });
|
|
17011
|
+
}
|
|
17012
|
+
catch (err) {
|
|
17013
|
+
// connectError effect handles failure
|
|
17014
|
+
}
|
|
17015
|
+
},
|
|
17016
|
+
// Per-method login bridge: jump straight to the Privy email
|
|
17017
|
+
// screen (mirrors the modal's email button) and resolve/reject
|
|
17018
|
+
// the pending login directly. Used for login({ method: 'email' }).
|
|
17019
|
+
switchToEmail: async () => {
|
|
17020
|
+
that.loginInProgress = false;
|
|
17021
|
+
walletClickedRef.current = true;
|
|
17022
|
+
setShowWalletModal(false);
|
|
17023
|
+
if (!that.onSwitchToPrivy) {
|
|
17024
|
+
if (that.pendingLogin) {
|
|
17025
|
+
that.pendingLogin.reject(new Error('Email login is not available'));
|
|
17026
|
+
that.pendingLogin = null;
|
|
17027
|
+
}
|
|
17028
|
+
return;
|
|
17029
|
+
}
|
|
17030
|
+
try {
|
|
17031
|
+
const privyProvider = await that.onSwitchToPrivy();
|
|
17032
|
+
const user = await privyProvider.login();
|
|
17033
|
+
if (that.pendingLogin && user) {
|
|
17034
|
+
that.pendingLogin.resolve(user);
|
|
17035
|
+
that.pendingLogin = null;
|
|
17036
|
+
}
|
|
17037
|
+
else if (that.pendingLogin) {
|
|
17038
|
+
that.pendingLogin.reject(new Error('User cancelled login'));
|
|
17039
|
+
that.pendingLogin = null;
|
|
17040
|
+
}
|
|
17041
|
+
}
|
|
17042
|
+
catch (error) {
|
|
17043
|
+
if (that.pendingLogin) {
|
|
17044
|
+
that.pendingLogin.reject(error);
|
|
17045
|
+
that.pendingLogin = null;
|
|
17046
|
+
}
|
|
17047
|
+
}
|
|
17048
|
+
},
|
|
16065
17049
|
solana: solana && solanaHook.isAvailable ? {
|
|
16066
17050
|
// Wrap methods to preserve 'this' context - direct references lose binding
|
|
16067
17051
|
signMessage: (message) => solana.signMessage(message),
|
|
@@ -16420,8 +17404,9 @@ class PhantomWalletProvider {
|
|
|
16420
17404
|
boxSizing: 'border-box',
|
|
16421
17405
|
});
|
|
16422
17406
|
const walletButtons = [];
|
|
16423
|
-
// Google OAuth button —
|
|
16424
|
-
|
|
17407
|
+
// Google OAuth button — default chooser only (hidden in wallet-only mode),
|
|
17408
|
+
// gated on modalProviders (registered-but-hidden under the email fallback).
|
|
17409
|
+
if (!that.modalWalletOnly && that.modalProviders.includes('google')) {
|
|
16425
17410
|
walletButtons.push(React$1.createElement('button', {
|
|
16426
17411
|
key: 'google-oauth',
|
|
16427
17412
|
style: buttonStyle('google-oauth'),
|
|
@@ -16445,8 +17430,9 @@ class PhantomWalletProvider {
|
|
|
16445
17430
|
fill: '#EA4335',
|
|
16446
17431
|
})), 'Continue with Google'));
|
|
16447
17432
|
}
|
|
16448
|
-
// Apple OAuth button —
|
|
16449
|
-
|
|
17433
|
+
// Apple OAuth button — default chooser only (hidden in wallet-only mode),
|
|
17434
|
+
// gated on modalProviders (registered-but-hidden under the email fallback).
|
|
17435
|
+
if (!that.modalWalletOnly && that.modalProviders.includes('apple')) {
|
|
16450
17436
|
walletButtons.push(React$1.createElement('button', {
|
|
16451
17437
|
key: 'apple-oauth',
|
|
16452
17438
|
style: buttonStyle('apple-oauth'),
|
|
@@ -16527,8 +17513,10 @@ class PhantomWalletProvider {
|
|
|
16527
17513
|
stroke: textColor, strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round', fill: 'none',
|
|
16528
17514
|
})), 'Connect Mobile Wallet'));
|
|
16529
17515
|
}
|
|
16530
|
-
// Email button — only
|
|
16531
|
-
|
|
17516
|
+
// Email button — default chooser only (hidden in wallet-only mode), and
|
|
17517
|
+
// only when the Privy email fallback owns the default modal's email button.
|
|
17518
|
+
// (login({ method:'email' }) bridges to Privy directly, independent of this.)
|
|
17519
|
+
if (!that.modalWalletOnly && that.config.enablePrivyFallback) {
|
|
16532
17520
|
walletButtons.push(React$1.createElement('button', {
|
|
16533
17521
|
key: 'email-login',
|
|
16534
17522
|
style: emailButtonStyle('email-login'),
|
|
@@ -16824,10 +17812,29 @@ class PhantomWalletProvider {
|
|
|
16824
17812
|
});
|
|
16825
17813
|
}
|
|
16826
17814
|
const loginPromise = new Promise((resolve, reject) => {
|
|
17815
|
+
var _a;
|
|
16827
17816
|
this.pendingLogin = { resolve, reject };
|
|
16828
17817
|
this.loginInProgress = true;
|
|
16829
|
-
//
|
|
16830
|
-
|
|
17818
|
+
// Drive the requested flow. pendingLogin + loginInProgress are already set
|
|
17819
|
+
// above, so the connection-success effect (google/apple/wallet) and the
|
|
17820
|
+
// email bridge resolve THIS promise. A method-specific call goes straight to
|
|
17821
|
+
// the matching connect/bridge; no method → the full chooser modal.
|
|
17822
|
+
const method = (_a = this.loginOverrides) === null || _a === void 0 ? void 0 : _a.method;
|
|
17823
|
+
if (method === 'google' || method === 'apple') {
|
|
17824
|
+
void this.phantomMethods.connectWithProvider(method);
|
|
17825
|
+
}
|
|
17826
|
+
else if (method === 'email') {
|
|
17827
|
+
void this.phantomMethods.switchToEmail();
|
|
17828
|
+
}
|
|
17829
|
+
else if (method === 'wallet') {
|
|
17830
|
+
// Wallet-only modal: wallets shown, social + email hidden.
|
|
17831
|
+
this.modalWalletOnly = true;
|
|
17832
|
+
this.phantomMethods.showCustomModal();
|
|
17833
|
+
}
|
|
17834
|
+
else {
|
|
17835
|
+
this.modalWalletOnly = false;
|
|
17836
|
+
this.phantomMethods.showCustomModal();
|
|
17837
|
+
}
|
|
16831
17838
|
// Safety timeout
|
|
16832
17839
|
setTimeout(() => {
|
|
16833
17840
|
if (this.pendingLogin) {
|
|
@@ -16839,6 +17846,7 @@ class PhantomWalletProvider {
|
|
|
16839
17846
|
});
|
|
16840
17847
|
return loginPromise.finally(() => {
|
|
16841
17848
|
this.loginOverrides = null;
|
|
17849
|
+
this.modalWalletOnly = false;
|
|
16842
17850
|
});
|
|
16843
17851
|
}
|
|
16844
17852
|
async restoreSession() {
|
|
@@ -22020,7 +23028,7 @@ async function registerMobileWalletAdapter(config) {
|
|
|
22020
23028
|
if (typeof window === 'undefined')
|
|
22021
23029
|
return;
|
|
22022
23030
|
try {
|
|
22023
|
-
const walletStandardMobile = await import('./index.browser-
|
|
23031
|
+
const walletStandardMobile = await import('./index.browser-BAtXWf8k.esm.js');
|
|
22024
23032
|
const registerMwa = walletStandardMobile.registerMwa || ((_a = walletStandardMobile.default) === null || _a === void 0 ? void 0 : _a.registerMwa);
|
|
22025
23033
|
if (!registerMwa) {
|
|
22026
23034
|
console.warn('[SolanaMobileWallet] registerMwa not found in @solana-mobile/wallet-standard-mobile');
|
|
@@ -22159,7 +23167,7 @@ class SolanaMobileWalletProvider {
|
|
|
22159
23167
|
async ensureWallet() {
|
|
22160
23168
|
if (this.wallet)
|
|
22161
23169
|
return this.wallet;
|
|
22162
|
-
const mod = await import('./index.browser-
|
|
23170
|
+
const mod = await import('./index.browser-BAtXWf8k.esm.js');
|
|
22163
23171
|
const chain = mapChainToWalletStandard(this.cluster);
|
|
22164
23172
|
this.wallet = new mod.LocalSolanaMobileWalletAdapterWallet({
|
|
22165
23173
|
appIdentity: this.appIdentity,
|
|
@@ -23351,5 +24359,5 @@ class PrivyExpoProvider {
|
|
|
23351
24359
|
}
|
|
23352
24360
|
}
|
|
23353
24361
|
|
|
23354
|
-
export {
|
|
23355
|
-
//# sourceMappingURL=index-
|
|
24362
|
+
export { genSolanaMessage as $, subscribe as A, useAuth as B, deserializeTransaction as C, getIdToken as D, setPlatform as E, getPlatform as F, PrivyWalletProvider as G, DEFAULT_TEST_ADDRESS as H, isMobileWalletAvailable as I, registerMobileWalletAdapter as J, PrivyExpoProvider as K, InsufficientBalanceError as L, MockAuthProvider as M, RealtimeStore as N, OffchainAuthProvider as O, PhantomWalletProvider as P, ServerSessionManager as Q, ReactNativeSessionManager as R, SolanaMobileWalletProvider as S, buildSetDocumentsTransaction as T, clearCache as U, closeAllSubscriptions as V, WebSessionManager as W, convertRemainingAccounts as X, createSessionWithPrivy as Y, createSessionWithSignature as Z, genAuthNonce as _, base58 as a, getCachedData as a0, getMany as a1, getRealtimeStore as a2, hasActiveConnection as a3, reconnectWithNewAuth as a4, refreshSession as a5, resetRealtimeStore as a6, signSessionCreateMessage as a7, wsDelete as a8, wsGet as a9, wsGetMany as aa, wsQuery as ab, wsSet as ac, bufferExports as b, getCurrentUser as c, onAuthLoadingChanged as d, getAuthLoading as e, logout as f, getDefaultExportFromCjs$1 as g, getConfig as h, init as i, getAuthProvider as j, get as k, login as l, setMany as m, setFile as n, onAuthStateChanged as o, getFiles as p, runQueryMany as q, runQuery as r, set as s, runExpression as t, runExpressionMany as u, signMessage as v, signTransaction as w, signAndSubmitTransaction as x, count as y, aggregate as z };
|
|
24363
|
+
//# sourceMappingURL=index-DOAgc25g.esm.js.map
|