dexie-cloud-addon 4.0.0-beta.15 → 4.0.0-beta.16
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/modern/dexie-cloud-addon.js +96 -36
- package/dist/modern/dexie-cloud-addon.js.map +1 -1
- package/dist/modern/dexie-cloud-addon.min.js +1 -1
- package/dist/modern/dexie-cloud-addon.min.js.map +1 -1
- package/dist/modern/service-worker.js +95 -35
- package/dist/modern/service-worker.js.map +1 -1
- package/dist/modern/service-worker.min.js +1 -1
- package/dist/modern/service-worker.min.js.map +1 -1
- package/dist/module-es5/dexie-cloud-addon.js +94 -31
- package/dist/module-es5/dexie-cloud-addon.js.map +1 -1
- package/dist/module-es5/dexie-cloud-addon.min.js +1 -1
- package/dist/module-es5/dexie-cloud-addon.min.js.map +1 -1
- package/dist/types/DexieCloudAPI.d.ts +4 -1
- package/dist/types/DexieCloudEntity.d.ts +8 -0
- package/dist/types/WSObservable.d.ts +1 -0
- package/dist/types/WebSocketStatus.d.ts +1 -0
- package/dist/types/createMyMembersObservable.d.ts +14 -0
- package/dist/types/currentUserObservable.d.ts +3 -0
- package/dist/types/getGlobalRolesObservable.d.ts +5 -0
- package/dist/types/getInvitesObservable.d.ts +1 -1
- package/dist/types/helpers/BroadcastedLocalEvent.d.ts +8 -0
- package/dist/types/helpers/visibleState.d.ts +1 -0
- package/dist/types/permissionsLookup.d.ts +9 -0
- package/dist/types/permissionsLookupObservable.d.ts +14 -0
- package/dist/types/sync/globalizePrivateIds.d.ts +4 -0
- package/dist/types/sync/syncServerToClientOnly.d.ts +3 -0
- package/dist/types/types/CloudConnectionStatus.d.ts +0 -0
- package/dist/types/types/ConnectionStatus.d.ts +0 -0
- package/dist/types/types/LoginState.d.ts +41 -0
- package/dist/types/types/SyncConnectionStatus.d.ts +1 -0
- package/dist/types/types/SyncFlowStatus.d.ts +6 -0
- package/dist/types/types/SyncStatus.d.ts +6 -0
- package/dist/umd/dexie-cloud-addon.js +94 -31
- package/dist/umd/dexie-cloud-addon.js.map +1 -1
- package/dist/umd/dexie-cloud-addon.min.js +1 -1
- package/dist/umd/dexie-cloud-addon.min.js.map +1 -1
- package/dist/umd/service-worker.js +95 -35
- package/dist/umd/service-worker.js.map +1 -1
- package/dist/umd/service-worker.min.js +1 -1
- package/dist/umd/service-worker.min.js.map +1 -1
- package/dist/umd-modern/dexie-cloud-addon.js +93 -33
- package/dist/umd-modern/dexie-cloud-addon.js.map +1 -1
- package/package.json +2 -2
|
@@ -4770,7 +4770,7 @@
|
|
|
4770
4770
|
console.debug("Done initial sync");
|
|
4771
4771
|
}
|
|
4772
4772
|
|
|
4773
|
-
const USER_INACTIVITY_TIMEOUT =
|
|
4773
|
+
const USER_INACTIVITY_TIMEOUT = 180000; // 3 minutes
|
|
4774
4774
|
const INACTIVE_WAIT_TIME = 20000;
|
|
4775
4775
|
// This observable will be emitted to later down....
|
|
4776
4776
|
const userIsActive = new rxjs.BehaviorSubject(true);
|
|
@@ -4784,9 +4784,13 @@
|
|
|
4784
4784
|
// for just a short time.
|
|
4785
4785
|
const userIsReallyActive = new rxjs.BehaviorSubject(true);
|
|
4786
4786
|
userIsActive
|
|
4787
|
-
.pipe(switchMap((isActive) =>
|
|
4788
|
-
|
|
4789
|
-
|
|
4787
|
+
.pipe(switchMap((isActive) => {
|
|
4788
|
+
//console.debug('SyncStatus: DUBB: isActive changed to', isActive);
|
|
4789
|
+
return isActive
|
|
4790
|
+
? rxjs.of(true)
|
|
4791
|
+
: rxjs.of(false).pipe(delay(INACTIVE_WAIT_TIME))
|
|
4792
|
+
;
|
|
4793
|
+
}), distinctUntilChanged())
|
|
4790
4794
|
.subscribe(userIsReallyActive);
|
|
4791
4795
|
//
|
|
4792
4796
|
// First create some corner-stone observables to build the flow on
|
|
@@ -4801,7 +4805,7 @@
|
|
|
4801
4805
|
const documentBecomesVisible = visibilityStateIsChanged.pipe(filter(() => document.visibilityState === 'visible'));
|
|
4802
4806
|
// Any of various user-activity-related events happen:
|
|
4803
4807
|
const userDoesSomething = typeof window !== 'undefined'
|
|
4804
|
-
? rxjs.merge(documentBecomesVisible, rxjs.fromEvent(window, 'mousemove'), rxjs.fromEvent(window, 'keydown'), rxjs.fromEvent(window, 'wheel'), rxjs.fromEvent(window, 'touchmove'))
|
|
4808
|
+
? rxjs.merge(documentBecomesVisible, rxjs.fromEvent(window, 'mousedown'), rxjs.fromEvent(window, 'mousemove'), rxjs.fromEvent(window, 'keydown'), rxjs.fromEvent(window, 'wheel'), rxjs.fromEvent(window, 'touchmove'))
|
|
4805
4809
|
: rxjs.of({});
|
|
4806
4810
|
if (typeof document !== 'undefined') {
|
|
4807
4811
|
//
|
|
@@ -4852,6 +4856,7 @@
|
|
|
4852
4856
|
constructor(databaseUrl, rev, realmSetHash, clientIdentity, token, tokenExpiration, subscriber, messageProducer, webSocketStatus) {
|
|
4853
4857
|
super(() => this.teardown());
|
|
4854
4858
|
this.id = ++counter;
|
|
4859
|
+
this.reconnecting = false;
|
|
4855
4860
|
console.debug('New WebSocket Connection', this.id, token ? 'authorized' : 'unauthorized');
|
|
4856
4861
|
this.databaseUrl = databaseUrl;
|
|
4857
4862
|
this.rev = rev;
|
|
@@ -4871,7 +4876,7 @@
|
|
|
4871
4876
|
this.disconnect();
|
|
4872
4877
|
}
|
|
4873
4878
|
disconnect() {
|
|
4874
|
-
this.webSocketStatus.next(
|
|
4879
|
+
this.webSocketStatus.next('disconnected');
|
|
4875
4880
|
if (this.pinger) {
|
|
4876
4881
|
clearInterval(this.pinger);
|
|
4877
4882
|
this.pinger = null;
|
|
@@ -4889,11 +4894,18 @@
|
|
|
4889
4894
|
}
|
|
4890
4895
|
}
|
|
4891
4896
|
reconnect() {
|
|
4892
|
-
this.
|
|
4893
|
-
|
|
4897
|
+
if (this.reconnecting)
|
|
4898
|
+
return;
|
|
4899
|
+
this.reconnecting = true;
|
|
4900
|
+
try {
|
|
4901
|
+
this.disconnect();
|
|
4902
|
+
}
|
|
4903
|
+
catch { }
|
|
4904
|
+
this.connect()
|
|
4905
|
+
.catch(() => { })
|
|
4906
|
+
.then(() => (this.reconnecting = false)); // finally()
|
|
4894
4907
|
}
|
|
4895
4908
|
async connect() {
|
|
4896
|
-
this.webSocketStatus.next("connecting");
|
|
4897
4909
|
this.lastServerActivity = new Date();
|
|
4898
4910
|
if (this.pauseUntil && this.pauseUntil > new Date()) {
|
|
4899
4911
|
console.debug('WS not reconnecting just yet', {
|
|
@@ -4908,12 +4920,14 @@
|
|
|
4908
4920
|
if (!this.databaseUrl)
|
|
4909
4921
|
throw new Error(`Cannot connect without a database URL`);
|
|
4910
4922
|
if (this.closed) {
|
|
4923
|
+
//console.debug('SyncStatus: DUBB: Ooops it was closed!');
|
|
4911
4924
|
return;
|
|
4912
4925
|
}
|
|
4913
4926
|
if (this.tokenExpiration && this.tokenExpiration < new Date()) {
|
|
4914
4927
|
this.subscriber.error(new TokenExpiredError()); // Will be handled in connectWebSocket.ts.
|
|
4915
4928
|
return;
|
|
4916
4929
|
}
|
|
4930
|
+
this.webSocketStatus.next('connecting');
|
|
4917
4931
|
this.pinger = setInterval(async () => {
|
|
4918
4932
|
if (this.closed) {
|
|
4919
4933
|
console.debug('pinger check', this.id, 'CLOSED.');
|
|
@@ -4960,7 +4974,7 @@
|
|
|
4960
4974
|
const searchParams = new URLSearchParams();
|
|
4961
4975
|
if (this.subscriber.closed)
|
|
4962
4976
|
return;
|
|
4963
|
-
searchParams.set('v',
|
|
4977
|
+
searchParams.set('v', '2');
|
|
4964
4978
|
searchParams.set('rev', this.rev);
|
|
4965
4979
|
searchParams.set('realmsHash', this.realmSetHash);
|
|
4966
4980
|
searchParams.set('clientId', this.clientIdentity);
|
|
@@ -4999,23 +5013,30 @@
|
|
|
4999
5013
|
}
|
|
5000
5014
|
};
|
|
5001
5015
|
try {
|
|
5016
|
+
let everConnected = false;
|
|
5002
5017
|
await new Promise((resolve, reject) => {
|
|
5003
5018
|
ws.onopen = (event) => {
|
|
5004
5019
|
console.debug('dexie-cloud WebSocket onopen');
|
|
5020
|
+
everConnected = true;
|
|
5005
5021
|
resolve(null);
|
|
5006
5022
|
};
|
|
5007
5023
|
ws.onerror = (event) => {
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5024
|
+
if (!everConnected) {
|
|
5025
|
+
const error = event.error || new Error('WebSocket Error');
|
|
5026
|
+
this.subscriber.error(error);
|
|
5027
|
+
this.webSocketStatus.next('error');
|
|
5028
|
+
reject(error);
|
|
5029
|
+
}
|
|
5030
|
+
else {
|
|
5031
|
+
this.reconnect();
|
|
5032
|
+
}
|
|
5013
5033
|
};
|
|
5014
5034
|
});
|
|
5015
|
-
this.messageProducerSubscription = this.messageProducer.subscribe(msg => {
|
|
5035
|
+
this.messageProducerSubscription = this.messageProducer.subscribe((msg) => {
|
|
5016
5036
|
if (!this.closed) {
|
|
5017
|
-
if (msg.type === 'ready' &&
|
|
5018
|
-
this.webSocketStatus.
|
|
5037
|
+
if (msg.type === 'ready' &&
|
|
5038
|
+
this.webSocketStatus.value !== 'connected') {
|
|
5039
|
+
this.webSocketStatus.next('connected');
|
|
5019
5040
|
}
|
|
5020
5041
|
this.ws?.send(TSON.stringify(msg));
|
|
5021
5042
|
}
|
|
@@ -5052,9 +5073,9 @@
|
|
|
5052
5073
|
rev: syncState.serverRevision,
|
|
5053
5074
|
})));
|
|
5054
5075
|
function createObservable() {
|
|
5055
|
-
return db.cloud.persistedSyncState.pipe(filter(syncState => syncState?.serverRevision), // Don't connect before there's no initial sync performed.
|
|
5076
|
+
return db.cloud.persistedSyncState.pipe(filter((syncState) => syncState?.serverRevision), // Don't connect before there's no initial sync performed.
|
|
5056
5077
|
take(1), // Don't continue waking up whenever syncState change
|
|
5057
|
-
switchMap((syncState) => db.cloud.currentUser.pipe(map(userLogin => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(async ([userLogin, syncState]) => [userLogin, await computeRealmSetHash(syncState)]), switchMap(([userLogin, realmSetHash]) =>
|
|
5078
|
+
switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(async ([userLogin, syncState]) => [userLogin, await computeRealmSetHash(syncState)]), switchMap(([userLogin, realmSetHash]) =>
|
|
5058
5079
|
// Let server end query changes from last entry of same client-ID and forward.
|
|
5059
5080
|
// If no new entries, server won't bother the client. If new entries, server sends only those
|
|
5060
5081
|
// and the baseRev of the last from same client-ID.
|
|
@@ -5077,7 +5098,10 @@
|
|
|
5077
5098
|
else {
|
|
5078
5099
|
return rxjs.throwError(error);
|
|
5079
5100
|
}
|
|
5080
|
-
}), catchError((error) =>
|
|
5101
|
+
}), catchError((error) => {
|
|
5102
|
+
db.cloud.webSocketStatus.next("error");
|
|
5103
|
+
return rxjs.from(waitAndReconnectWhenUserDoesSomething(error)).pipe(switchMap(() => createObservable()));
|
|
5104
|
+
}));
|
|
5081
5105
|
}
|
|
5082
5106
|
return createObservable().subscribe((msg) => {
|
|
5083
5107
|
if (msg) {
|
|
@@ -5501,6 +5525,21 @@
|
|
|
5501
5525
|
return rv;
|
|
5502
5526
|
}
|
|
5503
5527
|
|
|
5528
|
+
const getGlobalRolesObservable = associate((db) => {
|
|
5529
|
+
return createSharedValueObservable(Dexie.liveQuery(() => db.roles
|
|
5530
|
+
.where({ realmId: 'rlm-public' })
|
|
5531
|
+
.toArray()
|
|
5532
|
+
.then((roles) => {
|
|
5533
|
+
const rv = {};
|
|
5534
|
+
for (const role of roles
|
|
5535
|
+
.slice()
|
|
5536
|
+
.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0))) {
|
|
5537
|
+
rv[role.name] = role;
|
|
5538
|
+
}
|
|
5539
|
+
return rv;
|
|
5540
|
+
})), {});
|
|
5541
|
+
});
|
|
5542
|
+
|
|
5504
5543
|
const getCurrentUserEmitter = associate((db) => new rxjs.BehaviorSubject(UNAUTHORIZED_USER));
|
|
5505
5544
|
|
|
5506
5545
|
const getInternalAccessControlObservable = associate((db) => {
|
|
@@ -5602,18 +5641,38 @@
|
|
|
5602
5641
|
}
|
|
5603
5642
|
|
|
5604
5643
|
const getPermissionsLookupObservable = associate((db) => {
|
|
5605
|
-
const o =
|
|
5606
|
-
|
|
5644
|
+
const o = createSharedValueObservable(rxjs.combineLatest([
|
|
5645
|
+
getInternalAccessControlObservable(db._novip),
|
|
5646
|
+
getGlobalRolesObservable(db._novip),
|
|
5647
|
+
]).pipe(map(([{ selfMembers, realms, userId }, globalRoles]) => ({
|
|
5648
|
+
selfMembers,
|
|
5649
|
+
realms,
|
|
5650
|
+
userId,
|
|
5651
|
+
globalRoles,
|
|
5652
|
+
}))), {
|
|
5653
|
+
selfMembers: [],
|
|
5654
|
+
realms: [],
|
|
5655
|
+
userId: UNAUTHORIZED_USER.userId,
|
|
5656
|
+
globalRoles: {},
|
|
5657
|
+
});
|
|
5658
|
+
return mapValueObservable(o, ({ selfMembers, realms, userId, globalRoles }) => {
|
|
5607
5659
|
const rv = realms
|
|
5608
|
-
.map((realm) =>
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5660
|
+
.map((realm) => {
|
|
5661
|
+
const selfRealmMembers = selfMembers.filter((m) => m.realmId === realm.realmId);
|
|
5662
|
+
const directPermissionSets = selfRealmMembers
|
|
5663
|
+
.map((m) => m.permissions)
|
|
5664
|
+
.filter((p) => p);
|
|
5665
|
+
const rolePermissionSets = flatten(selfRealmMembers.map((m) => m.roles).filter((roleName) => roleName))
|
|
5666
|
+
.map((role) => globalRoles[role])
|
|
5667
|
+
.filter((role) => role)
|
|
5668
|
+
.map((role) => role.permissions);
|
|
5669
|
+
return {
|
|
5670
|
+
...realm,
|
|
5671
|
+
permissions: realm.owner === userId
|
|
5672
|
+
? { manage: '*' }
|
|
5673
|
+
: mergePermissions(...directPermissionSets, ...rolePermissionSets),
|
|
5674
|
+
};
|
|
5675
|
+
})
|
|
5617
5676
|
.reduce((p, c) => ({ ...p, [c.realmId]: c }), {
|
|
5618
5677
|
[userId]: {
|
|
5619
5678
|
realmId: userId,
|
|
@@ -5697,7 +5756,7 @@
|
|
|
5697
5756
|
const realm = permissionsLookup[realmId || dexie.cloud.currentUserId];
|
|
5698
5757
|
if (!realm)
|
|
5699
5758
|
return new PermissionChecker({}, tableName, !owner || owner === dexie.cloud.currentUserId);
|
|
5700
|
-
return new PermissionChecker(realm.permissions, tableName,
|
|
5759
|
+
return new PermissionChecker(realm.permissions, tableName, realmId === dexie.cloud.currentUserId || owner === dexie.cloud.currentUserId);
|
|
5701
5760
|
};
|
|
5702
5761
|
const o = source.pipe(map(mapper));
|
|
5703
5762
|
o.getValue = () => mapper(source.getValue());
|
|
@@ -5781,6 +5840,7 @@
|
|
|
5781
5840
|
await login(db, hint);
|
|
5782
5841
|
},
|
|
5783
5842
|
invites: getInvitesObservable(dexie),
|
|
5843
|
+
roles: getGlobalRolesObservable(dexie),
|
|
5784
5844
|
configure(options) {
|
|
5785
5845
|
options = dexie.cloud.options = { ...dexie.cloud.options, ...options };
|
|
5786
5846
|
configuredProgramatically = true;
|