dexie-cloud-addon 4.4.3 → 4.4.4

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.
@@ -0,0 +1,23 @@
1
+ /** Error codes for server-side policy rejections.
2
+ *
3
+ * These are returned by the server as structured 403 JSON responses.
4
+ * Use a switch statement on `code` to display translated or custom messages.
5
+ */
6
+ export type PolicyErrorCode = 'USER_NOT_REGISTERED' | 'USER_NOT_ACCEPTED' | 'NO_SEATS_AVAILABLE' | 'USER_DEACTIVATED' | 'WEBHOOK_ERROR';
7
+ export interface PolicyErrorBody {
8
+ code: PolicyErrorCode;
9
+ message: string;
10
+ }
11
+ /** Thrown when the server rejects a user due to a policy rule.
12
+ *
13
+ * Unlike a generic 403, this error carries a machine-readable `code` so that
14
+ * the addon can convert it into a DXCUserInteraction challenge rather than
15
+ * simply throwing.
16
+ */
17
+ export declare class PolicyRejectionError extends Error {
18
+ readonly code: PolicyErrorCode;
19
+ constructor(body: PolicyErrorBody);
20
+ get name(): string;
21
+ }
22
+ /** Returns true when a plain fetch Response contains a structured PolicyError body. */
23
+ export declare function isPolicyErrorBody(value: unknown): value is PolicyErrorBody;
@@ -10,7 +10,7 @@ declare module 'dexie' {
10
10
  roles: Table<DBRealmRole, [string, string], Optional<DBRealmRole, 'owner'>>;
11
11
  }
12
12
  interface Table {
13
- newId(options: NewIdOptions): string;
13
+ newId(options?: NewIdOptions): string;
14
14
  idPrefix(): string;
15
15
  }
16
16
  interface DexieConstructor {
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.4.3, Sat Mar 21 2026
11
+ * Version 4.4.4, Wed Mar 25 2026
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -1845,9 +1845,10 @@ function alertUser(userInteraction, title, ...alerts) {
1845
1845
  cancelLabel: null,
1846
1846
  });
1847
1847
  }
1848
- function promptForEmail(userInteraction, title, emailHint) {
1848
+ function promptForEmail(userInteraction, title, emailHint, initialAlert) {
1849
1849
  return __awaiter(this, void 0, void 0, function* () {
1850
1850
  let email = emailHint || '';
1851
+ let firstPrompt = true;
1851
1852
  // Regular expression for email validation
1852
1853
  // ^[\w-+.]+@([\w-]+\.)+[\w-]{2,10}(\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$
1853
1854
  //
@@ -1870,19 +1871,21 @@ function promptForEmail(userInteraction, title, emailHint) {
1870
1871
  // and GLOBAL_WRITE permissions on the database. The email will be checked on the server before
1871
1872
  // allowing it and giving out a token for email2, using the OTP sent to email1.
1872
1873
  while (!email || !/^[\w-+.]+@([\w-]+\.)+[\w-]{2,10}(\sas\s[\w-+.]+@([\w-]+\.)+[\w-]{2,10})?$/.test(email)) {
1874
+ const alerts = [];
1875
+ if (firstPrompt && initialAlert)
1876
+ alerts.push(initialAlert);
1877
+ if (email)
1878
+ alerts.push({
1879
+ type: 'error',
1880
+ messageCode: 'INVALID_EMAIL',
1881
+ message: 'Please enter a valid email address',
1882
+ messageParams: {},
1883
+ });
1884
+ firstPrompt = false;
1873
1885
  email = (yield interactWithUser(userInteraction, {
1874
1886
  type: 'email',
1875
1887
  title,
1876
- alerts: email
1877
- ? [
1878
- {
1879
- type: 'error',
1880
- messageCode: 'INVALID_EMAIL',
1881
- message: 'Please enter a valid email address',
1882
- messageParams: {},
1883
- },
1884
- ]
1885
- : [],
1888
+ alerts,
1886
1889
  fields: {
1887
1890
  email: {
1888
1891
  type: 'email',
@@ -2025,6 +2028,29 @@ class OAuthRedirectError extends Error {
2025
2028
  }
2026
2029
  }
2027
2030
 
2031
+ /** Thrown when the server rejects a user due to a policy rule.
2032
+ *
2033
+ * Unlike a generic 403, this error carries a machine-readable `code` so that
2034
+ * the addon can convert it into a DXCUserInteraction challenge rather than
2035
+ * simply throwing.
2036
+ */
2037
+ class PolicyRejectionError extends Error {
2038
+ constructor(body) {
2039
+ super(body.message);
2040
+ this.code = body.code;
2041
+ }
2042
+ get name() {
2043
+ return 'PolicyRejectionError';
2044
+ }
2045
+ }
2046
+ /** Returns true when a plain fetch Response contains a structured PolicyError body. */
2047
+ function isPolicyErrorBody(value) {
2048
+ return (typeof value === 'object' &&
2049
+ value !== null &&
2050
+ typeof value.code === 'string' &&
2051
+ typeof value.message === 'string');
2052
+ }
2053
+
2028
2054
  const SECONDS = 1000;
2029
2055
  const MINUTES = 60 * SECONDS;
2030
2056
 
@@ -2199,6 +2225,10 @@ function userAuthenticate(context, fetchToken, userInteraction, hints) {
2199
2225
  if (error instanceof OAuthRedirectError || (error === null || error === void 0 ? void 0 : error.name) === 'OAuthRedirectError') {
2200
2226
  throw error; // Re-throw without logging
2201
2227
  }
2228
+ // Policy rejections have already been shown to the user as a challenge
2229
+ if (error instanceof PolicyRejectionError || (error === null || error === void 0 ? void 0 : error.name) === 'PolicyRejectionError') {
2230
+ throw error;
2231
+ }
2202
2232
  if (error instanceof TokenErrorResponseError) {
2203
2233
  yield alertUser(userInteraction, error.title, {
2204
2234
  type: 'error',
@@ -4677,13 +4707,8 @@ class OAuthError extends Error {
4677
4707
  */
4678
4708
  function exchangeOAuthCode(options) {
4679
4709
  return __awaiter(this, void 0, void 0, function* () {
4680
- const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'] } = options;
4681
- const tokenRequest = {
4682
- grant_type: 'authorization_code',
4683
- code,
4684
- public_key: publicKey,
4685
- scopes,
4686
- };
4710
+ const { databaseUrl, code, publicKey, scopes = ['ACCESS_DB'], intent } = options;
4711
+ const tokenRequest = Object.assign({ grant_type: 'authorization_code', code, public_key: publicKey, scopes }, (intent !== undefined ? { intent } : {}));
4687
4712
  try {
4688
4713
  const res = yield fetch(`${databaseUrl}/token`, {
4689
4714
  method: 'POST',
@@ -4694,6 +4719,20 @@ function exchangeOAuthCode(options) {
4694
4719
  if (!res.ok) {
4695
4720
  // Read body once as text to avoid stream consumption issues
4696
4721
  const bodyText = yield res.text().catch(() => res.statusText);
4722
+ // Check for structured policy rejection (403 with JSON body)
4723
+ if (res.status === 403) {
4724
+ try {
4725
+ const body = JSON.parse(bodyText);
4726
+ if (isPolicyErrorBody(body)) {
4727
+ throw new PolicyRejectionError(body);
4728
+ }
4729
+ }
4730
+ catch (e) {
4731
+ if (e instanceof PolicyRejectionError)
4732
+ throw e;
4733
+ // Fall through to generic error
4734
+ }
4735
+ }
4697
4736
  if (res.status === 400 || res.status === 401) {
4698
4737
  // Try to parse error response as JSON
4699
4738
  try {
@@ -4829,32 +4868,59 @@ function startOAuthRedirect(options) {
4829
4868
 
4830
4869
  function otpFetchTokenCallback(db) {
4831
4870
  const { userInteraction } = db.cloud;
4832
- return function otpAuthenticate(_a) {
4833
- return __awaiter(this, arguments, void 0, function* ({ public_key, hints }) {
4871
+ /**
4872
+ * Core authentication function.
4873
+ *
4874
+ * @param public_key - RSA public key PEM for the session
4875
+ * @param hints - Optional login hints from the caller
4876
+ * @param policyAlert - When set, a previous attempt was rejected by a server
4877
+ * policy rule. The alert is injected into the first
4878
+ * interactive prompt so the user sees why they were
4879
+ * rejected without changing any other flow logic.
4880
+ */
4881
+ function otpAuthenticate(_a, policyAlert_1) {
4882
+ return __awaiter(this, arguments, void 0, function* ({ public_key, hints }, policyAlert) {
4834
4883
  var _b, _c;
4835
4884
  let tokenRequest;
4836
4885
  const url = (_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.databaseUrl;
4837
4886
  if (!url)
4838
4887
  throw new Error(`No database URL given.`);
4888
+ const intent = hints === null || hints === void 0 ? void 0 : hints.intent;
4889
+ // ── Non-interactive paths ──────────────────────────────────────────────
4890
+ // These paths POST directly without prompting the user. If a policyAlert
4891
+ // exists (from a previous rejected attempt), show it with a message-alert
4892
+ // before proceeding so the user understands what happened.
4839
4893
  // Handle OAuth code exchange (from redirect/deep link flows)
4840
4894
  if ((hints === null || hints === void 0 ? void 0 : hints.oauthCode) && hints.provider) {
4841
- return yield exchangeOAuthCode({
4842
- databaseUrl: url,
4843
- code: hints.oauthCode,
4844
- publicKey: public_key,
4845
- scopes: ['ACCESS_DB'],
4846
- });
4895
+ try {
4896
+ return yield exchangeOAuthCode({
4897
+ databaseUrl: url,
4898
+ code: hints.oauthCode,
4899
+ publicKey: public_key,
4900
+ scopes: ['ACCESS_DB'],
4901
+ intent,
4902
+ });
4903
+ }
4904
+ catch (err) {
4905
+ if (err instanceof PolicyRejectionError) {
4906
+ return yield otpAuthenticate({ public_key, hints: undefined }, toPolicyAlert(err));
4907
+ }
4908
+ throw err;
4909
+ }
4847
4910
  }
4848
- // Handle OAuth provider login via redirect
4911
+ // Handle OAuth provider login via redirect (programmatic, no interaction)
4849
4912
  if (hints === null || hints === void 0 ? void 0 : hints.provider) {
4913
+ if (policyAlert) {
4914
+ // A previous OAuth attempt was rejected. Fall through to the
4915
+ // interactive flow — policyAlert will be shown inside the prompt.
4916
+ return yield otpAuthenticate({ public_key, hints: undefined }, policyAlert);
4917
+ }
4850
4918
  let resolvedRedirectUri = undefined;
4851
4919
  if (hints.redirectPath) {
4852
- // If redirectPath is absolute, use as is. If relative, resolve against current location
4853
4920
  if (/^https?:\/\//i.test(hints.redirectPath)) {
4854
4921
  resolvedRedirectUri = hints.redirectPath;
4855
4922
  }
4856
4923
  else if (typeof window !== 'undefined' && window.location) {
4857
- // Use URL constructor to resolve relative path
4858
4924
  resolvedRedirectUri = new URL(hints.redirectPath, window.location.href).toString();
4859
4925
  }
4860
4926
  else if (typeof location !== 'undefined' && location.href) {
@@ -4862,23 +4928,27 @@ function otpFetchTokenCallback(db) {
4862
4928
  }
4863
4929
  }
4864
4930
  initiateOAuthRedirect(db, hints.provider, resolvedRedirectUri);
4865
- // This function never returns - page navigates away
4866
4931
  throw new OAuthRedirectError(hints.provider);
4867
4932
  }
4933
+ // ── Interactive paths ──────────────────────────────────────────────────
4934
+ // policyAlert (if set) is injected into the first prompt so the user sees
4935
+ // it alongside the normal auth UI — no separate error screen needed.
4868
4936
  if ((hints === null || hints === void 0 ? void 0 : hints.grant_type) === 'demo') {
4869
- const demo_user = yield promptForEmail(userInteraction, 'Enter a demo user email', (hints === null || hints === void 0 ? void 0 : hints.email) || (hints === null || hints === void 0 ? void 0 : hints.userId));
4937
+ const demo_user = yield promptForEmail(userInteraction, 'Enter a demo user email', (hints === null || hints === void 0 ? void 0 : hints.email) || (hints === null || hints === void 0 ? void 0 : hints.userId), policyAlert);
4870
4938
  tokenRequest = {
4871
4939
  demo_user,
4872
4940
  grant_type: 'demo',
4873
4941
  scopes: ['ACCESS_DB'],
4874
- public_key
4942
+ public_key,
4875
4943
  };
4876
4944
  }
4877
4945
  else if ((hints === null || hints === void 0 ? void 0 : hints.otpId) && hints.otp) {
4878
- // User provided OTP ID and OTP code. This means that the OTP email
4879
- // has already gone out and the user may have clicked a magic link
4880
- // in the email with otp and otpId in query and the app has picked
4881
- // up those values and passed them to db.cloud.login().
4946
+ // Magic-link flow: OTP already supplied by the caller (e.g. from email).
4947
+ // No interaction show alert as a plain message if there is one.
4948
+ if (policyAlert) {
4949
+ yield alertUser(userInteraction, 'Access Denied', policyAlert);
4950
+ return yield otpAuthenticate({ public_key, hints: undefined }, policyAlert);
4951
+ }
4882
4952
  tokenRequest = {
4883
4953
  grant_type: 'otp',
4884
4954
  otp_id: hints.otpId,
@@ -4888,56 +4958,52 @@ function otpFetchTokenCallback(db) {
4888
4958
  };
4889
4959
  }
4890
4960
  else if ((hints === null || hints === void 0 ? void 0 : hints.grant_type) === 'otp' || (hints === null || hints === void 0 ? void 0 : hints.email)) {
4891
- // User explicitly requested OTP flow - skip provider selection
4892
- const email = (hints === null || hints === void 0 ? void 0 : hints.email) || (yield promptForEmail(userInteraction, 'Enter email address'));
4961
+ // Caller explicitly requested OTP skip provider selection.
4962
+ const email = (hints === null || hints === void 0 ? void 0 : hints.email) ||
4963
+ (yield promptForEmail(userInteraction, 'Enter email address', undefined, policyAlert));
4893
4964
  if (/@demo.local$/.test(email)) {
4894
4965
  tokenRequest = {
4895
4966
  demo_user: email,
4896
4967
  grant_type: 'demo',
4897
4968
  scopes: ['ACCESS_DB'],
4898
- public_key
4969
+ public_key,
4899
4970
  };
4900
4971
  }
4901
4972
  else {
4902
- tokenRequest = {
4903
- email,
4904
- grant_type: 'otp',
4905
- scopes: ['ACCESS_DB'],
4906
- };
4973
+ tokenRequest = Object.assign({ email, grant_type: 'otp', scopes: ['ACCESS_DB'] }, (intent !== undefined ? { intent } : {}));
4907
4974
  }
4908
4975
  }
4909
4976
  else {
4910
- // Check for available auth providers (OAuth + OTP)
4977
+ // Default path: check for OAuth providers, then fall back to OTP.
4911
4978
  const socialAuthEnabled = ((_c = db.cloud.options) === null || _c === void 0 ? void 0 : _c.socialAuth) !== false;
4912
4979
  const authProviders = yield fetchAuthProviders(url, socialAuthEnabled);
4913
- // If we have OAuth providers available, prompt for selection
4914
4980
  if (authProviders.providers.length > 0) {
4915
- const selection = yield promptForProvider(userInteraction, authProviders.providers, authProviders.otpEnabled, 'Sign in');
4981
+ const providerAlerts = policyAlert ? [policyAlert] : [];
4982
+ const selection = yield promptForProvider(userInteraction, authProviders.providers, authProviders.otpEnabled, 'Sign in', providerAlerts);
4916
4983
  if (selection.type === 'provider') {
4917
- // User selected an OAuth provider - initiate redirect
4918
4984
  initiateOAuthRedirect(db, selection.provider);
4919
- // This function never returns - page navigates away
4920
4985
  throw new OAuthRedirectError(selection.provider);
4921
4986
  }
4922
- // User chose OTP - continue with email prompt below
4987
+ // User chose OTP fall through to email prompt (no policyAlert here;
4988
+ // it was already shown in the provider prompt above).
4923
4989
  }
4924
- const email = yield promptForEmail(userInteraction, 'Enter email address', hints === null || hints === void 0 ? void 0 : hints.email);
4990
+ const email = yield promptForEmail(userInteraction, 'Enter email address', hints === null || hints === void 0 ? void 0 : hints.email,
4991
+ // Show policyAlert in email prompt only if there were no providers
4992
+ // (otherwise it was already shown in the provider selection above).
4993
+ authProviders.providers.length === 0 ? policyAlert : undefined);
4925
4994
  if (/@demo.local$/.test(email)) {
4926
4995
  tokenRequest = {
4927
4996
  demo_user: email,
4928
4997
  grant_type: 'demo',
4929
4998
  scopes: ['ACCESS_DB'],
4930
- public_key
4999
+ public_key,
4931
5000
  };
4932
5001
  }
4933
5002
  else {
4934
- tokenRequest = {
4935
- email,
4936
- grant_type: 'otp',
4937
- scopes: ['ACCESS_DB'],
4938
- };
5003
+ tokenRequest = Object.assign({ email, grant_type: 'otp', scopes: ['ACCESS_DB'] }, (intent !== undefined ? { intent } : {}));
4939
5004
  }
4940
5005
  }
5006
+ // ── POST /token (step 1) ───────────────────────────────────────────────
4941
5007
  const res1 = yield fetch(`${url}/token`, {
4942
5008
  body: JSON.stringify(tokenRequest),
4943
5009
  method: 'post',
@@ -4945,19 +5011,22 @@ function otpFetchTokenCallback(db) {
4945
5011
  mode: 'cors',
4946
5012
  });
4947
5013
  if (res1.status !== 200) {
5014
+ const alert = yield tryParsePolicyAlert(res1);
5015
+ if (alert) {
5016
+ // Policy rejection — restart the flow with the error injected.
5017
+ return yield otpAuthenticate({ public_key, hints: undefined }, alert);
5018
+ }
4948
5019
  const errMsg = yield res1.text();
4949
- yield alertUser(userInteraction, "Token request failed", {
5020
+ yield alertUser(userInteraction, 'Token request failed', {
4950
5021
  type: 'error',
4951
5022
  messageCode: 'GENERIC_ERROR',
4952
5023
  message: errMsg,
4953
- messageParams: {}
5024
+ messageParams: {},
4954
5025
  }).catch(() => { });
4955
5026
  throw new HttpError(res1, errMsg);
4956
5027
  }
4957
5028
  const response = yield res1.json();
4958
5029
  if (response.type === 'tokens' || response.type === 'error') {
4959
- // Demo user request can get a "tokens" response right away
4960
- // Error can also be returned right away.
4961
5030
  return response;
4962
5031
  }
4963
5032
  else if (tokenRequest.grant_type === 'otp' && 'email' in tokenRequest) {
@@ -4965,6 +5034,7 @@ function otpFetchTokenCallback(db) {
4965
5034
  throw new Error(`Unexpected response from ${url}/token`);
4966
5035
  const otp = yield promptForOTP(userInteraction, tokenRequest.email);
4967
5036
  const tokenRequest2 = Object.assign(Object.assign({}, tokenRequest), { otp: otp || '', otp_id: response.otp_id, public_key });
5037
+ // ── POST /token (step 2: OTP verification) ─────────────────────────
4968
5038
  let res2 = yield fetch(`${url}/token`, {
4969
5039
  body: JSON.stringify(tokenRequest2),
4970
5040
  method: 'post',
@@ -4977,7 +5047,7 @@ function otpFetchTokenCallback(db) {
4977
5047
  type: 'error',
4978
5048
  messageCode: 'INVALID_OTP',
4979
5049
  message: errorText,
4980
- messageParams: {}
5050
+ messageParams: {},
4981
5051
  });
4982
5052
  res2 = yield fetch(`${url}/token`, {
4983
5053
  body: JSON.stringify(tokenRequest2),
@@ -4987,6 +5057,10 @@ function otpFetchTokenCallback(db) {
4987
5057
  });
4988
5058
  }
4989
5059
  if (res2.status !== 200) {
5060
+ const alert = yield tryParsePolicyAlert(res2);
5061
+ if (alert) {
5062
+ return yield otpAuthenticate({ public_key, hints: undefined }, alert);
5063
+ }
4990
5064
  const errMsg = yield res2.text();
4991
5065
  throw new HttpError(res2, errMsg);
4992
5066
  }
@@ -4997,14 +5071,11 @@ function otpFetchTokenCallback(db) {
4997
5071
  throw new Error(`Unexpected response from ${url}/token`);
4998
5072
  }
4999
5073
  });
5000
- };
5074
+ }
5075
+ return ({ public_key, hints }) => otpAuthenticate({ public_key, hints });
5001
5076
  }
5002
5077
  /**
5003
5078
  * Initiates OAuth login via full page redirect.
5004
- *
5005
- * The page will navigate away to the OAuth provider. After authentication,
5006
- * the user is redirected back with a dxc-auth query parameter that is
5007
- * automatically detected by db.cloud.configure().
5008
5079
  */
5009
5080
  function initiateOAuthRedirect(db, provider, redirectUriOverride) {
5010
5081
  var _a, _b;
@@ -5014,17 +5085,44 @@ function initiateOAuthRedirect(db, provider, redirectUriOverride) {
5014
5085
  const redirectUri = redirectUriOverride ||
5015
5086
  ((_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.oauthRedirectUri) ||
5016
5087
  (typeof location !== 'undefined' ? location.href : undefined);
5017
- // CodeRabbit suggested to fail fast here, but the only situation where
5018
- // redirectUri would be undefined is in non-browser environments, and
5019
- // in those environments OAuth redirect does not make sense anyway
5020
- // and will fail fast in startOAuthRedirect().
5021
- // Start OAuth redirect flow - page navigates away
5022
5088
  startOAuthRedirect({
5023
5089
  databaseUrl: url,
5024
5090
  provider,
5025
5091
  redirectUri,
5026
5092
  });
5027
5093
  }
5094
+ /**
5095
+ * Converts a PolicyRejectionError to a DXCAlert for injection into prompts.
5096
+ */
5097
+ function toPolicyAlert(err) {
5098
+ return {
5099
+ type: 'error',
5100
+ messageCode: err.code,
5101
+ message: err.message,
5102
+ messageParams: {},
5103
+ };
5104
+ }
5105
+ /**
5106
+ * Tries to parse a failed Response as a structured PolicyError body.
5107
+ * Returns a DXCAlert if it is one, otherwise returns null.
5108
+ * Safe to call: reads body via clone() so the original Response is untouched.
5109
+ */
5110
+ function tryParsePolicyAlert(res) {
5111
+ return __awaiter(this, void 0, void 0, function* () {
5112
+ if (res.status !== 403)
5113
+ return null;
5114
+ try {
5115
+ const body = yield res.clone().json();
5116
+ if (isPolicyErrorBody(body)) {
5117
+ return toPolicyAlert(new PolicyRejectionError(body));
5118
+ }
5119
+ }
5120
+ catch (_a) {
5121
+ // Not JSON
5122
+ }
5123
+ return null;
5124
+ });
5125
+ }
5028
5126
 
5029
5127
  /** A way to log to console in production without terser stripping out
5030
5128
  * it from the release bundle.
@@ -6038,6 +6136,7 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
6038
6136
  return cursor.start(() => {
6039
6137
  const rawValue = cursor.value;
6040
6138
  if (!rawValue || !hasUnresolvedBlobRefs(rawValue)) {
6139
+ wrappedCursor.value = rawValue;
6041
6140
  onNext();
6042
6141
  return;
6043
6142
  }
@@ -6046,6 +6145,7 @@ function createBlobResolvingCursor(cursor, table, blobSavingQueue, db) {
6046
6145
  onNext();
6047
6146
  }, err => {
6048
6147
  console.error('Failed to resolve BlobRefs for cursor value:', err);
6148
+ wrappedCursor.value = rawValue;
6049
6149
  onNext();
6050
6150
  });
6051
6151
  });
@@ -8102,7 +8202,7 @@ function dexieCloud(dexie) {
8102
8202
  const downloading$ = createDownloadingState();
8103
8203
  dexie.cloud = {
8104
8204
  // @ts-ignore
8105
- version: "4.4.3",
8205
+ version: "4.4.4",
8106
8206
  options: Object.assign({}, DEFAULT_OPTIONS),
8107
8207
  schema: null,
8108
8208
  get currentUserId() {
@@ -8529,7 +8629,7 @@ function dexieCloud(dexie) {
8529
8629
  }
8530
8630
  }
8531
8631
  // @ts-ignore
8532
- dexieCloud.version = "4.4.3";
8632
+ dexieCloud.version = "4.4.4";
8533
8633
  Dexie.Cloud = dexieCloud;
8534
8634
 
8535
8635
  // In case the SW lives for a while, let it reuse already opened connections: