@abtnode/ux 1.16.14-beta-ab7f615e → 1.16.14-beta-cb53c14b
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/es/actions.js +97 -0
- package/es/analytics/card.js +92 -0
- package/es/analytics/chart.js +96 -0
- package/es/analytics/cpu.js +36 -0
- package/es/analytics/disk.js +111 -0
- package/es/analytics/memory.js +72 -0
- package/es/analytics/runtime.js +173 -0
- package/es/analytics/traffic.js +259 -0
- package/es/blocklet/access/config-access.js +307 -0
- package/es/blocklet/access/index.js +216 -0
- package/es/blocklet/actions.js +474 -0
- package/es/blocklet/add-cert.js +177 -0
- package/es/blocklet/agreement-app.js +21 -0
- package/es/blocklet/agreement.js +127 -0
- package/es/blocklet/app-avatar.js +57 -0
- package/es/blocklet/audit-logs.js +259 -0
- package/es/blocklet/blocklet-source.js +48 -0
- package/es/blocklet/bundle-avatar.js +64 -0
- package/es/blocklet/component/add.js +1308 -0
- package/es/blocklet/component/configuration.js +122 -0
- package/es/blocklet/component/delete.js +134 -0
- package/es/blocklet/component/environment.js +370 -0
- package/es/blocklet/component/index.js +975 -0
- package/es/blocklet/component/line.js +20 -0
- package/es/blocklet/component/navigation/locale-tabs.js +225 -0
- package/es/blocklet/component/navigation/navigation-actions.js +112 -0
- package/es/blocklet/component/navigation/navigation-dialog.js +607 -0
- package/es/blocklet/component/navigation/navigation-preview.js +101 -0
- package/es/blocklet/component/navigation/simple-select.js +124 -0
- package/es/blocklet/component/select-store.js +155 -0
- package/es/blocklet/component/setting.js +109 -0
- package/es/blocklet/component/sortable-tree.js +126 -0
- package/es/blocklet/component/space-connector.js +199 -0
- package/es/blocklet/component/space-selector.js +178 -0
- package/es/blocklet/component/start.js +101 -0
- package/es/blocklet/component/store-blocklet-list.js +200 -0
- package/es/blocklet/component/switch-control.js +57 -0
- package/es/blocklet/config-navigation.js +331 -0
- package/es/blocklet/configuration.js +603 -0
- package/es/blocklet/disk-info.js +75 -0
- package/es/blocklet/icons.js +18 -0
- package/es/blocklet/install-from-url.js +337 -0
- package/es/blocklet/log.js +90 -0
- package/es/blocklet/migration.js +149 -0
- package/es/blocklet/mode.js +19 -0
- package/es/blocklet/notification/email.js +257 -0
- package/es/blocklet/notification/index.js +49 -0
- package/es/blocklet/oauth/auth0.js +145 -0
- package/es/blocklet/oauth/common-settings.js +133 -0
- package/es/blocklet/oauth/federated-detail-dialog.js +175 -0
- package/es/blocklet/oauth/federated-invite-dialog.js +83 -0
- package/es/blocklet/oauth/federated-join-dialog.js +111 -0
- package/es/blocklet/oauth/federated-site-list.js +338 -0
- package/es/blocklet/oauth/federated.js +81 -0
- package/es/blocklet/oauth/index.js +69 -0
- package/es/blocklet/overview.js +293 -0
- package/es/blocklet/page-group.js +19 -0
- package/es/blocklet/preferences/app-sk.js +142 -0
- package/es/blocklet/preferences/index.js +305 -0
- package/es/blocklet/purchase/common.js +95 -0
- package/es/blocklet/purchase/component-purchase.js +237 -0
- package/es/blocklet/purchase/index.js +4 -0
- package/es/blocklet/router/action/add-domain-alias.js +167 -0
- package/es/blocklet/router/action/add-rule.js +211 -0
- package/es/blocklet/router/action/config-routing-rule.js +232 -0
- package/es/blocklet/router/action/delete-domain-alias.js +99 -0
- package/es/blocklet/router/action/delete-rule.js +108 -0
- package/es/blocklet/router/action/update-rule.js +209 -0
- package/es/blocklet/router/domain-actions.js +64 -0
- package/es/blocklet/router/domain-status.js +88 -0
- package/es/blocklet/router/rule-actions.js +66 -0
- package/es/blocklet/router/rule-list.js +190 -0
- package/es/blocklet/router/util.js +131 -0
- package/es/blocklet/runtime-info.js +68 -0
- package/es/blocklet/status.js +91 -0
- package/es/blocklet/storage/action.js +134 -0
- package/es/blocklet/storage/backups.js +241 -0
- package/es/blocklet/storage/connect-to.js +373 -0
- package/es/blocklet/storage/connected.js +198 -0
- package/es/blocklet/storage/delete.js +113 -0
- package/es/blocklet/storage/disconnect.js +243 -0
- package/es/blocklet/storage/index.js +19 -0
- package/es/blocklet/storage/item.js +558 -0
- package/es/blocklet/storage/preview-nft.js +286 -0
- package/es/blocklet/transfer-owner.js +198 -0
- package/es/blocklet/types.js +18 -0
- package/es/blocklet/util.js +145 -0
- package/es/blocklet/version.js +141 -0
- package/es/card-selector.js +134 -0
- package/es/certificate.js +105 -0
- package/es/chain.js +13 -0
- package/es/click-to-copy.js +22 -0
- package/es/confirm.js +149 -0
- package/es/contexts/audit-log.js +152 -0
- package/es/contexts/blocklet.js +10 -0
- package/es/contexts/deleting-blocklets.js +70 -0
- package/es/contexts/node.js +17 -0
- package/es/contexts/session.js +8 -0
- package/es/contexts/team.js +10 -0
- package/es/delete-confirm.js +121 -0
- package/es/did-address.js +46 -0
- package/es/dot.js +14 -0
- package/es/exchange-passport.js +102 -0
- package/es/form/form-select-input.js +184 -0
- package/es/form/form-text-input.js +178 -0
- package/es/form/form-wrapper.js +88 -0
- package/es/form/input-triggers.js +98 -0
- package/es/form/required.js +8 -0
- package/es/hooks/blocklet.js +229 -0
- package/es/hooks/confirm.js +90 -0
- package/es/hooks/mobile-width.js +11 -0
- package/es/hooks/url-evaluation.js +155 -0
- package/es/hooks/use-app-logo.js +16 -0
- package/es/hooks/use-backup-progress.js +31 -0
- package/es/hooks/use-blocklet-info-for-connect-did-spaces.js +50 -0
- package/es/hooks/use-bundle-logo.js +27 -0
- package/es/hooks/use-navigation.js +347 -0
- package/es/hooks/use-passport-id.js +14 -0
- package/es/hooks/use-subscription.js +22 -0
- package/es/icons/empty-space-nft.svg +59 -0
- package/es/icons/empty-spaces-nft.svg +58 -0
- package/es/icons/long-arrow.svg +5 -0
- package/es/icons/space-connected.svg +3 -0
- package/es/icons/space-disconnect.svg +3 -0
- package/es/index.js +3 -0
- package/es/invitation/invitation-app.js +58 -0
- package/es/invitation/invitation-login.js +68 -0
- package/es/invitation/invitation-passport.js +144 -0
- package/es/invitation/invitation-receive.js +138 -0
- package/es/invitation/invitation-success.js +93 -0
- package/es/invitation/invitation-user.js +90 -0
- package/es/invitation/invitation.js +90 -0
- package/es/issue-passport.js +142 -0
- package/es/launch-blocklet/content-layout.js +58 -0
- package/es/launch-blocklet/page-header.js +43 -0
- package/es/layout/addon.js +114 -0
- package/es/layout/feedback.js +55 -0
- package/es/locales/en.js +1534 -0
- package/es/locales/index.js +9 -0
- package/es/locales/zh.js +1537 -0
- package/es/logs/clock.js +11 -0
- package/es/logs/download.js +132 -0
- package/es/logs/log-terminal.js +253 -0
- package/es/lost-passport.js +452 -0
- package/es/nav-logo.js +219 -0
- package/es/passport-tag.js +43 -0
- package/es/permission.js +57 -0
- package/es/relative-time.js +53 -0
- package/es/result-message.js +11 -0
- package/es/schema-form/color-input.js +98 -0
- package/es/schema-form/common-prop-types.js +13 -0
- package/es/schema-form/index.js +215 -0
- package/es/schema-form/passport-input.js +54 -0
- package/es/schema-form/text-input.js +57 -0
- package/es/store/add.js +179 -0
- package/es/store/delete.js +96 -0
- package/es/store/item.js +76 -0
- package/es/subscription.js +144 -0
- package/es/table-icons.js +34 -0
- package/es/table.js +52 -0
- package/es/tag.js +21 -0
- package/es/team/members/actions.js +89 -0
- package/es/team/members/index.js +636 -0
- package/es/team/members/invitations.js +188 -0
- package/es/team/members/invite-member.js +208 -0
- package/es/team/members/issue-passport.js +152 -0
- package/es/team/members/member.js +408 -0
- package/es/team/members/passport-issuances.js +155 -0
- package/es/team/members/passports.js +364 -0
- package/es/team/members/toggle-user-approval.js +122 -0
- package/es/team/members/transfer-node.js +256 -0
- package/es/team/members/util.js +14 -0
- package/es/team/passports/color.js +126 -0
- package/es/team/passports/detail.js +312 -0
- package/es/team/passports/index.js +282 -0
- package/es/team/passports/mutate-role.js +198 -0
- package/es/team/passports/trusted-factories.js +221 -0
- package/es/team/passports/trusted-factory.js +343 -0
- package/es/team/passports/trusted-issuer.js +296 -0
- package/es/team/passports/trusted-issuers.js +226 -0
- package/es/team/search-input.js +46 -0
- package/es/team/styles/dialog.js +72 -0
- package/es/team/styles/list-header.js +31 -0
- package/es/util/api.js +6 -0
- package/es/util/constants.js +2 -0
- package/es/util/index.js +598 -0
- package/es/util/mode.js +4 -0
- package/es/util/space-gateway.js +51 -0
- package/es/util/spaces.js +151 -0
- package/es/who-can-access/config.js +38 -0
- package/es/wrap-locale.js +15 -0
- package/lib/blocklet/component/space-connector.js +1 -1
- package/lib/blocklet/component/space-selector.js +1 -1
- package/lib/blocklet/storage/backups.js +1 -1
- package/lib/blocklet/storage/connect-to.js +1 -1
- package/lib/blocklet/storage/connected.js +1 -1
- package/lib/blocklet/storage/disconnect.js +1 -1
- package/lib/blocklet/storage/index.js +1 -1
- package/lib/blocklet/storage/item.js +1 -1
- package/lib/invitation/invitation-receive.js +1 -1
- package/lib/team/passports/trusted-factory.js +1 -1
- package/package.json +81 -18
package/es/util/index.js
ADDED
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
2
|
+
/* eslint-disable implicit-arrow-linebreak */
|
|
3
|
+
/* eslint-disable import/prefer-default-export */
|
|
4
|
+
import { DEFAULT_IP_DOMAIN_SUFFIX, DEFAULT_DID_DOMAIN, DOMAIN_FOR_IP_SITE, DOMAIN_FOR_IP_SITE_REGEXP, DOMAIN_FOR_DEFAULT_SITE, DOMAIN_FOR_INTERNAL_SITE, ROLES, WELLKNOWN_SERVICE_PATH_PREFIX, WELLKNOWN_PING_PREFIX, IP, SLOT_FOR_IP_DNS_SITE, WELLKNOWN_PATH_PREFIX, WEB_WALLET_URL, BLOCKLET_STORE_API_PREFIX } from '@abtnode/constant';
|
|
5
|
+
import qs from 'querystring';
|
|
6
|
+
import isUrl from 'is-url';
|
|
7
|
+
import humanizeUrl from 'humanize-url';
|
|
8
|
+
import filesize from 'filesize';
|
|
9
|
+
import joinUrl from 'url-join';
|
|
10
|
+
import get from 'lodash/get';
|
|
11
|
+
import last from 'lodash/last';
|
|
12
|
+
import trimEnd from 'lodash/trimEnd';
|
|
13
|
+
import { BLOCKLET_MODES } from '@blocklet/constant';
|
|
14
|
+
import { evaluateURLs, isDidDomain, isIpEcho, isSlpDomain } from '@abtnode/util/lib/url-evaluation';
|
|
15
|
+
import checkAccessible from '@abtnode/util/lib/url-evaluation/check-accessible-browser';
|
|
16
|
+
import axios from '@abtnode/util/lib/axios';
|
|
17
|
+
import normalizePathPrefix from '@abtnode/util/lib/normalize-path-prefix';
|
|
18
|
+
import urlPathFriendly from '@blocklet/meta/lib/url-path-friendly';
|
|
19
|
+
import formatError from '@abtnode/util/lib/format-error';
|
|
20
|
+
import dayjs from '@abtnode/util/lib/dayjs';
|
|
21
|
+
export { formatError };
|
|
22
|
+
export function sleep(t) {
|
|
23
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
24
|
+
return new Promise(resolve => setTimeout(resolve, t));
|
|
25
|
+
}
|
|
26
|
+
export const validateDomain = (domain, locale = 'en') => {
|
|
27
|
+
if (!domain) {
|
|
28
|
+
return {
|
|
29
|
+
en: 'Site domain cannot be empty',
|
|
30
|
+
zh: '站点域名不能为空'
|
|
31
|
+
}[locale];
|
|
32
|
+
}
|
|
33
|
+
if (domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX)) {
|
|
34
|
+
return {
|
|
35
|
+
en: `Site domain cannot include ${DEFAULT_IP_DOMAIN_SUFFIX}`,
|
|
36
|
+
zh: `站点域名不能包含 ${DEFAULT_IP_DOMAIN_SUFFIX}`
|
|
37
|
+
}[locale];
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* get access url
|
|
44
|
+
* auto fix http/https, port, query
|
|
45
|
+
* docker friendly
|
|
46
|
+
*/
|
|
47
|
+
export function getAccessUrl(hostname, path = '', params = undefined) {
|
|
48
|
+
if (!hostname) {
|
|
49
|
+
return '';
|
|
50
|
+
}
|
|
51
|
+
let protocol = 'http';
|
|
52
|
+
if (window.location.protocol === 'https:') {
|
|
53
|
+
if (isIpEcho(hostname) || isSlpDomain(hostname) || isDidDomain(hostname)) {
|
|
54
|
+
protocol = 'https';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
let port = '';
|
|
58
|
+
const browserPort = Number(window.location.port);
|
|
59
|
+
if (process.env.NODE_ENV !== 'development' && browserPort && ![80, 443].includes(browserPort)) {
|
|
60
|
+
port = `:${browserPort}`;
|
|
61
|
+
}
|
|
62
|
+
const urlObj = new URL(`${protocol}://${hostname}${port}`);
|
|
63
|
+
urlObj.pathname = path;
|
|
64
|
+
const url = urlObj.href.replace(/\/$/, '');
|
|
65
|
+
if (!params || !Object.keys(params)) {
|
|
66
|
+
return url;
|
|
67
|
+
}
|
|
68
|
+
const searchParams = new URLSearchParams();
|
|
69
|
+
Object.keys(params).forEach(key => {
|
|
70
|
+
searchParams.append(key, params[key]);
|
|
71
|
+
});
|
|
72
|
+
return `${url}${urlObj.pathname === '/' ? '/' : ''}?${searchParams.toString()}`;
|
|
73
|
+
}
|
|
74
|
+
export function getBlockletUrl({
|
|
75
|
+
blocklet,
|
|
76
|
+
domain: inputDomain,
|
|
77
|
+
mountPoint: inputMountPoint,
|
|
78
|
+
params
|
|
79
|
+
} = {}) {
|
|
80
|
+
const {
|
|
81
|
+
site
|
|
82
|
+
} = blocklet;
|
|
83
|
+
if (!site) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const domain = inputDomain || (site.domainAliases || [])[0];
|
|
87
|
+
if (!domain) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
let mountPoint = inputMountPoint;
|
|
91
|
+
if (!mountPoint) {
|
|
92
|
+
const rule = site.rules.filter(x => !x.from.pathPrefix.startsWith(WELLKNOWN_PATH_PREFIX))[0];
|
|
93
|
+
mountPoint = rule ? rule.from.pathPrefix : '/';
|
|
94
|
+
}
|
|
95
|
+
return getAccessUrl(domain.value, mountPoint, params);
|
|
96
|
+
}
|
|
97
|
+
export function getBlockletUrls({
|
|
98
|
+
blocklet,
|
|
99
|
+
mountPoint: inputMountPoint,
|
|
100
|
+
params
|
|
101
|
+
} = {}) {
|
|
102
|
+
const {
|
|
103
|
+
site
|
|
104
|
+
} = blocklet;
|
|
105
|
+
if (!site) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
const domains = site.domainAliases || [];
|
|
109
|
+
if (!domains.length) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
let mountPoint = inputMountPoint;
|
|
113
|
+
if (!mountPoint) {
|
|
114
|
+
const rules = site.rules.filter(x => !x.from.pathPrefix.startsWith(WELLKNOWN_PATH_PREFIX));
|
|
115
|
+
let rule = rules[0];
|
|
116
|
+
if (rule?.from?.pathPrefix !== '/') {
|
|
117
|
+
const rootRule = rules.find(x => x.from?.pathPrefix === '/');
|
|
118
|
+
if (rootRule) {
|
|
119
|
+
rule = rootRule;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
mountPoint = normalizePathPrefix(rule?.from?.pathPrefix || '/');
|
|
123
|
+
}
|
|
124
|
+
return domains.map(domain => getAccessUrl(domain.value, mountPoint, params));
|
|
125
|
+
}
|
|
126
|
+
export function getExplorerLink(chainHost, did, type) {
|
|
127
|
+
if (!chainHost) return undefined;
|
|
128
|
+
try {
|
|
129
|
+
const chainUrl = new URL(chainHost);
|
|
130
|
+
switch (type) {
|
|
131
|
+
case 'asset':
|
|
132
|
+
chainUrl.pathname = `/explorer/assets/${did}`;
|
|
133
|
+
break;
|
|
134
|
+
case 'account':
|
|
135
|
+
chainUrl.pathname = `/explorer/accounts/${did}`;
|
|
136
|
+
break;
|
|
137
|
+
case 'tx':
|
|
138
|
+
chainUrl.pathname = `/explorer/txs/${did}`;
|
|
139
|
+
break;
|
|
140
|
+
case 'token':
|
|
141
|
+
chainUrl.pathname = `/explorer/tokens/${did}`;
|
|
142
|
+
break;
|
|
143
|
+
case 'factory':
|
|
144
|
+
chainUrl.pathname = `/explorer/factories/${did}`;
|
|
145
|
+
break;
|
|
146
|
+
case 'bridge':
|
|
147
|
+
chainUrl.pathname = `/explorer/bridges/${did}`;
|
|
148
|
+
break;
|
|
149
|
+
default:
|
|
150
|
+
chainUrl.pathname = '/';
|
|
151
|
+
}
|
|
152
|
+
return chainUrl.href;
|
|
153
|
+
} catch {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export function patchJsxToLocale(rawStr, replaceMap = {}) {
|
|
158
|
+
return rawStr.split(/{{|}}/).map(item => {
|
|
159
|
+
if (replaceMap[item]) {
|
|
160
|
+
if (replaceMap[item] instanceof Function) {
|
|
161
|
+
return replaceMap[item]();
|
|
162
|
+
}
|
|
163
|
+
return replaceMap[item];
|
|
164
|
+
}
|
|
165
|
+
return item;
|
|
166
|
+
}).filter(Boolean);
|
|
167
|
+
}
|
|
168
|
+
export function formatToDate(date, locale = 'en') {
|
|
169
|
+
if (!date) {
|
|
170
|
+
return '-';
|
|
171
|
+
}
|
|
172
|
+
return dayjs(date).locale(formatLocale(locale)).format('ll');
|
|
173
|
+
}
|
|
174
|
+
export function formatToDatetime(date, locale = 'en') {
|
|
175
|
+
if (!date) {
|
|
176
|
+
return '-';
|
|
177
|
+
}
|
|
178
|
+
return dayjs(date).locale(formatLocale(locale)).format('lll');
|
|
179
|
+
}
|
|
180
|
+
export function formatTime(date, format = 'lll', locale = 'en') {
|
|
181
|
+
if (!date) {
|
|
182
|
+
return '-';
|
|
183
|
+
}
|
|
184
|
+
return dayjs(date).locale(formatLocale(locale)).format(format);
|
|
185
|
+
}
|
|
186
|
+
export function formatDateTime(date, locale = 'en') {
|
|
187
|
+
return dayjs(date).locale(formatLocale(locale)).format('YYYY-MM-DD HH:mm');
|
|
188
|
+
}
|
|
189
|
+
export const formatLocale = (locale = 'en') => {
|
|
190
|
+
if (locale === 'tw') {
|
|
191
|
+
return 'zh';
|
|
192
|
+
}
|
|
193
|
+
return locale;
|
|
194
|
+
};
|
|
195
|
+
export const formatPrettyMsLocale = locale => locale === 'zh' ? 'zh_CN' : 'en_US';
|
|
196
|
+
export const parseQuery = str => str.replace(/^\?/, '').split('&').map(x => x.split('=')).filter(([key]) => !!key).reduce((memo, x) => {
|
|
197
|
+
const key = x[0];
|
|
198
|
+
const value = decodeURIComponent(x[1]) || true;
|
|
199
|
+
memo[key] = value;
|
|
200
|
+
return memo;
|
|
201
|
+
}, {});
|
|
202
|
+
|
|
203
|
+
// Append any query string url to api requests
|
|
204
|
+
export const appendParams = (url, extraParams = {}) => {
|
|
205
|
+
const [pathname, query = ''] = url.split('?');
|
|
206
|
+
const oldParams = parseQuery(query);
|
|
207
|
+
const params = Object.assign({}, oldParams, extraParams);
|
|
208
|
+
return `${pathname}?${qs.stringify(params)}`;
|
|
209
|
+
};
|
|
210
|
+
export const isInstalling = status => ['waiting', 'downloading', 'installing', 'upgrading'].includes(status);
|
|
211
|
+
export const isDownloading = status => ['waiting', 'downloading'].includes(status);
|
|
212
|
+
export const isRunning = status => status === 'running';
|
|
213
|
+
export const formatDiskSize = (size, serverPlatform = '') => {
|
|
214
|
+
const base = serverPlatform === 'linux' ? 2 : 10;
|
|
215
|
+
return filesize(size, {
|
|
216
|
+
base,
|
|
217
|
+
round: 2
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
export const checkInputByType = (type, value) => {
|
|
221
|
+
const typesMap = {
|
|
222
|
+
url: isUrl
|
|
223
|
+
};
|
|
224
|
+
if (!type) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
if (typesMap[type]) {
|
|
228
|
+
return typesMap[type](value);
|
|
229
|
+
}
|
|
230
|
+
return false;
|
|
231
|
+
};
|
|
232
|
+
export const formatUrl = url => humanizeUrl(url.split('?').shift());
|
|
233
|
+
export const formatPerson = person => {
|
|
234
|
+
if (!person) {
|
|
235
|
+
return '-';
|
|
236
|
+
}
|
|
237
|
+
if (typeof person === 'string') {
|
|
238
|
+
return person;
|
|
239
|
+
}
|
|
240
|
+
const name = person.name || '';
|
|
241
|
+
const u = person.url || person.web;
|
|
242
|
+
const url = u ? ` (${u})` : '';
|
|
243
|
+
const e = person.email || person.mail;
|
|
244
|
+
const email = e ? ` <${e}>` : '';
|
|
245
|
+
return name + email + url;
|
|
246
|
+
};
|
|
247
|
+
export const shouldCheckDomainStatus = domain => domain &&
|
|
248
|
+
// eslint-disable-line
|
|
249
|
+
![DOMAIN_FOR_IP_SITE, DOMAIN_FOR_IP_SITE_REGEXP, DOMAIN_FOR_DEFAULT_SITE, DOMAIN_FOR_INTERNAL_SITE].includes(domain);
|
|
250
|
+
export const checkIsWildcardDomain = url => {
|
|
251
|
+
try {
|
|
252
|
+
if (!url) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
const tempUrl = url.startsWith('http') ? url : `http://${url}`;
|
|
256
|
+
const urlObj = new window.URL(tempUrl);
|
|
257
|
+
return decodeURIComponent(urlObj.host).split('.').some(x => x === '*');
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error(url, error);
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
export const stringSortHandlerAsc = (strA = '', strB = '') => {
|
|
264
|
+
if (strA > strB) {
|
|
265
|
+
return 1;
|
|
266
|
+
}
|
|
267
|
+
if (strB > strA) {
|
|
268
|
+
return -1;
|
|
269
|
+
}
|
|
270
|
+
return 0;
|
|
271
|
+
};
|
|
272
|
+
export const getInviteLink = ({
|
|
273
|
+
inviteId,
|
|
274
|
+
endpoint
|
|
275
|
+
}) => {
|
|
276
|
+
if (!endpoint) {
|
|
277
|
+
return '';
|
|
278
|
+
}
|
|
279
|
+
const u = new URL(endpoint);
|
|
280
|
+
u.pathname = joinUrl(u.pathname, WELLKNOWN_SERVICE_PATH_PREFIX, 'invite');
|
|
281
|
+
u.searchParams.set('inviteId', inviteId);
|
|
282
|
+
return u.href;
|
|
283
|
+
};
|
|
284
|
+
export const getTransferAppLink = ({
|
|
285
|
+
transferId,
|
|
286
|
+
endpoint
|
|
287
|
+
}) => {
|
|
288
|
+
if (!endpoint) {
|
|
289
|
+
return '';
|
|
290
|
+
}
|
|
291
|
+
const u = new URL(endpoint);
|
|
292
|
+
u.pathname = joinUrl(u.pathname, WELLKNOWN_SERVICE_PATH_PREFIX, 'transfer');
|
|
293
|
+
u.searchParams.set('transferId', transferId);
|
|
294
|
+
return u.href;
|
|
295
|
+
};
|
|
296
|
+
export const getIssuePassportLink = ({
|
|
297
|
+
id,
|
|
298
|
+
endpoint
|
|
299
|
+
}) => {
|
|
300
|
+
if (!endpoint) {
|
|
301
|
+
return '';
|
|
302
|
+
}
|
|
303
|
+
const u = new URL(endpoint);
|
|
304
|
+
u.pathname = joinUrl(u.pathname, WELLKNOWN_SERVICE_PATH_PREFIX, 'issue-passport');
|
|
305
|
+
u.searchParams.set('id', id);
|
|
306
|
+
return u.href;
|
|
307
|
+
};
|
|
308
|
+
export const formatRegistryScreenshotPath = (did, asset) => {
|
|
309
|
+
if (asset.startsWith('/assets')) {
|
|
310
|
+
return asset;
|
|
311
|
+
}
|
|
312
|
+
return `/assets/${did}/screenshots/${asset}`;
|
|
313
|
+
};
|
|
314
|
+
export const formatRegistryLogoPath = (did, asset) => {
|
|
315
|
+
if (asset.startsWith('/assets')) {
|
|
316
|
+
return asset;
|
|
317
|
+
}
|
|
318
|
+
return `/assets/${did}/${asset}`;
|
|
319
|
+
};
|
|
320
|
+
export function getWebWalletUrl(info) {
|
|
321
|
+
try {
|
|
322
|
+
const url = window.localStorage.getItem('wallet_url');
|
|
323
|
+
if (url) {
|
|
324
|
+
return url;
|
|
325
|
+
}
|
|
326
|
+
} catch (err) {
|
|
327
|
+
// Do nothing
|
|
328
|
+
}
|
|
329
|
+
return info && info.webWalletUrl ? info.webWalletUrl : WEB_WALLET_URL;
|
|
330
|
+
}
|
|
331
|
+
export function isValidClusterSize(data) {
|
|
332
|
+
const {
|
|
333
|
+
value,
|
|
334
|
+
cpuCores
|
|
335
|
+
} = data;
|
|
336
|
+
if (!value) {
|
|
337
|
+
return '';
|
|
338
|
+
}
|
|
339
|
+
const v = Number(value);
|
|
340
|
+
if (Number.isNaN(v)) {
|
|
341
|
+
return 'Cluster size should be a number';
|
|
342
|
+
}
|
|
343
|
+
if (!Number.isInteger(v)) {
|
|
344
|
+
return 'Cluster size should be integer';
|
|
345
|
+
}
|
|
346
|
+
if (v <= 0 || v > cpuCores) {
|
|
347
|
+
return `Cluster size should between 1 to ${cpuCores}`;
|
|
348
|
+
}
|
|
349
|
+
return '';
|
|
350
|
+
}
|
|
351
|
+
export function isProtectedRole(role) {
|
|
352
|
+
return Object.values(ROLES).includes(role);
|
|
353
|
+
}
|
|
354
|
+
export function formatFactoryPrice(blocklet) {
|
|
355
|
+
if (!blocklet?.payment) {
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
const list = (blocklet.payment?.price || []).map(item => ({
|
|
359
|
+
name: item.symbol,
|
|
360
|
+
value: item.value
|
|
361
|
+
}));
|
|
362
|
+
return list;
|
|
363
|
+
}
|
|
364
|
+
export const getBlockletLogoUrl = ({
|
|
365
|
+
did,
|
|
366
|
+
baseUrl,
|
|
367
|
+
logoPath
|
|
368
|
+
}) => {
|
|
369
|
+
if (logoPath && logoPath.startsWith('http')) {
|
|
370
|
+
return logoPath;
|
|
371
|
+
}
|
|
372
|
+
if (baseUrl.startsWith('http') && logoPath) {
|
|
373
|
+
return joinUrl(baseUrl, formatRegistryLogoPath(did, logoPath));
|
|
374
|
+
}
|
|
375
|
+
const prefix = window.env.apiPrefix || '/';
|
|
376
|
+
let apiPrefix = prefix.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
377
|
+
if (apiPrefix) {
|
|
378
|
+
apiPrefix = `/${apiPrefix}`;
|
|
379
|
+
}
|
|
380
|
+
return joinUrl(apiPrefix, `/blocklet/logo/${did}`);
|
|
381
|
+
};
|
|
382
|
+
export const getPathPrefix = () => window.env && window.env.apiPrefix ? window.env.apiPrefix : '/';
|
|
383
|
+
export const isUrlAccessible = url => checkAccessible(joinUrl(new URL(url).origin, WELLKNOWN_PING_PREFIX));
|
|
384
|
+
export const getAccessibleUrl = async urls => {
|
|
385
|
+
try {
|
|
386
|
+
const res = await evaluateURLs(urls);
|
|
387
|
+
return res[0].url;
|
|
388
|
+
} catch (error) {
|
|
389
|
+
console.warn('get accessible url failed');
|
|
390
|
+
return '';
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 检查证书是否与 blocklet 匹配
|
|
396
|
+
* @param {string[]} blockletUrls - 通过 blocklet#interfaces#url 获取到的一组 url
|
|
397
|
+
* @param {object[]} matchedSites - 通过 certificate#matchedSites 获取到的一组 site
|
|
398
|
+
* @returns {boolean} - 匹配则返回 true
|
|
399
|
+
*/
|
|
400
|
+
export const isCertificateMatch = (blockletUrls = [], matchedSites = []) => {
|
|
401
|
+
try {
|
|
402
|
+
return matchedSites.map(item => item.domain).some(domain => {
|
|
403
|
+
return blockletUrls.some(u => {
|
|
404
|
+
const url = new window.URL(u.startsWith('http') ? u : `http://${u}`);
|
|
405
|
+
return url.hostname === domain;
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
} catch (e) {
|
|
409
|
+
console.warn('domain match failed');
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
export const getBlockletUrlParams = (blocklet, locale) => (blocklet || {}).status === 'running' ? {
|
|
414
|
+
locale
|
|
415
|
+
} : {
|
|
416
|
+
locale,
|
|
417
|
+
__start__: 1
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* 判断是否在safari浏览器中
|
|
422
|
+
* 不传的ua情况下,使用当前页面的ua
|
|
423
|
+
* chrome浏览器的ua也会带有 Safari 字样,所以要排除 Chrome 字符串
|
|
424
|
+
* iPhone 设备下,所有浏览器都是 safari 的 webkit
|
|
425
|
+
* @param {String} ua userAgent 字符串
|
|
426
|
+
* @returns bool
|
|
427
|
+
*/
|
|
428
|
+
export const isSafari = (ua = window.navigator.userAgent) => {
|
|
429
|
+
return ua.includes('iPhone') || ua.includes('Safari') && !ua.includes('Chrome');
|
|
430
|
+
};
|
|
431
|
+
export const isChrome = (ua = window.navigator.userAgent) => {
|
|
432
|
+
return ua.includes('Chrome');
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
*
|
|
437
|
+
* @export
|
|
438
|
+
* @param {string} url
|
|
439
|
+
* @return {string}
|
|
440
|
+
*/
|
|
441
|
+
export function deepDecodeURIComponent(url) {
|
|
442
|
+
let lastDecodeUrl = decodeURIComponent(url);
|
|
443
|
+
while (lastDecodeUrl !== decodeURIComponent(lastDecodeUrl)) {
|
|
444
|
+
lastDecodeUrl = decodeURIComponent(lastDecodeUrl);
|
|
445
|
+
}
|
|
446
|
+
return lastDecodeUrl;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
*
|
|
451
|
+
* @description 已知nextWorkflow的地址,提取它的statusUrl和token
|
|
452
|
+
* @export
|
|
453
|
+
* @param {string} nextWorkflow
|
|
454
|
+
* @returns {{
|
|
455
|
+
* statusUrl: string;
|
|
456
|
+
* token: string;
|
|
457
|
+
* }}
|
|
458
|
+
*/
|
|
459
|
+
export function extractStatusUrlFromNextWorkflow(nextWorkflow) {
|
|
460
|
+
const nextWorkflowURL = new URL(deepDecodeURIComponent(nextWorkflow)).searchParams.get('url');
|
|
461
|
+
return {
|
|
462
|
+
statusUrl: nextWorkflowURL.replace('/auth?', '/status?'),
|
|
463
|
+
token: new URL(nextWorkflowURL).searchParams.get('_t_')
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
export function getBlockletMetaUrl(storeUrl, did) {
|
|
467
|
+
return joinUrl(storeUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json`);
|
|
468
|
+
}
|
|
469
|
+
export async function getAsset(chainHost, address) {
|
|
470
|
+
const result = await axios.post(joinUrl(chainHost, '/api/gql/'), JSON.stringify({
|
|
471
|
+
query: `{
|
|
472
|
+
getAssetState(address: "${address}") {
|
|
473
|
+
state {
|
|
474
|
+
address
|
|
475
|
+
data {
|
|
476
|
+
typeUrl
|
|
477
|
+
value
|
|
478
|
+
}
|
|
479
|
+
issuer
|
|
480
|
+
owner
|
|
481
|
+
parent
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}`
|
|
485
|
+
}), {
|
|
486
|
+
headers: {
|
|
487
|
+
'Content-Type': 'application/json',
|
|
488
|
+
Accept: 'application/json'
|
|
489
|
+
},
|
|
490
|
+
timeout: 60 * 1000
|
|
491
|
+
});
|
|
492
|
+
const state = get(result.data, 'data.getAssetState.state');
|
|
493
|
+
if (state && state.data.typeUrl === 'json') {
|
|
494
|
+
state.data.value = JSON.parse(state.data.value);
|
|
495
|
+
}
|
|
496
|
+
return state;
|
|
497
|
+
}
|
|
498
|
+
export function getAssetExpiration(asset) {
|
|
499
|
+
return last(get(asset, 'data.value.expirationDate', []));
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* 检查url是否 未添加到 store list 中
|
|
504
|
+
* @param {string} url - 需要检查的url
|
|
505
|
+
* @param {object[]} storeList - 后端的store list, 一般是 node.blockletRegistryList 或 blocklet.settings.storeList
|
|
506
|
+
* @returns {Object.freeze({
|
|
507
|
+
* isNew: boolean;
|
|
508
|
+
* decoded: string;
|
|
509
|
+
* })} - 返回判断是否是新的url和解码后的url
|
|
510
|
+
*/
|
|
511
|
+
export const isNewStoreUrl = (url, storeList) => {
|
|
512
|
+
if (typeof url === 'string') {
|
|
513
|
+
let decoded = decodeURIComponent(url?.trim());
|
|
514
|
+
const regex = /^https?:\/\//;
|
|
515
|
+
if (!regex.test(decoded)) {
|
|
516
|
+
decoded = `https://${decoded}`;
|
|
517
|
+
}
|
|
518
|
+
decoded = trimEnd(decoded, '/');
|
|
519
|
+
|
|
520
|
+
// validate
|
|
521
|
+
try {
|
|
522
|
+
new URL(decoded); // eslint-disable-line no-new
|
|
523
|
+
} catch {
|
|
524
|
+
throw new Error('Invalid Blocklet Store URL');
|
|
525
|
+
}
|
|
526
|
+
if (storeList?.some(item => [url, decoded].includes(item.url))) {
|
|
527
|
+
return {
|
|
528
|
+
isNew: false,
|
|
529
|
+
decoded
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
isNew: true,
|
|
534
|
+
decoded
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
return {
|
|
538
|
+
isNew: false,
|
|
539
|
+
decoded: ''
|
|
540
|
+
};
|
|
541
|
+
};
|
|
542
|
+
export const isBlockletDev = blocklet => blocklet.mode === BLOCKLET_MODES.DEVELOPMENT;
|
|
543
|
+
export const APP_PREFIX = window.env?.groupPathPrefix || '/';
|
|
544
|
+
export const BlockletAdminRoles = [ROLES.ADMIN, ROLES.OWNER];
|
|
545
|
+
export const toSlotDomain = domain => {
|
|
546
|
+
if (domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX)) {
|
|
547
|
+
const subDomain = domain.split('.').shift();
|
|
548
|
+
const matches = subDomain.match(IP);
|
|
549
|
+
if (matches) {
|
|
550
|
+
return domain.replace(matches[0].slice(1), SLOT_FOR_IP_DNS_SITE);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return domain;
|
|
554
|
+
};
|
|
555
|
+
export const getStoreList = ({
|
|
556
|
+
fromBlocklet,
|
|
557
|
+
nodeInfo,
|
|
558
|
+
blocklet
|
|
559
|
+
}) => {
|
|
560
|
+
const teamDid = fromBlocklet ? blocklet?.meta?.did : nodeInfo?.did;
|
|
561
|
+
const storeList = fromBlocklet ? blocklet?.settings?.storeList || [] : nodeInfo?.blockletRegistryList || [];
|
|
562
|
+
return {
|
|
563
|
+
teamDid,
|
|
564
|
+
storeList
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
const isDidDomainOrIpEchoDomain = domain => {
|
|
568
|
+
if (!domain) {
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
return domain.endsWith(DEFAULT_DID_DOMAIN) || domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX);
|
|
572
|
+
};
|
|
573
|
+
export const sortDomains = domains => {
|
|
574
|
+
return (domains || []).sort((x, y) => {
|
|
575
|
+
if (isDidDomainOrIpEchoDomain(x.value) && isDidDomainOrIpEchoDomain(y.value)) {
|
|
576
|
+
return 0;
|
|
577
|
+
}
|
|
578
|
+
if (isDidDomainOrIpEchoDomain(x.value)) {
|
|
579
|
+
return 1;
|
|
580
|
+
}
|
|
581
|
+
if (isDidDomainOrIpEchoDomain(y.value)) {
|
|
582
|
+
return -1;
|
|
583
|
+
}
|
|
584
|
+
return 1;
|
|
585
|
+
});
|
|
586
|
+
};
|
|
587
|
+
export const formatMountPoint = value => normalizePathPrefix(urlPathFriendly(value));
|
|
588
|
+
export const getRenewBlockletURL = ({
|
|
589
|
+
launcherUrl = '',
|
|
590
|
+
nftId = '',
|
|
591
|
+
locale = 'en'
|
|
592
|
+
}) => joinUrl(launcherUrl, `/instances/${nftId}/renewal?locale=${locale}&return-url=${encodeURIComponent(window.location.href)}`);
|
|
593
|
+
export const getSubscriptionURL = ({
|
|
594
|
+
launcherUrl = '',
|
|
595
|
+
nftId = '',
|
|
596
|
+
locale = 'en'
|
|
597
|
+
}) => joinUrl(launcherUrl, `/instances/${nftId}/subscription?locale=${locale}&return-url=${encodeURIComponent(window.location.href)}`);
|
|
598
|
+
export const nanoid = (length = 16) => [...Array(length)].map(() => Math.random().toString(36)[2]).join('');
|
package/es/util/mode.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
import { isEmpty } from 'lodash';
|
|
3
|
+
import { getSpaceNameByEndpoint } from './spaces';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* @export
|
|
8
|
+
* @param {{
|
|
9
|
+
* nodeApi: import('@abtnode/client'),
|
|
10
|
+
* blockletDid: string,
|
|
11
|
+
* spaceGateways: import('../blocklet/storage/connected').SpaceGateway[],
|
|
12
|
+
* }} { nodeApi, blockletDid, spaceGateways }
|
|
13
|
+
* @return {Promise<import('../blocklet/storage/connected').SpaceGateway[]>}
|
|
14
|
+
*/
|
|
15
|
+
export async function updateSpaceGatewaysFromDIDSpaces({
|
|
16
|
+
blockletDid,
|
|
17
|
+
nodeApi,
|
|
18
|
+
spaceGateways
|
|
19
|
+
}) {
|
|
20
|
+
let shouldUpdate = false;
|
|
21
|
+
const latestSpaceGateways = await Promise.all(spaceGateways.map(async x => {
|
|
22
|
+
let {
|
|
23
|
+
name
|
|
24
|
+
} = x;
|
|
25
|
+
const newName = await getSpaceNameByEndpoint(x.endpoint);
|
|
26
|
+
if (!isEmpty(newName) && newName !== name) {
|
|
27
|
+
name = newName;
|
|
28
|
+
shouldUpdate = true;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
...x,
|
|
32
|
+
name
|
|
33
|
+
};
|
|
34
|
+
}));
|
|
35
|
+
if (shouldUpdate) {
|
|
36
|
+
await Promise.all(latestSpaceGateways.filter(x => x.did).map(x => {
|
|
37
|
+
return nodeApi.updateBlockletSpaceGateway({
|
|
38
|
+
input: {
|
|
39
|
+
did: blockletDid,
|
|
40
|
+
where: {
|
|
41
|
+
did: x.did
|
|
42
|
+
},
|
|
43
|
+
spaceGateway: {
|
|
44
|
+
...x
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
return latestSpaceGateways;
|
|
51
|
+
}
|