@instantdb/core 0.22.97 → 0.22.98-experimental.drewh-ts-target.20762041587.1
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/commonjs/Connection.js +50 -51
- package/dist/commonjs/Connection.js.map +1 -1
- package/dist/commonjs/InMemoryStorage.js +13 -32
- package/dist/commonjs/InMemoryStorage.js.map +1 -1
- package/dist/commonjs/IndexedDBStorage.js +193 -217
- package/dist/commonjs/IndexedDBStorage.js.map +1 -1
- package/dist/commonjs/InstantError.js +1 -0
- package/dist/commonjs/InstantError.js.map +1 -1
- package/dist/commonjs/Reactor.js +566 -610
- package/dist/commonjs/Reactor.js.map +1 -1
- package/dist/commonjs/StorageAPI.js +51 -70
- package/dist/commonjs/StorageAPI.js.map +1 -1
- package/dist/commonjs/SyncTable.js +68 -81
- package/dist/commonjs/SyncTable.js.map +1 -1
- package/dist/commonjs/WindowNetworkListener.js +2 -13
- package/dist/commonjs/WindowNetworkListener.js.map +1 -1
- package/dist/commonjs/__types__/fieldsTypeTest.js +8 -16
- package/dist/commonjs/__types__/fieldsTypeTest.js.map +1 -1
- package/dist/commonjs/__types__/useDatesTypeTest.js +3 -6
- package/dist/commonjs/__types__/useDatesTypeTest.js.map +1 -1
- package/dist/commonjs/authAPI.js +62 -79
- package/dist/commonjs/authAPI.js.map +1 -1
- package/dist/commonjs/createRouteHandler.js +5 -15
- package/dist/commonjs/createRouteHandler.js.map +1 -1
- package/dist/commonjs/datalog.js +1 -1
- package/dist/commonjs/datalog.js.map +1 -1
- package/dist/commonjs/devtool.js +26 -8
- package/dist/commonjs/devtool.js.map +1 -1
- package/dist/commonjs/framework.d.ts.map +1 -1
- package/dist/commonjs/framework.js +142 -152
- package/dist/commonjs/framework.js.map +1 -1
- package/dist/commonjs/index.js +204 -190
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/instaml.js +44 -30
- package/dist/commonjs/instaml.js.map +1 -1
- package/dist/commonjs/instaql.js +25 -33
- package/dist/commonjs/instaql.js.map +1 -1
- package/dist/commonjs/parseSchemaFromJSON.js +6 -7
- package/dist/commonjs/parseSchemaFromJSON.js.map +1 -1
- package/dist/commonjs/presence.js +7 -8
- package/dist/commonjs/presence.js.map +1 -1
- package/dist/commonjs/queryValidation.js +1 -2
- package/dist/commonjs/queryValidation.js.map +1 -1
- package/dist/commonjs/schema.js +8 -6
- package/dist/commonjs/schema.js.map +1 -1
- package/dist/commonjs/schemaTypes.js +22 -3
- package/dist/commonjs/schemaTypes.js.map +1 -1
- package/dist/commonjs/store.js +29 -38
- package/dist/commonjs/store.js.map +1 -1
- package/dist/commonjs/transactionValidation.js +1 -2
- package/dist/commonjs/transactionValidation.js.map +1 -1
- package/dist/commonjs/utils/Deferred.js +3 -0
- package/dist/commonjs/utils/Deferred.js.map +1 -1
- package/dist/commonjs/utils/PersistedObject.js +216 -233
- package/dist/commonjs/utils/PersistedObject.js.map +1 -1
- package/dist/commonjs/utils/fetch.js +9 -19
- package/dist/commonjs/utils/fetch.js.map +1 -1
- package/dist/commonjs/utils/linkIndex.js +2 -4
- package/dist/commonjs/utils/linkIndex.js.map +1 -1
- package/dist/commonjs/utils/object.js +1 -1
- package/dist/commonjs/utils/object.js.map +1 -1
- package/dist/esm/Connection.js +50 -51
- package/dist/esm/Connection.js.map +1 -1
- package/dist/esm/InMemoryStorage.js +13 -32
- package/dist/esm/InMemoryStorage.js.map +1 -1
- package/dist/esm/IndexedDBStorage.js +193 -217
- package/dist/esm/IndexedDBStorage.js.map +1 -1
- package/dist/esm/InstantError.js +1 -0
- package/dist/esm/InstantError.js.map +1 -1
- package/dist/esm/Reactor.js +566 -610
- package/dist/esm/Reactor.js.map +1 -1
- package/dist/esm/StorageAPI.js +51 -70
- package/dist/esm/StorageAPI.js.map +1 -1
- package/dist/esm/SyncTable.js +68 -81
- package/dist/esm/SyncTable.js.map +1 -1
- package/dist/esm/WindowNetworkListener.js +2 -13
- package/dist/esm/WindowNetworkListener.js.map +1 -1
- package/dist/esm/__types__/fieldsTypeTest.js +8 -16
- package/dist/esm/__types__/fieldsTypeTest.js.map +1 -1
- package/dist/esm/__types__/useDatesTypeTest.js +3 -6
- package/dist/esm/__types__/useDatesTypeTest.js.map +1 -1
- package/dist/esm/authAPI.js +62 -79
- package/dist/esm/authAPI.js.map +1 -1
- package/dist/esm/createRouteHandler.js +5 -15
- package/dist/esm/createRouteHandler.js.map +1 -1
- package/dist/esm/datalog.js +1 -1
- package/dist/esm/datalog.js.map +1 -1
- package/dist/esm/devtool.js +26 -8
- package/dist/esm/devtool.js.map +1 -1
- package/dist/esm/framework.d.ts.map +1 -1
- package/dist/esm/framework.js +142 -152
- package/dist/esm/framework.js.map +1 -1
- package/dist/esm/index.js +204 -190
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/instaml.js +44 -30
- package/dist/esm/instaml.js.map +1 -1
- package/dist/esm/instaql.js +25 -33
- package/dist/esm/instaql.js.map +1 -1
- package/dist/esm/parseSchemaFromJSON.js +6 -7
- package/dist/esm/parseSchemaFromJSON.js.map +1 -1
- package/dist/esm/presence.js +7 -8
- package/dist/esm/presence.js.map +1 -1
- package/dist/esm/queryValidation.js +1 -2
- package/dist/esm/queryValidation.js.map +1 -1
- package/dist/esm/schema.js +8 -6
- package/dist/esm/schema.js.map +1 -1
- package/dist/esm/schemaTypes.js +22 -3
- package/dist/esm/schemaTypes.js.map +1 -1
- package/dist/esm/store.js +29 -38
- package/dist/esm/store.js.map +1 -1
- package/dist/esm/transactionValidation.js +1 -2
- package/dist/esm/transactionValidation.js.map +1 -1
- package/dist/esm/utils/Deferred.js +3 -0
- package/dist/esm/utils/Deferred.js.map +1 -1
- package/dist/esm/utils/PersistedObject.js +216 -233
- package/dist/esm/utils/PersistedObject.js.map +1 -1
- package/dist/esm/utils/fetch.js +9 -19
- package/dist/esm/utils/fetch.js.map +1 -1
- package/dist/esm/utils/linkIndex.js +2 -4
- package/dist/esm/utils/linkIndex.js.map +1 -1
- package/dist/esm/utils/object.js +1 -1
- package/dist/esm/utils/object.js.map +1 -1
- package/dist/standalone/index.js +2610 -2367
- package/dist/standalone/index.umd.cjs +3 -3
- package/package.json +2 -2
- package/src/framework.ts +0 -1
package/dist/esm/Reactor.js
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
-
var t = {};
|
|
12
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
-
t[p] = s[p];
|
|
14
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
-
t[p[i]] = s[p[i]];
|
|
18
|
-
}
|
|
19
|
-
return t;
|
|
20
|
-
};
|
|
21
1
|
// @ts-check
|
|
22
2
|
import weakHash from "./utils/weakHash.js";
|
|
23
3
|
import instaql from "./instaql.js";
|
|
@@ -58,10 +38,10 @@ const STATUS = {
|
|
|
58
38
|
CLOSED: 'closed',
|
|
59
39
|
ERRORED: 'errored',
|
|
60
40
|
};
|
|
61
|
-
const QUERY_ONCE_TIMEOUT =
|
|
62
|
-
const PENDING_TX_CLEANUP_TIMEOUT =
|
|
41
|
+
const QUERY_ONCE_TIMEOUT = 30_000;
|
|
42
|
+
const PENDING_TX_CLEANUP_TIMEOUT = 30_000;
|
|
63
43
|
const PENDING_MUTATION_CLEANUP_THRESHOLD = 200;
|
|
64
|
-
const ONE_MIN_MS =
|
|
44
|
+
const ONE_MIN_MS = 1_000 * 60;
|
|
65
45
|
const defaultConfig = {
|
|
66
46
|
apiURI: 'https://api.instantdb.com',
|
|
67
47
|
websocketURI: 'wss://api.instantdb.com/runtime/session',
|
|
@@ -110,13 +90,15 @@ const ignoreLogging = {
|
|
|
110
90
|
* @returns {QuerySub}
|
|
111
91
|
*/
|
|
112
92
|
function querySubFromStorage(x, useDateObjects) {
|
|
113
|
-
var _a;
|
|
114
93
|
const v = typeof x === 'string' ? JSON.parse(x) : x;
|
|
115
|
-
if (
|
|
94
|
+
if (v?.result?.store) {
|
|
116
95
|
const attrsStore = s.attrsStoreFromJSON(v.result.attrsStore, v.result.store);
|
|
117
96
|
if (attrsStore) {
|
|
118
97
|
const storeJSON = v.result.store;
|
|
119
|
-
v.result.store = s.fromJSON(attrsStore,
|
|
98
|
+
v.result.store = s.fromJSON(attrsStore, {
|
|
99
|
+
...storeJSON,
|
|
100
|
+
useDateObjects: useDateObjects,
|
|
101
|
+
});
|
|
120
102
|
v.result.attrsStore = attrsStore;
|
|
121
103
|
}
|
|
122
104
|
}
|
|
@@ -129,11 +111,15 @@ function querySubFromStorage(x, useDateObjects) {
|
|
|
129
111
|
* @returns QuerySubInStorage
|
|
130
112
|
*/
|
|
131
113
|
function querySubToStorage(_key, sub) {
|
|
132
|
-
const { result
|
|
114
|
+
const { result, ...rest } = sub;
|
|
133
115
|
const jsonSub = /** @type {import('./reactorTypes.ts').QuerySubInStorage} */ (rest);
|
|
134
116
|
if (result) {
|
|
135
117
|
/** @type {import('./reactorTypes.ts').QuerySubResultInStorage} */
|
|
136
|
-
const jsonResult =
|
|
118
|
+
const jsonResult = {
|
|
119
|
+
...result,
|
|
120
|
+
store: s.toJSON(result.store),
|
|
121
|
+
attrsStore: result.attrsStore.toJSON(),
|
|
122
|
+
};
|
|
137
123
|
jsonSub.result = jsonResult;
|
|
138
124
|
}
|
|
139
125
|
return jsonSub;
|
|
@@ -155,8 +141,8 @@ function kvToStorage(key, x) {
|
|
|
155
141
|
}
|
|
156
142
|
}
|
|
157
143
|
function onMergeQuerySub(_k, storageSub, inMemorySub) {
|
|
158
|
-
const storageResult = storageSub
|
|
159
|
-
const memoryResult = inMemorySub
|
|
144
|
+
const storageResult = storageSub?.result;
|
|
145
|
+
const memoryResult = inMemorySub?.result;
|
|
160
146
|
if (storageResult && !memoryResult && inMemorySub) {
|
|
161
147
|
inMemorySub.result = storageResult;
|
|
162
148
|
}
|
|
@@ -178,241 +164,72 @@ function sortedMutationEntries(entries) {
|
|
|
178
164
|
* @template {import('./presence.ts').RoomSchemaShape} [RoomSchema = {}]
|
|
179
165
|
*/
|
|
180
166
|
export default class Reactor {
|
|
167
|
+
/** @type {s.AttrsStore | undefined} */
|
|
168
|
+
attrs;
|
|
169
|
+
_isOnline = true;
|
|
170
|
+
_isShutdown = false;
|
|
171
|
+
status = STATUS.CONNECTING;
|
|
172
|
+
/** @type {PersistedObject<string, QuerySub, QuerySubInStorage>} */
|
|
173
|
+
querySubs;
|
|
174
|
+
/** @type {PersistedObject} */
|
|
175
|
+
kv;
|
|
176
|
+
/** @type {SyncTable} */
|
|
177
|
+
_syncTable;
|
|
178
|
+
/** @type {Record<string, Array<{ q: any, cb: (data: any) => any }>>} */
|
|
179
|
+
queryCbs = {};
|
|
180
|
+
/** @type {Record<string, Array<{ q: any, eventId: string, dfd: Deferred }>>} */
|
|
181
|
+
queryOnceDfds = {};
|
|
182
|
+
authCbs = [];
|
|
183
|
+
attrsCbs = [];
|
|
184
|
+
mutationErrorCbs = [];
|
|
185
|
+
connectionStatusCbs = [];
|
|
186
|
+
config;
|
|
187
|
+
mutationDeferredStore = new Map();
|
|
188
|
+
_reconnectTimeoutId = null;
|
|
189
|
+
_reconnectTimeoutMs = 0;
|
|
190
|
+
/** @type {Connection} */
|
|
191
|
+
_transport;
|
|
192
|
+
/** @type {TransportType} */
|
|
193
|
+
_transportType = 'ws';
|
|
194
|
+
/** @type {EventSourceConstructor} */
|
|
195
|
+
_EventSource;
|
|
196
|
+
/** @type {boolean | null} */
|
|
197
|
+
_wsOk = null;
|
|
198
|
+
_localIdPromises = {};
|
|
199
|
+
_errorMessage = null;
|
|
200
|
+
/** @type {Promise<null | {error: {message: string}}> | null}**/
|
|
201
|
+
_oauthCallbackResponse = null;
|
|
202
|
+
/** @type {null | import('./utils/linkIndex.ts').LinkIndex}} */
|
|
203
|
+
_linkIndex = null;
|
|
204
|
+
/** @type BroadcastChannel | undefined */
|
|
205
|
+
_broadcastChannel;
|
|
206
|
+
/** @type {Record<string, {isConnected: boolean; error: any}>} */
|
|
207
|
+
_rooms = {};
|
|
208
|
+
/** @type {Record<string, boolean>} */
|
|
209
|
+
_roomsPendingLeave = {};
|
|
210
|
+
_presence = {};
|
|
211
|
+
_broadcastQueue = [];
|
|
212
|
+
_broadcastSubs = {};
|
|
213
|
+
/** @type {{isLoading: boolean; error: any | undefined, user: any | undefined}} */
|
|
214
|
+
_currentUserCached = { isLoading: true, error: undefined, user: undefined };
|
|
215
|
+
_beforeUnloadCbs = [];
|
|
216
|
+
_dataForQueryCache = {};
|
|
217
|
+
/** @type {Logger} */
|
|
218
|
+
_log;
|
|
219
|
+
_pendingTxCleanupTimeout;
|
|
220
|
+
_pendingMutationCleanupThreshold;
|
|
221
|
+
_inFlightMutationEventIds = new Set();
|
|
181
222
|
constructor(config, Storage = IndexedDBStorage, NetworkListener = WindowNetworkListener, versions, EventSourceConstructor) {
|
|
182
|
-
var _a, _b, _c;
|
|
183
|
-
this._isOnline = true;
|
|
184
|
-
this._isShutdown = false;
|
|
185
|
-
this.status = STATUS.CONNECTING;
|
|
186
|
-
/** @type {Record<string, Array<{ q: any, cb: (data: any) => any }>>} */
|
|
187
|
-
this.queryCbs = {};
|
|
188
|
-
/** @type {Record<string, Array<{ q: any, eventId: string, dfd: Deferred }>>} */
|
|
189
|
-
this.queryOnceDfds = {};
|
|
190
|
-
this.authCbs = [];
|
|
191
|
-
this.attrsCbs = [];
|
|
192
|
-
this.mutationErrorCbs = [];
|
|
193
|
-
this.connectionStatusCbs = [];
|
|
194
|
-
this.mutationDeferredStore = new Map();
|
|
195
|
-
this._reconnectTimeoutId = null;
|
|
196
|
-
this._reconnectTimeoutMs = 0;
|
|
197
|
-
/** @type {TransportType} */
|
|
198
|
-
this._transportType = 'ws';
|
|
199
|
-
/** @type {boolean | null} */
|
|
200
|
-
this._wsOk = null;
|
|
201
|
-
this._localIdPromises = {};
|
|
202
|
-
this._errorMessage = null;
|
|
203
|
-
/** @type {Promise<null | {error: {message: string}}> | null}**/
|
|
204
|
-
this._oauthCallbackResponse = null;
|
|
205
|
-
/** @type {null | import('./utils/linkIndex.ts').LinkIndex}} */
|
|
206
|
-
this._linkIndex = null;
|
|
207
|
-
/** @type {Record<string, {isConnected: boolean; error: any}>} */
|
|
208
|
-
this._rooms = {};
|
|
209
|
-
/** @type {Record<string, boolean>} */
|
|
210
|
-
this._roomsPendingLeave = {};
|
|
211
|
-
this._presence = {};
|
|
212
|
-
this._broadcastQueue = [];
|
|
213
|
-
this._broadcastSubs = {};
|
|
214
|
-
/** @type {{isLoading: boolean; error: any | undefined, user: any | undefined}} */
|
|
215
|
-
this._currentUserCached = { isLoading: true, error: undefined, user: undefined };
|
|
216
|
-
this._beforeUnloadCbs = [];
|
|
217
|
-
this._dataForQueryCache = {};
|
|
218
|
-
this._inFlightMutationEventIds = new Set();
|
|
219
|
-
this._onMergeKv = (key, storageV, inMemoryV) => {
|
|
220
|
-
var _a, _b;
|
|
221
|
-
switch (key) {
|
|
222
|
-
case 'pendingMutations': {
|
|
223
|
-
const storageEntries = (_a = storageV === null || storageV === void 0 ? void 0 : storageV.entries()) !== null && _a !== void 0 ? _a : [];
|
|
224
|
-
const inMemoryEntries = (_b = inMemoryV === null || inMemoryV === void 0 ? void 0 : inMemoryV.entries()) !== null && _b !== void 0 ? _b : [];
|
|
225
|
-
const muts = new Map([...storageEntries, ...inMemoryEntries]);
|
|
226
|
-
const rewrittenStorageMuts = storageV
|
|
227
|
-
? this._rewriteMutationsSorted(this.attrs, storageV)
|
|
228
|
-
: [];
|
|
229
|
-
rewrittenStorageMuts.forEach(([k, mut]) => {
|
|
230
|
-
var _a;
|
|
231
|
-
if (!((_a = inMemoryV === null || inMemoryV === void 0 ? void 0 : inMemoryV.pendingMutations) === null || _a === void 0 ? void 0 : _a.has(k)) && !mut['tx-id']) {
|
|
232
|
-
this._sendMutation(k, mut);
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
return muts;
|
|
236
|
-
}
|
|
237
|
-
default:
|
|
238
|
-
return inMemoryV || storageV;
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
// ---------------------------
|
|
242
|
-
// Queries
|
|
243
|
-
this.getPreviousResult = (q) => {
|
|
244
|
-
var _a;
|
|
245
|
-
const hash = weakHash(q);
|
|
246
|
-
return (_a = this.dataForQuery(hash)) === null || _a === void 0 ? void 0 : _a.data;
|
|
247
|
-
};
|
|
248
|
-
/** Re-run instaql and call all callbacks with new data */
|
|
249
|
-
this.notifyOne = (hash) => {
|
|
250
|
-
var _a, _b;
|
|
251
|
-
const cbs = (_a = this.queryCbs[hash]) !== null && _a !== void 0 ? _a : [];
|
|
252
|
-
const prevData = (_b = this._dataForQueryCache[hash]) === null || _b === void 0 ? void 0 : _b.data;
|
|
253
|
-
const resp = this.dataForQuery(hash);
|
|
254
|
-
if (!(resp === null || resp === void 0 ? void 0 : resp.data))
|
|
255
|
-
return;
|
|
256
|
-
this._dataForQueryCache[hash] = resp;
|
|
257
|
-
if (areObjectsDeepEqual(resp.data, prevData))
|
|
258
|
-
return;
|
|
259
|
-
cbs.forEach((r) => r.cb(resp.data));
|
|
260
|
-
};
|
|
261
|
-
this.notifyOneQueryOnce = (hash) => {
|
|
262
|
-
var _a, _b;
|
|
263
|
-
const dfds = (_a = this.queryOnceDfds[hash]) !== null && _a !== void 0 ? _a : [];
|
|
264
|
-
const data = (_b = this.dataForQuery(hash)) === null || _b === void 0 ? void 0 : _b.data;
|
|
265
|
-
dfds.forEach((r) => {
|
|
266
|
-
this._completeQueryOnce(r.q, hash, r.dfd);
|
|
267
|
-
r.dfd.resolve(data);
|
|
268
|
-
});
|
|
269
|
-
};
|
|
270
|
-
this.notifyQueryError = (hash, error) => {
|
|
271
|
-
const cbs = this.queryCbs[hash] || [];
|
|
272
|
-
cbs.forEach((r) => r.cb({ error }));
|
|
273
|
-
};
|
|
274
|
-
/** Applies transactions locally and sends transact message to server */
|
|
275
|
-
this.pushTx = (chunks) => {
|
|
276
|
-
// Throws if transactions are invalid
|
|
277
|
-
if (!this.config.disableValidation) {
|
|
278
|
-
validateTransactions(chunks, this.config.schema);
|
|
279
|
-
}
|
|
280
|
-
try {
|
|
281
|
-
const txSteps = instaml.transform({
|
|
282
|
-
attrsStore: this.optimisticAttrs(),
|
|
283
|
-
schema: this.config.schema,
|
|
284
|
-
stores: Object.values(this.querySubs.currentValue).map((sub) => { var _a; return (_a = sub === null || sub === void 0 ? void 0 : sub.result) === null || _a === void 0 ? void 0 : _a.store; }),
|
|
285
|
-
useDateObjects: this.config.useDateObjects,
|
|
286
|
-
}, chunks);
|
|
287
|
-
return this.pushOps(txSteps);
|
|
288
|
-
}
|
|
289
|
-
catch (e) {
|
|
290
|
-
return this.pushOps([], e);
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
/**
|
|
294
|
-
* @param {*} txSteps
|
|
295
|
-
* @param {*} [error]
|
|
296
|
-
* @returns
|
|
297
|
-
*/
|
|
298
|
-
this.pushOps = (txSteps, error) => {
|
|
299
|
-
const eventId = uuid();
|
|
300
|
-
const mutations = [...this._pendingMutations().values()];
|
|
301
|
-
const order = Math.max(0, ...mutations.map((mut) => mut.order || 0)) + 1;
|
|
302
|
-
const mutation = {
|
|
303
|
-
op: 'transact',
|
|
304
|
-
'tx-steps': txSteps,
|
|
305
|
-
created: Date.now(),
|
|
306
|
-
error,
|
|
307
|
-
order,
|
|
308
|
-
};
|
|
309
|
-
this._updatePendingMutations((prev) => {
|
|
310
|
-
prev.set(eventId, mutation);
|
|
311
|
-
});
|
|
312
|
-
const dfd = new Deferred();
|
|
313
|
-
this.mutationDeferredStore.set(eventId, dfd);
|
|
314
|
-
this._sendMutation(eventId, mutation);
|
|
315
|
-
this.notifyAll();
|
|
316
|
-
return dfd.promise;
|
|
317
|
-
};
|
|
318
|
-
this._transportOnOpen = (e) => {
|
|
319
|
-
const targetTransport = e.target;
|
|
320
|
-
if (this._transport !== targetTransport) {
|
|
321
|
-
this._log.info('[socket][open]', targetTransport.id, 'skip; this is no longer the current transport');
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
this._log.info('[socket][open]', this._transport.id);
|
|
325
|
-
this._setStatus(STATUS.OPENED);
|
|
326
|
-
this.getCurrentUser()
|
|
327
|
-
.then((resp) => {
|
|
328
|
-
var _a;
|
|
329
|
-
this._trySend(uuid(), {
|
|
330
|
-
op: 'init',
|
|
331
|
-
'app-id': this.config.appId,
|
|
332
|
-
'refresh-token': (_a = resp.user) === null || _a === void 0 ? void 0 : _a['refresh_token'],
|
|
333
|
-
versions: this.versions,
|
|
334
|
-
// If an admin token is provided for an app, we will
|
|
335
|
-
// skip all permission checks. This is an advanced feature,
|
|
336
|
-
// to let users write internal tools
|
|
337
|
-
// This option is not exposed in `Config`, as it's
|
|
338
|
-
// not ready for prime time
|
|
339
|
-
'__admin-token': this.config.__adminToken,
|
|
340
|
-
});
|
|
341
|
-
})
|
|
342
|
-
.catch((e) => {
|
|
343
|
-
this._log.error('[socket][error]', targetTransport.id, e);
|
|
344
|
-
});
|
|
345
|
-
};
|
|
346
|
-
this._transportOnMessage = (e) => {
|
|
347
|
-
const targetTransport = e.target;
|
|
348
|
-
const m = e.message;
|
|
349
|
-
if (this._transport !== targetTransport) {
|
|
350
|
-
this._log.info('[socket][message]', targetTransport.id, m, 'skip; this is no longer the current transport');
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
if (!this._wsOk && targetTransport.type === 'ws') {
|
|
354
|
-
this._wsOk = true;
|
|
355
|
-
}
|
|
356
|
-
// Try to reconnect via websocket the next time we connect
|
|
357
|
-
this._transportType = 'ws';
|
|
358
|
-
if (Array.isArray(e.message)) {
|
|
359
|
-
for (const msg of e.message) {
|
|
360
|
-
this._handleReceive(targetTransport.id, msg);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
this._handleReceive(targetTransport.id, e.message);
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
this._transportOnError = (e) => {
|
|
368
|
-
const targetTransport = e.target;
|
|
369
|
-
if (this._transport !== targetTransport) {
|
|
370
|
-
this._log.info('[socket][error]', targetTransport.id, 'skip; this is no longer the current transport');
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
this._log.error('[socket][error]', targetTransport.id, e);
|
|
374
|
-
};
|
|
375
|
-
this._scheduleReconnect = () => {
|
|
376
|
-
// If we couldn't connect with a websocket last time, try sse
|
|
377
|
-
if (!this._wsOk && this._transportType !== 'sse') {
|
|
378
|
-
this._transportType = 'sse';
|
|
379
|
-
this._reconnectTimeoutMs = 0;
|
|
380
|
-
}
|
|
381
|
-
setTimeout(() => {
|
|
382
|
-
this._reconnectTimeoutMs = Math.min(this._reconnectTimeoutMs + 1000, 10000);
|
|
383
|
-
if (!this._isOnline) {
|
|
384
|
-
this._log.info('[socket][close]', this._transport.id, 'we are offline, no need to start socket');
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
this._startSocket();
|
|
388
|
-
}, this._reconnectTimeoutMs);
|
|
389
|
-
};
|
|
390
|
-
this._transportOnClose = (e) => {
|
|
391
|
-
const targetTransport = e.target;
|
|
392
|
-
if (this._transport !== targetTransport) {
|
|
393
|
-
this._log.info('[socket][close]', targetTransport.id, 'skip; this is no longer the current transport');
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
this._setStatus(STATUS.CLOSED);
|
|
397
|
-
for (const room of Object.values(this._rooms)) {
|
|
398
|
-
room.isConnected = false;
|
|
399
|
-
}
|
|
400
|
-
if (this._isShutdown) {
|
|
401
|
-
this._log.info('[socket][close]', targetTransport.id, 'Reactor has been shut down and will not reconnect');
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
this._log.info('[socket][close]', targetTransport.id, 'schedule reconnect, ms =', this._reconnectTimeoutMs);
|
|
405
|
-
this._scheduleReconnect();
|
|
406
|
-
};
|
|
407
223
|
this._EventSource = EventSourceConstructor;
|
|
408
|
-
this.config =
|
|
409
|
-
this.queryCacheLimit =
|
|
224
|
+
this.config = { ...defaultConfig, ...config };
|
|
225
|
+
this.queryCacheLimit = this.config.queryCacheLimit ?? 10;
|
|
410
226
|
this._pendingTxCleanupTimeout =
|
|
411
|
-
|
|
227
|
+
this.config.pendingTxCleanupTimeout ?? PENDING_TX_CLEANUP_TIMEOUT;
|
|
412
228
|
this._pendingMutationCleanupThreshold =
|
|
413
|
-
|
|
229
|
+
this.config.pendingMutationCleanupThreshold ??
|
|
230
|
+
PENDING_MUTATION_CLEANUP_THRESHOLD;
|
|
414
231
|
this._log = createLogger(config.verbose || flags.devBackend || flags.instantLogs, () => this._reactorStats());
|
|
415
|
-
this.versions =
|
|
232
|
+
this.versions = { ...(versions || {}), '@instantdb/core': version };
|
|
416
233
|
if (this.config.schema) {
|
|
417
234
|
this._linkIndex = createLinkIndex(this.config.schema);
|
|
418
235
|
}
|
|
@@ -429,18 +246,17 @@ export default class Reactor {
|
|
|
429
246
|
}
|
|
430
247
|
if (typeof BroadcastChannel === 'function') {
|
|
431
248
|
this._broadcastChannel = new BroadcastChannel('@instantdb');
|
|
432
|
-
this._broadcastChannel.addEventListener('message', (e) =>
|
|
433
|
-
var _a;
|
|
249
|
+
this._broadcastChannel.addEventListener('message', async (e) => {
|
|
434
250
|
try {
|
|
435
|
-
if (
|
|
436
|
-
const res =
|
|
251
|
+
if (e.data?.type === 'auth') {
|
|
252
|
+
const res = await this.getCurrentUser();
|
|
437
253
|
this.updateUser(res.user);
|
|
438
254
|
}
|
|
439
255
|
}
|
|
440
256
|
catch (e) {
|
|
441
257
|
this._log.error('[error] handle broadcast channel', e);
|
|
442
258
|
}
|
|
443
|
-
})
|
|
259
|
+
});
|
|
444
260
|
}
|
|
445
261
|
this._initStorage(Storage);
|
|
446
262
|
this._syncTable = new SyncTable(this._trySendAuthed.bind(this), new Storage(this.config.appId, 'syncSubs'), {
|
|
@@ -453,10 +269,10 @@ export default class Reactor {
|
|
|
453
269
|
this.getCurrentUser().then((userInfo) => {
|
|
454
270
|
this.syncUserToEndpoint(userInfo.user);
|
|
455
271
|
});
|
|
456
|
-
setInterval(() =>
|
|
457
|
-
const currentUser =
|
|
272
|
+
setInterval(async () => {
|
|
273
|
+
const currentUser = await this.getCurrentUser();
|
|
458
274
|
this.syncUserToEndpoint(currentUser.user);
|
|
459
|
-
}
|
|
275
|
+
}, ONE_MIN_MS);
|
|
460
276
|
NetworkListener.getIsOnline().then((isOnline) => {
|
|
461
277
|
this._isOnline = isOnline;
|
|
462
278
|
this._startSocket();
|
|
@@ -490,7 +306,11 @@ export default class Reactor {
|
|
|
490
306
|
return this.attrs;
|
|
491
307
|
}
|
|
492
308
|
updateSchema(schema) {
|
|
493
|
-
this.config =
|
|
309
|
+
this.config = {
|
|
310
|
+
...this.config,
|
|
311
|
+
schema: schema,
|
|
312
|
+
cardinalityInference: Boolean(schema),
|
|
313
|
+
};
|
|
494
314
|
this._linkIndex = schema ? createLinkIndex(this.config.schema) : null;
|
|
495
315
|
}
|
|
496
316
|
_reactorStats() {
|
|
@@ -512,14 +332,14 @@ export default class Reactor {
|
|
|
512
332
|
serialize: querySubToStorage,
|
|
513
333
|
parse: (_key, x) => querySubFromStorage(x, this.config.useDateObjects),
|
|
514
334
|
// objectSize
|
|
515
|
-
objectSize: (x) =>
|
|
335
|
+
objectSize: (x) => x?.result?.store?.triples?.length ?? 0,
|
|
516
336
|
logger: this._log,
|
|
517
337
|
preloadEntryCount: 10,
|
|
518
338
|
gc: {
|
|
519
339
|
maxAgeMs: 1000 * 60 * 60 * 24 * 7 * 52, // 1 year
|
|
520
340
|
maxEntries: 1000,
|
|
521
341
|
// Size of each query is the number of triples
|
|
522
|
-
maxSize:
|
|
342
|
+
maxSize: 1_000_000, // 1 million triples
|
|
523
343
|
},
|
|
524
344
|
});
|
|
525
345
|
this.querySubs.onKeyLoaded = (k) => this._onQuerySubLoaded(k);
|
|
@@ -565,7 +385,7 @@ export default class Reactor {
|
|
|
565
385
|
const ok = status !== 'error' && status !== 'timeout';
|
|
566
386
|
if (!dfd && !ok) {
|
|
567
387
|
// console.erroring here, as there are no listeners to let know
|
|
568
|
-
console.error('Mutation failed',
|
|
388
|
+
console.error('Mutation failed', { status, eventId, ...errorMsg });
|
|
569
389
|
}
|
|
570
390
|
if (!dfd) {
|
|
571
391
|
return;
|
|
@@ -575,16 +395,16 @@ export default class Reactor {
|
|
|
575
395
|
}
|
|
576
396
|
else {
|
|
577
397
|
// Check if error comes from server or client
|
|
578
|
-
if (errorMsg
|
|
579
|
-
const { status
|
|
398
|
+
if (errorMsg?.type) {
|
|
399
|
+
const { status, ...body } = errorMsg;
|
|
580
400
|
dfd.reject(new InstantAPIError({
|
|
581
401
|
// @ts-expect-error body.type is not constant typed
|
|
582
402
|
body,
|
|
583
|
-
status: status
|
|
403
|
+
status: status ?? 0,
|
|
584
404
|
}));
|
|
585
405
|
}
|
|
586
406
|
else {
|
|
587
|
-
dfd.reject(new InstantError(
|
|
407
|
+
dfd.reject(new InstantError(errorMsg?.message || 'Unknown error', errorMsg?.hint));
|
|
588
408
|
}
|
|
589
409
|
}
|
|
590
410
|
}
|
|
@@ -593,9 +413,28 @@ export default class Reactor {
|
|
|
593
413
|
this._errorMessage = err;
|
|
594
414
|
this.notifyConnectionStatusSubs(status);
|
|
595
415
|
}
|
|
416
|
+
_onMergeKv = (key, storageV, inMemoryV) => {
|
|
417
|
+
switch (key) {
|
|
418
|
+
case 'pendingMutations': {
|
|
419
|
+
const storageEntries = storageV?.entries() ?? [];
|
|
420
|
+
const inMemoryEntries = inMemoryV?.entries() ?? [];
|
|
421
|
+
const muts = new Map([...storageEntries, ...inMemoryEntries]);
|
|
422
|
+
const rewrittenStorageMuts = storageV
|
|
423
|
+
? this._rewriteMutationsSorted(this.attrs, storageV)
|
|
424
|
+
: [];
|
|
425
|
+
rewrittenStorageMuts.forEach(([k, mut]) => {
|
|
426
|
+
if (!inMemoryV?.pendingMutations?.has(k) && !mut['tx-id']) {
|
|
427
|
+
this._sendMutation(k, mut);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
return muts;
|
|
431
|
+
}
|
|
432
|
+
default:
|
|
433
|
+
return inMemoryV || storageV;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
596
436
|
_flushEnqueuedRoomData(roomId) {
|
|
597
|
-
|
|
598
|
-
const enqueuedUserPresence = (_b = (_a = this._presence[roomId]) === null || _a === void 0 ? void 0 : _a.result) === null || _b === void 0 ? void 0 : _b.user;
|
|
437
|
+
const enqueuedUserPresence = this._presence[roomId]?.result?.user;
|
|
599
438
|
const enqueuedBroadcasts = this._broadcastQueue[roomId];
|
|
600
439
|
this._broadcastQueue[roomId] = [];
|
|
601
440
|
if (enqueuedUserPresence) {
|
|
@@ -640,7 +479,6 @@ export default class Reactor {
|
|
|
640
479
|
this._cleanupPendingMutationsTimeout();
|
|
641
480
|
}
|
|
642
481
|
_handleReceive(connId, msg) {
|
|
643
|
-
var _a, _b, _c, _d, _e, _f;
|
|
644
482
|
// opt-out, enabled by default if schema
|
|
645
483
|
const enableCardinalityInference = Boolean(this.config.schema) &&
|
|
646
484
|
('cardinalityInference' in this.config
|
|
@@ -659,7 +497,7 @@ export default class Reactor {
|
|
|
659
497
|
// which item is us
|
|
660
498
|
this._sessionId = msg['session-id'];
|
|
661
499
|
for (const roomId of Object.keys(this._rooms)) {
|
|
662
|
-
const enqueuedUserPresence =
|
|
500
|
+
const enqueuedUserPresence = this._presence[roomId]?.result?.user;
|
|
663
501
|
this._tryJoinRoom(roomId, enqueuedUserPresence);
|
|
664
502
|
}
|
|
665
503
|
break;
|
|
@@ -674,8 +512,8 @@ export default class Reactor {
|
|
|
674
512
|
if (!this._hasQueryListeners() && !this.querySubs.currentValue[hash]) {
|
|
675
513
|
break;
|
|
676
514
|
}
|
|
677
|
-
const pageInfo =
|
|
678
|
-
const aggregate =
|
|
515
|
+
const pageInfo = result?.[0]?.data?.['page-info'];
|
|
516
|
+
const aggregate = result?.[0]?.data?.['aggregate'];
|
|
679
517
|
const triples = extractTriples(result);
|
|
680
518
|
const attrsStore = this.ensureAttrs();
|
|
681
519
|
const store = s.createStore(attrsStore, triples, enableCardinalityInference, this.config.useDateObjects);
|
|
@@ -732,7 +570,6 @@ export default class Reactor {
|
|
|
732
570
|
}
|
|
733
571
|
const mutations = sortedMutationEntries(rewrittenMutations.entries());
|
|
734
572
|
const updates = computations.map((x) => {
|
|
735
|
-
var _a, _b, _c, _d;
|
|
736
573
|
const q = x['instaql-query'];
|
|
737
574
|
const result = x['instaql-result'];
|
|
738
575
|
const hash = weakHash(q);
|
|
@@ -740,8 +577,8 @@ export default class Reactor {
|
|
|
740
577
|
const attrsStore = this.ensureAttrs();
|
|
741
578
|
const store = s.createStore(attrsStore, triples, enableCardinalityInference, this.config.useDateObjects);
|
|
742
579
|
const { store: newStore, attrsStore: newAttrsStore } = this._applyOptimisticUpdates(store, attrsStore, mutations, processedTxId);
|
|
743
|
-
const pageInfo =
|
|
744
|
-
const aggregate =
|
|
580
|
+
const pageInfo = result?.[0]?.data?.['page-info'];
|
|
581
|
+
const aggregate = result?.[0]?.data?.['aggregate'];
|
|
745
582
|
return {
|
|
746
583
|
q,
|
|
747
584
|
hash,
|
|
@@ -782,7 +619,11 @@ export default class Reactor {
|
|
|
782
619
|
}
|
|
783
620
|
// update pendingMutation with server-side tx-id
|
|
784
621
|
this._updatePendingMutations((prev) => {
|
|
785
|
-
prev.set(eventId,
|
|
622
|
+
prev.set(eventId, {
|
|
623
|
+
...prev.get(eventId),
|
|
624
|
+
'tx-id': txId,
|
|
625
|
+
confirmed: Date.now(),
|
|
626
|
+
});
|
|
786
627
|
});
|
|
787
628
|
const newAttrs = [];
|
|
788
629
|
for (const step of prevMutation['tx-steps']) {
|
|
@@ -856,13 +697,11 @@ export default class Reactor {
|
|
|
856
697
|
}
|
|
857
698
|
}
|
|
858
699
|
_pendingMutations() {
|
|
859
|
-
|
|
860
|
-
return (_a = this.kv.currentValue.pendingMutations) !== null && _a !== void 0 ? _a : new Map();
|
|
700
|
+
return this.kv.currentValue.pendingMutations ?? new Map();
|
|
861
701
|
}
|
|
862
702
|
_updatePendingMutations(f) {
|
|
863
703
|
this.kv.updateInPlace((prev) => {
|
|
864
|
-
|
|
865
|
-
const muts = (_a = prev.pendingMutations) !== null && _a !== void 0 ? _a : new Map();
|
|
704
|
+
const muts = prev.pendingMutations ?? new Map();
|
|
866
705
|
prev.pendingMutations = muts;
|
|
867
706
|
f(muts);
|
|
868
707
|
});
|
|
@@ -891,7 +730,6 @@ export default class Reactor {
|
|
|
891
730
|
}
|
|
892
731
|
}
|
|
893
732
|
_handleReceiveError(msg) {
|
|
894
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
895
733
|
console.log('error', msg);
|
|
896
734
|
const eventId = msg['client-event-id'];
|
|
897
735
|
// This might not be a mutation, but it can't hurt to delete it
|
|
@@ -907,18 +745,18 @@ export default class Reactor {
|
|
|
907
745
|
this._handleMutationError('error', eventId, msg);
|
|
908
746
|
return;
|
|
909
747
|
}
|
|
910
|
-
if (
|
|
911
|
-
|
|
912
|
-
const q =
|
|
748
|
+
if (msg['original-event']?.hasOwnProperty('q') &&
|
|
749
|
+
msg['original-event']?.op === 'add-query') {
|
|
750
|
+
const q = msg['original-event']?.q;
|
|
913
751
|
const hash = weakHash(q);
|
|
914
752
|
this.notifyQueryError(weakHash(q), errorMessage);
|
|
915
753
|
this.notifyQueryOnceError(q, hash, eventId, errorMessage);
|
|
916
754
|
return;
|
|
917
755
|
}
|
|
918
|
-
const isInitError =
|
|
756
|
+
const isInitError = msg['original-event']?.op === 'init';
|
|
919
757
|
if (isInitError) {
|
|
920
758
|
if (msg.type === 'record-not-found' &&
|
|
921
|
-
|
|
759
|
+
msg.hint?.['record-type'] === 'app-user') {
|
|
922
760
|
// User has been logged out
|
|
923
761
|
this.changeCurrentUser(null);
|
|
924
762
|
return;
|
|
@@ -928,17 +766,17 @@ export default class Reactor {
|
|
|
928
766
|
this.notifyAll();
|
|
929
767
|
return;
|
|
930
768
|
}
|
|
931
|
-
if (
|
|
769
|
+
if (msg['original-event']?.op === 'resync-table') {
|
|
932
770
|
this._syncTable.onResyncError(msg);
|
|
933
771
|
return;
|
|
934
772
|
}
|
|
935
|
-
if (
|
|
773
|
+
if (msg['original-event']?.op === 'start-sync') {
|
|
936
774
|
this._syncTable.onStartSyncError(msg);
|
|
937
775
|
return;
|
|
938
776
|
}
|
|
939
777
|
// We've caught some error which has no corresponding listener.
|
|
940
778
|
// Let's console.error to let the user know.
|
|
941
|
-
const errorObj =
|
|
779
|
+
const errorObj = { ...msg };
|
|
942
780
|
delete errorObj.message;
|
|
943
781
|
delete errorObj.hint;
|
|
944
782
|
console.error(msg.message, errorObj);
|
|
@@ -947,8 +785,7 @@ export default class Reactor {
|
|
|
947
785
|
}
|
|
948
786
|
}
|
|
949
787
|
notifyQueryOnceError(q, hash, eventId, e) {
|
|
950
|
-
|
|
951
|
-
const r = (_a = this.queryOnceDfds[hash]) === null || _a === void 0 ? void 0 : _a.find((r) => r.eventId === eventId);
|
|
788
|
+
const r = this.queryOnceDfds[hash]?.find((r) => r.eventId === eventId);
|
|
952
789
|
if (!r)
|
|
953
790
|
return;
|
|
954
791
|
r.dfd.reject(e);
|
|
@@ -961,6 +798,12 @@ export default class Reactor {
|
|
|
961
798
|
}, {}), this._linkIndex);
|
|
962
799
|
this.notifyAttrsSubs();
|
|
963
800
|
}
|
|
801
|
+
// ---------------------------
|
|
802
|
+
// Queries
|
|
803
|
+
getPreviousResult = (q) => {
|
|
804
|
+
const hash = weakHash(q);
|
|
805
|
+
return this.dataForQuery(hash)?.data;
|
|
806
|
+
};
|
|
964
807
|
_startQuerySub(q, hash) {
|
|
965
808
|
const eventId = uuid();
|
|
966
809
|
this.querySubs.updateInPlace((prev) => {
|
|
@@ -984,19 +827,18 @@ export default class Reactor {
|
|
|
984
827
|
* Returns an unsubscribe function
|
|
985
828
|
*/
|
|
986
829
|
subscribeQuery(q, cb, opts) {
|
|
987
|
-
var _a;
|
|
988
830
|
if (!this.config.disableValidation) {
|
|
989
831
|
validateQuery(q, this.config.schema);
|
|
990
832
|
}
|
|
991
833
|
if (opts && 'ruleParams' in opts) {
|
|
992
|
-
q =
|
|
834
|
+
q = { $$ruleParams: opts['ruleParams'], ...q };
|
|
993
835
|
}
|
|
994
836
|
const hash = weakHash(q);
|
|
995
837
|
const prevResult = this.getPreviousResult(q);
|
|
996
838
|
if (prevResult) {
|
|
997
839
|
cb(prevResult);
|
|
998
840
|
}
|
|
999
|
-
this.queryCbs[hash] =
|
|
841
|
+
this.queryCbs[hash] = this.queryCbs[hash] ?? [];
|
|
1000
842
|
this.queryCbs[hash].push({ q, cb });
|
|
1001
843
|
this._startQuerySub(q, hash);
|
|
1002
844
|
return () => {
|
|
@@ -1004,12 +846,11 @@ export default class Reactor {
|
|
|
1004
846
|
};
|
|
1005
847
|
}
|
|
1006
848
|
queryOnce(q, opts) {
|
|
1007
|
-
var _a;
|
|
1008
849
|
if (!this.config.disableValidation) {
|
|
1009
850
|
validateQuery(q, this.config.schema);
|
|
1010
851
|
}
|
|
1011
852
|
if (opts && 'ruleParams' in opts) {
|
|
1012
|
-
q =
|
|
853
|
+
q = { $$ruleParams: opts['ruleParams'], ...q };
|
|
1013
854
|
}
|
|
1014
855
|
const dfd = new Deferred();
|
|
1015
856
|
if (!this._isOnline) {
|
|
@@ -1022,7 +863,7 @@ export default class Reactor {
|
|
|
1022
863
|
}
|
|
1023
864
|
const hash = weakHash(q);
|
|
1024
865
|
const eventId = this._startQuerySub(q, hash);
|
|
1025
|
-
this.queryOnceDfds[hash] =
|
|
866
|
+
this.queryOnceDfds[hash] = this.queryOnceDfds[hash] ?? [];
|
|
1026
867
|
this.queryOnceDfds[hash].push({ q, dfd, eventId });
|
|
1027
868
|
setTimeout(() => dfd.reject(new Error('Query timed out')), QUERY_ONCE_TIMEOUT);
|
|
1028
869
|
return dfd.promise;
|
|
@@ -1040,8 +881,7 @@ export default class Reactor {
|
|
|
1040
881
|
this._cleanupQuery(q, hash);
|
|
1041
882
|
}
|
|
1042
883
|
_hasQueryListeners(hash) {
|
|
1043
|
-
|
|
1044
|
-
return !!(((_a = this.queryCbs[hash]) === null || _a === void 0 ? void 0 : _a.length) || ((_b = this.queryOnceDfds[hash]) === null || _b === void 0 ? void 0 : _b.length));
|
|
884
|
+
return !!(this.queryCbs[hash]?.length || this.queryOnceDfds[hash]?.length);
|
|
1045
885
|
}
|
|
1046
886
|
_cleanupQuery(q, hash) {
|
|
1047
887
|
const hasListeners = this._hasQueryListeners(hash);
|
|
@@ -1133,7 +973,10 @@ export default class Reactor {
|
|
|
1133
973
|
};
|
|
1134
974
|
const rewritten = new Map();
|
|
1135
975
|
for (const [k, mut] of muts.entries()) {
|
|
1136
|
-
rewritten.set(k,
|
|
976
|
+
rewritten.set(k, {
|
|
977
|
+
...mut,
|
|
978
|
+
'tx-steps': rewriteTxSteps(mut['tx-steps'], mut['tx-id']),
|
|
979
|
+
});
|
|
1137
980
|
}
|
|
1138
981
|
if (!mappingChanged) {
|
|
1139
982
|
return muts;
|
|
@@ -1149,7 +992,6 @@ export default class Reactor {
|
|
|
1149
992
|
* @returns {s.AttrsStore}
|
|
1150
993
|
*/
|
|
1151
994
|
optimisticAttrs() {
|
|
1152
|
-
var _a, _b;
|
|
1153
995
|
const pendingMutationSteps = [...this._pendingMutations().values()] // hack due to Map()
|
|
1154
996
|
.flatMap((x) => x['tx-steps']);
|
|
1155
997
|
const deletedAttrIds = new Set(pendingMutationSteps
|
|
@@ -1162,15 +1004,15 @@ export default class Reactor {
|
|
|
1162
1004
|
}
|
|
1163
1005
|
else if (_action === 'update-attr' &&
|
|
1164
1006
|
attr.id &&
|
|
1165
|
-
|
|
1166
|
-
const fullAttr =
|
|
1007
|
+
this.attrs?.getAttr(attr.id)) {
|
|
1008
|
+
const fullAttr = { ...this.attrs.getAttr(attr.id), ...attr };
|
|
1167
1009
|
pendingAttrs.push(fullAttr);
|
|
1168
1010
|
}
|
|
1169
1011
|
}
|
|
1170
1012
|
if (!deletedAttrIds.size && !pendingAttrs.length) {
|
|
1171
1013
|
return this.attrs || new s.AttrsStoreClass({}, this._linkIndex);
|
|
1172
1014
|
}
|
|
1173
|
-
const attrs =
|
|
1015
|
+
const attrs = { ...(this.attrs?.attrs || {}) };
|
|
1174
1016
|
for (const attr of pendingAttrs) {
|
|
1175
1017
|
attrs[attr.id] = attr;
|
|
1176
1018
|
}
|
|
@@ -1224,6 +1066,30 @@ export default class Reactor {
|
|
|
1224
1066
|
}
|
|
1225
1067
|
return { store, attrsStore };
|
|
1226
1068
|
}
|
|
1069
|
+
/** Re-run instaql and call all callbacks with new data */
|
|
1070
|
+
notifyOne = (hash) => {
|
|
1071
|
+
const cbs = this.queryCbs[hash] ?? [];
|
|
1072
|
+
const prevData = this._dataForQueryCache[hash]?.data;
|
|
1073
|
+
const resp = this.dataForQuery(hash);
|
|
1074
|
+
if (!resp?.data)
|
|
1075
|
+
return;
|
|
1076
|
+
this._dataForQueryCache[hash] = resp;
|
|
1077
|
+
if (areObjectsDeepEqual(resp.data, prevData))
|
|
1078
|
+
return;
|
|
1079
|
+
cbs.forEach((r) => r.cb(resp.data));
|
|
1080
|
+
};
|
|
1081
|
+
notifyOneQueryOnce = (hash) => {
|
|
1082
|
+
const dfds = this.queryOnceDfds[hash] ?? [];
|
|
1083
|
+
const data = this.dataForQuery(hash)?.data;
|
|
1084
|
+
dfds.forEach((r) => {
|
|
1085
|
+
this._completeQueryOnce(r.q, hash, r.dfd);
|
|
1086
|
+
r.dfd.resolve(data);
|
|
1087
|
+
});
|
|
1088
|
+
};
|
|
1089
|
+
notifyQueryError = (hash, error) => {
|
|
1090
|
+
const cbs = this.queryCbs[hash] || [];
|
|
1091
|
+
cbs.forEach((r) => r.cb({ error }));
|
|
1092
|
+
};
|
|
1227
1093
|
/** Re-compute all subscriptions */
|
|
1228
1094
|
notifyAll() {
|
|
1229
1095
|
Object.keys(this.queryCbs).forEach((hash) => {
|
|
@@ -1239,11 +1105,54 @@ export default class Reactor {
|
|
|
1239
1105
|
.then(() => this.notifyAll())
|
|
1240
1106
|
.catch(() => this.notifyAll());
|
|
1241
1107
|
}
|
|
1108
|
+
/** Applies transactions locally and sends transact message to server */
|
|
1109
|
+
pushTx = (chunks) => {
|
|
1110
|
+
// Throws if transactions are invalid
|
|
1111
|
+
if (!this.config.disableValidation) {
|
|
1112
|
+
validateTransactions(chunks, this.config.schema);
|
|
1113
|
+
}
|
|
1114
|
+
try {
|
|
1115
|
+
const txSteps = instaml.transform({
|
|
1116
|
+
attrsStore: this.optimisticAttrs(),
|
|
1117
|
+
schema: this.config.schema,
|
|
1118
|
+
stores: Object.values(this.querySubs.currentValue).map((sub) => sub?.result?.store),
|
|
1119
|
+
useDateObjects: this.config.useDateObjects,
|
|
1120
|
+
}, chunks);
|
|
1121
|
+
return this.pushOps(txSteps);
|
|
1122
|
+
}
|
|
1123
|
+
catch (e) {
|
|
1124
|
+
return this.pushOps([], e);
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
/**
|
|
1128
|
+
* @param {*} txSteps
|
|
1129
|
+
* @param {*} [error]
|
|
1130
|
+
* @returns
|
|
1131
|
+
*/
|
|
1132
|
+
pushOps = (txSteps, error) => {
|
|
1133
|
+
const eventId = uuid();
|
|
1134
|
+
const mutations = [...this._pendingMutations().values()];
|
|
1135
|
+
const order = Math.max(0, ...mutations.map((mut) => mut.order || 0)) + 1;
|
|
1136
|
+
const mutation = {
|
|
1137
|
+
op: 'transact',
|
|
1138
|
+
'tx-steps': txSteps,
|
|
1139
|
+
created: Date.now(),
|
|
1140
|
+
error,
|
|
1141
|
+
order,
|
|
1142
|
+
};
|
|
1143
|
+
this._updatePendingMutations((prev) => {
|
|
1144
|
+
prev.set(eventId, mutation);
|
|
1145
|
+
});
|
|
1146
|
+
const dfd = new Deferred();
|
|
1147
|
+
this.mutationDeferredStore.set(eventId, dfd);
|
|
1148
|
+
this._sendMutation(eventId, mutation);
|
|
1149
|
+
this.notifyAll();
|
|
1150
|
+
return dfd.promise;
|
|
1151
|
+
};
|
|
1242
1152
|
shutdown() {
|
|
1243
|
-
var _a;
|
|
1244
1153
|
this._log.info('[shutdown]', this.config.appId);
|
|
1245
1154
|
this._isShutdown = true;
|
|
1246
|
-
|
|
1155
|
+
this._transport?.close();
|
|
1247
1156
|
}
|
|
1248
1157
|
/**
|
|
1249
1158
|
* Sends mutation to server and schedules a timeout to cancel it if
|
|
@@ -1316,8 +1225,8 @@ export default class Reactor {
|
|
|
1316
1225
|
_cleanupPendingMutationsQueries() {
|
|
1317
1226
|
let minProcessedTxId = Number.MAX_SAFE_INTEGER;
|
|
1318
1227
|
for (const { result } of Object.values(this.querySubs.currentValue)) {
|
|
1319
|
-
if (result
|
|
1320
|
-
minProcessedTxId = Math.min(minProcessedTxId, result
|
|
1228
|
+
if (result?.processedTxId) {
|
|
1229
|
+
minProcessedTxId = Math.min(minProcessedTxId, result?.processedTxId);
|
|
1321
1230
|
}
|
|
1322
1231
|
}
|
|
1323
1232
|
this._updatePendingMutations((prev) => {
|
|
@@ -1370,8 +1279,96 @@ export default class Reactor {
|
|
|
1370
1279
|
this._inFlightMutationEventIds.clear();
|
|
1371
1280
|
}
|
|
1372
1281
|
}
|
|
1373
|
-
this._transport.send(
|
|
1282
|
+
this._transport.send({ 'client-event-id': eventId, ...msg });
|
|
1374
1283
|
}
|
|
1284
|
+
_transportOnOpen = (e) => {
|
|
1285
|
+
const targetTransport = e.target;
|
|
1286
|
+
if (this._transport !== targetTransport) {
|
|
1287
|
+
this._log.info('[socket][open]', targetTransport.id, 'skip; this is no longer the current transport');
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
this._log.info('[socket][open]', this._transport.id);
|
|
1291
|
+
this._setStatus(STATUS.OPENED);
|
|
1292
|
+
this.getCurrentUser()
|
|
1293
|
+
.then((resp) => {
|
|
1294
|
+
this._trySend(uuid(), {
|
|
1295
|
+
op: 'init',
|
|
1296
|
+
'app-id': this.config.appId,
|
|
1297
|
+
'refresh-token': resp.user?.['refresh_token'],
|
|
1298
|
+
versions: this.versions,
|
|
1299
|
+
// If an admin token is provided for an app, we will
|
|
1300
|
+
// skip all permission checks. This is an advanced feature,
|
|
1301
|
+
// to let users write internal tools
|
|
1302
|
+
// This option is not exposed in `Config`, as it's
|
|
1303
|
+
// not ready for prime time
|
|
1304
|
+
'__admin-token': this.config.__adminToken,
|
|
1305
|
+
});
|
|
1306
|
+
})
|
|
1307
|
+
.catch((e) => {
|
|
1308
|
+
this._log.error('[socket][error]', targetTransport.id, e);
|
|
1309
|
+
});
|
|
1310
|
+
};
|
|
1311
|
+
_transportOnMessage = (e) => {
|
|
1312
|
+
const targetTransport = e.target;
|
|
1313
|
+
const m = e.message;
|
|
1314
|
+
if (this._transport !== targetTransport) {
|
|
1315
|
+
this._log.info('[socket][message]', targetTransport.id, m, 'skip; this is no longer the current transport');
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
if (!this._wsOk && targetTransport.type === 'ws') {
|
|
1319
|
+
this._wsOk = true;
|
|
1320
|
+
}
|
|
1321
|
+
// Try to reconnect via websocket the next time we connect
|
|
1322
|
+
this._transportType = 'ws';
|
|
1323
|
+
if (Array.isArray(e.message)) {
|
|
1324
|
+
for (const msg of e.message) {
|
|
1325
|
+
this._handleReceive(targetTransport.id, msg);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
this._handleReceive(targetTransport.id, e.message);
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
_transportOnError = (e) => {
|
|
1333
|
+
const targetTransport = e.target;
|
|
1334
|
+
if (this._transport !== targetTransport) {
|
|
1335
|
+
this._log.info('[socket][error]', targetTransport.id, 'skip; this is no longer the current transport');
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
this._log.error('[socket][error]', targetTransport.id, e);
|
|
1339
|
+
};
|
|
1340
|
+
_scheduleReconnect = () => {
|
|
1341
|
+
// If we couldn't connect with a websocket last time, try sse
|
|
1342
|
+
if (!this._wsOk && this._transportType !== 'sse') {
|
|
1343
|
+
this._transportType = 'sse';
|
|
1344
|
+
this._reconnectTimeoutMs = 0;
|
|
1345
|
+
}
|
|
1346
|
+
setTimeout(() => {
|
|
1347
|
+
this._reconnectTimeoutMs = Math.min(this._reconnectTimeoutMs + 1000, 10000);
|
|
1348
|
+
if (!this._isOnline) {
|
|
1349
|
+
this._log.info('[socket][close]', this._transport.id, 'we are offline, no need to start socket');
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
this._startSocket();
|
|
1353
|
+
}, this._reconnectTimeoutMs);
|
|
1354
|
+
};
|
|
1355
|
+
_transportOnClose = (e) => {
|
|
1356
|
+
const targetTransport = e.target;
|
|
1357
|
+
if (this._transport !== targetTransport) {
|
|
1358
|
+
this._log.info('[socket][close]', targetTransport.id, 'skip; this is no longer the current transport');
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
this._setStatus(STATUS.CLOSED);
|
|
1362
|
+
for (const room of Object.values(this._rooms)) {
|
|
1363
|
+
room.isConnected = false;
|
|
1364
|
+
}
|
|
1365
|
+
if (this._isShutdown) {
|
|
1366
|
+
this._log.info('[socket][close]', targetTransport.id, 'Reactor has been shut down and will not reconnect');
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
this._log.info('[socket][close]', targetTransport.id, 'schedule reconnect, ms =', this._reconnectTimeoutMs);
|
|
1370
|
+
this._scheduleReconnect();
|
|
1371
|
+
};
|
|
1375
1372
|
_startSocket() {
|
|
1376
1373
|
// Reset whether we support websockets each time we connect
|
|
1377
1374
|
// new networks may not support websockets
|
|
@@ -1400,7 +1397,7 @@ export default class Reactor {
|
|
|
1400
1397
|
this._transport.onclose = this._transportOnClose;
|
|
1401
1398
|
this._transport.onerror = this._transportOnError;
|
|
1402
1399
|
this._log.info('[socket][start]', this._transport.id);
|
|
1403
|
-
if (prevTransport
|
|
1400
|
+
if (prevTransport?.isOpen()) {
|
|
1404
1401
|
// When the network dies, it doesn't always mean that our
|
|
1405
1402
|
// socket connection will fire a close event.
|
|
1406
1403
|
//
|
|
@@ -1421,24 +1418,22 @@ export default class Reactor {
|
|
|
1421
1418
|
* Note: If the user deletes their local storage, this id will change.
|
|
1422
1419
|
*
|
|
1423
1420
|
*/
|
|
1424
|
-
getLocalId(name) {
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
prev[k] = newId;
|
|
1439
|
-
});
|
|
1440
|
-
return yield this.kv.waitForKeyToLoad(k);
|
|
1421
|
+
async getLocalId(name) {
|
|
1422
|
+
const k = `localToken_${name}`;
|
|
1423
|
+
if (this.kv.currentValue[k]) {
|
|
1424
|
+
return this.kv.currentValue[k];
|
|
1425
|
+
}
|
|
1426
|
+
const current = await this.kv.waitForKeyToLoad(k);
|
|
1427
|
+
if (current) {
|
|
1428
|
+
return current;
|
|
1429
|
+
}
|
|
1430
|
+
const newId = uuid();
|
|
1431
|
+
this.kv.updateInPlace((prev) => {
|
|
1432
|
+
if (prev[k])
|
|
1433
|
+
return;
|
|
1434
|
+
prev[k] = newId;
|
|
1441
1435
|
});
|
|
1436
|
+
return await this.kv.waitForKeyToLoad(k);
|
|
1442
1437
|
}
|
|
1443
1438
|
// ----
|
|
1444
1439
|
// Auth
|
|
@@ -1473,14 +1468,13 @@ export default class Reactor {
|
|
|
1473
1468
|
// The next.js app router will reset the URL when the router loads.
|
|
1474
1469
|
// This puts it back after the router loads.
|
|
1475
1470
|
const listener = (e) => {
|
|
1476
|
-
var _a;
|
|
1477
1471
|
if (!ran) {
|
|
1478
1472
|
ran = true;
|
|
1479
1473
|
// @ts-ignore (waiting for ts support)
|
|
1480
1474
|
navigation.removeEventListener('navigate', listener);
|
|
1481
1475
|
if (!e.userInitiated &&
|
|
1482
1476
|
e.navigationType === 'replace' &&
|
|
1483
|
-
|
|
1477
|
+
e.destination?.url === startUrl) {
|
|
1484
1478
|
history.replaceState(history.state, '', newPath);
|
|
1485
1479
|
}
|
|
1486
1480
|
}
|
|
@@ -1494,57 +1488,52 @@ export default class Reactor {
|
|
|
1494
1488
|
*
|
|
1495
1489
|
* @returns Promise<null | {error: {message: string}}>
|
|
1496
1490
|
*/
|
|
1497
|
-
_oauthLoginInit() {
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
const error = params.get('error');
|
|
1510
|
-
if (error) {
|
|
1511
|
-
this._replaceUrlAfterOAuth();
|
|
1512
|
-
return { error: { message: error } };
|
|
1513
|
-
}
|
|
1514
|
-
const code = params.get('code');
|
|
1515
|
-
if (!code) {
|
|
1516
|
-
return null;
|
|
1517
|
-
}
|
|
1491
|
+
async _oauthLoginInit() {
|
|
1492
|
+
if (typeof window === 'undefined' ||
|
|
1493
|
+
typeof window.location === 'undefined' ||
|
|
1494
|
+
typeof URLSearchParams === 'undefined') {
|
|
1495
|
+
return null;
|
|
1496
|
+
}
|
|
1497
|
+
const params = new URLSearchParams(window.location.search);
|
|
1498
|
+
if (!params.get(OAUTH_REDIRECT_PARAM)) {
|
|
1499
|
+
return null;
|
|
1500
|
+
}
|
|
1501
|
+
const error = params.get('error');
|
|
1502
|
+
if (error) {
|
|
1518
1503
|
this._replaceUrlAfterOAuth();
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1504
|
+
return { error: { message: error } };
|
|
1505
|
+
}
|
|
1506
|
+
const code = params.get('code');
|
|
1507
|
+
if (!code) {
|
|
1508
|
+
return null;
|
|
1509
|
+
}
|
|
1510
|
+
this._replaceUrlAfterOAuth();
|
|
1511
|
+
try {
|
|
1512
|
+
const currentUser = await this._getCurrentUser();
|
|
1513
|
+
const isGuest = currentUser?.type === 'guest';
|
|
1514
|
+
const { user } = await authAPI.exchangeCodeForToken({
|
|
1515
|
+
apiURI: this.config.apiURI,
|
|
1516
|
+
appId: this.config.appId,
|
|
1517
|
+
code,
|
|
1518
|
+
refreshToken: isGuest ? currentUser.refresh_token : undefined,
|
|
1519
|
+
});
|
|
1520
|
+
this.setCurrentUser(user);
|
|
1521
|
+
return null;
|
|
1522
|
+
}
|
|
1523
|
+
catch (e) {
|
|
1524
|
+
if (e?.body?.type === 'record-not-found' &&
|
|
1525
|
+
e?.body?.hint?.['record-type'] === 'app-oauth-code' &&
|
|
1526
|
+
(await this._hasCurrentUser())) {
|
|
1527
|
+
// We probably just weren't able to clean up the URL, so
|
|
1528
|
+
// let's just ignore this error
|
|
1529
1529
|
return null;
|
|
1530
1530
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
(yield this._hasCurrentUser())) {
|
|
1535
|
-
// We probably just weren't able to clean up the URL, so
|
|
1536
|
-
// let's just ignore this error
|
|
1537
|
-
return null;
|
|
1538
|
-
}
|
|
1539
|
-
const message = ((_d = e === null || e === void 0 ? void 0 : e.body) === null || _d === void 0 ? void 0 : _d.message) || 'Error logging in.';
|
|
1540
|
-
return { error: { message } };
|
|
1541
|
-
}
|
|
1542
|
-
});
|
|
1531
|
+
const message = e?.body?.message || 'Error logging in.';
|
|
1532
|
+
return { error: { message } };
|
|
1533
|
+
}
|
|
1543
1534
|
}
|
|
1544
|
-
_waitForOAuthCallbackResponse() {
|
|
1545
|
-
return
|
|
1546
|
-
return yield this._oauthCallbackResponse;
|
|
1547
|
-
});
|
|
1535
|
+
async _waitForOAuthCallbackResponse() {
|
|
1536
|
+
return await this._oauthCallbackResponse;
|
|
1548
1537
|
}
|
|
1549
1538
|
__subscribeMutationErrors(cb) {
|
|
1550
1539
|
this.mutationErrorCbs.push(cb);
|
|
@@ -1571,14 +1560,12 @@ export default class Reactor {
|
|
|
1571
1560
|
this.authCbs = this.authCbs.filter((x) => x !== cb);
|
|
1572
1561
|
};
|
|
1573
1562
|
}
|
|
1574
|
-
getAuth() {
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
return user;
|
|
1581
|
-
});
|
|
1563
|
+
async getAuth() {
|
|
1564
|
+
const { user, error } = await this.getCurrentUser();
|
|
1565
|
+
if (error) {
|
|
1566
|
+
throw new InstantError('Could not get current user: ' + error.message);
|
|
1567
|
+
}
|
|
1568
|
+
return user;
|
|
1582
1569
|
}
|
|
1583
1570
|
subscribeConnectionStatus(cb) {
|
|
1584
1571
|
this.connectionStatusCbs.push(cb);
|
|
@@ -1610,99 +1597,89 @@ export default class Reactor {
|
|
|
1610
1597
|
notifyConnectionStatusSubs(status) {
|
|
1611
1598
|
this.connectionStatusCbs.forEach((cb) => cb(status));
|
|
1612
1599
|
}
|
|
1613
|
-
setCurrentUser(user) {
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
prev[currentUserKey] = user;
|
|
1617
|
-
});
|
|
1618
|
-
yield this.kv.waitForKeyToLoad(currentUserKey);
|
|
1600
|
+
async setCurrentUser(user) {
|
|
1601
|
+
this.kv.updateInPlace((prev) => {
|
|
1602
|
+
prev[currentUserKey] = user;
|
|
1619
1603
|
});
|
|
1604
|
+
await this.kv.waitForKeyToLoad(currentUserKey);
|
|
1620
1605
|
}
|
|
1621
1606
|
getCurrentUserCached() {
|
|
1622
1607
|
return this._currentUserCached;
|
|
1623
1608
|
}
|
|
1624
|
-
_getCurrentUser() {
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
});
|
|
1609
|
+
async _getCurrentUser() {
|
|
1610
|
+
const user = await this.kv.waitForKeyToLoad(currentUserKey);
|
|
1611
|
+
return typeof user === 'string' ? JSON.parse(user) : user;
|
|
1612
|
+
}
|
|
1613
|
+
async getCurrentUser() {
|
|
1614
|
+
const oauthResp = await this._waitForOAuthCallbackResponse();
|
|
1615
|
+
if (oauthResp?.error) {
|
|
1616
|
+
const errorV = { error: oauthResp.error, user: undefined };
|
|
1617
|
+
this._currentUserCached = { isLoading: false, ...errorV };
|
|
1618
|
+
return errorV;
|
|
1619
|
+
}
|
|
1620
|
+
try {
|
|
1621
|
+
const user = await this._getCurrentUser();
|
|
1622
|
+
const userV = { user: user, error: undefined };
|
|
1623
|
+
this._currentUserCached = {
|
|
1624
|
+
isLoading: false,
|
|
1625
|
+
...userV,
|
|
1626
|
+
};
|
|
1627
|
+
return userV;
|
|
1628
|
+
}
|
|
1629
|
+
catch (e) {
|
|
1630
|
+
return {
|
|
1631
|
+
user: undefined,
|
|
1632
|
+
isLoading: false,
|
|
1633
|
+
error: { message: e?.message || 'Error loading user' },
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1652
1636
|
}
|
|
1653
|
-
_hasCurrentUser() {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
return typeof user === 'string' ? JSON.parse(user) != null : user != null;
|
|
1657
|
-
});
|
|
1637
|
+
async _hasCurrentUser() {
|
|
1638
|
+
const user = await this.kv.waitForKeyToLoad(currentUserKey);
|
|
1639
|
+
return typeof user === 'string' ? JSON.parse(user) != null : user != null;
|
|
1658
1640
|
}
|
|
1659
|
-
changeCurrentUser(newUser) {
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
this.
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
console.error('Error posting message to broadcast channel', error);
|
|
1677
|
-
}
|
|
1678
|
-
});
|
|
1641
|
+
async changeCurrentUser(newUser) {
|
|
1642
|
+
const { user: oldUser } = await this.getCurrentUser();
|
|
1643
|
+
if (areObjectsDeepEqual(oldUser, newUser)) {
|
|
1644
|
+
// We were already logged in as the newUser, don't
|
|
1645
|
+
// bother updating
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
await this.setCurrentUser(newUser);
|
|
1649
|
+
// We need to remove all `result` from querySubs,
|
|
1650
|
+
// as they are no longer valid for the new user
|
|
1651
|
+
this.updateUser(newUser);
|
|
1652
|
+
try {
|
|
1653
|
+
this._broadcastChannel?.postMessage({ type: 'auth' });
|
|
1654
|
+
}
|
|
1655
|
+
catch (error) {
|
|
1656
|
+
console.error('Error posting message to broadcast channel', error);
|
|
1657
|
+
}
|
|
1679
1658
|
}
|
|
1680
|
-
syncUserToEndpoint(user) {
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
}
|
|
1700
|
-
});
|
|
1659
|
+
async syncUserToEndpoint(user) {
|
|
1660
|
+
if (!this.config.firstPartyPath)
|
|
1661
|
+
return;
|
|
1662
|
+
try {
|
|
1663
|
+
fetch(this.config.firstPartyPath + '/', {
|
|
1664
|
+
method: 'POST',
|
|
1665
|
+
body: JSON.stringify({
|
|
1666
|
+
type: 'sync-user',
|
|
1667
|
+
appId: this.config.appId,
|
|
1668
|
+
user: user,
|
|
1669
|
+
}),
|
|
1670
|
+
headers: {
|
|
1671
|
+
'Content-Type': 'application/json',
|
|
1672
|
+
},
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
catch (error) {
|
|
1676
|
+
this._log.error('Error syncing user with external endpoint', error);
|
|
1677
|
+
}
|
|
1701
1678
|
}
|
|
1702
1679
|
updateUser(newUser) {
|
|
1703
1680
|
this.syncUserToEndpoint(newUser);
|
|
1704
1681
|
const newV = { error: undefined, user: newUser };
|
|
1705
|
-
this._currentUserCached =
|
|
1682
|
+
this._currentUserCached = { isLoading: false, ...newV };
|
|
1706
1683
|
this._dataForQueryCache = {};
|
|
1707
1684
|
this.querySubs.updateInPlace((prev) => {
|
|
1708
1685
|
Object.keys(prev).forEach((k) => {
|
|
@@ -1721,46 +1698,38 @@ export default class Reactor {
|
|
|
1721
1698
|
email: email,
|
|
1722
1699
|
});
|
|
1723
1700
|
}
|
|
1724
|
-
signInWithMagicCode(
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
code,
|
|
1734
|
-
refreshToken: isGuest ? currentUser.user.refresh_token : undefined,
|
|
1735
|
-
});
|
|
1736
|
-
yield this.changeCurrentUser(res.user);
|
|
1737
|
-
return res;
|
|
1701
|
+
async signInWithMagicCode({ email, code }) {
|
|
1702
|
+
const currentUser = await this.getCurrentUser();
|
|
1703
|
+
const isGuest = currentUser?.user?.type === 'guest';
|
|
1704
|
+
const res = await authAPI.verifyMagicCode({
|
|
1705
|
+
apiURI: this.config.apiURI,
|
|
1706
|
+
appId: this.config.appId,
|
|
1707
|
+
email,
|
|
1708
|
+
code,
|
|
1709
|
+
refreshToken: isGuest ? currentUser.user.refresh_token : undefined,
|
|
1738
1710
|
});
|
|
1711
|
+
await this.changeCurrentUser(res.user);
|
|
1712
|
+
return res;
|
|
1739
1713
|
}
|
|
1740
|
-
signInWithCustomToken(authToken) {
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
refreshToken: authToken,
|
|
1746
|
-
});
|
|
1747
|
-
yield this.changeCurrentUser(res.user);
|
|
1748
|
-
return res;
|
|
1714
|
+
async signInWithCustomToken(authToken) {
|
|
1715
|
+
const res = await authAPI.verifyRefreshToken({
|
|
1716
|
+
apiURI: this.config.apiURI,
|
|
1717
|
+
appId: this.config.appId,
|
|
1718
|
+
refreshToken: authToken,
|
|
1749
1719
|
});
|
|
1720
|
+
await this.changeCurrentUser(res.user);
|
|
1721
|
+
return res;
|
|
1750
1722
|
}
|
|
1751
|
-
signInAsGuest() {
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
appId: this.config.appId,
|
|
1756
|
-
});
|
|
1757
|
-
yield this.changeCurrentUser(res.user);
|
|
1758
|
-
return res;
|
|
1723
|
+
async signInAsGuest() {
|
|
1724
|
+
const res = await authAPI.signInAsGuest({
|
|
1725
|
+
apiURI: this.config.apiURI,
|
|
1726
|
+
appId: this.config.appId,
|
|
1759
1727
|
});
|
|
1728
|
+
await this.changeCurrentUser(res.user);
|
|
1729
|
+
return res;
|
|
1760
1730
|
}
|
|
1761
1731
|
potentiallyInvalidateToken(currentUser, opts) {
|
|
1762
|
-
|
|
1763
|
-
const refreshToken = (_a = currentUser === null || currentUser === void 0 ? void 0 : currentUser.user) === null || _a === void 0 ? void 0 : _a.refresh_token;
|
|
1732
|
+
const refreshToken = currentUser?.user?.refresh_token;
|
|
1764
1733
|
if (!refreshToken) {
|
|
1765
1734
|
return;
|
|
1766
1735
|
}
|
|
@@ -1780,12 +1749,10 @@ export default class Reactor {
|
|
|
1780
1749
|
})
|
|
1781
1750
|
.catch((e) => { });
|
|
1782
1751
|
}
|
|
1783
|
-
signOut(opts) {
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
yield this.changeCurrentUser(null);
|
|
1788
|
-
});
|
|
1752
|
+
async signOut(opts) {
|
|
1753
|
+
const currentUser = await this.getCurrentUser();
|
|
1754
|
+
this.potentiallyInvalidateToken(currentUser, opts);
|
|
1755
|
+
await this.changeCurrentUser(null);
|
|
1789
1756
|
}
|
|
1790
1757
|
/**
|
|
1791
1758
|
* Creates an OAuth authorization URL.
|
|
@@ -1804,21 +1771,18 @@ export default class Reactor {
|
|
|
1804
1771
|
* @param {string} params.code - The code received from the OAuth service.
|
|
1805
1772
|
* @param {string} [params.codeVerifier] - The code verifier used to generate the code challenge.
|
|
1806
1773
|
*/
|
|
1807
|
-
exchangeCodeForToken(
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
codeVerifier,
|
|
1817
|
-
refreshToken: isGuest ? currentUser.user.refresh_token : undefined,
|
|
1818
|
-
});
|
|
1819
|
-
yield this.changeCurrentUser(res.user);
|
|
1820
|
-
return res;
|
|
1774
|
+
async exchangeCodeForToken({ code, codeVerifier }) {
|
|
1775
|
+
const currentUser = await this.getCurrentUser();
|
|
1776
|
+
const isGuest = currentUser?.user?.type === 'guest';
|
|
1777
|
+
const res = await authAPI.exchangeCodeForToken({
|
|
1778
|
+
apiURI: this.config.apiURI,
|
|
1779
|
+
appId: this.config.appId,
|
|
1780
|
+
code: code,
|
|
1781
|
+
codeVerifier,
|
|
1782
|
+
refreshToken: isGuest ? currentUser.user.refresh_token : undefined,
|
|
1821
1783
|
});
|
|
1784
|
+
await this.changeCurrentUser(res.user);
|
|
1785
|
+
return res;
|
|
1822
1786
|
}
|
|
1823
1787
|
issuerURI() {
|
|
1824
1788
|
const { apiURI, appId } = this.config;
|
|
@@ -1830,22 +1794,19 @@ export default class Reactor {
|
|
|
1830
1794
|
* @param {string} params.idToken - The id_token from the external service
|
|
1831
1795
|
* @param {string | null | undefined} [params.nonce] - The nonce used when requesting the id_token from the external service
|
|
1832
1796
|
*/
|
|
1833
|
-
signInWithIdToken(
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
nonce,
|
|
1844
|
-
refreshToken,
|
|
1845
|
-
});
|
|
1846
|
-
yield this.changeCurrentUser(res.user);
|
|
1847
|
-
return res;
|
|
1797
|
+
async signInWithIdToken({ idToken, clientName, nonce }) {
|
|
1798
|
+
const currentUser = await this.getCurrentUser();
|
|
1799
|
+
const refreshToken = currentUser?.user?.refresh_token;
|
|
1800
|
+
const res = await authAPI.signInWithIdToken({
|
|
1801
|
+
apiURI: this.config.apiURI,
|
|
1802
|
+
appId: this.config.appId,
|
|
1803
|
+
idToken,
|
|
1804
|
+
clientName,
|
|
1805
|
+
nonce,
|
|
1806
|
+
refreshToken,
|
|
1848
1807
|
});
|
|
1808
|
+
await this.changeCurrentUser(res.user);
|
|
1809
|
+
return res;
|
|
1849
1810
|
}
|
|
1850
1811
|
// --------
|
|
1851
1812
|
// Rooms
|
|
@@ -1878,10 +1839,9 @@ export default class Reactor {
|
|
|
1878
1839
|
};
|
|
1879
1840
|
}
|
|
1880
1841
|
_cleanupRoom(roomId) {
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
const isConnected = (_d = this._rooms[roomId]) === null || _d === void 0 ? void 0 : _d.isConnected;
|
|
1842
|
+
if (!this._presence[roomId]?.handlers?.length &&
|
|
1843
|
+
!Object.keys(this._broadcastSubs[roomId] ?? {}).length) {
|
|
1844
|
+
const isConnected = this._rooms[roomId]?.isConnected;
|
|
1885
1845
|
delete this._rooms[roomId];
|
|
1886
1846
|
delete this._presence[roomId];
|
|
1887
1847
|
delete this._broadcastSubs[roomId];
|
|
@@ -1901,7 +1861,11 @@ export default class Reactor {
|
|
|
1901
1861
|
const presence = this._presence[roomId];
|
|
1902
1862
|
if (!room || !presence || !presence.result)
|
|
1903
1863
|
return null;
|
|
1904
|
-
return
|
|
1864
|
+
return {
|
|
1865
|
+
...buildPresenceSlice(presence.result, opts, this._sessionId),
|
|
1866
|
+
isLoading: !room.isConnected,
|
|
1867
|
+
error: room.error,
|
|
1868
|
+
};
|
|
1905
1869
|
}
|
|
1906
1870
|
// TODO: look into typing again
|
|
1907
1871
|
publishPresence(roomType, roomId, partialData) {
|
|
@@ -1911,7 +1875,10 @@ export default class Reactor {
|
|
|
1911
1875
|
return;
|
|
1912
1876
|
}
|
|
1913
1877
|
presence.result = presence.result || {};
|
|
1914
|
-
const data =
|
|
1878
|
+
const data = {
|
|
1879
|
+
...presence.result.user,
|
|
1880
|
+
...partialData,
|
|
1881
|
+
};
|
|
1915
1882
|
presence.result.user = data;
|
|
1916
1883
|
if (!room.isConnected) {
|
|
1917
1884
|
return;
|
|
@@ -1946,21 +1913,19 @@ export default class Reactor {
|
|
|
1946
1913
|
// Note: initialData is deprecated.
|
|
1947
1914
|
// Keeping here for backwards compatibility
|
|
1948
1915
|
opts.initialPresence || opts.initialData);
|
|
1949
|
-
const handler =
|
|
1916
|
+
const handler = { ...opts, roomId, cb, prev: null };
|
|
1950
1917
|
this._presence[roomId] = this._presence[roomId] || {};
|
|
1951
1918
|
this._presence[roomId].handlers = this._presence[roomId].handlers || [];
|
|
1952
1919
|
this._presence[roomId].handlers.push(handler);
|
|
1953
1920
|
this._notifyPresenceSub(roomId, handler);
|
|
1954
1921
|
return () => {
|
|
1955
|
-
var _a, _b, _c;
|
|
1956
1922
|
this._presence[roomId].handlers =
|
|
1957
|
-
|
|
1923
|
+
this._presence[roomId]?.handlers?.filter((x) => x !== handler) ?? [];
|
|
1958
1924
|
leaveRoom();
|
|
1959
1925
|
};
|
|
1960
1926
|
}
|
|
1961
1927
|
_notifyPresenceSubs(roomId) {
|
|
1962
|
-
|
|
1963
|
-
(_b = (_a = this._presence[roomId]) === null || _a === void 0 ? void 0 : _a.handlers) === null || _b === void 0 ? void 0 : _b.forEach((handler) => {
|
|
1928
|
+
this._presence[roomId]?.handlers?.forEach((handler) => {
|
|
1964
1929
|
this._notifyPresenceSub(roomId, handler);
|
|
1965
1930
|
});
|
|
1966
1931
|
}
|
|
@@ -1976,10 +1941,9 @@ export default class Reactor {
|
|
|
1976
1941
|
handler.cb(slice);
|
|
1977
1942
|
}
|
|
1978
1943
|
_patchPresencePeers(roomId, edits) {
|
|
1979
|
-
|
|
1980
|
-
const peers = ((_b = (_a = this._presence[roomId]) === null || _a === void 0 ? void 0 : _a.result) === null || _b === void 0 ? void 0 : _b.peers) || {};
|
|
1944
|
+
const peers = this._presence[roomId]?.result?.peers || {};
|
|
1981
1945
|
let sessions = Object.fromEntries(Object.entries(peers).map(([k, v]) => [k, { data: v }]));
|
|
1982
|
-
const myPresence =
|
|
1946
|
+
const myPresence = this._presence[roomId]?.result;
|
|
1983
1947
|
const newSessions = create(sessions, (draft) => {
|
|
1984
1948
|
for (let [path, op, value] of edits) {
|
|
1985
1949
|
switch (op) {
|
|
@@ -2000,7 +1964,7 @@ export default class Reactor {
|
|
|
2000
1964
|
this._setPresencePeers(roomId, newSessions);
|
|
2001
1965
|
}
|
|
2002
1966
|
_setPresencePeers(roomId, data) {
|
|
2003
|
-
const sessions =
|
|
1967
|
+
const sessions = { ...data };
|
|
2004
1968
|
// no need to keep track of `user`
|
|
2005
1969
|
delete sessions[this._sessionId];
|
|
2006
1970
|
const peers = Object.fromEntries(Object.entries(sessions).map(([k, v]) => [k, v.data]));
|
|
@@ -2011,13 +1975,12 @@ export default class Reactor {
|
|
|
2011
1975
|
// --------
|
|
2012
1976
|
// Broadcast
|
|
2013
1977
|
publishTopic({ roomType, roomId, topic, data }) {
|
|
2014
|
-
var _a;
|
|
2015
1978
|
const room = this._rooms[roomId];
|
|
2016
1979
|
if (!room) {
|
|
2017
1980
|
return;
|
|
2018
1981
|
}
|
|
2019
1982
|
if (!room.isConnected) {
|
|
2020
|
-
this._broadcastQueue[roomId] =
|
|
1983
|
+
this._broadcastQueue[roomId] = this._broadcastQueue[roomId] ?? [];
|
|
2021
1984
|
this._broadcastQueue[roomId].push({ topic, roomType, data });
|
|
2022
1985
|
return;
|
|
2023
1986
|
}
|
|
@@ -2048,71 +2011,64 @@ export default class Reactor {
|
|
|
2048
2011
|
};
|
|
2049
2012
|
}
|
|
2050
2013
|
_notifyBroadcastSubs(room, topic, msg) {
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2054
|
-
const data = (_a = msg.data) === null || _a === void 0 ? void 0 : _a.data;
|
|
2014
|
+
this._broadcastSubs?.[room]?.[topic]?.forEach((cb) => {
|
|
2015
|
+
const data = msg.data?.data;
|
|
2055
2016
|
const peer = msg.data['peer-id'] === this._sessionId
|
|
2056
|
-
?
|
|
2057
|
-
:
|
|
2017
|
+
? this._presence[room]?.result?.user
|
|
2018
|
+
: this._presence[room]?.result?.peers?.[msg.data['peer-id']];
|
|
2058
2019
|
return cb(data, peer);
|
|
2059
2020
|
});
|
|
2060
2021
|
}
|
|
2061
2022
|
// --------
|
|
2062
2023
|
// Storage
|
|
2063
|
-
uploadFile(path, file, opts) {
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2024
|
+
async uploadFile(path, file, opts) {
|
|
2025
|
+
const currentUser = await this.getCurrentUser();
|
|
2026
|
+
const refreshToken = currentUser?.user?.refresh_token;
|
|
2027
|
+
return StorageApi.uploadFile({
|
|
2028
|
+
...opts,
|
|
2029
|
+
apiURI: this.config.apiURI,
|
|
2030
|
+
appId: this.config.appId,
|
|
2031
|
+
path: path,
|
|
2032
|
+
file,
|
|
2033
|
+
refreshToken: refreshToken,
|
|
2069
2034
|
});
|
|
2070
2035
|
}
|
|
2071
|
-
deleteFile(path) {
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
path,
|
|
2080
|
-
refreshToken: refreshToken,
|
|
2081
|
-
});
|
|
2082
|
-
return result;
|
|
2036
|
+
async deleteFile(path) {
|
|
2037
|
+
const currentUser = await this.getCurrentUser();
|
|
2038
|
+
const refreshToken = currentUser?.user?.refresh_token;
|
|
2039
|
+
const result = await StorageApi.deleteFile({
|
|
2040
|
+
apiURI: this.config.apiURI,
|
|
2041
|
+
appId: this.config.appId,
|
|
2042
|
+
path,
|
|
2043
|
+
refreshToken: refreshToken,
|
|
2083
2044
|
});
|
|
2045
|
+
return result;
|
|
2084
2046
|
}
|
|
2085
2047
|
// Deprecated Storage API (Jan 2025)
|
|
2086
2048
|
// ---------------------------------
|
|
2087
|
-
upload(path, file) {
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
fileName: fileName,
|
|
2097
|
-
refreshToken: refreshToken,
|
|
2098
|
-
});
|
|
2099
|
-
const isSuccess = yield StorageApi.upload(url, file);
|
|
2100
|
-
return isSuccess;
|
|
2049
|
+
async upload(path, file) {
|
|
2050
|
+
const currentUser = await this.getCurrentUser();
|
|
2051
|
+
const refreshToken = currentUser?.user?.refresh_token;
|
|
2052
|
+
const fileName = path || file.name;
|
|
2053
|
+
const url = await StorageApi.getSignedUploadUrl({
|
|
2054
|
+
apiURI: this.config.apiURI,
|
|
2055
|
+
appId: this.config.appId,
|
|
2056
|
+
fileName: fileName,
|
|
2057
|
+
refreshToken: refreshToken,
|
|
2101
2058
|
});
|
|
2059
|
+
const isSuccess = await StorageApi.upload(url, file);
|
|
2060
|
+
return isSuccess;
|
|
2102
2061
|
}
|
|
2103
|
-
getDownloadUrl(path) {
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
path: path,
|
|
2112
|
-
refreshToken: refreshToken,
|
|
2113
|
-
});
|
|
2114
|
-
return url;
|
|
2062
|
+
async getDownloadUrl(path) {
|
|
2063
|
+
const currentUser = await this.getCurrentUser();
|
|
2064
|
+
const refreshToken = currentUser?.user?.refresh_token;
|
|
2065
|
+
const url = await StorageApi.getDownloadUrl({
|
|
2066
|
+
apiURI: this.config.apiURI,
|
|
2067
|
+
appId: this.config.appId,
|
|
2068
|
+
path: path,
|
|
2069
|
+
refreshToken: refreshToken,
|
|
2115
2070
|
});
|
|
2071
|
+
return url;
|
|
2116
2072
|
}
|
|
2117
2073
|
}
|
|
2118
2074
|
//# sourceMappingURL=Reactor.js.map
|