dexie-cloud-addon 4.0.0-beta.14 → 4.0.0-beta.17

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.
@@ -1,5 +1,5 @@
1
1
  import { DexieCloudOptions } from './DexieCloudOptions';
2
- import { DexieCloudSchema } from 'dexie-cloud-common';
2
+ import { DBRealmRole, DexieCloudSchema } from 'dexie-cloud-common';
3
3
  import { UserLogin } from './db/entities/UserLogin';
4
4
  import * as Rx from 'rxjs';
5
5
  import { PersistedSyncState } from './db/entities/PersistedSyncState';
@@ -22,6 +22,9 @@ export interface DexieCloudAPI {
22
22
  persistedSyncState: Rx.BehaviorSubject<PersistedSyncState | undefined>;
23
23
  userInteraction: Rx.BehaviorSubject<DXCUserInteraction | undefined>;
24
24
  invites: Rx.Observable<Invite[]>;
25
+ roles: Rx.Observable<{
26
+ [roleName: string]: DBRealmRole;
27
+ }>;
25
28
  usingServiceWorker?: boolean;
26
29
  /** Login using Dexie Cloud OTP or Demo user.
27
30
  *
@@ -61,6 +61,7 @@ export declare class WSConnection extends Subscription {
61
61
  constructor(databaseUrl: string, rev: string, realmSetHash: string, clientIdentity: string, token: string | undefined, tokenExpiration: Date | undefined, subscriber: Subscriber<WSConnectionMsg>, messageProducer: Observable<WSClientToServerMsg>, webSocketStatus: BehaviorSubject<DXCWebSocketStatus>);
62
62
  private teardown;
63
63
  private disconnect;
64
+ reconnecting: boolean;
64
65
  reconnect(): void;
65
66
  connect(): Promise<void>;
66
67
  }
@@ -0,0 +1,5 @@
1
+ import Dexie from 'dexie';
2
+ import { DBRealmRole } from 'dexie-cloud-common';
3
+ export declare const getGlobalRolesObservable: (x: Dexie) => import("./mapValueObservable").ObservableWithCurrentValue<{
4
+ [roleName: string]: DBRealmRole;
5
+ }>;
@@ -4,7 +4,7 @@ export declare const getInvitesObservable: (x: Dexie) => import("./mapValueObser
4
4
  realm: import("dexie-cloud-common").DBRealm & {
5
5
  permissions: import("dexie-cloud-common").DBPermissionSet;
6
6
  };
7
- id?: string | undefined;
7
+ id: string;
8
8
  userId?: string | undefined;
9
9
  email?: string | undefined;
10
10
  name?: string | undefined;
@@ -108,7 +108,7 @@
108
108
  *
109
109
  * ==========================================================================
110
110
  *
111
- * Version 4.0.0-beta.14, Mon Dec 20 2021
111
+ * Version 4.0.0-beta.17, Fri Apr 08 2022
112
112
  *
113
113
  * https://dexie.org
114
114
  *
@@ -5303,166 +5303,22 @@
5303
5303
  return rv;
5304
5304
  };
5305
5305
  }
5306
- var SECONDS = 1000;
5307
- var MINUTES = 60 * SECONDS;
5308
- var myId = randomString(16);
5309
- var GUARDED_JOB_HEARTBEAT = 1 * SECONDS;
5310
- var GUARDED_JOB_TIMEOUT = 1 * MINUTES;
5311
- function performGuardedJob(db, jobName, jobsTableName, job, _e) {
5312
- var _f = _e === void 0 ? {} : _e, awaitRemoteJob = _f.awaitRemoteJob;
5313
- return __awaiter$1(this, void 0, void 0, function () {
5314
- function aquireLock() {
5315
- return __awaiter$1(this, void 0, void 0, function () {
5316
- var gotTheLock, jobDoneObservable, err_1;
5317
- var _this_1 = this;
5318
- return __generator$1(this, function (_e) {
5319
- switch (_e.label) {
5320
- case 0: return [4 /*yield*/, db.transaction('rw!', jobsTableName, function () { return __awaiter$1(_this_1, void 0, void 0, function () {
5321
- var currentWork;
5322
- return __generator$1(this, function (_e) {
5323
- switch (_e.label) {
5324
- case 0: return [4 /*yield*/, jobsTable.get(jobName)];
5325
- case 1:
5326
- currentWork = _e.sent();
5327
- if (!!currentWork) return [3 /*break*/, 3];
5328
- // No one else is working. Let's record that we are.
5329
- return [4 /*yield*/, jobsTable.add({
5330
- nodeId: myId,
5331
- started: new Date(),
5332
- heartbeat: new Date()
5333
- }, jobName)];
5334
- case 2:
5335
- // No one else is working. Let's record that we are.
5336
- _e.sent();
5337
- return [2 /*return*/, true];
5338
- case 3:
5339
- if (!(currentWork.heartbeat.getTime() <
5340
- Date.now() - GUARDED_JOB_TIMEOUT)) return [3 /*break*/, 5];
5341
- console.warn("Latest ".concat(jobName, " worker seem to have died.\n"), "The dead job started:", currentWork.started, "\n", "Last heart beat was:", currentWork.heartbeat, '\n', "We're now taking over!");
5342
- // Now, take over!
5343
- return [4 /*yield*/, jobsTable.put({
5344
- nodeId: myId,
5345
- started: new Date(),
5346
- heartbeat: new Date()
5347
- }, jobName)];
5348
- case 4:
5349
- // Now, take over!
5350
- _e.sent();
5351
- return [2 /*return*/, true];
5352
- case 5: return [2 /*return*/, false];
5353
- }
5354
- });
5355
- }); })];
5356
- case 1:
5357
- gotTheLock = _e.sent();
5358
- if (gotTheLock)
5359
- return [2 /*return*/, true];
5360
- if (!awaitRemoteJob) return [3 /*break*/, 6];
5361
- _e.label = 2;
5362
- case 2:
5363
- _e.trys.push([2, 4, , 6]);
5364
- jobDoneObservable = rxjs.from(Dexie.liveQuery(function () { return jobsTable.get(jobName); })).pipe(timeout(GUARDED_JOB_TIMEOUT), filter(function (job) { return !job; }));
5365
- return [4 /*yield*/, jobDoneObservable.toPromise()];
5366
- case 3:
5367
- _e.sent();
5368
- return [2 /*return*/, false];
5369
- case 4:
5370
- err_1 = _e.sent();
5371
- if (err_1.name !== 'TimeoutError') {
5372
- throw err_1;
5373
- }
5374
- return [4 /*yield*/, aquireLock()];
5375
- case 5:
5376
- // Timeout stopped us! Try aquire the lock now.
5377
- // It will likely succeed this time unless
5378
- // another client took it.
5379
- return [2 /*return*/, _e.sent()];
5380
- case 6: return [2 /*return*/, false];
5381
- }
5382
- });
5383
- });
5384
- }
5385
- var jobsTable, heartbeat;
5386
- var _this_1 = this;
5387
- return __generator$1(this, function (_g) {
5388
- switch (_g.label) {
5389
- case 0:
5390
- jobsTable = db.table(jobsTableName);
5391
- return [4 /*yield*/, aquireLock()];
5392
- case 1:
5393
- if (!_g.sent()) return [3 /*break*/, 6];
5394
- heartbeat = setInterval(function () {
5395
- jobsTable.update(jobName, function (job) {
5396
- if (job.nodeId === myId) {
5397
- job.heartbeat = new Date();
5398
- }
5399
- });
5400
- }, GUARDED_JOB_HEARTBEAT);
5401
- _g.label = 2;
5402
- case 2:
5403
- _g.trys.push([2, , 4, 6]);
5404
- return [4 /*yield*/, job()];
5405
- case 3: return [2 /*return*/, _g.sent()];
5406
- case 4:
5407
- // Stop heartbeat
5408
- clearInterval(heartbeat);
5409
- // Remove the persisted job state:
5410
- return [4 /*yield*/, db.transaction('rw!', jobsTableName, function () { return __awaiter$1(_this_1, void 0, void 0, function () {
5411
- var currentWork;
5412
- return __generator$1(this, function (_e) {
5413
- switch (_e.label) {
5414
- case 0: return [4 /*yield*/, jobsTable.get(jobName)];
5415
- case 1:
5416
- currentWork = _e.sent();
5417
- if (currentWork && currentWork.nodeId === myId) {
5418
- jobsTable.delete(jobName);
5419
- }
5420
- return [2 /*return*/];
5421
- }
5422
- });
5423
- }); })];
5424
- case 5:
5425
- // Remove the persisted job state:
5426
- _g.sent();
5427
- return [7 /*endfinally*/];
5428
- case 6: return [2 /*return*/];
5429
- }
5430
- });
5431
- });
5432
- }
5433
5306
  function performInitialSync(db, cloudOptions, cloudSchema) {
5434
5307
  return __awaiter$1(this, void 0, void 0, function () {
5435
- var _this_1 = this;
5436
5308
  return __generator$1(this, function (_e) {
5437
5309
  switch (_e.label) {
5438
5310
  case 0:
5439
- console.debug("Performing initial sync");
5440
- return [4 /*yield*/, performGuardedJob(db, 'initialSync', '$jobs', function () { return __awaiter$1(_this_1, void 0, void 0, function () {
5441
- var syncState;
5442
- return __generator$1(this, function (_e) {
5443
- switch (_e.label) {
5444
- case 0: return [4 /*yield*/, db.getPersistedSyncState()];
5445
- case 1:
5446
- syncState = _e.sent();
5447
- if (!!(syncState === null || syncState === void 0 ? void 0 : syncState.initiallySynced)) return [3 /*break*/, 3];
5448
- return [4 /*yield*/, sync(db, cloudOptions, cloudSchema, { isInitialSync: true })];
5449
- case 2:
5450
- _e.sent();
5451
- _e.label = 3;
5452
- case 3: return [2 /*return*/];
5453
- }
5454
- });
5455
- }); }, { awaitRemoteJob: true } // Don't return until the job is done!
5456
- )];
5311
+ console.debug('Performing initial sync');
5312
+ return [4 /*yield*/, sync(db, cloudOptions, cloudSchema, { isInitialSync: true })];
5457
5313
  case 1:
5458
5314
  _e.sent();
5459
- console.debug("Done initial sync");
5315
+ console.debug('Done initial sync');
5460
5316
  return [2 /*return*/];
5461
5317
  }
5462
5318
  });
5463
5319
  });
5464
5320
  }
5465
- var USER_INACTIVITY_TIMEOUT = 300000; // 300_000;
5321
+ var USER_INACTIVITY_TIMEOUT = 180000; // 3 minutes
5466
5322
  var INACTIVE_WAIT_TIME = 20000;
5467
5323
  // This observable will be emitted to later down....
5468
5324
  var userIsActive = new rxjs.BehaviorSubject(true);
@@ -5476,9 +5332,12 @@
5476
5332
  // for just a short time.
5477
5333
  var userIsReallyActive = new rxjs.BehaviorSubject(true);
5478
5334
  userIsActive
5479
- .pipe(switchMap(function (isActive) { return isActive
5480
- ? rxjs.of(true)
5481
- : rxjs.of(false).pipe(delay(INACTIVE_WAIT_TIME)); }), distinctUntilChanged())
5335
+ .pipe(switchMap(function (isActive) {
5336
+ //console.debug('SyncStatus: DUBB: isActive changed to', isActive);
5337
+ return isActive
5338
+ ? rxjs.of(true)
5339
+ : rxjs.of(false).pipe(delay(INACTIVE_WAIT_TIME));
5340
+ }), distinctUntilChanged())
5482
5341
  .subscribe(userIsReallyActive);
5483
5342
  //
5484
5343
  // First create some corner-stone observables to build the flow on
@@ -5493,7 +5352,7 @@
5493
5352
  var documentBecomesVisible = visibilityStateIsChanged.pipe(filter(function () { return document.visibilityState === 'visible'; }));
5494
5353
  // Any of various user-activity-related events happen:
5495
5354
  var userDoesSomething = typeof window !== 'undefined'
5496
- ? rxjs.merge(documentBecomesVisible, rxjs.fromEvent(window, 'mousemove'), rxjs.fromEvent(window, 'keydown'), rxjs.fromEvent(window, 'wheel'), rxjs.fromEvent(window, 'touchmove'))
5355
+ ? rxjs.merge(documentBecomesVisible, rxjs.fromEvent(window, 'mousedown'), rxjs.fromEvent(window, 'mousemove'), rxjs.fromEvent(window, 'keydown'), rxjs.fromEvent(window, 'wheel'), rxjs.fromEvent(window, 'touchmove'))
5497
5356
  : rxjs.of({});
5498
5357
  if (typeof document !== 'undefined') {
5499
5358
  //
@@ -5548,6 +5407,7 @@
5548
5407
  function WSConnection(databaseUrl, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
5549
5408
  var _this_1 = _super_1.call(this, function () { return _this_1.teardown(); }) || this;
5550
5409
  _this_1.id = ++counter;
5410
+ _this_1.reconnecting = false;
5551
5411
  console.debug('New WebSocket Connection', _this_1.id, token ? 'authorized' : 'unauthorized');
5552
5412
  _this_1.databaseUrl = databaseUrl;
5553
5413
  _this_1.rev = rev;
@@ -5568,7 +5428,7 @@
5568
5428
  this.disconnect();
5569
5429
  };
5570
5430
  WSConnection.prototype.disconnect = function () {
5571
- this.webSocketStatus.next("disconnected");
5431
+ this.webSocketStatus.next('disconnected');
5572
5432
  if (this.pinger) {
5573
5433
  clearInterval(this.pinger);
5574
5434
  this.pinger = null;
@@ -5586,17 +5446,25 @@
5586
5446
  }
5587
5447
  };
5588
5448
  WSConnection.prototype.reconnect = function () {
5589
- this.disconnect();
5590
- this.connect();
5449
+ var _this_1 = this;
5450
+ if (this.reconnecting)
5451
+ return;
5452
+ this.reconnecting = true;
5453
+ try {
5454
+ this.disconnect();
5455
+ }
5456
+ catch (_e) { }
5457
+ this.connect()
5458
+ .catch(function () { })
5459
+ .then(function () { return (_this_1.reconnecting = false); }); // finally()
5591
5460
  };
5592
5461
  WSConnection.prototype.connect = function () {
5593
5462
  return __awaiter$1(this, void 0, void 0, function () {
5594
- var wsUrl, searchParams, ws;
5463
+ var wsUrl, searchParams, ws, everConnected_1;
5595
5464
  var _this_1 = this;
5596
5465
  return __generator$1(this, function (_e) {
5597
5466
  switch (_e.label) {
5598
5467
  case 0:
5599
- this.webSocketStatus.next("connecting");
5600
5468
  this.lastServerActivity = new Date();
5601
5469
  if (this.pauseUntil && this.pauseUntil > new Date()) {
5602
5470
  console.debug('WS not reconnecting just yet', {
@@ -5611,12 +5479,14 @@
5611
5479
  if (!this.databaseUrl)
5612
5480
  throw new Error("Cannot connect without a database URL");
5613
5481
  if (this.closed) {
5482
+ //console.debug('SyncStatus: DUBB: Ooops it was closed!');
5614
5483
  return [2 /*return*/];
5615
5484
  }
5616
5485
  if (this.tokenExpiration && this.tokenExpiration < new Date()) {
5617
5486
  this.subscriber.error(new TokenExpiredError()); // Will be handled in connectWebSocket.ts.
5618
5487
  return [2 /*return*/];
5619
5488
  }
5489
+ this.webSocketStatus.next('connecting');
5620
5490
  this.pinger = setInterval(function () { return __awaiter$1(_this_1, void 0, void 0, function () {
5621
5491
  var _this_1 = this;
5622
5492
  return __generator$1(this, function (_e) {
@@ -5666,7 +5536,7 @@
5666
5536
  searchParams = new URLSearchParams();
5667
5537
  if (this.subscriber.closed)
5668
5538
  return [2 /*return*/];
5669
- searchParams.set('v', "2");
5539
+ searchParams.set('v', '2');
5670
5540
  searchParams.set('rev', this.rev);
5671
5541
  searchParams.set('realmsHash', this.realmSetHash);
5672
5542
  searchParams.set('clientId', this.clientIdentity);
@@ -5707,17 +5577,23 @@
5707
5577
  _e.label = 1;
5708
5578
  case 1:
5709
5579
  _e.trys.push([1, 3, , 4]);
5580
+ everConnected_1 = false;
5710
5581
  return [4 /*yield*/, new Promise(function (resolve, reject) {
5711
5582
  ws.onopen = function (event) {
5712
5583
  console.debug('dexie-cloud WebSocket onopen');
5584
+ everConnected_1 = true;
5713
5585
  resolve(null);
5714
5586
  };
5715
5587
  ws.onerror = function (event) {
5716
- var error = event.error || new Error('WebSocket Error');
5717
- _this_1.disconnect();
5718
- _this_1.subscriber.error(error);
5719
- _this_1.webSocketStatus.next("error");
5720
- reject(error);
5588
+ if (!everConnected_1) {
5589
+ var error = event.error || new Error('WebSocket Error');
5590
+ _this_1.subscriber.error(error);
5591
+ _this_1.webSocketStatus.next('error');
5592
+ reject(error);
5593
+ }
5594
+ else {
5595
+ _this_1.reconnect();
5596
+ }
5721
5597
  };
5722
5598
  })];
5723
5599
  case 2:
@@ -5725,8 +5601,9 @@
5725
5601
  this.messageProducerSubscription = this.messageProducer.subscribe(function (msg) {
5726
5602
  var _e;
5727
5603
  if (!_this_1.closed) {
5728
- if (msg.type === 'ready' && _this_1.webSocketStatus.value !== 'connected') {
5729
- _this_1.webSocketStatus.next("connected");
5604
+ if (msg.type === 'ready' &&
5605
+ _this_1.webSocketStatus.value !== 'connected') {
5606
+ _this_1.webSocketStatus.next('connected');
5730
5607
  }
5731
5608
  (_e = _this_1.ws) === null || _e === void 0 ? void 0 : _e.send(TSON.stringify(msg));
5732
5609
  }
@@ -5835,7 +5712,10 @@
5835
5712
  else {
5836
5713
  return rxjs.throwError(error);
5837
5714
  }
5838
- }), catchError(function (error) { return rxjs.from(waitAndReconnectWhenUserDoesSomething(error)).pipe(switchMap(function () { return createObservable(); })); }));
5715
+ }), catchError(function (error) {
5716
+ db.cloud.webSocketStatus.next("error");
5717
+ return rxjs.from(waitAndReconnectWhenUserDoesSomething(error)).pipe(switchMap(function () { return createObservable(); }));
5718
+ }));
5839
5719
  }
5840
5720
  return createObservable().subscribe(function (msg) {
5841
5721
  if (msg) {
@@ -5868,6 +5748,135 @@
5868
5748
  });
5869
5749
  });
5870
5750
  }
5751
+ var SECONDS = 1000;
5752
+ var MINUTES = 60 * SECONDS;
5753
+ var myId = randomString(16);
5754
+ var GUARDED_JOB_HEARTBEAT = 1 * SECONDS;
5755
+ var GUARDED_JOB_TIMEOUT = 1 * MINUTES;
5756
+ function performGuardedJob(db, jobName, jobsTableName, job, _e) {
5757
+ var _f = _e === void 0 ? {} : _e, awaitRemoteJob = _f.awaitRemoteJob;
5758
+ return __awaiter$1(this, void 0, void 0, function () {
5759
+ function aquireLock() {
5760
+ return __awaiter$1(this, void 0, void 0, function () {
5761
+ var gotTheLock, jobDoneObservable, err_1;
5762
+ var _this_1 = this;
5763
+ return __generator$1(this, function (_e) {
5764
+ switch (_e.label) {
5765
+ case 0: return [4 /*yield*/, db.transaction('rw!', jobsTableName, function () { return __awaiter$1(_this_1, void 0, void 0, function () {
5766
+ var currentWork;
5767
+ return __generator$1(this, function (_e) {
5768
+ switch (_e.label) {
5769
+ case 0: return [4 /*yield*/, jobsTable.get(jobName)];
5770
+ case 1:
5771
+ currentWork = _e.sent();
5772
+ if (!!currentWork) return [3 /*break*/, 3];
5773
+ // No one else is working. Let's record that we are.
5774
+ return [4 /*yield*/, jobsTable.add({
5775
+ nodeId: myId,
5776
+ started: new Date(),
5777
+ heartbeat: new Date()
5778
+ }, jobName)];
5779
+ case 2:
5780
+ // No one else is working. Let's record that we are.
5781
+ _e.sent();
5782
+ return [2 /*return*/, true];
5783
+ case 3:
5784
+ if (!(currentWork.heartbeat.getTime() <
5785
+ Date.now() - GUARDED_JOB_TIMEOUT)) return [3 /*break*/, 5];
5786
+ console.warn("Latest ".concat(jobName, " worker seem to have died.\n"), "The dead job started:", currentWork.started, "\n", "Last heart beat was:", currentWork.heartbeat, '\n', "We're now taking over!");
5787
+ // Now, take over!
5788
+ return [4 /*yield*/, jobsTable.put({
5789
+ nodeId: myId,
5790
+ started: new Date(),
5791
+ heartbeat: new Date()
5792
+ }, jobName)];
5793
+ case 4:
5794
+ // Now, take over!
5795
+ _e.sent();
5796
+ return [2 /*return*/, true];
5797
+ case 5: return [2 /*return*/, false];
5798
+ }
5799
+ });
5800
+ }); })];
5801
+ case 1:
5802
+ gotTheLock = _e.sent();
5803
+ if (gotTheLock)
5804
+ return [2 /*return*/, true];
5805
+ if (!awaitRemoteJob) return [3 /*break*/, 6];
5806
+ _e.label = 2;
5807
+ case 2:
5808
+ _e.trys.push([2, 4, , 6]);
5809
+ jobDoneObservable = rxjs.from(Dexie.liveQuery(function () { return jobsTable.get(jobName); })).pipe(timeout(GUARDED_JOB_TIMEOUT), filter(function (job) { return !job; }));
5810
+ return [4 /*yield*/, jobDoneObservable.toPromise()];
5811
+ case 3:
5812
+ _e.sent();
5813
+ return [2 /*return*/, false];
5814
+ case 4:
5815
+ err_1 = _e.sent();
5816
+ if (err_1.name !== 'TimeoutError') {
5817
+ throw err_1;
5818
+ }
5819
+ return [4 /*yield*/, aquireLock()];
5820
+ case 5:
5821
+ // Timeout stopped us! Try aquire the lock now.
5822
+ // It will likely succeed this time unless
5823
+ // another client took it.
5824
+ return [2 /*return*/, _e.sent()];
5825
+ case 6: return [2 /*return*/, false];
5826
+ }
5827
+ });
5828
+ });
5829
+ }
5830
+ var jobsTable, heartbeat;
5831
+ var _this_1 = this;
5832
+ return __generator$1(this, function (_g) {
5833
+ switch (_g.label) {
5834
+ case 0:
5835
+ jobsTable = db.table(jobsTableName);
5836
+ return [4 /*yield*/, aquireLock()];
5837
+ case 1:
5838
+ if (!_g.sent()) return [3 /*break*/, 6];
5839
+ heartbeat = setInterval(function () {
5840
+ jobsTable.update(jobName, function (job) {
5841
+ if (job.nodeId === myId) {
5842
+ job.heartbeat = new Date();
5843
+ }
5844
+ });
5845
+ }, GUARDED_JOB_HEARTBEAT);
5846
+ _g.label = 2;
5847
+ case 2:
5848
+ _g.trys.push([2, , 4, 6]);
5849
+ return [4 /*yield*/, job()];
5850
+ case 3: return [2 /*return*/, _g.sent()];
5851
+ case 4:
5852
+ // Stop heartbeat
5853
+ clearInterval(heartbeat);
5854
+ // Remove the persisted job state:
5855
+ return [4 /*yield*/, db.transaction('rw!', jobsTableName, function () { return __awaiter$1(_this_1, void 0, void 0, function () {
5856
+ var currentWork;
5857
+ return __generator$1(this, function (_e) {
5858
+ switch (_e.label) {
5859
+ case 0: return [4 /*yield*/, jobsTable.get(jobName)];
5860
+ case 1:
5861
+ currentWork = _e.sent();
5862
+ if (!(currentWork && currentWork.nodeId === myId)) return [3 /*break*/, 3];
5863
+ return [4 /*yield*/, jobsTable.delete(jobName)];
5864
+ case 2:
5865
+ _e.sent();
5866
+ _e.label = 3;
5867
+ case 3: return [2 /*return*/];
5868
+ }
5869
+ });
5870
+ }); })];
5871
+ case 5:
5872
+ // Remove the persisted job state:
5873
+ _g.sent();
5874
+ return [7 /*endfinally*/];
5875
+ case 6: return [2 /*return*/];
5876
+ }
5877
+ });
5878
+ });
5879
+ }
5871
5880
  var ongoingSyncs = new WeakMap();
5872
5881
  function syncIfPossible(db, cloudOptions, cloudSchema, options) {
5873
5882
  var ongoing = ongoingSyncs.get(db);
@@ -6476,6 +6485,21 @@
6476
6485
  rv.getValue = function () { return currentValue; };
6477
6486
  return rv;
6478
6487
  }
6488
+ var getGlobalRolesObservable = associate(function (db) {
6489
+ return createSharedValueObservable(Dexie.liveQuery(function () { return db.roles
6490
+ .where({ realmId: 'rlm-public' })
6491
+ .toArray()
6492
+ .then(function (roles) {
6493
+ var rv = {};
6494
+ for (var _e = 0, _f = roles
6495
+ .slice()
6496
+ .sort(function (a, b) { return (a.sortOrder || 0) - (b.sortOrder || 0); }); _e < _f.length; _e++) {
6497
+ var role = _f[_e];
6498
+ rv[role.name] = role;
6499
+ }
6500
+ return rv;
6501
+ }); }), {});
6502
+ });
6479
6503
  var getCurrentUserEmitter = associate(function (db) { return new rxjs.BehaviorSubject(UNAUTHORIZED_USER); });
6480
6504
  var getInternalAccessControlObservable = associate(function (db) {
6481
6505
  return createSharedValueObservable(getCurrentUserEmitter(db._novip).pipe(switchMap(function (currentUser) { return Dexie.liveQuery(function () { return db.transaction('r', 'realms', 'members', function () { return Promise.all([
@@ -6578,17 +6602,40 @@
6578
6602
  return reduced;
6579
6603
  }
6580
6604
  var getPermissionsLookupObservable = associate(function (db) {
6581
- var o = getInternalAccessControlObservable(db._novip);
6605
+ var o = createSharedValueObservable(rxjs.combineLatest([
6606
+ getInternalAccessControlObservable(db._novip),
6607
+ getGlobalRolesObservable(db._novip),
6608
+ ]).pipe(map(function (_e) {
6609
+ var _f = _e[0], selfMembers = _f.selfMembers, realms = _f.realms, userId = _f.userId, globalRoles = _e[1];
6610
+ return ({
6611
+ selfMembers: selfMembers,
6612
+ realms: realms,
6613
+ userId: userId,
6614
+ globalRoles: globalRoles,
6615
+ });
6616
+ })), {
6617
+ selfMembers: [],
6618
+ realms: [],
6619
+ userId: UNAUTHORIZED_USER.userId,
6620
+ globalRoles: {},
6621
+ });
6582
6622
  return mapValueObservable(o, function (_e) {
6583
6623
  var _f;
6584
- var selfMembers = _e.selfMembers, realms = _e.realms, userId = _e.userId;
6624
+ var selfMembers = _e.selfMembers, realms = _e.realms, userId = _e.userId, globalRoles = _e.globalRoles;
6585
6625
  var rv = realms
6586
- .map(function (realm) { return (__assign(__assign({}, realm), { permissions: realm.owner === userId
6587
- ? { manage: '*' }
6588
- : mergePermissions.apply(void 0, selfMembers
6589
- .filter(function (m) { return m.realmId === realm.realmId; })
6590
- .map(function (m) { return m.permissions; })
6591
- .filter(function (p) { return p; })) })); })
6626
+ .map(function (realm) {
6627
+ var selfRealmMembers = selfMembers.filter(function (m) { return m.realmId === realm.realmId; });
6628
+ var directPermissionSets = selfRealmMembers
6629
+ .map(function (m) { return m.permissions; })
6630
+ .filter(function (p) { return p; });
6631
+ var rolePermissionSets = flatten(selfRealmMembers.map(function (m) { return m.roles; }).filter(function (roleName) { return roleName; }))
6632
+ .map(function (role) { return globalRoles[role]; })
6633
+ .filter(function (role) { return role; })
6634
+ .map(function (role) { return role.permissions; });
6635
+ return __assign(__assign({}, realm), { permissions: realm.owner === userId
6636
+ ? { manage: '*' }
6637
+ : mergePermissions.apply(void 0, __spreadArray$1(__spreadArray$1([], directPermissionSets, false), rolePermissionSets, false)) });
6638
+ })
6592
6639
  .reduce(function (p, c) {
6593
6640
  var _e;
6594
6641
  return (__assign(__assign({}, p), (_e = {}, _e[c.realmId] = c, _e)));
@@ -6686,7 +6733,7 @@
6686
6733
  var realm = permissionsLookup[realmId || dexie.cloud.currentUserId];
6687
6734
  if (!realm)
6688
6735
  return new PermissionChecker({}, tableName, !owner || owner === dexie.cloud.currentUserId);
6689
- return new PermissionChecker(realm.permissions, tableName, !owner || owner === dexie.cloud.currentUserId);
6736
+ return new PermissionChecker(realm.permissions, tableName, realmId === dexie.cloud.currentUserId || owner === dexie.cloud.currentUserId);
6690
6737
  };
6691
6738
  var o = source.pipe(map(mapper));
6692
6739
  o.getValue = function () { return mapper(source.getValue()); };
@@ -6724,6 +6771,7 @@
6724
6771
  //
6725
6772
  var currentUserEmitter = getCurrentUserEmitter(dexie);
6726
6773
  var subscriptions = [];
6774
+ var configuredProgramatically = false;
6727
6775
  // local sync worker - used when there's no service worker.
6728
6776
  var localSyncWorker = null;
6729
6777
  dexie.on('ready', function (dexie) { return __awaiter$1(_this_1, void 0, void 0, function () {
@@ -6759,7 +6807,7 @@
6759
6807
  currentUserEmitter.next(UNAUTHORIZED_USER);
6760
6808
  });
6761
6809
  dexie.cloud = {
6762
- version: '4.0.0-beta.14',
6810
+ version: '4.0.0-beta.17',
6763
6811
  options: __assign({}, DEFAULT_OPTIONS),
6764
6812
  schema: null,
6765
6813
  serverState: null,
@@ -6793,8 +6841,10 @@
6793
6841
  });
6794
6842
  },
6795
6843
  invites: getInvitesObservable(dexie),
6844
+ roles: getGlobalRolesObservable(dexie),
6796
6845
  configure: function (options) {
6797
6846
  options = dexie.cloud.options = __assign(__assign({}, dexie.cloud.options), options);
6847
+ configuredProgramatically = true;
6798
6848
  if (options.databaseUrl && options.nameSuffix) {
6799
6849
  // @ts-ignore
6800
6850
  dexie.name = "".concat(origIdbName, "-").concat(getDbNameFromDbUrl(options.databaseUrl));
@@ -6929,7 +6979,7 @@
6929
6979
  ])];
6930
6980
  case 1:
6931
6981
  _f = _m.sent(), persistedOptions = _f[0], persistedSchema = _f[1], persistedSyncState = _f[2];
6932
- if (!!options) return [3 /*break*/, 2];
6982
+ if (!!configuredProgramatically) return [3 /*break*/, 2];
6933
6983
  // Options not specified programatically (use case for SW!)
6934
6984
  // Take persisted options:
6935
6985
  db.cloud.options = persistedOptions || null;
@@ -6938,9 +6988,10 @@
6938
6988
  if (!(!persistedOptions ||
6939
6989
  JSON.stringify(persistedOptions) !== JSON.stringify(options))) return [3 /*break*/, 4];
6940
6990
  // Update persisted options:
6991
+ if (!options)
6992
+ throw new Error("Internal error"); // options cannot be null if configuredProgramatically is set.
6941
6993
  return [4 /*yield*/, db.$syncState.put(options, 'options')];
6942
6994
  case 3:
6943
- // Update persisted options:
6944
6995
  _m.sent();
6945
6996
  _m.label = 4;
6946
6997
  case 4:
@@ -7086,7 +7137,7 @@
7086
7137
  });
7087
7138
  }
7088
7139
  }
7089
- dexieCloud.version = '4.0.0-beta.14';
7140
+ dexieCloud.version = '4.0.0-beta.17';
7090
7141
  Dexie__default["default"].Cloud = dexieCloud;
7091
7142
 
7092
7143
  exports["default"] = dexieCloud;