@lowdefy/client 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Client.js +54 -17
- package/dist/Context.js +30 -12
- package/dist/HtmlOverlay.js +127 -0
- package/dist/IconProvider.js +24 -0
- package/dist/MountEvents.js +3 -3
- package/dist/adapters/createRouter.js +9 -3
- package/dist/adapters/url.js +1 -7
- package/dist/auth/createAuthMethods.js +1034 -41
- package/dist/block/Block.js +6 -3
- package/dist/block/CategorySwitch.js +6 -0
- package/dist/block/Container.js +3 -0
- package/dist/block/InputContainer.js +8 -2
- package/dist/block/List.js +3 -0
- package/dist/block/LoadingBlock.js +6 -12
- package/dist/block/LoadingContainer.js +6 -1
- package/dist/block/LoadingList.js +6 -1
- package/dist/block/loadingBlockMethods.js +26 -0
- package/dist/claimCallerReload.js +38 -0
- package/dist/createAntdIconConfig.js +91 -0
- package/dist/createCallAPI.js +6 -2
- package/dist/createCallRequest.js +6 -2
- package/dist/createHandleError.js +21 -11
- package/dist/createIcon.js +138 -36
- package/dist/createPageLifecycleManager.js +172 -0
- package/dist/formatIconTitle.js +26 -0
- package/dist/getActiveLocale.js +27 -0
- package/dist/getContextKey.js +29 -0
- package/dist/getMessageIcon.js +43 -0
- package/dist/hasOtherRoles.js +30 -0
- package/dist/index.js +1 -0
- package/dist/initLowdefyContext.js +103 -4
- package/dist/isOtherCaller.js +29 -0
- package/dist/recordCallerStamp.js +31 -0
- package/dist/renderIconNodes.js +46 -0
- package/dist/request.js +74 -6
- package/dist/setLowdefyUser.js +32 -0
- package/dist/setupLink.js +19 -13
- package/dist/shouldReloadForAuthError.js +39 -0
- package/dist/shouldReloadForBuild.js +44 -0
- package/dist/shouldReloadForCaller.js +50 -0
- package/dist/storage/clearUserStorage.js +36 -0
- package/dist/storage/clearUserStorageOnOwnerChange.js +41 -0
- package/dist/storage/createStorage.js +48 -0
- package/dist/storage/listUserStorageKeys.js +36 -0
- package/dist/storage/readStorageItem.js +31 -0
- package/dist/storage/userStorageKey.js +24 -0
- package/dist/storage/userStoragePrefix.js +25 -0
- package/dist/useDarkMode.js +17 -4
- package/dist/useLocale.js +18 -5
- package/dist/websocket/createWebSocketClient.js +239 -100
- package/package.json +11 -10
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import clearUserStorage from './clearUserStorage.js';
|
|
16
|
+
import listUserStorageKeys from './listUserStorageKeys.js';
|
|
17
|
+
// The person signed in (or nobody) may not be the one who left data on this browser: another
|
|
18
|
+
// person signed in on it, or a session ended without Logout running. Their keys go before any
|
|
19
|
+
// block reads storage.
|
|
20
|
+
function clearUserStorageOnOwnerChange({ basePath, slug, userId, window }) {
|
|
21
|
+
let entries;
|
|
22
|
+
try {
|
|
23
|
+
entries = listUserStorageKeys({
|
|
24
|
+
basePath,
|
|
25
|
+
slug,
|
|
26
|
+
storage: window.localStorage
|
|
27
|
+
});
|
|
28
|
+
} catch {
|
|
29
|
+
// Storage the browser blocks holds nothing to clear.
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (entries.some((entry)=>entry.userId !== userId)) {
|
|
33
|
+
clearUserStorage({
|
|
34
|
+
basePath,
|
|
35
|
+
keepUserId: userId,
|
|
36
|
+
slug,
|
|
37
|
+
window
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export default clearUserStorageOnOwnerChange;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { appStorageKey } from '@lowdefy/helpers';
|
|
16
|
+
import clearUserStorage from './clearUserStorage.js';
|
|
17
|
+
import clearUserStorageOnOwnerChange from './clearUserStorageOnOwnerChange.js';
|
|
18
|
+
import userStorageKey from './userStorageKey.js';
|
|
19
|
+
// Storage keys for this app, reached by blocks and actions through their methods. getUserId is
|
|
20
|
+
// read on every call, so a user key always names the person signed in now.
|
|
21
|
+
function createStorage({ basePath, getUserId, slug, window }) {
|
|
22
|
+
return {
|
|
23
|
+
appKey: (name)=>appStorageKey({
|
|
24
|
+
basePath,
|
|
25
|
+
name,
|
|
26
|
+
slug
|
|
27
|
+
}),
|
|
28
|
+
clearUserStorage: ({ keepUserId })=>clearUserStorage({
|
|
29
|
+
basePath,
|
|
30
|
+
keepUserId,
|
|
31
|
+
slug,
|
|
32
|
+
window
|
|
33
|
+
}),
|
|
34
|
+
clearUserStorageOnOwnerChange: ()=>clearUserStorageOnOwnerChange({
|
|
35
|
+
basePath,
|
|
36
|
+
slug,
|
|
37
|
+
userId: getUserId(),
|
|
38
|
+
window
|
|
39
|
+
}),
|
|
40
|
+
userKey: (name)=>userStorageKey({
|
|
41
|
+
basePath,
|
|
42
|
+
name,
|
|
43
|
+
slug,
|
|
44
|
+
userId: getUserId()
|
|
45
|
+
})
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export default createStorage;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import userStoragePrefix from './userStoragePrefix.js';
|
|
16
|
+
// Every user key of this app in storage, with its owner's user id (null for an anonymous
|
|
17
|
+
// visitor). Keys are read before any is removed, since removing shifts storage indexes.
|
|
18
|
+
function listUserStorageKeys({ basePath, slug, storage }) {
|
|
19
|
+
const prefix = userStoragePrefix({
|
|
20
|
+
basePath,
|
|
21
|
+
slug
|
|
22
|
+
});
|
|
23
|
+
const entries = [];
|
|
24
|
+
for(let index = 0; index < storage.length; index += 1){
|
|
25
|
+
const key = storage.key(index);
|
|
26
|
+
if (key.startsWith(prefix)) {
|
|
27
|
+
const owner = key.slice(prefix.length, key.indexOf(':', prefix.length));
|
|
28
|
+
entries.push({
|
|
29
|
+
key,
|
|
30
|
+
userId: owner === '' ? null : decodeURIComponent(owner)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return entries;
|
|
35
|
+
}
|
|
36
|
+
export default listUserStorageKeys;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
// Reads key, moving a value left under legacyKey (written before keys were kept per app) to it
|
|
17
|
+
// the first time. Returns null when neither holds a value or the browser blocks storage.
|
|
18
|
+
function readStorageItem({ key, legacyKey, storage }) {
|
|
19
|
+
try {
|
|
20
|
+
const value = storage.getItem(key);
|
|
21
|
+
if (!type.isNone(value)) return value;
|
|
22
|
+
const legacyValue = storage.getItem(legacyKey);
|
|
23
|
+
if (type.isNone(legacyValue)) return null;
|
|
24
|
+
storage.setItem(key, legacyValue);
|
|
25
|
+
storage.removeItem(legacyKey);
|
|
26
|
+
return legacyValue;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export default readStorageItem;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import userStoragePrefix from './userStoragePrefix.js';
|
|
16
|
+
// The user id is encoded so the owner always ends at the next ":", whatever the id holds. An
|
|
17
|
+
// anonymous visitor owns the empty id.
|
|
18
|
+
function userStorageKey({ basePath, name, slug, userId }) {
|
|
19
|
+
return `${userStoragePrefix({
|
|
20
|
+
basePath,
|
|
21
|
+
slug
|
|
22
|
+
})}${encodeURIComponent(userId ?? '')}:${name}`;
|
|
23
|
+
}
|
|
24
|
+
export default userStorageKey;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { appStorageKey } from '@lowdefy/helpers';
|
|
16
|
+
// A person's data sits under one name in the app's namespace, then the owner's user id. Keys set
|
|
17
|
+
// with SetLocalStorage can not start with "lowdefy_", so no app key reads as a user key.
|
|
18
|
+
function userStoragePrefix({ basePath, slug }) {
|
|
19
|
+
return appStorageKey({
|
|
20
|
+
basePath,
|
|
21
|
+
name: 'lowdefy_user:',
|
|
22
|
+
slug
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export default userStoragePrefix;
|
package/dist/useDarkMode.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
16
16
|
import { theme as antdTheme } from 'antd';
|
|
17
|
+
import readStorageItem from './storage/readStorageItem.js';
|
|
17
18
|
const algorithmMap = {
|
|
18
19
|
default: antdTheme.defaultAlgorithm,
|
|
19
20
|
dark: antdTheme.darkAlgorithm,
|
|
@@ -67,11 +68,16 @@ function mergeComponents(shared, mode) {
|
|
|
67
68
|
});
|
|
68
69
|
return merged;
|
|
69
70
|
}
|
|
70
|
-
|
|
71
|
+
// storageKey is the app key the preference is kept under (see @lowdefy/helpers appStorageKey).
|
|
72
|
+
function useDarkMode({ antd, configDarkMode, storageKey }) {
|
|
71
73
|
const baseAlgorithm = antd?.algorithm;
|
|
72
74
|
const cleanAlgorithm = stripDarkFromAlgorithm(baseAlgorithm);
|
|
73
75
|
const [userPreference, setUserPreference] = useState(()=>{
|
|
74
|
-
return
|
|
76
|
+
return readStorageItem({
|
|
77
|
+
key: storageKey,
|
|
78
|
+
legacyKey: 'lowdefy_darkMode',
|
|
79
|
+
storage: window.localStorage
|
|
80
|
+
}) ?? 'system';
|
|
75
81
|
});
|
|
76
82
|
const [systemIsDark, setSystemIsDark] = useState(()=>{
|
|
77
83
|
return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ?? false;
|
|
@@ -85,10 +91,17 @@ function useDarkMode({ antd, configDarkMode }) {
|
|
|
85
91
|
return ()=>mql.removeEventListener('change', handler);
|
|
86
92
|
}, []);
|
|
87
93
|
const setPreference = useCallback((newPref)=>{
|
|
88
|
-
window.localStorage?.setItem(
|
|
94
|
+
window.localStorage?.setItem(storageKey, newPref);
|
|
95
|
+
// Set now, not on the next render: SetDarkMode updates the engine straight after, and
|
|
96
|
+
// _media: darkModePreference reads it then.
|
|
97
|
+
window.__lowdefy_darkModePreference = newPref;
|
|
89
98
|
setUserPreference(newPref);
|
|
90
|
-
}, [
|
|
99
|
+
}, [
|
|
100
|
+
storageKey
|
|
101
|
+
]);
|
|
91
102
|
window.__lowdefy_setDarkMode = setPreference;
|
|
103
|
+
// SetDarkMode, _media and the header toggles read the preference here, not from storage.
|
|
104
|
+
window.__lowdefy_darkModePreference = userPreference;
|
|
92
105
|
const isDark = resolveIsDark({
|
|
93
106
|
configDarkMode,
|
|
94
107
|
userPreference,
|
package/dist/useLocale.js
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
16
16
|
import dayjs from 'dayjs';
|
|
17
|
+
import antdEnUS from 'antd/locale/en_US.js';
|
|
18
|
+
import readStorageItem from './storage/readStorageItem.js';
|
|
19
|
+
// antd shows its en_US strings until an app locale loads, and with none configured.
|
|
20
|
+
const defaultAntdLocale = antdEnUS.default ?? antdEnUS;
|
|
17
21
|
function pickBest(candidates, supported) {
|
|
18
22
|
for (const candidate of candidates ?? []){
|
|
19
23
|
if (supported.includes(candidate)) return candidate;
|
|
@@ -40,12 +44,17 @@ async function loadAntdXLocale({ active, antdXLocaleLoaders }) {
|
|
|
40
44
|
const mod = await antdXLocaleLoaders[active]();
|
|
41
45
|
return mod?.default ?? mod;
|
|
42
46
|
}
|
|
43
|
-
|
|
47
|
+
// storageKey is the app key the preference is kept under (see @lowdefy/helpers appStorageKey).
|
|
48
|
+
function useLocale({ i18n, antdLocaleLoaders, antdXLocaleLoaders, dayjsLocaleMap, storageKey }) {
|
|
44
49
|
const supportedCodes = useMemo(()=>(i18n?.locales ?? []).map((l)=>l.code), [
|
|
45
50
|
i18n?.locales
|
|
46
51
|
]);
|
|
47
52
|
const [userPreference, setUserPreference] = useState(()=>{
|
|
48
|
-
return
|
|
53
|
+
return readStorageItem({
|
|
54
|
+
key: storageKey,
|
|
55
|
+
legacyKey: 'lowdefy_locale',
|
|
56
|
+
storage: window.localStorage
|
|
57
|
+
}) ?? 'auto';
|
|
49
58
|
});
|
|
50
59
|
const browserLocale = useMemo(()=>{
|
|
51
60
|
if (supportedCodes.length === 0) return undefined;
|
|
@@ -58,12 +67,14 @@ function useLocale({ i18n, antdLocaleLoaders, antdXLocaleLoaders, dayjsLocaleMap
|
|
|
58
67
|
]);
|
|
59
68
|
const setPreference = useCallback((code)=>{
|
|
60
69
|
if (code === 'auto') {
|
|
61
|
-
window.localStorage?.removeItem(
|
|
70
|
+
window.localStorage?.removeItem(storageKey);
|
|
62
71
|
} else {
|
|
63
|
-
window.localStorage?.setItem(
|
|
72
|
+
window.localStorage?.setItem(storageKey, code);
|
|
64
73
|
}
|
|
65
74
|
setUserPreference(code ?? 'auto');
|
|
66
|
-
}, [
|
|
75
|
+
}, [
|
|
76
|
+
storageKey
|
|
77
|
+
]);
|
|
67
78
|
window.__lowdefy_setLocale = setPreference;
|
|
68
79
|
const active = resolveActive({
|
|
69
80
|
userPreference,
|
|
@@ -75,6 +86,8 @@ function useLocale({ i18n, antdLocaleLoaders, antdXLocaleLoaders, dayjsLocaleMap
|
|
|
75
86
|
window.__lowdefy_supported_locales = i18n?.locales ?? [];
|
|
76
87
|
const [antdLocale, setAntdLocale] = useState(null);
|
|
77
88
|
const [antdXLocale, setAntdXLocale] = useState(null);
|
|
89
|
+
// The engine trace reads the antd strings in use as config text; it has no antd dependency.
|
|
90
|
+
window.__lowdefy_antd_locale = antdLocale ?? defaultAntdLocale;
|
|
78
91
|
useEffect(()=>{
|
|
79
92
|
let cancelled = false;
|
|
80
93
|
loadAntdLocale({
|