dexie-cloud-addon 4.0.1-beta.46 → 4.0.1-beta.48

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.
Files changed (264) hide show
  1. package/dist/{types → modern}/DexieCloudAPI.d.ts +3 -0
  2. package/dist/{types → modern}/DexieCloudOptions.d.ts +1 -0
  3. package/dist/modern/InvalidLicenseError.d.ts +5 -0
  4. package/dist/{types → modern}/TSON.d.ts +1 -1
  5. package/dist/modern/authentication/TokenErrorResponseError.d.ts +10 -0
  6. package/dist/{types → modern}/authentication/authenticate.d.ts +3 -3
  7. package/dist/{types → modern}/authentication/interactWithUser.d.ts +3 -0
  8. package/dist/modern/authentication/logout.d.ts +5 -0
  9. package/dist/modern/authentication/waitUntil.d.ts +3 -0
  10. package/dist/{types → modern}/currentUserEmitter.d.ts +1 -1
  11. package/dist/{types → modern}/db/entities/UserLogin.d.ts +6 -0
  12. package/dist/modern/default-ui/LoginDialog.d.ts +3 -0
  13. package/dist/modern/dexie-cloud-addon.d.ts +3 -0
  14. package/dist/modern/dexie-cloud-addon.js +488 -367
  15. package/dist/modern/dexie-cloud-addon.js.map +1 -1
  16. package/dist/modern/dexie-cloud-addon.min.js +2 -2
  17. package/dist/modern/dexie-cloud-addon.min.js.map +1 -1
  18. package/dist/{types → modern}/dexie-cloud-client.d.ts +2 -0
  19. package/dist/modern/helpers/resolveText.d.ts +16 -0
  20. package/dist/modern/isEagerSyncDisabled.d.ts +2 -0
  21. package/dist/{types → modern}/middlewares/createMutationTrackingMiddleware.d.ts +1 -1
  22. package/dist/modern/prodLog.d.ts +9 -0
  23. package/dist/modern/service-worker.js +2027 -268
  24. package/dist/modern/service-worker.js.map +1 -1
  25. package/dist/modern/service-worker.min.js +2 -2
  26. package/dist/modern/service-worker.min.js.map +1 -1
  27. package/dist/modern/sync/performGuardedJob.d.ts +2 -0
  28. package/dist/modern/sync/ratelimit.d.ts +3 -0
  29. package/dist/{types → modern}/sync/sync.d.ts +0 -1
  30. package/dist/{types → modern}/types/DXCAlert.d.ts +1 -1
  31. package/dist/{types → modern}/types/DXCUserInteraction.d.ts +40 -2
  32. package/dist/{types → modern}/types/SyncState.d.ts +1 -0
  33. package/dist/umd/DISABLE_SERVICEWORKER_STRATEGY.d.ts +1 -0
  34. package/dist/umd/DXCWebSocketStatus.d.ts +1 -0
  35. package/dist/umd/DexieCloudAPI.d.ts +72 -0
  36. package/dist/umd/DexieCloudOptions.d.ts +22 -0
  37. package/dist/umd/DexieCloudSyncOptions.d.ts +4 -0
  38. package/dist/umd/DexieCloudTable.d.ts +18 -0
  39. package/dist/umd/InvalidLicenseError.d.ts +5 -0
  40. package/dist/umd/Invite.d.ts +8 -0
  41. package/dist/umd/PermissionChecker.d.ts +15 -0
  42. package/dist/umd/TSON.d.ts +17 -0
  43. package/dist/umd/WSObservable.d.ts +68 -0
  44. package/dist/umd/associate.d.ts +1 -0
  45. package/dist/umd/authentication/AuthPersistedContext.d.ts +9 -0
  46. package/dist/umd/authentication/TokenErrorResponseError.d.ts +10 -0
  47. package/dist/umd/authentication/TokenExpiredError.d.ts +3 -0
  48. package/dist/umd/authentication/UNAUTHORIZED_USER.d.ts +2 -0
  49. package/dist/umd/authentication/authenticate.d.ts +20 -0
  50. package/dist/umd/authentication/currentUserObservable.d.ts +1 -0
  51. package/dist/umd/authentication/interactWithUser.d.ts +21 -0
  52. package/dist/umd/authentication/login.d.ts +6 -0
  53. package/dist/umd/authentication/logout.d.ts +5 -0
  54. package/dist/umd/authentication/otpFetchTokenCallback.d.ts +3 -0
  55. package/dist/umd/authentication/setCurrentUser.d.ts +14 -0
  56. package/dist/umd/authentication/waitUntil.d.ts +3 -0
  57. package/dist/umd/computeSyncState.d.ts +4 -0
  58. package/dist/umd/createSharedValueObservable.d.ts +3 -0
  59. package/dist/umd/currentUserEmitter.d.ts +3 -0
  60. package/dist/umd/db/DexieCloudDB.d.ts +59 -0
  61. package/dist/umd/db/entities/BaseRevisionMapEntry.d.ts +5 -0
  62. package/dist/umd/db/entities/EntityCommon.d.ts +5 -0
  63. package/dist/umd/db/entities/GuardedJob.d.ts +5 -0
  64. package/dist/umd/db/entities/Member.d.ts +19 -0
  65. package/dist/umd/db/entities/PersistedSyncState.d.ts +14 -0
  66. package/dist/umd/db/entities/Realm.d.ts +16 -0
  67. package/dist/umd/db/entities/Role.d.ts +11 -0
  68. package/dist/umd/db/entities/UserLogin.d.ts +22 -0
  69. package/dist/umd/default-ui/Dialog.d.ts +5 -0
  70. package/dist/umd/default-ui/LoginDialog.d.ts +3 -0
  71. package/dist/umd/default-ui/Styles.d.ts +3 -0
  72. package/dist/umd/default-ui/index.d.ts +24 -0
  73. package/dist/umd/dexie-cloud-addon.d.ts +3 -0
  74. package/dist/umd/dexie-cloud-addon.js +505 -388
  75. package/dist/umd/dexie-cloud-addon.js.map +1 -1
  76. package/dist/umd/dexie-cloud-client.d.ts +13 -0
  77. package/dist/umd/errors/HttpError.d.ts +5 -0
  78. package/dist/umd/extend-dexie-interface.d.ts +23 -0
  79. package/dist/umd/getGlobalRolesObservable.d.ts +5 -0
  80. package/dist/umd/getInternalAccessControlObservable.d.ts +12 -0
  81. package/dist/umd/getInvitesObservable.d.ts +23 -0
  82. package/dist/umd/getPermissionsLookupObservable.d.ts +16 -0
  83. package/dist/umd/getTiedRealmId.d.ts +2 -0
  84. package/dist/umd/helpers/BroadcastedAndLocalEvent.d.ts +8 -0
  85. package/dist/umd/helpers/CancelToken.d.ts +4 -0
  86. package/dist/umd/helpers/IS_SERVICE_WORKER.d.ts +1 -0
  87. package/dist/umd/helpers/SWBroadcastChannel.d.ts +12 -0
  88. package/dist/umd/helpers/allSettled.d.ts +1 -0
  89. package/dist/umd/helpers/bulkUpdate.d.ts +4 -0
  90. package/dist/umd/helpers/computeRealmSetHash.d.ts +2 -0
  91. package/dist/umd/helpers/date-constants.d.ts +5 -0
  92. package/dist/umd/helpers/dbOnClosed.d.ts +2 -0
  93. package/dist/umd/helpers/flatten.d.ts +1 -0
  94. package/dist/umd/helpers/getMutationTable.d.ts +1 -0
  95. package/dist/umd/helpers/getSyncableTables.d.ts +4 -0
  96. package/dist/umd/helpers/getTableFromMutationTable.d.ts +1 -0
  97. package/dist/umd/helpers/makeArray.d.ts +1 -0
  98. package/dist/umd/helpers/randomString.d.ts +1 -0
  99. package/dist/umd/helpers/resolveText.d.ts +16 -0
  100. package/dist/umd/helpers/throwVersionIncrementNeeded.d.ts +1 -0
  101. package/dist/umd/helpers/visibilityState.d.ts +1 -0
  102. package/dist/umd/isEagerSyncDisabled.d.ts +2 -0
  103. package/dist/umd/isFirefox.d.ts +1 -0
  104. package/dist/umd/isSafari.d.ts +2 -0
  105. package/dist/umd/mapValueObservable.d.ts +5 -0
  106. package/dist/umd/mergePermissions.d.ts +2 -0
  107. package/dist/umd/middleware-helpers/guardedTable.d.ts +11 -0
  108. package/dist/umd/middleware-helpers/idGenerationHelpers.d.ts +18 -0
  109. package/dist/umd/middlewares/createIdGenerationMiddleware.d.ts +3 -0
  110. package/dist/umd/middlewares/createImplicitPropSetterMiddleware.d.ts +3 -0
  111. package/dist/umd/middlewares/createMutationTrackingMiddleware.d.ts +17 -0
  112. package/dist/umd/middlewares/outstandingTransaction.d.ts +4 -0
  113. package/dist/umd/overrideParseStoresSpec.d.ts +4 -0
  114. package/dist/umd/performInitialSync.d.ts +4 -0
  115. package/dist/umd/permissions.d.ts +9 -0
  116. package/dist/umd/prodLog.d.ts +9 -0
  117. package/dist/umd/service-worker.d.ts +1 -0
  118. package/dist/umd/service-worker.js +2078 -322
  119. package/dist/umd/service-worker.js.map +1 -1
  120. package/dist/umd/sync/LocalSyncWorker.d.ts +7 -0
  121. package/dist/umd/sync/SyncRequiredError.d.ts +3 -0
  122. package/dist/umd/sync/applyServerChanges.d.ts +3 -0
  123. package/dist/umd/sync/connectWebSocket.d.ts +2 -0
  124. package/dist/umd/sync/encodeIdsForServer.d.ts +4 -0
  125. package/dist/umd/sync/extractRealm.d.ts +2 -0
  126. package/dist/umd/sync/getLatestRevisionsPerTable.d.ts +6 -0
  127. package/dist/umd/sync/getTablesToSyncify.d.ts +3 -0
  128. package/dist/umd/sync/isOnline.d.ts +1 -0
  129. package/dist/umd/sync/isSyncNeeded.d.ts +2 -0
  130. package/dist/umd/sync/listClientChanges.d.ts +9 -0
  131. package/dist/umd/sync/listSyncifiedChanges.d.ts +5 -0
  132. package/dist/umd/sync/messageConsumerIsReady.d.ts +2 -0
  133. package/dist/umd/sync/messagesFromServerQueue.d.ts +8 -0
  134. package/dist/umd/sync/modifyLocalObjectsWithNewUserId.d.ts +4 -0
  135. package/dist/umd/sync/myId.d.ts +1 -0
  136. package/dist/umd/sync/numUnsyncedMutations.d.ts +2 -0
  137. package/dist/umd/sync/old_startSyncingClientChanges.d.ts +39 -0
  138. package/dist/umd/sync/performGuardedJob.d.ts +2 -0
  139. package/dist/umd/sync/ratelimit.d.ts +3 -0
  140. package/dist/umd/sync/registerSyncEvent.d.ts +3 -0
  141. package/dist/umd/sync/sync.d.ts +15 -0
  142. package/dist/umd/sync/syncIfPossible.d.ts +5 -0
  143. package/dist/umd/sync/syncWithServer.d.ts +6 -0
  144. package/dist/umd/sync/triggerSync.d.ts +2 -0
  145. package/dist/umd/sync/updateBaseRevs.d.ts +5 -0
  146. package/dist/umd/types/DXCAlert.d.ts +25 -0
  147. package/dist/umd/types/DXCInputField.d.ts +11 -0
  148. package/dist/umd/types/DXCUserInteraction.d.ts +93 -0
  149. package/dist/umd/types/NewIdOptions.d.ts +3 -0
  150. package/dist/umd/types/SWMessageEvent.d.ts +3 -0
  151. package/dist/umd/types/SWSyncEvent.d.ts +4 -0
  152. package/dist/umd/types/SyncState.d.ts +9 -0
  153. package/dist/umd/types/TXExpandos.d.ts +11 -0
  154. package/dist/umd/updateSchemaFromOptions.d.ts +3 -0
  155. package/dist/umd/userIsActive.d.ts +7 -0
  156. package/dist/umd/verifyConfig.d.ts +2 -0
  157. package/dist/umd/verifySchema.d.ts +2 -0
  158. package/package.json +14 -48
  159. package/LICENSE +0 -202
  160. package/copydts.sh +0 -5
  161. package/dist/types/default-ui/LoginDialog.d.ts +0 -6
  162. package/dist/types/helpers/resolveText.d.ts +0 -2
  163. package/dist/types/sync/performGuardedJob.d.ts +0 -4
  164. package/dist/umd/dexie-cloud-addon.min.js +0 -2
  165. package/dist/umd/dexie-cloud-addon.min.js.map +0 -1
  166. package/dist/umd/service-worker.min.js +0 -2
  167. package/dist/umd/service-worker.min.js.map +0 -1
  168. /package/dist/{types → modern}/DISABLE_SERVICEWORKER_STRATEGY.d.ts +0 -0
  169. /package/dist/{types → modern}/DXCWebSocketStatus.d.ts +0 -0
  170. /package/dist/{types → modern}/DexieCloudSyncOptions.d.ts +0 -0
  171. /package/dist/{types → modern}/DexieCloudTable.d.ts +0 -0
  172. /package/dist/{types → modern}/Invite.d.ts +0 -0
  173. /package/dist/{types → modern}/PermissionChecker.d.ts +0 -0
  174. /package/dist/{types → modern}/WSObservable.d.ts +0 -0
  175. /package/dist/{types → modern}/associate.d.ts +0 -0
  176. /package/dist/{types → modern}/authentication/AuthPersistedContext.d.ts +0 -0
  177. /package/dist/{types → modern}/authentication/TokenExpiredError.d.ts +0 -0
  178. /package/dist/{types → modern}/authentication/UNAUTHORIZED_USER.d.ts +0 -0
  179. /package/dist/{types → modern}/authentication/currentUserObservable.d.ts +0 -0
  180. /package/dist/{types → modern}/authentication/login.d.ts +0 -0
  181. /package/dist/{types → modern}/authentication/otpFetchTokenCallback.d.ts +0 -0
  182. /package/dist/{types → modern}/authentication/setCurrentUser.d.ts +0 -0
  183. /package/dist/{types → modern}/computeSyncState.d.ts +0 -0
  184. /package/dist/{types → modern}/createSharedValueObservable.d.ts +0 -0
  185. /package/dist/{types → modern}/db/DexieCloudDB.d.ts +0 -0
  186. /package/dist/{types → modern}/db/entities/BaseRevisionMapEntry.d.ts +0 -0
  187. /package/dist/{types → modern}/db/entities/EntityCommon.d.ts +0 -0
  188. /package/dist/{types → modern}/db/entities/GuardedJob.d.ts +0 -0
  189. /package/dist/{types → modern}/db/entities/Member.d.ts +0 -0
  190. /package/dist/{types → modern}/db/entities/PersistedSyncState.d.ts +0 -0
  191. /package/dist/{types → modern}/db/entities/Realm.d.ts +0 -0
  192. /package/dist/{types → modern}/db/entities/Role.d.ts +0 -0
  193. /package/dist/{types → modern}/default-ui/Dialog.d.ts +0 -0
  194. /package/dist/{types → modern}/default-ui/Styles.d.ts +0 -0
  195. /package/dist/{types → modern}/default-ui/index.d.ts +0 -0
  196. /package/dist/{types → modern}/errors/HttpError.d.ts +0 -0
  197. /package/dist/{types → modern}/extend-dexie-interface.d.ts +0 -0
  198. /package/dist/{types → modern}/getGlobalRolesObservable.d.ts +0 -0
  199. /package/dist/{types → modern}/getInternalAccessControlObservable.d.ts +0 -0
  200. /package/dist/{types → modern}/getInvitesObservable.d.ts +0 -0
  201. /package/dist/{types → modern}/getPermissionsLookupObservable.d.ts +0 -0
  202. /package/dist/{types → modern}/getTiedRealmId.d.ts +0 -0
  203. /package/dist/{types → modern}/helpers/BroadcastedAndLocalEvent.d.ts +0 -0
  204. /package/dist/{types → modern}/helpers/CancelToken.d.ts +0 -0
  205. /package/dist/{types → modern}/helpers/IS_SERVICE_WORKER.d.ts +0 -0
  206. /package/dist/{types → modern}/helpers/SWBroadcastChannel.d.ts +0 -0
  207. /package/dist/{types → modern}/helpers/allSettled.d.ts +0 -0
  208. /package/dist/{types → modern}/helpers/bulkUpdate.d.ts +0 -0
  209. /package/dist/{types → modern}/helpers/computeRealmSetHash.d.ts +0 -0
  210. /package/dist/{types → modern}/helpers/date-constants.d.ts +0 -0
  211. /package/dist/{types → modern}/helpers/dbOnClosed.d.ts +0 -0
  212. /package/dist/{types → modern}/helpers/flatten.d.ts +0 -0
  213. /package/dist/{types → modern}/helpers/getMutationTable.d.ts +0 -0
  214. /package/dist/{types → modern}/helpers/getSyncableTables.d.ts +0 -0
  215. /package/dist/{types → modern}/helpers/getTableFromMutationTable.d.ts +0 -0
  216. /package/dist/{types → modern}/helpers/makeArray.d.ts +0 -0
  217. /package/dist/{types → modern}/helpers/randomString.d.ts +0 -0
  218. /package/dist/{types → modern}/helpers/throwVersionIncrementNeeded.d.ts +0 -0
  219. /package/dist/{types → modern}/helpers/visibilityState.d.ts +0 -0
  220. /package/dist/{types → modern}/isFirefox.d.ts +0 -0
  221. /package/dist/{types → modern}/isSafari.d.ts +0 -0
  222. /package/dist/{types → modern}/mapValueObservable.d.ts +0 -0
  223. /package/dist/{types → modern}/mergePermissions.d.ts +0 -0
  224. /package/dist/{types → modern}/middleware-helpers/guardedTable.d.ts +0 -0
  225. /package/dist/{types → modern}/middleware-helpers/idGenerationHelpers.d.ts +0 -0
  226. /package/dist/{types → modern}/middlewares/createIdGenerationMiddleware.d.ts +0 -0
  227. /package/dist/{types → modern}/middlewares/createImplicitPropSetterMiddleware.d.ts +0 -0
  228. /package/dist/{types → modern}/middlewares/outstandingTransaction.d.ts +0 -0
  229. /package/dist/{types → modern}/overrideParseStoresSpec.d.ts +0 -0
  230. /package/dist/{types → modern}/performInitialSync.d.ts +0 -0
  231. /package/dist/{types → modern}/permissions.d.ts +0 -0
  232. /package/dist/{types → modern}/service-worker.d.ts +0 -0
  233. /package/dist/{types → modern}/sync/LocalSyncWorker.d.ts +0 -0
  234. /package/dist/{types → modern}/sync/SyncRequiredError.d.ts +0 -0
  235. /package/dist/{types → modern}/sync/applyServerChanges.d.ts +0 -0
  236. /package/dist/{types → modern}/sync/connectWebSocket.d.ts +0 -0
  237. /package/dist/{types → modern}/sync/encodeIdsForServer.d.ts +0 -0
  238. /package/dist/{types → modern}/sync/extractRealm.d.ts +0 -0
  239. /package/dist/{types → modern}/sync/getLatestRevisionsPerTable.d.ts +0 -0
  240. /package/dist/{types → modern}/sync/getTablesToSyncify.d.ts +0 -0
  241. /package/dist/{types → modern}/sync/isOnline.d.ts +0 -0
  242. /package/dist/{types → modern}/sync/isSyncNeeded.d.ts +0 -0
  243. /package/dist/{types → modern}/sync/listClientChanges.d.ts +0 -0
  244. /package/dist/{types → modern}/sync/listSyncifiedChanges.d.ts +0 -0
  245. /package/dist/{types → modern}/sync/messageConsumerIsReady.d.ts +0 -0
  246. /package/dist/{types → modern}/sync/messagesFromServerQueue.d.ts +0 -0
  247. /package/dist/{types → modern}/sync/modifyLocalObjectsWithNewUserId.d.ts +0 -0
  248. /package/dist/{types → modern}/sync/myId.d.ts +0 -0
  249. /package/dist/{types → modern}/sync/numUnsyncedMutations.d.ts +0 -0
  250. /package/dist/{types → modern}/sync/old_startSyncingClientChanges.d.ts +0 -0
  251. /package/dist/{types → modern}/sync/registerSyncEvent.d.ts +0 -0
  252. /package/dist/{types → modern}/sync/syncIfPossible.d.ts +0 -0
  253. /package/dist/{types → modern}/sync/syncWithServer.d.ts +0 -0
  254. /package/dist/{types → modern}/sync/triggerSync.d.ts +0 -0
  255. /package/dist/{types → modern}/sync/updateBaseRevs.d.ts +0 -0
  256. /package/dist/{types → modern}/types/DXCInputField.d.ts +0 -0
  257. /package/dist/{types → modern}/types/NewIdOptions.d.ts +0 -0
  258. /package/dist/{types → modern}/types/SWMessageEvent.d.ts +0 -0
  259. /package/dist/{types → modern}/types/SWSyncEvent.d.ts +0 -0
  260. /package/dist/{types → modern}/types/TXExpandos.d.ts +0 -0
  261. /package/dist/{types → modern}/updateSchemaFromOptions.d.ts +0 -0
  262. /package/dist/{types → modern}/userIsActive.d.ts +0 -0
  263. /package/dist/{types → modern}/verifyConfig.d.ts +0 -0
  264. /package/dist/{types → modern}/verifySchema.d.ts +0 -0
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.0.1-beta.46, Sat Aug 05 2023
11
+ * Version 4.0.1-beta.48, Tue Oct 17 2023
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -17,7 +17,7 @@
17
17
  */
18
18
 
19
19
  import Dexie, { cmp, liveQuery } from 'dexie';
20
- import { Observable as Observable$1, BehaviorSubject, Subject, fromEvent, of, merge, Subscription as Subscription$1, from as from$1, throwError, combineLatest, map as map$1, share, timer as timer$1 } from 'rxjs';
20
+ import { firstValueFrom, from as from$1, filter as filter$1, Observable as Observable$1, BehaviorSubject, Subject, fromEvent, of, merge, Subscription as Subscription$1, throwError, combineLatest, map as map$1, share, timer as timer$1 } from 'rxjs';
21
21
 
22
22
  /******************************************************************************
23
23
  Copyright (c) Microsoft Corporation.
@@ -680,11 +680,7 @@ var timeoutProvider = {
680
680
 
681
681
  function reportUnhandledError(err) {
682
682
  timeoutProvider.setTimeout(function () {
683
- var onUnhandledError = config.onUnhandledError;
684
- if (onUnhandledError) {
685
- onUnhandledError(err);
686
- }
687
- else {
683
+ {
688
684
  throw err;
689
685
  }
690
686
  });
@@ -692,38 +688,8 @@ function reportUnhandledError(err) {
692
688
 
693
689
  function noop() { }
694
690
 
695
- var COMPLETE_NOTIFICATION = (function () { return createNotification('C', undefined, undefined); })();
696
- function errorNotification(error) {
697
- return createNotification('E', undefined, error);
698
- }
699
- function nextNotification(value) {
700
- return createNotification('N', value, undefined);
701
- }
702
- function createNotification(kind, value, error) {
703
- return {
704
- kind: kind,
705
- value: value,
706
- error: error,
707
- };
708
- }
709
-
710
- var context = null;
711
691
  function errorContext(cb) {
712
- if (config.useDeprecatedSynchronousErrorHandling) {
713
- var isRoot = !context;
714
- if (isRoot) {
715
- context = { errorThrown: false, error: null };
716
- }
717
- cb();
718
- if (isRoot) {
719
- var _a = context, errorThrown = _a.errorThrown, error = _a.error;
720
- context = null;
721
- if (errorThrown) {
722
- throw error;
723
- }
724
- }
725
- }
726
- else {
692
+ {
727
693
  cb();
728
694
  }
729
695
  }
@@ -748,26 +714,20 @@ var Subscriber = (function (_super) {
748
714
  return new SafeSubscriber(next, error, complete);
749
715
  };
750
716
  Subscriber.prototype.next = function (value) {
751
- if (this.isStopped) {
752
- handleStoppedNotification(nextNotification(value), this);
753
- }
717
+ if (this.isStopped) ;
754
718
  else {
755
719
  this._next(value);
756
720
  }
757
721
  };
758
722
  Subscriber.prototype.error = function (err) {
759
- if (this.isStopped) {
760
- handleStoppedNotification(errorNotification(err), this);
761
- }
723
+ if (this.isStopped) ;
762
724
  else {
763
725
  this.isStopped = true;
764
726
  this._error(err);
765
727
  }
766
728
  };
767
729
  Subscriber.prototype.complete = function () {
768
- if (this.isStopped) {
769
- handleStoppedNotification(COMPLETE_NOTIFICATION, this);
770
- }
730
+ if (this.isStopped) ;
771
731
  else {
772
732
  this.isStopped = true;
773
733
  this._complete();
@@ -887,10 +847,6 @@ function handleUnhandledError(error) {
887
847
  function defaultErrorHandler(err) {
888
848
  throw err;
889
849
  }
890
- function handleStoppedNotification(notification, subscriber) {
891
- var onStoppedNotification = config.onStoppedNotification;
892
- onStoppedNotification && timeoutProvider.setTimeout(function () { return onStoppedNotification(notification, subscriber); });
893
- }
894
850
  var EMPTY_OBSERVER = {
895
851
  closed: true,
896
852
  next: noop,
@@ -1917,58 +1873,6 @@ function tap(observerOrNext, error, complete) {
1917
1873
  identity;
1918
1874
  }
1919
1875
 
1920
- var TimeoutError = createErrorClass(function (_super) {
1921
- return function TimeoutErrorImpl(info) {
1922
- if (info === void 0) { info = null; }
1923
- _super(this);
1924
- this.message = 'Timeout has occurred';
1925
- this.name = 'TimeoutError';
1926
- this.info = info;
1927
- };
1928
- });
1929
- function timeout(config, schedulerArg) {
1930
- var _a = (isValidDate(config) ? { first: config } : typeof config === 'number' ? { each: config } : config), first = _a.first, each = _a.each, _b = _a.with, _with = _b === void 0 ? timeoutErrorFactory : _b, _c = _a.scheduler, scheduler = _c === void 0 ? schedulerArg !== null && schedulerArg !== void 0 ? schedulerArg : asyncScheduler : _c, _d = _a.meta, meta = _d === void 0 ? null : _d;
1931
- if (first == null && each == null) {
1932
- throw new TypeError('No timeout provided.');
1933
- }
1934
- return operate(function (source, subscriber) {
1935
- var originalSourceSubscription;
1936
- var timerSubscription;
1937
- var lastValue = null;
1938
- var seen = 0;
1939
- var startTimer = function (delay) {
1940
- timerSubscription = executeSchedule(subscriber, scheduler, function () {
1941
- try {
1942
- originalSourceSubscription.unsubscribe();
1943
- innerFrom(_with({
1944
- meta: meta,
1945
- lastValue: lastValue,
1946
- seen: seen,
1947
- })).subscribe(subscriber);
1948
- }
1949
- catch (err) {
1950
- subscriber.error(err);
1951
- }
1952
- }, delay);
1953
- };
1954
- originalSourceSubscription = source.subscribe(createOperatorSubscriber(subscriber, function (value) {
1955
- timerSubscription === null || timerSubscription === void 0 ? void 0 : timerSubscription.unsubscribe();
1956
- seen++;
1957
- subscriber.next((lastValue = value));
1958
- each > 0 && startTimer(each);
1959
- }, undefined, undefined, function () {
1960
- if (!(timerSubscription === null || timerSubscription === void 0 ? void 0 : timerSubscription.closed)) {
1961
- timerSubscription === null || timerSubscription === void 0 ? void 0 : timerSubscription.unsubscribe();
1962
- }
1963
- lastValue = null;
1964
- }));
1965
- !seen && startTimer(first != null ? (typeof first === 'number' ? first : +first - scheduler.now()) : each);
1966
- });
1967
- }
1968
- function timeoutErrorFactory(info) {
1969
- throw new TimeoutError(info);
1970
- }
1971
-
1972
1876
  //const hasSW = 'serviceWorker' in navigator;
1973
1877
  let hasComplainedAboutSyncEvent = false;
1974
1878
  function registerSyncEvent(db, purpose) {
@@ -2029,6 +1933,7 @@ function registerPeriodicSyncEvent(db) {
2029
1933
 
2030
1934
  function triggerSync(db, purpose) {
2031
1935
  if (db.cloud.usingServiceWorker) {
1936
+ console.debug('registering sync event');
2032
1937
  registerSyncEvent(db, purpose);
2033
1938
  }
2034
1939
  else {
@@ -2057,17 +1962,34 @@ const b64encode = typeof Buffer !== "undefined"
2057
1962
  }
2058
1963
  }
2059
1964
  : (b) => {
2060
- return btoa(String.fromCharCode.apply(null, ArrayBuffer.isView(b) ? b : new Uint8Array(b)));
1965
+ const u8a = ArrayBuffer.isView(b) ? b : new Uint8Array(b);
1966
+ const CHUNK_SIZE = 0x1000;
1967
+ const strs = [];
1968
+ for (let i = 0, l = u8a.length; i < l; i += CHUNK_SIZE) {
1969
+ const chunk = u8a.subarray(i, i + CHUNK_SIZE);
1970
+ strs.push(String.fromCharCode.apply(null, chunk));
1971
+ }
1972
+ return btoa(strs.join(""));
2061
1973
  };
2062
1974
 
1975
+ class TokenErrorResponseError extends Error {
1976
+ constructor({ title, message, messageCode, messageParams, }) {
1977
+ super(message);
1978
+ this.name = 'TokenErrorResponseError';
1979
+ this.title = title;
1980
+ this.messageCode = messageCode;
1981
+ this.messageParams = messageParams;
1982
+ }
1983
+ }
1984
+
2063
1985
  function interactWithUser(userInteraction, req) {
2064
1986
  return new Promise((resolve, reject) => {
2065
- const interactionProps = Object.assign(Object.assign({}, req), { onSubmit: (res) => {
1987
+ const interactionProps = Object.assign(Object.assign({ submitLabel: 'Submit', cancelLabel: 'Cancel' }, req), { onSubmit: (res) => {
2066
1988
  userInteraction.next(undefined);
2067
1989
  resolve(res);
2068
1990
  }, onCancel: () => {
2069
1991
  userInteraction.next(undefined);
2070
- reject(new Dexie.AbortError("User cancelled"));
1992
+ reject(new Dexie.AbortError('User cancelled'));
2071
1993
  } });
2072
1994
  userInteraction.next(interactionProps);
2073
1995
  // Start subscribing for external updates to db.cloud.userInteraction, and if so, cancel this request.
@@ -2086,7 +2008,9 @@ function alertUser(userInteraction, title, ...alerts) {
2086
2008
  type: 'message-alert',
2087
2009
  title,
2088
2010
  alerts,
2089
- fields: {}
2011
+ fields: {},
2012
+ submitLabel: 'OK',
2013
+ cancelLabel: null,
2090
2014
  });
2091
2015
  }
2092
2016
  function promptForEmail(userInteraction, title, emailHint) {
@@ -2145,22 +2069,48 @@ function promptForOTP(userInteraction, email, alert) {
2145
2069
  return otp;
2146
2070
  });
2147
2071
  }
2072
+ function confirmLogout(userInteraction, currentUserId, numUnsyncedChanges) {
2073
+ return __awaiter(this, void 0, void 0, function* () {
2074
+ const alerts = [
2075
+ {
2076
+ type: 'warning',
2077
+ messageCode: 'LOGOUT_CONFIRMATION',
2078
+ message: `{numUnsyncedChanges} unsynced changes will get lost!
2079
+ Logout anyway?`,
2080
+ messageParams: {
2081
+ currentUserId,
2082
+ numUnsyncedChanges: numUnsyncedChanges.toString(),
2083
+ }
2084
+ },
2085
+ ];
2086
+ return yield interactWithUser(userInteraction, {
2087
+ type: 'logout-confirmation',
2088
+ title: 'Confirm Logout',
2089
+ alerts,
2090
+ fields: {},
2091
+ submitLabel: 'Confirm logout',
2092
+ cancelLabel: 'Cancel'
2093
+ })
2094
+ .then(() => true)
2095
+ .catch(() => false);
2096
+ });
2097
+ }
2148
2098
 
2149
2099
  function loadAccessToken(db) {
2150
- var _a, _b;
2100
+ var _a, _b, _c;
2151
2101
  return __awaiter(this, void 0, void 0, function* () {
2152
2102
  const currentUser = yield db.getCurrentUser();
2153
2103
  const { accessToken, accessTokenExpiration, refreshToken, refreshTokenExpiration, claims, } = currentUser;
2154
2104
  if (!accessToken)
2155
- return;
2105
+ return null;
2156
2106
  const expTime = (_a = accessTokenExpiration === null || accessTokenExpiration === void 0 ? void 0 : accessTokenExpiration.getTime()) !== null && _a !== void 0 ? _a : Infinity;
2157
- if (expTime > Date.now()) {
2158
- return accessToken;
2107
+ if (expTime > Date.now() && (((_b = currentUser.license) === null || _b === void 0 ? void 0 : _b.status) || 'ok') === 'ok') {
2108
+ return currentUser;
2159
2109
  }
2160
2110
  if (!refreshToken) {
2161
2111
  throw new Error(`Refresh token missing`);
2162
2112
  }
2163
- const refreshExpTime = (_b = refreshTokenExpiration === null || refreshTokenExpiration === void 0 ? void 0 : refreshTokenExpiration.getTime()) !== null && _b !== void 0 ? _b : Infinity;
2113
+ const refreshExpTime = (_c = refreshTokenExpiration === null || refreshTokenExpiration === void 0 ? void 0 : refreshTokenExpiration.getTime()) !== null && _c !== void 0 ? _c : Infinity;
2164
2114
  if (refreshExpTime <= Date.now()) {
2165
2115
  throw new Error(`Refresh token has expired`);
2166
2116
  }
@@ -2168,8 +2118,10 @@ function loadAccessToken(db) {
2168
2118
  yield db.table('$logins').update(claims.sub, {
2169
2119
  accessToken: refreshedLogin.accessToken,
2170
2120
  accessTokenExpiration: refreshedLogin.accessTokenExpiration,
2121
+ claims: refreshedLogin.claims,
2122
+ license: refreshedLogin.license,
2171
2123
  });
2172
- return refreshedLogin.accessToken;
2124
+ return refreshedLogin;
2173
2125
  });
2174
2126
  }
2175
2127
  function authenticate(url, context, fetchToken, userInteraction, hints) {
@@ -2217,10 +2169,24 @@ function refreshAccessToken(url, login) {
2217
2169
  if (res.status !== 200)
2218
2170
  throw new Error(`RefreshToken: Status ${res.status} from ${url}/token`);
2219
2171
  const response = yield res.json();
2172
+ if (response.type === 'error') {
2173
+ throw new TokenErrorResponseError(response);
2174
+ }
2220
2175
  login.accessToken = response.accessToken;
2221
2176
  login.accessTokenExpiration = response.accessTokenExpiration
2222
2177
  ? new Date(response.accessTokenExpiration)
2223
2178
  : undefined;
2179
+ login.claims = response.claims;
2180
+ login.license = {
2181
+ type: response.userType,
2182
+ status: response.claims.license || 'ok',
2183
+ };
2184
+ if (response.evalDaysLeft != null) {
2185
+ login.license.evalDaysLeft = response.evalDaysLeft;
2186
+ }
2187
+ if (response.userValidUntil != null) {
2188
+ login.license.validUntil = new Date(response.userValidUntil);
2189
+ }
2224
2190
  return login;
2225
2191
  });
2226
2192
  }
@@ -2252,8 +2218,15 @@ function userAuthenticate(context, fetchToken, userInteraction, hints) {
2252
2218
  public_key: publicKeyPEM,
2253
2219
  hints,
2254
2220
  });
2221
+ if (response2.type === 'error') {
2222
+ throw new TokenErrorResponseError(response2);
2223
+ }
2255
2224
  if (response2.type !== 'tokens')
2256
2225
  throw new Error(`Unexpected response type from token endpoint: ${response2.type}`);
2226
+ /*const licenseStatus = response2.claims.license || 'ok';
2227
+ if (licenseStatus !== 'ok') {
2228
+ throw new InvalidLicenseError(licenseStatus);
2229
+ }*/
2257
2230
  context.accessToken = response2.accessToken;
2258
2231
  context.accessTokenExpiration = new Date(response2.accessTokenExpiration);
2259
2232
  context.refreshToken = response2.refreshToken;
@@ -2264,6 +2237,16 @@ function userAuthenticate(context, fetchToken, userInteraction, hints) {
2264
2237
  context.email = response2.claims.email;
2265
2238
  context.name = response2.claims.name;
2266
2239
  context.claims = response2.claims;
2240
+ context.license = {
2241
+ type: response2.userType,
2242
+ status: response2.claims.license || 'ok',
2243
+ };
2244
+ if (response2.evalDaysLeft != null) {
2245
+ context.license.evalDaysLeft = response2.evalDaysLeft;
2246
+ }
2247
+ if (response2.userValidUntil != null) {
2248
+ context.license.validUntil = new Date(response2.userValidUntil);
2249
+ }
2267
2250
  if (response2.alerts && response2.alerts.length > 0) {
2268
2251
  yield interactWithUser(userInteraction, {
2269
2252
  type: 'message-alert',
@@ -2275,12 +2258,36 @@ function userAuthenticate(context, fetchToken, userInteraction, hints) {
2275
2258
  return context;
2276
2259
  }
2277
2260
  catch (error) {
2278
- yield alertUser(userInteraction, 'Authentication Failed', {
2279
- type: 'error',
2280
- messageCode: 'GENERIC_ERROR',
2281
- message: `We're having a problem authenticating right now.`,
2282
- messageParams: {},
2283
- }).catch(() => { });
2261
+ if (error instanceof TokenErrorResponseError) {
2262
+ yield alertUser(userInteraction, error.title, {
2263
+ type: 'error',
2264
+ messageCode: error.messageCode,
2265
+ message: error.message,
2266
+ messageParams: {},
2267
+ });
2268
+ throw error;
2269
+ }
2270
+ let message = `We're having a problem authenticating right now.`;
2271
+ console.error(`Error authenticating`, error);
2272
+ if (error instanceof TypeError) {
2273
+ const isOffline = typeof navigator !== undefined && !navigator.onLine;
2274
+ if (isOffline) {
2275
+ message = `You seem to be offline. Please connect to the internet and try again.`;
2276
+ }
2277
+ else if (Dexie.debug || (typeof location !== 'undefined' && (location.hostname === 'localhost' || location.hostname === '127.0.0.1'))) {
2278
+ // The audience is most likely the developer. Suggest to whitelist the localhost origin:
2279
+ message = `Could not connect to server. Please verify that your origin '${location.origin}' is whitelisted using \`npx dexie-cloud whitelist\``;
2280
+ }
2281
+ else {
2282
+ message = `Could not connect to server. Please verify the connection.`;
2283
+ }
2284
+ yield alertUser(userInteraction, 'Authentication Failed', {
2285
+ type: 'error',
2286
+ messageCode: 'GENERIC_ERROR',
2287
+ message,
2288
+ messageParams: {},
2289
+ }).catch(() => { });
2290
+ }
2284
2291
  throw error;
2285
2292
  }
2286
2293
  });
@@ -2327,6 +2334,75 @@ class AuthPersistedContext {
2327
2334
  }
2328
2335
  }
2329
2336
 
2337
+ const UNAUTHORIZED_USER = {
2338
+ userId: "unauthorized",
2339
+ name: "Unauthorized",
2340
+ claims: {
2341
+ sub: "unauthorized",
2342
+ },
2343
+ lastLogin: new Date(0)
2344
+ };
2345
+ try {
2346
+ Object.freeze(UNAUTHORIZED_USER);
2347
+ Object.freeze(UNAUTHORIZED_USER.claims);
2348
+ }
2349
+ catch (_a) { }
2350
+
2351
+ function waitUntil(o, // Works with Dexie's liveQuery observables if we'd need that
2352
+ predicate) {
2353
+ return firstValueFrom(from$1(o).pipe(filter$1(predicate)));
2354
+ }
2355
+
2356
+ function logout(db) {
2357
+ return __awaiter(this, void 0, void 0, function* () {
2358
+ const numUnsyncedChanges = yield _logout(db);
2359
+ if (numUnsyncedChanges) {
2360
+ if (yield confirmLogout(db.cloud.userInteraction, db.cloud.currentUserId, numUnsyncedChanges)) {
2361
+ yield _logout(db, { deleteUnsyncedData: true });
2362
+ }
2363
+ else {
2364
+ throw new Error(`User cancelled logout due to unsynced changes`);
2365
+ }
2366
+ }
2367
+ });
2368
+ }
2369
+ function _logout(db, { deleteUnsyncedData = false } = {}) {
2370
+ return __awaiter(this, void 0, void 0, function* () {
2371
+ // Clear the database without emptying configuration options.
2372
+ const [numUnsynced, loggedOut] = yield db.dx.transaction('rw', db.dx.tables, (tx) => __awaiter(this, void 0, void 0, function* () {
2373
+ // @ts-ignore
2374
+ const idbtrans = tx.idbtrans;
2375
+ idbtrans.disableChangeTracking = true;
2376
+ idbtrans.disableAccessControl = true;
2377
+ const mutationTables = tx.storeNames.filter((tableName) => tableName.endsWith('_mutations'));
2378
+ // Count unsynced changes
2379
+ const unsyncCounts = yield Promise.all(mutationTables.map((mutationTable) => tx.table(mutationTable).count()));
2380
+ const sumUnSynced = unsyncCounts.reduce((a, b) => a + b, 0);
2381
+ if (sumUnSynced > 0 && !deleteUnsyncedData) {
2382
+ // Let caller ask user if they want to delete unsynced data.
2383
+ return [sumUnSynced, false];
2384
+ }
2385
+ // Either there are no unsynched changes, or caller provided flag deleteUnsynchedData = true.
2386
+ // Clear all tables except $jobs and $syncState (except the persisted sync state which is
2387
+ // also cleared because we're going to rebuild it using a fresh sync).
2388
+ db.$syncState.delete('syncState');
2389
+ for (const table of db.dx.tables) {
2390
+ if (table.name !== '$jobs' && table.name !== '$syncState') {
2391
+ table.clear();
2392
+ }
2393
+ }
2394
+ return [sumUnSynced, true];
2395
+ }));
2396
+ if (loggedOut) {
2397
+ // Wait for currentUser observable to emit UNAUTHORIZED_USER
2398
+ yield waitUntil(db.cloud.currentUser, (user) => user.userId === UNAUTHORIZED_USER.userId);
2399
+ // Then perform an initial sync
2400
+ yield db.cloud.sync({ purpose: 'pull', wait: true });
2401
+ }
2402
+ return numUnsynced;
2403
+ });
2404
+ }
2405
+
2330
2406
  class HttpError extends Error {
2331
2407
  constructor(res, message) {
2332
2408
  super(message || `${res.status} ${res.statusText}`);
@@ -2380,8 +2456,9 @@ function otpFetchTokenCallback(db) {
2380
2456
  throw new HttpError(res1, errMsg);
2381
2457
  }
2382
2458
  const response = yield res1.json();
2383
- if (response.type === 'tokens') {
2459
+ if (response.type === 'tokens' || response.type === 'error') {
2384
2460
  // Demo user request can get a "tokens" response right away
2461
+ // Error can also be returned right away.
2385
2462
  return response;
2386
2463
  }
2387
2464
  else if (tokenRequest.grant_type === 'otp') {
@@ -2413,12 +2490,6 @@ function otpFetchTokenCallback(db) {
2413
2490
  }
2414
2491
  if (res2.status !== 200) {
2415
2492
  const errMsg = yield res2.text();
2416
- yield alertUser(userInteraction, "OTP Authentication Failed", {
2417
- type: 'error',
2418
- messageCode: 'GENERIC_ERROR',
2419
- message: errMsg,
2420
- messageParams: {}
2421
- }).catch(() => { });
2422
2493
  throw new HttpError(res2, errMsg);
2423
2494
  }
2424
2495
  const response2 = yield res2.json();
@@ -2431,6 +2502,18 @@ function otpFetchTokenCallback(db) {
2431
2502
  };
2432
2503
  }
2433
2504
 
2505
+ /** A way to log to console in production without terser stripping out
2506
+ * it from the release bundle.
2507
+ * This should be used very rarely and only in places where it's
2508
+ * absolutely necessary to log something in production.
2509
+ *
2510
+ * @param level
2511
+ * @param args
2512
+ */
2513
+ function prodLog(level, ...args) {
2514
+ globalThis["con" + "sole"][level](...args);
2515
+ }
2516
+
2434
2517
  /** This function changes or sets the current user as requested.
2435
2518
  *
2436
2519
  * Use cases:
@@ -2457,102 +2540,76 @@ function setCurrentUser(db, user) {
2457
2540
  }));
2458
2541
  user.isLoggedIn = true;
2459
2542
  user.lastLogin = new Date();
2460
- yield user.save();
2461
- console.debug('Saved new user', user.email);
2462
- }));
2463
- yield new Promise((resolve) => {
2464
- if (db.cloud.currentUserId === user.userId) {
2465
- resolve(null);
2543
+ try {
2544
+ yield user.save();
2466
2545
  }
2467
- else {
2468
- const subscription = db.cloud.currentUser.subscribe((currentUser) => {
2469
- if (currentUser.userId === user.userId) {
2470
- subscription.unsubscribe();
2471
- resolve(null);
2546
+ catch (e) {
2547
+ try {
2548
+ if (e.name === 'DataCloneError') {
2549
+ // We've seen this buggy behavior in some browsers and in case it happens
2550
+ // again we really need to collect the details to understand what's going on.
2551
+ prodLog('debug', `Login context property names:`, Object.keys(user));
2552
+ prodLog('debug', `Login context property names:`, Object.keys(user));
2553
+ prodLog('debug', `Login context:`, user);
2554
+ prodLog('debug', `Login context JSON:`, JSON.stringify(user));
2472
2555
  }
2473
- });
2556
+ }
2557
+ catch (_a) { }
2558
+ throw e;
2474
2559
  }
2475
- });
2476
- // TANKAR!!!!
2477
- // V: Service workern kommer inte ha tillgång till currentUserObservable om den inte istället härrör från ett liveQuery.
2478
- // V: Samma med andra windows.
2479
- // V: Så kanske göra om den till att häröra från liveQuery som läser $logins.orderBy('lastLogin').last().
2480
- // V: Då bara vara medveten om:
2481
- // V: En sån observable börjar hämta data vid första subscribe
2482
- // V: Vi har inget "inital value" men kan emulera det till att vara ANONYMOUS_USER
2483
- // V: Om requireAuth är true, så borde db.on(ready) hålla databasen stängd för alla utom denna observable.
2484
- // V: Om inte så behöver den inte blocka.
2485
- // Andra tankar:
2486
- // * Man kan inte byta användare när man är offline. Skulle gå att flytta realms till undanstuff-tabell vid user-change.
2487
- // men troligen inte värt det.
2488
- // * Istället: sälj inte inte switch-user funktionalitet utan tala enbart om inloggat vs icke inloggat läge.
2489
- // * populate $logins med ANONYMOUS så att en påbörjad inloggning inte räknas, alternativt ha en boolean prop!
2490
- // Kanske bäst ha en boolean prop!
2491
- // * Alternativ switch-user funktionalitet:
2492
- // * DBCore gömmer data från realms man inte har tillgång till.
2493
- // * Cursor impl behövs också då.
2494
- // * Då blir det snabba user switch.
2495
- // * claims-settet som skickas till servern blir summan av alla claims. Då måste servern stödja multipla tokens eller
2496
- // att ens token är ett samlad.
2560
+ console.debug('Saved new user', user.email);
2561
+ }));
2562
+ yield waitUntil(db.cloud.currentUser, (currentUser) => currentUser.userId === user.userId);
2497
2563
  });
2498
2564
  }
2499
2565
 
2500
2566
  function login(db, hints) {
2567
+ var _a;
2501
2568
  return __awaiter(this, void 0, void 0, function* () {
2502
2569
  const currentUser = yield db.getCurrentUser();
2503
- if (currentUser.isLoggedIn) {
2504
- if (hints) {
2505
- if (hints.email && db.cloud.currentUser.value.email !== hints.email) {
2506
- throw new Error(`Must logout before changing user`);
2507
- }
2508
- if (hints.userId && db.cloud.currentUserId !== hints.userId) {
2509
- throw new Error(`Must logout before changing user`);
2510
- }
2570
+ const origUserId = currentUser.userId;
2571
+ if (currentUser.isLoggedIn && (!hints || (!hints.email && !hints.userId))) {
2572
+ const licenseStatus = ((_a = currentUser.license) === null || _a === void 0 ? void 0 : _a.status) || 'ok';
2573
+ if (licenseStatus === 'ok' && currentUser.accessToken && (!currentUser.accessTokenExpiration || currentUser.accessTokenExpiration.getTime() > Date.now())) {
2574
+ // Already authenticated according to given hints. And license is valid.
2575
+ return false;
2511
2576
  }
2512
- // Already authenticated according to given hints.
2513
- return false;
2577
+ if (currentUser.refreshToken && (!currentUser.refreshTokenExpiration || currentUser.refreshTokenExpiration.getTime() > Date.now())) {
2578
+ // Refresh the token
2579
+ yield loadAccessToken(db);
2580
+ return false;
2581
+ }
2582
+ // No refresh token - must re-authenticate:
2514
2583
  }
2515
2584
  const context = new AuthPersistedContext(db, {
2516
2585
  claims: {},
2517
2586
  lastLogin: new Date(0),
2518
2587
  });
2519
2588
  yield authenticate(db.cloud.options.databaseUrl, context, db.cloud.options.fetchTokens || otpFetchTokenCallback(db), db.cloud.userInteraction, hints);
2520
- try {
2521
- yield context.save();
2522
- }
2523
- catch (e) {
2524
- try {
2525
- if (e.name === 'DataCloneError') {
2526
- console.debug(`Login context property names:`, Object.keys(context));
2527
- console.debug(`Login context:`, context);
2528
- console.debug(`Login context JSON:`, JSON.stringify(context));
2529
- }
2530
- }
2531
- catch (_a) { }
2532
- throw e;
2533
- }
2589
+ if (origUserId !== UNAUTHORIZED_USER.userId && context.userId !== origUserId) {
2590
+ // User was logged in before, but now logged in as another user.
2591
+ yield logout(db);
2592
+ }
2593
+ /*try {
2594
+ await context.save();
2595
+ } catch (e) {
2596
+ try {
2597
+ if (e.name === 'DataCloneError') {
2598
+ console.debug(`Login context property names:`, Object.keys(context));
2599
+ console.debug(`Login context:`, context);
2600
+ console.debug(`Login context JSON:`, JSON.stringify(context));
2601
+ }
2602
+ } catch {}
2603
+ throw e;
2604
+ }*/
2534
2605
  yield setCurrentUser(db, context);
2535
2606
  // Make sure to resync as the new login will be authorized
2536
2607
  // for new realms.
2537
2608
  triggerSync(db, "pull");
2538
- return true;
2609
+ return context.userId !== origUserId;
2539
2610
  });
2540
2611
  }
2541
2612
 
2542
- const UNAUTHORIZED_USER = {
2543
- userId: "unauthorized",
2544
- name: "Unauthorized",
2545
- claims: {
2546
- sub: "unauthorized",
2547
- },
2548
- lastLogin: new Date(0)
2549
- };
2550
- try {
2551
- Object.freeze(UNAUTHORIZED_USER);
2552
- Object.freeze(UNAUTHORIZED_USER.claims);
2553
- }
2554
- catch (_a) { }
2555
-
2556
2613
  const swHolder = {};
2557
2614
  const swContainer = typeof self !== 'undefined' && self.document && // self.document is to verify we're not the SW ourself
2558
2615
  typeof navigator !== 'undefined' && navigator.serviceWorker;
@@ -3058,13 +3115,13 @@ var MapDef = {
3058
3115
  },
3059
3116
  };
3060
3117
 
3061
- const _global = typeof globalThis !== "undefined"
3118
+ const _global = typeof globalThis !== "undefined" // All modern environments (node, bun, deno, browser, workers, webview etc)
3062
3119
  ? globalThis
3063
- : typeof self !== "undefined"
3120
+ : typeof self !== "undefined" // Older browsers, workers, webview, window etc
3064
3121
  ? self
3065
- : typeof global === "undefined"
3122
+ : typeof global !== "undefined" // Older versions of node
3066
3123
  ? global
3067
- : undefined;
3124
+ : undefined; // Unsupported environment. No idea to return 'this' since we are in a module or a function scope anyway.
3068
3125
 
3069
3126
  var TypedArraysDefs = [
3070
3127
  "Int8Array",
@@ -3449,6 +3506,40 @@ function cloneChange(change, rewriteValues) {
3449
3506
  : change.muts.map((m) => (Object.assign(Object.assign({}, m), { keys: m.keys.slice() }))) });
3450
3507
  }
3451
3508
 
3509
+ // If we get Ratelimit-Limit and Ratelimit-Remaining where Ratelimit-Remaining is below
3510
+ // (Ratelimit-Limit / 2), we should delay the next sync by (Ratelimit-Reset / Ratelimit-Remaining)
3511
+ // seconds (given that there is a Ratelimit-Reset header).
3512
+ let syncRatelimitDelays = new WeakMap();
3513
+ function checkSyncRateLimitDelay(db) {
3514
+ var _a, _b;
3515
+ return __awaiter(this, void 0, void 0, function* () {
3516
+ const delatMilliseconds = ((_b = (_a = syncRatelimitDelays.get(db)) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0) - Date.now();
3517
+ if (delatMilliseconds > 0) {
3518
+ console.debug(`Stalling sync request ${delatMilliseconds} ms to spare ratelimits`);
3519
+ yield new Promise(resolve => setTimeout(resolve, delatMilliseconds));
3520
+ }
3521
+ });
3522
+ }
3523
+ function updateSyncRateLimitDelays(db, res) {
3524
+ const limit = res.headers.get('Ratelimit-Limit');
3525
+ const remaining = res.headers.get('Ratelimit-Remaining');
3526
+ const reset = res.headers.get('Ratelimit-Reset');
3527
+ if (limit && remaining && reset) {
3528
+ const limitNum = Number(limit);
3529
+ const remainingNum = Math.max(0, Number(remaining));
3530
+ const willResetInSeconds = Number(reset);
3531
+ if (remainingNum < limitNum / 2) {
3532
+ const delay = Math.ceil(willResetInSeconds / (remainingNum + 1));
3533
+ syncRatelimitDelays.set(db, new Date(Date.now() + delay * 1000));
3534
+ console.debug(`Sync ratelimit delay set to ${delay} seconds`);
3535
+ }
3536
+ else {
3537
+ syncRatelimitDelays.delete(db);
3538
+ console.debug(`Sync ratelimit delay cleared`);
3539
+ }
3540
+ }
3541
+ }
3542
+
3452
3543
  //import {BisonWebStreamReader} from "dreambase-library/dist/typeson-simplified/BisonWebStreamReader";
3453
3544
  function syncWithServer(changes, syncState, baseRevs, db, databaseUrl, schema, clientIdentity, currentUser) {
3454
3545
  return __awaiter(this, void 0, void 0, function* () {
@@ -3457,9 +3548,20 @@ function syncWithServer(changes, syncState, baseRevs, db, databaseUrl, schema, c
3457
3548
  //
3458
3549
  const headers = {
3459
3550
  Accept: 'application/json, application/x-bison, application/x-bison-stream',
3460
- 'Content-Type': 'application/tson'
3551
+ 'Content-Type': 'application/tson',
3461
3552
  };
3462
- const accessToken = yield loadAccessToken(db);
3553
+ const updatedUser = yield loadAccessToken(db);
3554
+ /*
3555
+ if (updatedUser?.license && changes.length > 0) {
3556
+ if (updatedUser.license.status === 'expired') {
3557
+ throw new Error(`License has expired`);
3558
+ }
3559
+ if (updatedUser.license.status === 'deactivated') {
3560
+ throw new Error(`License deactivated`);
3561
+ }
3562
+ }
3563
+ */
3564
+ const accessToken = updatedUser === null || updatedUser === void 0 ? void 0 : updatedUser.accessToken;
3463
3565
  if (accessToken) {
3464
3566
  headers.Authorization = `Bearer ${accessToken}`;
3465
3567
  }
@@ -3468,27 +3570,31 @@ function syncWithServer(changes, syncState, baseRevs, db, databaseUrl, schema, c
3468
3570
  dbID: syncState === null || syncState === void 0 ? void 0 : syncState.remoteDbId,
3469
3571
  clientIdentity,
3470
3572
  schema: schema || {},
3471
- lastPull: syncState ? {
3472
- serverRevision: syncState.serverRevision,
3473
- realms: syncState.realms,
3474
- inviteRealms: syncState.inviteRealms
3475
- } : undefined,
3573
+ lastPull: syncState
3574
+ ? {
3575
+ serverRevision: syncState.serverRevision,
3576
+ realms: syncState.realms,
3577
+ inviteRealms: syncState.inviteRealms,
3578
+ }
3579
+ : undefined,
3476
3580
  baseRevs,
3477
- changes: encodeIdsForServer(db.dx.core.schema, currentUser, changes)
3581
+ changes: encodeIdsForServer(db.dx.core.schema, currentUser, changes),
3478
3582
  };
3479
- console.debug("Sync request", syncRequest);
3583
+ console.debug('Sync request', syncRequest);
3480
3584
  db.syncStateChangedEvent.next({
3481
3585
  phase: 'pushing',
3482
3586
  });
3483
3587
  const res = yield fetch(`${databaseUrl}/sync`, {
3484
3588
  method: 'post',
3485
3589
  headers,
3486
- body: TSON.stringify(syncRequest)
3590
+ credentials: 'include',
3591
+ body: TSON.stringify(syncRequest),
3487
3592
  });
3488
3593
  //const contentLength = Number(res.headers.get('content-length'));
3489
3594
  db.syncStateChangedEvent.next({
3490
- phase: 'pulling'
3595
+ phase: 'pulling',
3491
3596
  });
3597
+ updateSyncRateLimitDelays(db, res);
3492
3598
  if (!res.ok) {
3493
3599
  throw new HttpError(res);
3494
3600
  }
@@ -3690,12 +3796,13 @@ const CURRENT_SYNC_WORKER = 'currentSyncWorker';
3690
3796
  function sync(db, options, schema, syncOptions) {
3691
3797
  return _sync
3692
3798
  .apply(this, arguments)
3693
- .then(() => {
3799
+ .then((result) => {
3694
3800
  if (!(syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)) { // && syncOptions?.purpose !== 'push') {
3695
3801
  db.syncStateChangedEvent.next({
3696
3802
  phase: 'in-sync',
3697
3803
  });
3698
3804
  }
3805
+ return result;
3699
3806
  })
3700
3807
  .catch((error) => __awaiter(this, void 0, void 0, function* () {
3701
3808
  if (syncOptions === null || syncOptions === void 0 ? void 0 : syncOptions.justCheckIfNeeded)
@@ -3910,6 +4017,7 @@ function _sync(db, options, schema, { isInitialSync, cancelToken, justCheckIfNee
3910
4017
  }));
3911
4018
  if (!done) {
3912
4019
  console.debug('MORE SYNC NEEDED. Go for it again!');
4020
+ yield checkSyncRateLimitDelay(db);
3913
4021
  return yield _sync(db, options, schema, { isInitialSync, cancelToken });
3914
4022
  }
3915
4023
  console.debug('SYNC DONE', { isInitialSync });
@@ -4046,6 +4154,8 @@ function MessagesFromServerConsumer(db) {
4046
4154
  yield db.table('$logins').update(user.userId, {
4047
4155
  accessToken: refreshedLogin.accessToken,
4048
4156
  accessTokenExpiration: refreshedLogin.accessTokenExpiration,
4157
+ claims: refreshedLogin.claims,
4158
+ license: refreshedLogin.license,
4049
4159
  });
4050
4160
  // Updating $logins will trigger emission of db.cloud.currentUser observable, which
4051
4161
  // in turn will lead to that connectWebSocket.ts will reconnect the socket with the
@@ -4614,6 +4724,13 @@ function writeLock(fn, prop) {
4614
4724
 
4615
4725
  const outstandingTransactions = new BehaviorSubject(new Set());
4616
4726
 
4727
+ function isEagerSyncDisabled(db) {
4728
+ var _a, _b, _c, _d;
4729
+ return (((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.disableEagerSync) ||
4730
+ ((_c = (_b = db.cloud.currentUser.value) === null || _b === void 0 ? void 0 : _b.license) === null || _c === void 0 ? void 0 : _c.status) !== 'ok' ||
4731
+ !((_d = db.cloud.options) === null || _d === void 0 ? void 0 : _d.databaseUrl));
4732
+ }
4733
+
4617
4734
  /** Tracks all mutations in the same transaction as the mutations -
4618
4735
  * so it is guaranteed that no mutation goes untracked - and if transaction
4619
4736
  * aborts, the mutations won't be tracked.
@@ -4622,7 +4739,7 @@ const outstandingTransactions = new BehaviorSubject(new Set());
4622
4739
  * changes to server and cleanup the tracked mutations once the server has
4623
4740
  * ackowledged that it got them.
4624
4741
  */
4625
- function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4742
+ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
4626
4743
  return {
4627
4744
  stack: 'dbcore',
4628
4745
  name: 'MutationTrackingMiddleware',
@@ -4633,7 +4750,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4633
4750
  try {
4634
4751
  mutTableMap = new Map(ordinaryTables.map((tbl) => [
4635
4752
  tbl.name,
4636
- core.table(`$${tbl.name}_mutations`)
4753
+ core.table(`$${tbl.name}_mutations`),
4637
4754
  ]));
4638
4755
  }
4639
4756
  catch (_a) {
@@ -4667,15 +4784,9 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4667
4784
  outstandingTransactions.next(outstandingTransactions.value);
4668
4785
  };
4669
4786
  const txComplete = () => {
4670
- var _a;
4671
- if (tx.mutationsAdded && ((_a = db.cloud.options) === null || _a === void 0 ? void 0 : _a.databaseUrl)) {
4672
- if (db.cloud.usingServiceWorker) {
4673
- console.debug('registering sync event');
4674
- registerSyncEvent(db, "push");
4675
- }
4676
- else {
4677
- db.localSyncEvent.next({ purpose: "push" });
4678
- }
4787
+ if (tx.mutationsAdded &&
4788
+ !isEagerSyncDisabled(db)) {
4789
+ triggerSync(db, 'push');
4679
4790
  }
4680
4791
  removeTransaction();
4681
4792
  };
@@ -4742,7 +4853,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4742
4853
  .query({
4743
4854
  query: { range: req.range, index: schema.primaryKey },
4744
4855
  trans: req.trans,
4745
- values: false
4856
+ values: false,
4746
4857
  })
4747
4858
  // Do a delete request instead, but keep the criteria info for the server to execute
4748
4859
  .then((res) => {
@@ -4750,7 +4861,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4750
4861
  type: 'delete',
4751
4862
  keys: res.result,
4752
4863
  trans: req.trans,
4753
- criteria: { index: null, range: req.range }
4864
+ criteria: { index: null, range: req.range },
4754
4865
  });
4755
4866
  })
4756
4867
  : mutateAndLog(req);
@@ -4758,7 +4869,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4758
4869
  function mutateAndLog(req) {
4759
4870
  const trans = req.trans;
4760
4871
  trans.mutationsAdded = true;
4761
- const { txid, currentUser: { userId } } = trans;
4872
+ const { txid, currentUser: { userId }, } = trans;
4762
4873
  const { type } = req;
4763
4874
  const opNo = ++trans.opCount;
4764
4875
  return table.mutate(req).then((res) => {
@@ -4779,7 +4890,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4779
4890
  keys,
4780
4891
  criteria: req.criteria,
4781
4892
  txid,
4782
- userId
4893
+ userId,
4783
4894
  }
4784
4895
  : req.type === 'add'
4785
4896
  ? {
@@ -4789,7 +4900,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4789
4900
  keys,
4790
4901
  txid,
4791
4902
  userId,
4792
- values
4903
+ values,
4793
4904
  }
4794
4905
  : req.criteria && req.changeSpec
4795
4906
  ? {
@@ -4801,7 +4912,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4801
4912
  criteria: req.criteria,
4802
4913
  changeSpec: req.changeSpec,
4803
4914
  txid,
4804
- userId
4915
+ userId,
4805
4916
  }
4806
4917
  : updates
4807
4918
  ? {
@@ -4812,7 +4923,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4812
4923
  keys: updates.keys,
4813
4924
  changeSpecs: updates.changeSpecs,
4814
4925
  txid,
4815
- userId
4926
+ userId,
4816
4927
  }
4817
4928
  : {
4818
4929
  type: 'upsert',
@@ -4821,7 +4932,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4821
4932
  keys,
4822
4933
  values,
4823
4934
  txid,
4824
- userId
4935
+ userId,
4825
4936
  };
4826
4937
  return keys.length > 0 || ('criteria' in req && req.criteria)
4827
4938
  ? mutsTable
@@ -4831,7 +4942,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db }) {
4831
4942
  });
4832
4943
  }
4833
4944
  } });
4834
- }
4945
+ },
4835
4946
  };
4836
4947
  }
4837
4948
 
@@ -5190,6 +5301,20 @@ class WSConnection extends Subscription$1 {
5190
5301
  }
5191
5302
  }
5192
5303
 
5304
+ class InvalidLicenseError extends Error {
5305
+ constructor(license) {
5306
+ super(license === 'expired'
5307
+ ? `License expired`
5308
+ : license === 'deactivated'
5309
+ ? `User deactivated`
5310
+ : 'Invalid license');
5311
+ this.name = 'InvalidLicenseError';
5312
+ if (license) {
5313
+ this.license = license;
5314
+ }
5315
+ }
5316
+ }
5317
+
5193
5318
  function sleep(ms) {
5194
5319
  return new Promise((resolve) => setTimeout(resolve, ms));
5195
5320
  }
@@ -5223,7 +5348,12 @@ function connectWebSocket(db) {
5223
5348
  function createObservable() {
5224
5349
  return db.cloud.persistedSyncState.pipe(filter((syncState) => syncState === null || syncState === void 0 ? void 0 : syncState.serverRevision), // Don't connect before there's no initial sync performed.
5225
5350
  take(1), // Don't continue waking up whenever syncState change
5226
- switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]))), switchMap(([userLogin, syncState]) => {
5351
+ switchMap((syncState) => db.cloud.currentUser.pipe(map((userLogin) => [userLogin, syncState]))), switchMap(([userLogin, syncState]) => {
5352
+ /*if (userLogin.license?.status && userLogin.license.status !== 'ok') {
5353
+ throw new InvalidLicenseError();
5354
+ }*/
5355
+ return userIsReallyActive.pipe(map((isActive) => [isActive ? userLogin : null, syncState]));
5356
+ }), switchMap(([userLogin, syncState]) => {
5227
5357
  if ((userLogin === null || userLogin === void 0 ? void 0 : userLogin.isLoggedIn) && !(syncState === null || syncState === void 0 ? void 0 : syncState.realms.includes(userLogin.userId))) {
5228
5358
  // We're in an in-between state when user is logged in but the user's realms are not yet synced.
5229
5359
  // Don't make this change reconnect the websocket just yet. Wait till syncState is updated
@@ -5252,14 +5382,20 @@ function connectWebSocket(db) {
5252
5382
  yield db.table('$logins').update(user.userId, {
5253
5383
  accessToken: refreshedLogin.accessToken,
5254
5384
  accessTokenExpiration: refreshedLogin.accessTokenExpiration,
5385
+ claims: refreshedLogin.claims,
5386
+ license: refreshedLogin.license,
5255
5387
  });
5256
5388
  })), switchMap(() => createObservable()));
5257
5389
  }
5258
5390
  else {
5259
- return throwError(error);
5391
+ return throwError(() => error);
5260
5392
  }
5261
5393
  }), catchError((error) => {
5262
5394
  db.cloud.webSocketStatus.next("error");
5395
+ if (error instanceof InvalidLicenseError) {
5396
+ // Don't retry. Just throw and don't try connect again.
5397
+ return throwError(() => error);
5398
+ }
5263
5399
  return from$1(waitAndReconnectWhenUserDoesSomething(error)).pipe(switchMap(() => createObservable()));
5264
5400
  }));
5265
5401
  }
@@ -5288,97 +5424,12 @@ function isSyncNeeded(db) {
5288
5424
  });
5289
5425
  }
5290
5426
 
5291
- const SECONDS = 1000;
5292
- const MINUTES = 60 * SECONDS;
5293
-
5294
- const myId = randomString(16);
5295
-
5296
- const GUARDED_JOB_HEARTBEAT = 1 * SECONDS;
5297
- const GUARDED_JOB_TIMEOUT = 1 * MINUTES;
5298
- function performGuardedJob(db, jobName, jobsTableName, job, { awaitRemoteJob } = {}) {
5299
- return __awaiter(this, void 0, void 0, function* () {
5300
- // Start working.
5301
- //
5302
- // Check if someone else is working on this already.
5303
- //
5304
- const jobsTable = db.table(jobsTableName);
5305
- function aquireLock() {
5306
- return __awaiter(this, void 0, void 0, function* () {
5307
- const gotTheLock = yield db.transaction('rw!', jobsTableName, () => __awaiter(this, void 0, void 0, function* () {
5308
- const currentWork = yield jobsTable.get(jobName);
5309
- if (!currentWork) {
5310
- // No one else is working. Let's record that we are.
5311
- yield jobsTable.add({
5312
- nodeId: myId,
5313
- started: new Date(),
5314
- heartbeat: new Date()
5315
- }, jobName);
5316
- return true;
5317
- }
5318
- else if (currentWork.heartbeat.getTime() <
5319
- Date.now() - GUARDED_JOB_TIMEOUT) {
5320
- console.warn(`Latest ${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!`);
5321
- // Now, take over!
5322
- yield jobsTable.put({
5323
- nodeId: myId,
5324
- started: new Date(),
5325
- heartbeat: new Date()
5326
- }, jobName);
5327
- return true;
5328
- }
5329
- return false;
5330
- }));
5331
- if (gotTheLock)
5332
- return true;
5333
- // Someone else took the job.
5334
- if (awaitRemoteJob) {
5335
- try {
5336
- const jobDoneObservable = from$1(liveQuery(() => jobsTable.get(jobName))).pipe(timeout(GUARDED_JOB_TIMEOUT), filter((job) => !job)); // Wait til job is not there anymore.
5337
- yield jobDoneObservable.toPromise();
5338
- return false;
5339
- }
5340
- catch (err) {
5341
- if (err.name !== 'TimeoutError') {
5342
- throw err;
5343
- }
5344
- // Timeout stopped us! Try aquire the lock now.
5345
- // It will likely succeed this time unless
5346
- // another client took it.
5347
- return yield aquireLock();
5348
- }
5349
- }
5350
- return false;
5351
- });
5352
- }
5353
- if (yield aquireLock()) {
5354
- // We own the lock entry and can do our job undisturbed.
5355
- // We're not within a transaction, but these type of locks
5356
- // spans over transactions.
5357
- // Start our heart beat during the job.
5358
- // Use setInterval to make sure we are updating heartbeat even during long-lived fetch calls.
5359
- const heartbeat = setInterval(() => {
5360
- jobsTable.update(jobName, (job) => {
5361
- if (job.nodeId === myId) {
5362
- job.heartbeat = new Date();
5363
- }
5364
- });
5365
- }, GUARDED_JOB_HEARTBEAT);
5366
- try {
5367
- return yield job();
5368
- }
5369
- finally {
5370
- // Stop heartbeat
5371
- clearInterval(heartbeat);
5372
- // Remove the persisted job state:
5373
- yield db.transaction('rw!', jobsTableName, () => __awaiter(this, void 0, void 0, function* () {
5374
- const currentWork = yield jobsTable.get(jobName);
5375
- if (currentWork && currentWork.nodeId === myId) {
5376
- yield jobsTable.delete(jobName);
5377
- }
5378
- }));
5379
- }
5380
- }
5381
- });
5427
+ function performGuardedJob(db, jobName, job) {
5428
+ if (typeof navigator === 'undefined' || !navigator.locks) {
5429
+ // No support for guarding jobs. IE11, node.js, etc.
5430
+ return job();
5431
+ }
5432
+ return navigator.locks.request(db.name + '|' + jobName, () => job());
5382
5433
  }
5383
5434
 
5384
5435
  const ongoingSyncs = new WeakMap();
@@ -5432,6 +5483,9 @@ function syncIfPossible(db, cloudOptions, cloudSchema, options) {
5432
5483
  function _syncIfPossible() {
5433
5484
  return __awaiter(this, void 0, void 0, function* () {
5434
5485
  try {
5486
+ // Check if should delay sync due to ratelimit:
5487
+ yield checkSyncRateLimitDelay(db);
5488
+ // Check if we need to lock the sync job. Not needed if we are the service worker.
5435
5489
  if (db.cloud.isServiceWorkerDB) {
5436
5490
  // We are the dedicated sync SW:
5437
5491
  yield sync(db, cloudOptions, cloudSchema, options);
@@ -5439,7 +5493,7 @@ function syncIfPossible(db, cloudOptions, cloudSchema, options) {
5439
5493
  else if (!db.cloud.usingServiceWorker) {
5440
5494
  // We use a flow that is better suited for the case when multiple workers want to
5441
5495
  // do the same thing.
5442
- yield performGuardedJob(db, CURRENT_SYNC_WORKER, '$jobs', () => sync(db, cloudOptions, cloudSchema, options));
5496
+ yield performGuardedJob(db, CURRENT_SYNC_WORKER, () => sync(db, cloudOptions, cloudSchema, options));
5443
5497
  }
5444
5498
  else {
5445
5499
  assert(false);
@@ -5461,19 +5515,29 @@ function syncIfPossible(db, cloudOptions, cloudSchema, options) {
5461
5515
  }
5462
5516
  }
5463
5517
 
5518
+ const SECONDS = 1000;
5519
+ const MINUTES = 60 * SECONDS;
5520
+
5464
5521
  function LocalSyncWorker(db, cloudOptions, cloudSchema) {
5465
5522
  let localSyncEventSubscription = null;
5466
5523
  //let syncHandler: ((event: Event) => void) | null = null;
5467
5524
  //let periodicSyncHandler: ((event: Event) => void) | null = null;
5468
5525
  let cancelToken = { cancelled: false };
5526
+ let retryHandle = null;
5527
+ let retryPurpose = null; // "pull" is superset of "push"
5469
5528
  function syncAndRetry(purpose, retryNum = 1) {
5470
5529
  // Use setTimeout() to get onto a clean stack and
5471
5530
  // break free from possible active transaction:
5472
5531
  setTimeout(() => {
5532
+ if (retryHandle)
5533
+ clearTimeout(retryHandle);
5534
+ const combPurpose = retryPurpose === 'pull' ? 'pull' : purpose;
5535
+ retryHandle = null;
5536
+ retryPurpose = null;
5473
5537
  syncIfPossible(db, cloudOptions, cloudSchema, {
5474
5538
  cancelToken,
5475
5539
  retryImmediatelyOnFetchError: true,
5476
- purpose,
5540
+ purpose: combPurpose,
5477
5541
  }).catch((e) => {
5478
5542
  console.error('error in syncIfPossible()', e);
5479
5543
  if (cancelToken.cancelled) {
@@ -5483,7 +5547,13 @@ function LocalSyncWorker(db, cloudOptions, cloudSchema) {
5483
5547
  // Mimic service worker sync event: retry 3 times
5484
5548
  // * first retry after 5 minutes
5485
5549
  // * second retry 15 minutes later
5486
- setTimeout(() => syncAndRetry(purpose, retryNum + 1), [0, 5, 15][retryNum] * MINUTES);
5550
+ const combinedPurpose = retryPurpose && retryPurpose === 'pull' ? 'pull' : purpose;
5551
+ const handle = setTimeout(() => syncAndRetry(combinedPurpose, retryNum + 1), [0, 5, 15][retryNum] * MINUTES);
5552
+ // Cancel the previous retryHandle if it exists to avoid scheduling loads of retries.
5553
+ if (retryHandle)
5554
+ clearTimeout(retryHandle);
5555
+ retryHandle = handle;
5556
+ retryPurpose = combinedPurpose;
5487
5557
  }
5488
5558
  });
5489
5559
  }, 0);
@@ -5550,10 +5620,12 @@ const Styles = {
5550
5620
  },
5551
5621
  Alert: {
5552
5622
  error: {
5553
- color: "red"
5623
+ color: "red",
5624
+ fontWeight: "bold"
5554
5625
  },
5555
5626
  warning: {
5556
- color: "yellow"
5627
+ color: "#f80",
5628
+ fontWeight: "bold"
5557
5629
  },
5558
5630
  info: {
5559
5631
  color: "black"
@@ -5594,7 +5666,8 @@ const Styles = {
5594
5666
  border: "3px solid #3d3d5d",
5595
5667
  borderRadius: "8px",
5596
5668
  boxShadow: "0 0 80px 10px #666",
5597
- width: "auto"
5669
+ width: "auto",
5670
+ fontFamily: "sans-serif",
5598
5671
  },
5599
5672
  Input: {
5600
5673
  height: "35px",
@@ -5615,11 +5688,26 @@ function Dialog({ children, className }) {
5615
5688
 
5616
5689
  var t,r,u,i,o=0,c=[],f=[],e=l$1.__b,a=l$1.__r,v=l$1.diffed,l=l$1.__c,m=l$1.unmount;function d(t,u){l$1.__h&&l$1.__h(r,t,o||u),o=0;var i=r.__H||(r.__H={__:[],__h:[]});return t>=i.__.length&&i.__.push({__V:f}),i.__[t]}function p(n){return o=1,y(z,n)}function y(n,u,i){var o=d(t++,2);if(o.t=n,!o.__c&&(o.__=[i?i(u):z(void 0,u),function(n){var t=o.__N?o.__N[0]:o.__[0],r=o.t(t,n);t!==r&&(o.__N=[r,o.__[1]],o.__c.setState({}));}],o.__c=r,!r.u)){r.u=!0;var c=r.shouldComponentUpdate;r.shouldComponentUpdate=function(n,t,r){if(!o.__c.__H)return !0;var u=o.__c.__H.__.filter(function(n){return n.__c});if(u.every(function(n){return !n.__N}))return !c||c.call(this,n,t,r);var i=!1;return u.forEach(function(n){if(n.__N){var t=n.__[0];n.__=n.__N,n.__N=void 0,t!==n.__[0]&&(i=!0);}}),!!i&&(!c||c.call(this,n,t,r))};}return o.__N||o.__}function s(u,i){var o=d(t++,4);!l$1.__s&&w(o.__H,i)&&(o.__=u,o.i=i,r.__h.push(o));}function _(n){return o=5,F(function(){return {current:n}},[])}function F(n,r){var u=d(t++,7);return w(u.__H,r)?(u.__V=n(),u.i=r,u.__h=n,u.__V):u.__}function b(){for(var t;t=c.shift();)if(t.__P&&t.__H)try{t.__H.__h.forEach(j),t.__H.__h.forEach(k),t.__H.__h=[];}catch(r){t.__H.__h=[],l$1.__e(r,t.__v);}}l$1.__b=function(n){r=null,e&&e(n);},l$1.__r=function(n){a&&a(n),t=0;var i=(r=n.__c).__H;i&&(u===r?(i.__h=[],r.__h=[],i.__.forEach(function(n){n.__N&&(n.__=n.__N),n.__V=f,n.__N=n.i=void 0;})):(i.__h.forEach(j),i.__h.forEach(k),i.__h=[])),u=r;},l$1.diffed=function(t){v&&v(t);var o=t.__c;o&&o.__H&&(o.__H.__h.length&&(1!==c.push(o)&&i===l$1.requestAnimationFrame||((i=l$1.requestAnimationFrame)||function(n){var t,r=function(){clearTimeout(u),g&&cancelAnimationFrame(t),setTimeout(n);},u=setTimeout(r,100);g&&(t=requestAnimationFrame(r));})(b)),o.__H.__.forEach(function(n){n.i&&(n.__H=n.i),n.__V!==f&&(n.__=n.__V),n.i=void 0,n.__V=f;})),u=r=null;},l$1.__c=function(t,r){r.some(function(t){try{t.__h.forEach(j),t.__h=t.__h.filter(function(n){return !n.__||k(n)});}catch(u){r.some(function(n){n.__h&&(n.__h=[]);}),r=[],l$1.__e(u,t.__v);}}),l&&l(t,r);},l$1.unmount=function(t){m&&m(t);var r,u=t.__c;u&&u.__H&&(u.__H.__.forEach(function(n){try{j(n);}catch(n){r=n;}}),r&&l$1.__e(r,u.__v));};var g="function"==typeof requestAnimationFrame;function j(n){var t=r,u=n.__c;"function"==typeof u&&(n.__c=void 0,u()),r=t;}function k(n){var t=r;n.__c=n.__(),r=t;}function w(n,t){return !n||n.length!==t.length||t.some(function(t,r){return t!==n[r]})}function z(n,t){return "function"==typeof t?t(n):t}
5617
5690
 
5691
+ /** Resolve a message template with parameters.
5692
+ *
5693
+ * Example:
5694
+ * resolveText({
5695
+ * message: "Hello {name}!",
5696
+ * messageCode: "HELLO",
5697
+ * messageParams: {name: "David"}
5698
+ * }) => "Hello David!"
5699
+ *
5700
+ * @param message Template message with {vars} in it.
5701
+ * @param messageCode Unique code for the message. Can be used for translation.
5702
+ * @param messageParams Parameters to be used in the message.
5703
+ * @returns A final message where parameters have been replaced with values.
5704
+ */
5618
5705
  function resolveText({ message, messageCode, messageParams }) {
5619
- return message.replace(/\{\w+\}/ig, n => messageParams[n.substr(1, n.length - 2)]);
5706
+ return message.replace(/\{\w+\}/ig, n => messageParams[n.substring(1, n.length - 1)]);
5620
5707
  }
5621
5708
 
5622
- function LoginDialog({ title, alerts, fields, onCancel, onSubmit, }) {
5709
+ const OTP_LENGTH = 8;
5710
+ function LoginDialog({ title, type, alerts, fields, submitLabel, cancelLabel, onCancel, onSubmit, }) {
5623
5711
  const [params, setParams] = p({});
5624
5712
  const firstFieldRef = _(null);
5625
5713
  s(() => { var _a; return (_a = firstFieldRef.current) === null || _a === void 0 ? void 0 : _a.focus(); }, []);
@@ -5627,21 +5715,34 @@ function LoginDialog({ title, alerts, fields, onCancel, onSubmit, }) {
5627
5715
  h(p$1, null,
5628
5716
  h("h3", { style: Styles.WindowHeader }, title),
5629
5717
  alerts.map((alert) => (h("p", { style: Styles.Alert[alert.type] }, resolveText(alert)))),
5630
- h("form", { onSubmit: ev => {
5718
+ h("form", { onSubmit: (ev) => {
5631
5719
  ev.preventDefault();
5632
5720
  onSubmit(params);
5633
- } }, Object.entries(fields).map(([fieldName, { type, label, placeholder }], idx) => (h("label", { style: Styles.Label },
5721
+ } }, Object.entries(fields).map(([fieldName, { type, label, placeholder }], idx) => (h("label", { style: Styles.Label, key: idx },
5634
5722
  label ? `${label}: ` : '',
5635
- h("input", { ref: idx === 0 ? firstFieldRef : undefined, type: type, name: fieldName, autoComplete: "on", style: Styles.Input, autoFocus: true, placeholder: placeholder, value: params[fieldName] || '', onInput: (ev) => { var _a; return setParams(Object.assign(Object.assign({}, params), { [fieldName]: valueTransformer(type, (_a = ev.target) === null || _a === void 0 ? void 0 : _a['value']) })); } })))))),
5723
+ h("input", { ref: idx === 0 ? firstFieldRef : undefined, type: type, name: fieldName, autoComplete: "on", style: Styles.Input, autoFocus: true, placeholder: placeholder, value: params[fieldName] || '', onInput: (ev) => {
5724
+ var _a;
5725
+ const value = valueTransformer(type, (_a = ev.target) === null || _a === void 0 ? void 0 : _a['value']);
5726
+ let updatedParams = Object.assign(Object.assign({}, params), { [fieldName]: value });
5727
+ setParams(updatedParams);
5728
+ if (type === 'otp' && (value === null || value === void 0 ? void 0 : value.trim().length) === OTP_LENGTH) {
5729
+ // Auto-submit when OTP is filled in.
5730
+ onSubmit(updatedParams);
5731
+ }
5732
+ } })))))),
5636
5733
  h("div", { style: Styles.ButtonsDiv },
5637
- h("button", { type: "submit", style: Styles.Button, onClick: () => onSubmit(params) }, "Submit"),
5638
- h("button", { style: Styles.Button, onClick: onCancel }, "Cancel"))));
5734
+ h(p$1, null,
5735
+ h("button", { type: "submit", style: Styles.Button, onClick: () => onSubmit(params) }, submitLabel),
5736
+ cancelLabel && (h("button", { style: Styles.Button, onClick: onCancel }, cancelLabel))))));
5639
5737
  }
5640
5738
  function valueTransformer(type, value) {
5641
5739
  switch (type) {
5642
- case "email": return value.toLowerCase();
5643
- case "otp": return value.toUpperCase();
5644
- default: return value;
5740
+ case 'email':
5741
+ return value.toLowerCase();
5742
+ case 'otp':
5743
+ return value.toUpperCase();
5744
+ default:
5745
+ return value;
5645
5746
  }
5646
5747
  }
5647
5748
 
@@ -5695,11 +5796,20 @@ function setupDefaultGUI(db) {
5695
5796
  }
5696
5797
  };
5697
5798
  }
5698
- // TODO:
5699
- /*
5700
- * Gjort klart allt kring user interaction förutom att mounta default-ui på ett element.
5701
- * Också att kolla först om nån annan subscribar och i så fall inte göra nåt.
5702
- */
5799
+
5800
+ function associate(factory) {
5801
+ const wm = new WeakMap();
5802
+ return (x) => {
5803
+ let rv = wm.get(x);
5804
+ if (!rv) {
5805
+ rv = factory(x);
5806
+ wm.set(x, rv);
5807
+ }
5808
+ return rv;
5809
+ };
5810
+ }
5811
+
5812
+ const getCurrentUserEmitter = associate((db) => new BehaviorSubject(UNAUTHORIZED_USER));
5703
5813
 
5704
5814
  function computeSyncState(db) {
5705
5815
  let _prevStatus = db.cloud.webSocketStatus.value;
@@ -5727,8 +5837,17 @@ function computeSyncState(db) {
5727
5837
  return combineLatest([
5728
5838
  lazyWebSocketStatus,
5729
5839
  db.syncStateChangedEvent.pipe(startWith({ phase: 'initial' })),
5840
+ getCurrentUserEmitter(db.dx._novip),
5730
5841
  userIsReallyActive
5731
- ]).pipe(map(([status, syncState, userIsActive]) => {
5842
+ ]).pipe(map(([status, syncState, user, userIsActive]) => {
5843
+ var _a;
5844
+ if (((_a = user.license) === null || _a === void 0 ? void 0 : _a.status) && user.license.status !== 'ok') {
5845
+ return {
5846
+ phase: 'offline',
5847
+ status: 'offline',
5848
+ license: user.license.status
5849
+ };
5850
+ }
5732
5851
  let { phase, error, progress } = syncState;
5733
5852
  let adjustedStatus = status;
5734
5853
  if (phase === 'error') {
@@ -5761,23 +5880,12 @@ function computeSyncState(db) {
5761
5880
  error,
5762
5881
  progress,
5763
5882
  status: isOnline ? adjustedStatus : 'offline',
5883
+ license: 'ok'
5764
5884
  };
5765
5885
  return retState;
5766
5886
  }));
5767
5887
  }
5768
5888
 
5769
- function associate(factory) {
5770
- const wm = new WeakMap();
5771
- return (x) => {
5772
- let rv = wm.get(x);
5773
- if (!rv) {
5774
- rv = factory(x);
5775
- wm.set(x, rv);
5776
- }
5777
- return rv;
5778
- };
5779
- }
5780
-
5781
5889
  function createSharedValueObservable(o, defaultValue) {
5782
5890
  let currentValue = defaultValue;
5783
5891
  let shared = from$1(o).pipe(map$1((x) => (currentValue = x)), share({ resetOnRefCountZero: () => timer$1(1000) }));
@@ -5819,8 +5927,6 @@ const getGlobalRolesObservable = associate((db) => {
5819
5927
  })), {});
5820
5928
  });
5821
5929
 
5822
- const getCurrentUserEmitter = associate((db) => new BehaviorSubject(UNAUTHORIZED_USER));
5823
-
5824
5930
  const getInternalAccessControlObservable = associate((db) => {
5825
5931
  return createSharedValueObservable(getCurrentUserEmitter(db._novip).pipe(switchMap((currentUser) => liveQuery(() => db.transaction('r', 'realms', 'members', () => Promise.all([
5826
5932
  db.members.where({ userId: currentUser.userId }).toArray(),
@@ -6110,7 +6216,7 @@ function dexieCloud(dexie) {
6110
6216
  });
6111
6217
  const syncComplete = new Subject();
6112
6218
  dexie.cloud = {
6113
- version: '4.0.1-beta.46',
6219
+ version: '{version}',
6114
6220
  options: Object.assign({}, DEFAULT_OPTIONS),
6115
6221
  schema: null,
6116
6222
  get currentUserId() {
@@ -6146,11 +6252,24 @@ function dexieCloud(dexie) {
6146
6252
  }
6147
6253
  updateSchemaFromOptions(dexie.cloud.schema, dexie.cloud.options);
6148
6254
  },
6255
+ logout({ force } = {}) {
6256
+ return __awaiter(this, void 0, void 0, function* () {
6257
+ force
6258
+ ? yield _logout(DexieCloudDB(dexie), { deleteUnsyncedData: true })
6259
+ : yield logout(DexieCloudDB(dexie));
6260
+ });
6261
+ },
6149
6262
  sync({ wait, purpose } = { wait: true, purpose: 'push' }) {
6263
+ var _a;
6150
6264
  return __awaiter(this, void 0, void 0, function* () {
6151
6265
  if (wait === undefined)
6152
6266
  wait = true;
6153
6267
  const db = DexieCloudDB(dexie);
6268
+ const licenseStatus = ((_a = db.cloud.currentUser.value.license) === null || _a === void 0 ? void 0 : _a.status) || 'ok';
6269
+ if (licenseStatus !== 'ok') {
6270
+ // Refresh access token to check for updated license
6271
+ yield loadAccessToken(db);
6272
+ }
6154
6273
  if (purpose === 'pull') {
6155
6274
  const syncState = db.cloud.persistedSyncState.value;
6156
6275
  triggerSync(db, purpose);
@@ -6354,7 +6473,9 @@ function dexieCloud(dexie) {
6354
6473
  db.syncStateChangedEvent.next({
6355
6474
  phase: 'not-in-sync',
6356
6475
  });
6357
- triggerSync(db, 'push');
6476
+ if (!isEagerSyncDisabled(db)) {
6477
+ triggerSync(db, 'push');
6478
+ }
6358
6479
  }), fromEvent(self, 'offline').subscribe(() => {
6359
6480
  console.debug('offline!');
6360
6481
  db.syncStateChangedEvent.next({
@@ -6371,7 +6492,7 @@ function dexieCloud(dexie) {
6371
6492
  });
6372
6493
  }
6373
6494
  }
6374
- dexieCloud.version = '4.0.1-beta.46';
6495
+ dexieCloud.version = '{version}';
6375
6496
  Dexie.Cloud = dexieCloud;
6376
6497
 
6377
6498
  export { dexieCloud as default, dexieCloud, getTiedObjectId, getTiedRealmId };