remult 3.3.18 → 3.4.0-next.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.
@@ -16,6 +16,12 @@ const wnn = [
16
16
  ];
17
17
  export const flags = {
18
18
  error500RetryCount: 4,
19
+ /** Client treats SSE as dead if no event for this long */
20
+ sseStaleMs: 20_000,
21
+ /** HTTP keep-alive while SSE is healthy (touches lastUsed) */
22
+ liveQueryKeepAliveMs: 30_000,
23
+ /** Version poll while SSE is stale */
24
+ liveQueryPollWhenStaleMs: 1_000,
19
25
  };
20
26
  /*p1 - issues in https://stackblitz.com/edit/demo-allow-delete-based-on-other-entity:
21
27
  - don't like the ensure schema
@@ -13,7 +13,10 @@ export declare class DataProviderLiveQueryStorage implements LiveQueryStorage, S
13
13
  query: StoredQuery;
14
14
  setData(data: any): Promise<void>;
15
15
  }) => Promise<void>): Promise<void>;
16
- keepAliveAndReturnUnknownQueryIds(queryIds: string[]): Promise<string[]>;
16
+ keepAliveAndReturnUnknownQueryIds(queryIds: string[]): Promise<{
17
+ unknownQueryIds: string[];
18
+ versions: Record<string, number>;
19
+ }>;
17
20
  }
18
21
  export declare class LiveQueryStorageEntity extends EntityBase {
19
22
  id: string;
@@ -170,46 +170,49 @@ var DataProviderLiveQueryStorage = /** @class */ (function () {
170
170
  };
171
171
  DataProviderLiveQueryStorage.prototype.keepAliveAndReturnUnknownQueryIds = function (queryIds) {
172
172
  return tslib_1.__awaiter(this, void 0, void 0, function () {
173
- var repo, _loop_2, _a, _b, query, e_2_1;
173
+ var repo, versions, _loop_2, _a, _b, query, e_2_1;
174
174
  var e_2, _c;
175
- return tslib_1.__generator(this, function (_d) {
176
- switch (_d.label) {
175
+ var _d, _e;
176
+ return tslib_1.__generator(this, function (_f) {
177
+ switch (_f.label) {
177
178
  case 0: return [4 /*yield*/, this.repo];
178
179
  case 1:
179
- repo = _d.sent();
180
+ repo = _f.sent();
181
+ versions = {};
180
182
  _loop_2 = function (query) {
181
- return tslib_1.__generator(this, function (_e) {
182
- switch (_e.label) {
183
+ return tslib_1.__generator(this, function (_g) {
184
+ switch (_g.label) {
183
185
  case 0:
184
186
  query.lastUsedIso = new Date().toISOString();
185
187
  return [4 /*yield*/, repo.save(query)];
186
188
  case 1:
187
- _e.sent();
189
+ _g.sent();
190
+ versions[query.id] = (_e = (_d = query.data) === null || _d === void 0 ? void 0 : _d.version) !== null && _e !== void 0 ? _e : 0;
188
191
  queryIds = queryIds.filter(function (x) { return x !== query.id; });
189
192
  return [2 /*return*/];
190
193
  }
191
194
  });
192
195
  };
193
- _d.label = 2;
196
+ _f.label = 2;
194
197
  case 2:
195
- _d.trys.push([2, 8, 9, 10]);
198
+ _f.trys.push([2, 8, 9, 10]);
196
199
  return [4 /*yield*/, repo.find({ where: { id: queryIds } })];
197
200
  case 3:
198
- _a = tslib_1.__values.apply(void 0, [_d.sent()]), _b = _a.next();
199
- _d.label = 4;
201
+ _a = tslib_1.__values.apply(void 0, [_f.sent()]), _b = _a.next();
202
+ _f.label = 4;
200
203
  case 4:
201
204
  if (!!_b.done) return [3 /*break*/, 7];
202
205
  query = _b.value;
203
206
  return [5 /*yield**/, _loop_2(query)];
204
207
  case 5:
205
- _d.sent();
206
- _d.label = 6;
208
+ _f.sent();
209
+ _f.label = 6;
207
210
  case 6:
208
211
  _b = _a.next();
209
212
  return [3 /*break*/, 4];
210
213
  case 7: return [3 /*break*/, 10];
211
214
  case 8:
212
- e_2_1 = _d.sent();
215
+ e_2_1 = _f.sent();
213
216
  e_2 = { error: e_2_1 };
214
217
  return [3 /*break*/, 10];
215
218
  case 9:
@@ -218,7 +221,7 @@ var DataProviderLiveQueryStorage = /** @class */ (function () {
218
221
  }
219
222
  finally { if (e_2) throw e_2.error; }
220
223
  return [7 /*endfinally*/];
221
- case 10: return [2 /*return*/, queryIds];
224
+ case 10: return [2 /*return*/, { unknownQueryIds: queryIds, versions: versions }];
222
225
  }
223
226
  });
224
227
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "3.3.18",
3
+ "version": "3.4.0-next.1",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -20,12 +20,12 @@ export declare class KnexDataProvider implements DataProvider, HasWrapIdentifier
20
20
  static rawFilter(build: CustomKnexFilterBuilderFunction): EntityFilter<any>;
21
21
  static filterToRaw<entityType>(entity: RepositoryOverloads<entityType>, condition: EntityFilter<entityType>, wrapIdentifier?: (name: string) => string): Promise<(knex: Knex.QueryBuilder) => void>;
22
22
  isProxy?: boolean;
23
- ensureSchema(entities: EntityMetadata<any>[]): Promise<void>;
23
+ ensureSchema(entities: EntityMetadata[]): Promise<void>;
24
24
  }
25
25
  export type CustomKnexFilterBuilderFunction = () => Promise<(builder: Knex.QueryBuilder) => void>;
26
26
  export declare class KnexSchemaBuilder {
27
27
  private knex;
28
- ensureSchema(entities: EntityMetadata<any>[]): Promise<void>;
28
+ ensureSchema(entities: EntityMetadata[]): Promise<void>;
29
29
  createIfNotExist(entity: EntityMetadata): Promise<void>;
30
30
  createTableKnexCommand(entity: EntityMetadata, e: EntityDbNamesBase): Knex.SchemaBuilder;
31
31
  addColumnIfNotExist(entity: EntityMetadata, c: (e: EntityMetadata) => FieldMetadata): Promise<void>;
@@ -482,16 +482,20 @@ var RemultServerImplementation = /** @class */ (function () {
482
482
  }); }));
483
483
  }
484
484
  r.route(this.options.rootPath + '/' + SubscriptionChannel_js_1.liveQueryKeepAliveRoute).post(this.process(function (remult, req, res, reqInfo, origRes, origReq) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
485
- var _a, _b, _c, _d;
486
- return tslib_1.__generator(this, function (_e) {
487
- switch (_e.label) {
488
- case 0:
489
- _b = (_a = res).success;
490
- _d = (_c = remult.liveQueryStorage).keepAliveAndReturnUnknownQueryIds;
491
- return [4 /*yield*/, this.coreOptions.getRequestBody(origReq)];
492
- case 1: return [4 /*yield*/, _d.apply(_c, [_e.sent()])];
485
+ var body, queryIds, result;
486
+ var _a;
487
+ return tslib_1.__generator(this, function (_b) {
488
+ switch (_b.label) {
489
+ case 0: return [4 /*yield*/, this.coreOptions.getRequestBody(origReq)];
490
+ case 1:
491
+ body = _b.sent();
492
+ queryIds = Array.isArray(body)
493
+ ? body
494
+ : ((_a = body === null || body === void 0 ? void 0 : body.queryIds) !== null && _a !== void 0 ? _a : []);
495
+ return [4 /*yield*/, remult.liveQueryStorage.keepAliveAndReturnUnknownQueryIds(queryIds)];
493
496
  case 2:
494
- _b.apply(_a, [_e.sent()]);
497
+ result = _b.sent();
498
+ res.success(Array.isArray(body) ? result.unknownQueryIds : result);
495
499
  return [2 /*return*/];
496
500
  }
497
501
  });
@@ -276,6 +276,7 @@ export interface ValueConverter<valueType> {
276
276
  toJson?(val: valueType): any;
277
277
  /**
278
278
  * Converts a value from the database format to the valueType.
279
+ * Defaults to `fromJson` when not provided.
279
280
  *
280
281
  * @param val The value to convert.
281
282
  * @returns The converted value.
@@ -286,6 +287,7 @@ export interface ValueConverter<valueType> {
286
287
  fromDb?(val: any): valueType;
287
288
  /**
288
289
  * Converts a value of valueType to the database format.
290
+ * Defaults to `toJson` when not provided.
289
291
  *
290
292
  * @param val The value to convert.
291
293
  * @returns The converted value.
@@ -297,6 +299,7 @@ export interface ValueConverter<valueType> {
297
299
  toDbSql?(val: string): string;
298
300
  /**
299
301
  * Converts a value of valueType to a string suitable for an HTML input element.
302
+ * Defaults to `toJson` when not provided.
300
303
  *
301
304
  * @param val The value to convert.
302
305
  * @param inputType The type of the input element (optional).
@@ -308,6 +311,7 @@ export interface ValueConverter<valueType> {
308
311
  toInput?(val: valueType, inputType?: string): string;
309
312
  /**
310
313
  * Converts a string from an HTML input element to the valueType.
314
+ * Defaults to `fromJson` when not provided.
311
315
  *
312
316
  * @param val The value to convert.
313
317
  * @param inputType The type of the input element (optional).
package/src/data-api.js CHANGED
@@ -687,6 +687,7 @@ var DataApi = /** @class */ (function () {
687
687
  data = (_a.requestJson = _b.sent(),
688
688
  _a.findOptionsJson = (0, rest_data_provider_js_1.findOptionsToJson)(r.findOptions, this.repository.metadata),
689
689
  _a.lastIds = r.r.map(function (y) { return _this.repository.metadata.idMetadata.getId(y); }),
690
+ _a.version = 0,
690
691
  _a);
691
692
  return [4 /*yield*/, this.remult.liveQueryStorage.add({
692
693
  entityKey: this.repository.metadata.key,
@@ -5,6 +5,7 @@ var tslib_1 = require("tslib");
5
5
  var buildRestDataProvider_js_1 = require("../buildRestDataProvider.js");
6
6
  var rest_data_provider_js_1 = require("../data-providers/rest-data-provider.js");
7
7
  var remult_static_js_1 = require("../remult-static.js");
8
+ var remult3_js_1 = require("../remult3/remult3.js");
8
9
  var repository_internals_js_1 = require("../remult3/repository-internals.js");
9
10
  var SubscriptionChannel_js_1 = require("./SubscriptionChannel.js");
10
11
  /* @internal*/
@@ -14,6 +15,9 @@ var LiveQueryClient = /** @class */ (function () {
14
15
  this.getUserId = getUserId;
15
16
  this.queries = new Map();
16
17
  this.channels = new Map();
18
+ this.lastKeepAliveAt = 0;
19
+ this.keepAliveBackoffMs = remult3_js_1.flags.liveQueryPollWhenStaleMs;
20
+ this.detachForeground = function () { };
17
21
  }
18
22
  LiveQueryClient.prototype.wrapMessageHandling = function (handleMessage) {
19
23
  var x = this.apiProvider().wrapMessageHandling;
@@ -31,6 +35,7 @@ var LiveQueryClient = /** @class */ (function () {
31
35
  LiveQueryClient.prototype.close = function () {
32
36
  this.queries.clear();
33
37
  this.channels.clear();
38
+ this.detachForeground();
34
39
  this.closeIfNoListeners();
35
40
  };
36
41
  LiveQueryClient.prototype.subscribeChannel = function (key, onResult) {
@@ -88,13 +93,15 @@ var LiveQueryClient = /** @class */ (function () {
88
93
  });
89
94
  };
90
95
  LiveQueryClient.prototype.closeIfNoListeners = function () {
91
- if (this.client)
92
- if (this.queries.size === 0 && this.channels.size === 0) {
93
- this.runPromise(this.client.then(function (x) { return x.close(); }));
94
- this.client = undefined;
95
- clearInterval(this.interval);
96
- this.interval = undefined;
97
- }
96
+ if (this.queries.size === 0 && this.channels.size === 0) {
97
+ if (this.client)
98
+ this.runPromise(this.client.then(function (x) { return x.close(); }).catch(function () { }));
99
+ this.client = undefined;
100
+ this.openedConnection = undefined;
101
+ this.detachForeground();
102
+ clearInterval(this.interval);
103
+ this.interval = undefined;
104
+ }
98
105
  };
99
106
  LiveQueryClient.prototype.subscribe = function (repo, options, listener) {
100
107
  var _this = this;
@@ -115,43 +122,56 @@ var LiveQueryClient = /** @class */ (function () {
115
122
  if (!q) {
116
123
  _this.queries.set(eventTypeKey, (q = new SubscriptionChannel_js_1.LiveQuerySubscriber(repo, { entityKey: repo.metadata.key, options: options }, _this.getUserId())));
117
124
  q.subscribeCode = function () {
118
- if (q.unsubscribe) {
119
- q.unsubscribe();
125
+ q.unsubscribeChannel();
126
+ var unsubscribeToChannel = function () { };
127
+ q.unsubscribeChannel = function () {
128
+ unsubscribeToChannel();
129
+ unsubscribeToChannel = function () { };
130
+ };
131
+ q.unsubscribe = function () {
120
132
  q.unsubscribe = function () { };
121
- }
133
+ q.unsubscribeChannel();
134
+ q.unsubscribeQuery();
135
+ };
136
+ var snapshotDone = false;
137
+ var applySnapshot = function (r) {
138
+ if (q.listeners.length === 0) {
139
+ r.unsubscribe();
140
+ return;
141
+ }
142
+ q.unsubscribeQuery = function () {
143
+ _this.runPromise(r.unsubscribe());
144
+ };
145
+ snapshotDone = true;
146
+ return _this.runPromise(q.setAllItems(r.result));
147
+ };
122
148
  _this.runPromise(_this.subscribeChannel(q.queryChannel, {
123
149
  next: function (value) { return _this.runPromise(q.handle(value)); },
124
150
  complete: function () { },
125
151
  error: function (er) {
126
152
  q.listeners.forEach(function (l) { return l.error(er); });
127
153
  },
128
- }).then(function (unsubscribeToChannel) {
154
+ })
155
+ .then(function (unsub) {
129
156
  if (q.listeners.length == 0) {
130
- unsubscribeToChannel();
157
+ unsub();
131
158
  return;
132
159
  }
133
- _this.runPromise(subscribe(q.queryChannel)
134
- .then(function (r) {
135
- if (q.listeners.length === 0) {
136
- r.unsubscribe();
137
- unsubscribeToChannel();
138
- return;
139
- }
140
- _this.runPromise(q.setAllItems(r.result));
141
- q.unsubscribe = function () {
142
- q.unsubscribe = function () { };
143
- unsubscribeToChannel();
144
- _this.runPromise(r.unsubscribe());
145
- };
146
- })
147
- .catch(function (err) {
148
- q.listeners.forEach(function (l) { return l.error(err); });
149
- unsubscribeToChannel();
150
- _this.queries.delete(eventTypeKey);
151
- }));
152
- })).catch(function (err) {
160
+ unsubscribeToChannel = unsub;
161
+ if (snapshotDone)
162
+ return _this.runPromise(_this.runKeepAlive({ checkVersions: true }));
163
+ })
164
+ .catch(function (err) {
165
+ q.listeners.forEach(function (l) { return l.error(err); });
166
+ }));
167
+ _this.runPromise(subscribe(q.queryChannel)
168
+ .then(applySnapshot)
169
+ .catch(function (err) {
153
170
  q.listeners.forEach(function (l) { return l.error(err); });
154
- });
171
+ unsubscribeToChannel();
172
+ _this.queries.delete(eventTypeKey);
173
+ _this.closeIfNoListeners();
174
+ }));
155
175
  };
156
176
  q.subscribeCode();
157
177
  }
@@ -176,84 +196,182 @@ var LiveQueryClient = /** @class */ (function () {
176
196
  onUnsubscribe();
177
197
  };
178
198
  };
179
- LiveQueryClient.prototype.openIfNoOpened = function () {
180
- var _this = this;
181
- if (!this.client) {
182
- this.interval = setInterval(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
183
- var ids, _a, _b, q, p_1, invalidIds, _c, invalidIds_1, invalidIds_1_1, id, _d, _e, q;
184
- var e_1, _f, e_2, _g, e_3, _h;
185
- return tslib_1.__generator(this, function (_j) {
186
- switch (_j.label) {
187
- case 0:
188
- ids = [];
199
+ LiveQueryClient.prototype.isSseStale = function () {
200
+ var conn = this.openedConnection;
201
+ if (!conn || conn.lastServerEvent === undefined)
202
+ return false;
203
+ return Date.now() - conn.lastServerEvent > remult3_js_1.flags.sseStaleMs;
204
+ };
205
+ LiveQueryClient.prototype.runKeepAlive = function (opts) {
206
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
207
+ var _this = this;
208
+ return tslib_1.__generator(this, function (_a) {
209
+ if (this.keepAliveInFlight)
210
+ return [2 /*return*/, this.keepAliveInFlight];
211
+ this.keepAliveInFlight = this.sendKeepAlive(opts).finally(function () {
212
+ _this.keepAliveInFlight = undefined;
213
+ });
214
+ return [2 /*return*/, this.keepAliveInFlight];
215
+ });
216
+ });
217
+ };
218
+ LiveQueryClient.prototype.sendKeepAlive = function (opts) {
219
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
220
+ var ids, _a, _b, q, p, raw, unknownIds, versions, stale, reloaded, _c, _d, q, serverVersion, unknown, mismatch;
221
+ var e_1, _e, e_2, _f;
222
+ var _g, _h;
223
+ return tslib_1.__generator(this, function (_j) {
224
+ switch (_j.label) {
225
+ case 0:
226
+ ids = [];
227
+ try {
228
+ for (_a = tslib_1.__values(this.queries.values()), _b = _a.next(); !_b.done; _b = _a.next()) {
229
+ q = _b.value;
230
+ ids.push(q.queryChannel);
231
+ }
232
+ }
233
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
234
+ finally {
189
235
  try {
190
- for (_a = tslib_1.__values(this.queries.values()), _b = _a.next(); !_b.done; _b = _a.next()) {
191
- q = _b.value;
192
- ids.push(q.queryChannel);
193
- }
236
+ if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
194
237
  }
195
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
196
- finally {
197
- try {
198
- if (_b && !_b.done && (_f = _a.return)) _f.call(_a);
238
+ finally { if (e_1) throw e_1.error; }
239
+ }
240
+ if (ids.length === 0)
241
+ return [2 /*return*/];
242
+ p = this.apiProvider();
243
+ return [4 /*yield*/, this.runPromise(remult_static_js_1.remultStatic.actionInfo.runActionWithoutBlockingUI(function () {
244
+ return (0, buildRestDataProvider_js_1.buildRestDataProvider)(p.httpClient).post(p.url + '/' + SubscriptionChannel_js_1.liveQueryKeepAliveRoute, { queryIds: ids });
245
+ }))];
246
+ case 1:
247
+ raw = _j.sent();
248
+ unknownIds = Array.isArray(raw)
249
+ ? raw
250
+ : ((_g = raw === null || raw === void 0 ? void 0 : raw.unknownQueryIds) !== null && _g !== void 0 ? _g : []);
251
+ versions = Array.isArray(raw)
252
+ ? {}
253
+ : ((_h = raw === null || raw === void 0 ? void 0 : raw.versions) !== null && _h !== void 0 ? _h : {});
254
+ stale = (opts === null || opts === void 0 ? void 0 : opts.checkVersions) || this.isSseStale();
255
+ reloaded = false;
256
+ try {
257
+ for (_c = tslib_1.__values(this.queries.values()), _d = _c.next(); !_d.done; _d = _c.next()) {
258
+ q = _d.value;
259
+ serverVersion = versions[q.queryChannel];
260
+ unknown = unknownIds.includes(q.queryChannel);
261
+ mismatch = stale && serverVersion !== undefined && serverVersion !== q.version;
262
+ if (unknown || mismatch) {
263
+ reloaded = true;
264
+ if (serverVersion !== undefined)
265
+ q.version = serverVersion;
266
+ q.subscribeCode();
199
267
  }
200
- finally { if (e_1) throw e_1.error; }
201
268
  }
202
- if (!(ids.length > 0)) return [3 /*break*/, 3];
203
- p_1 = this.apiProvider();
204
- _c = this.runPromise;
205
- return [4 /*yield*/, remult_static_js_1.remultStatic.actionInfo.runActionWithoutBlockingUI(function () {
206
- return (0, buildRestDataProvider_js_1.buildRestDataProvider)(p_1.httpClient).post(p_1.url + '/' + SubscriptionChannel_js_1.liveQueryKeepAliveRoute, ids);
207
- })];
208
- case 1: return [4 /*yield*/, _c.apply(this, [_j.sent()])];
209
- case 2:
210
- invalidIds = _j.sent();
269
+ }
270
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
271
+ finally {
211
272
  try {
212
- for (invalidIds_1 = tslib_1.__values(invalidIds), invalidIds_1_1 = invalidIds_1.next(); !invalidIds_1_1.done; invalidIds_1_1 = invalidIds_1.next()) {
213
- id = invalidIds_1_1.value;
214
- try {
215
- for (_d = (e_3 = void 0, tslib_1.__values(this.queries.values())), _e = _d.next(); !_e.done; _e = _d.next()) {
216
- q = _e.value;
217
- if (q.queryChannel === id)
218
- q.subscribeCode();
219
- }
220
- }
221
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
222
- finally {
223
- try {
224
- if (_e && !_e.done && (_h = _d.return)) _h.call(_d);
225
- }
226
- finally { if (e_3) throw e_3.error; }
227
- }
228
- }
229
- }
230
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
231
- finally {
232
- try {
233
- if (invalidIds_1_1 && !invalidIds_1_1.done && (_g = invalidIds_1.return)) _g.call(invalidIds_1);
234
- }
235
- finally { if (e_2) throw e_2.error; }
273
+ if (_d && !_d.done && (_f = _c.return)) _f.call(_c);
236
274
  }
237
- _j.label = 3;
238
- case 3: return [2 /*return*/];
239
- }
240
- });
241
- }); }, 30000);
242
- return this.runPromise((this.client = this.apiProvider().subscriptionClient.openConnection(function () {
243
- var e_4, _a;
275
+ finally { if (e_2) throw e_2.error; }
276
+ }
277
+ if (this.isSseStale()) {
278
+ this.keepAliveBackoffMs = reloaded
279
+ ? remult3_js_1.flags.liveQueryPollWhenStaleMs
280
+ : Math.min(this.keepAliveBackoffMs * 2, remult3_js_1.flags.liveQueryKeepAliveMs);
281
+ }
282
+ else {
283
+ this.keepAliveBackoffMs = remult3_js_1.flags.liveQueryPollWhenStaleMs;
284
+ }
285
+ return [2 /*return*/];
286
+ }
287
+ });
288
+ });
289
+ };
290
+ LiveQueryClient.prototype.maybeKeepAlive = function () {
291
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
292
+ var stale, interval;
293
+ var _a, _b;
294
+ return tslib_1.__generator(this, function (_c) {
295
+ switch (_c.label) {
296
+ case 0:
297
+ stale = this.isSseStale();
298
+ if (!stale)
299
+ this.keepAliveBackoffMs = remult3_js_1.flags.liveQueryPollWhenStaleMs;
300
+ interval = stale
301
+ ? this.keepAliveBackoffMs
302
+ : remult3_js_1.flags.liveQueryKeepAliveMs;
303
+ if (Date.now() - this.lastKeepAliveAt < interval)
304
+ return [2 /*return*/];
305
+ this.lastKeepAliveAt = Date.now();
306
+ if (stale)
307
+ (_b = (_a = this.openedConnection) === null || _a === void 0 ? void 0 : _a.resume) === null || _b === void 0 ? void 0 : _b.call(_a, true);
308
+ return [4 /*yield*/, this.runKeepAlive()];
309
+ case 1:
310
+ _c.sent();
311
+ return [2 /*return*/];
312
+ }
313
+ });
314
+ });
315
+ };
316
+ LiveQueryClient.prototype.attachForeground = function () {
317
+ var _this = this;
318
+ this.detachForeground();
319
+ var unsub = (0, SubscriptionChannel_js_1.onBrowserForeground)(function () {
320
+ var _a, _b;
321
+ (_b = (_a = _this.openedConnection) === null || _a === void 0 ? void 0 : _a.resume) === null || _b === void 0 ? void 0 : _b.call(_a);
322
+ if (_this.foregroundKeepAliveTimer !== undefined)
323
+ clearTimeout(_this.foregroundKeepAliveTimer);
324
+ _this.foregroundKeepAliveTimer = setTimeout(function () {
325
+ _this.foregroundKeepAliveTimer = undefined;
326
+ _this.keepAliveBackoffMs = remult3_js_1.flags.liveQueryPollWhenStaleMs;
327
+ _this.lastKeepAliveAt = 0;
328
+ _this.runPromise(_this.runKeepAlive({ checkVersions: true }));
329
+ }, 300);
330
+ });
331
+ this.detachForeground = function () {
332
+ unsub();
333
+ if (_this.foregroundKeepAliveTimer !== undefined) {
334
+ clearTimeout(_this.foregroundKeepAliveTimer);
335
+ _this.foregroundKeepAliveTimer = undefined;
336
+ }
337
+ _this.detachForeground = function () { };
338
+ };
339
+ };
340
+ LiveQueryClient.prototype.openIfNoOpened = function () {
341
+ var _this = this;
342
+ if (!this.client) {
343
+ this.lastKeepAliveAt = Date.now();
344
+ this.keepAliveBackoffMs = remult3_js_1.flags.liveQueryPollWhenStaleMs;
345
+ this.attachForeground();
346
+ this.interval = setInterval(function () {
347
+ _this.runPromise(_this.maybeKeepAlive());
348
+ }, Math.min(remult3_js_1.flags.liveQueryPollWhenStaleMs, remult3_js_1.flags.liveQueryKeepAliveMs));
349
+ return this.runPromise((this.client = this.apiProvider()
350
+ .subscriptionClient.openConnection(function () {
351
+ var e_3, _a;
244
352
  try {
245
353
  for (var _b = tslib_1.__values(_this.queries.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
246
354
  var q = _c.value;
247
355
  q.subscribeCode();
248
356
  }
249
357
  }
250
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
358
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
251
359
  finally {
252
360
  try {
253
361
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
254
362
  }
255
- finally { if (e_4) throw e_4.error; }
363
+ finally { if (e_3) throw e_3.error; }
256
364
  }
365
+ })
366
+ .then(function (c) {
367
+ _this.openedConnection = c;
368
+ return c;
369
+ })
370
+ .catch(function (err) {
371
+ _this.client = undefined;
372
+ _this.openedConnection = undefined;
373
+ _this.closeIfNoListeners();
374
+ throw err;
257
375
  })));
258
376
  }
259
377
  return this.client;
@@ -269,7 +387,7 @@ var MessageChannel = /** @class */ (function () {
269
387
  MessageChannel.prototype.handle = function (message) {
270
388
  return tslib_1.__awaiter(this, void 0, void 0, function () {
271
389
  var _a, _b, l;
272
- var e_5, _c;
390
+ var e_4, _c;
273
391
  return tslib_1.__generator(this, function (_d) {
274
392
  try {
275
393
  for (_a = tslib_1.__values(this.listeners), _b = _a.next(); !_b.done; _b = _a.next()) {
@@ -277,12 +395,12 @@ var MessageChannel = /** @class */ (function () {
277
395
  l.next(message);
278
396
  }
279
397
  }
280
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
398
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
281
399
  finally {
282
400
  try {
283
401
  if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
284
402
  }
285
- finally { if (e_5) throw e_5.error; }
403
+ finally { if (e_4) throw e_4.error; }
286
404
  }
287
405
  return [2 /*return*/];
288
406
  });