@blocklet/did-space-react 0.5.66 → 0.5.68

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.
@@ -2,13 +2,13 @@
2
2
 
3
3
  const jsxRuntime = require('react/jsx-runtime');
4
4
  const React = require('react');
5
- const did = require('@arcblock/did');
6
5
  const material = require('@mui/material');
7
6
  const HelpOutlineIcon = require('@mui/icons-material/HelpOutline');
8
7
  const Button = require('@arcblock/ux/lib/Button');
9
8
  const SplitButton = require('@arcblock/ux/lib/SplitButton');
10
9
  const Dialog = require('@arcblock/ux/lib/Dialog');
11
10
  const ufo = require('ufo');
11
+ const axios = require('axios');
12
12
  const constants = require('../../libs/constants.js');
13
13
  const util = require('../../libs/util.js');
14
14
  const gateway = require('../../libs/gateway.js');
@@ -25,16 +25,17 @@ function BaseConnectTo({ style, onWalletClick, onGatewayConfirm, ...rest }) {
25
25
  setLoading(true);
26
26
  const spaceGatewayUrl = await gateway.getSpaceGatewayUrl(url);
27
27
  const didSpacesCoreUrl = util.extraDIDSpacesCoreUrl(spaceGatewayUrl);
28
- const spaceDid = util.getSpaceDidFromGatewayUrl(url);
29
- if (!did.isValid(spaceDid) || !await gateway.isValidSpaceGatewayUrl(didSpacesCoreUrl)) {
30
- throw new Error(t("storage.spaces.gateway.add.invalidUrl"));
31
- }
28
+ const spaceDid = util.getSpaceDidFromSpaceUrl(url);
29
+ await gateway.verifySpaceUrl({ spaceGatewayUrl, spaceDid, locale });
32
30
  onGatewayConfirm?.({
33
31
  spaceDid,
34
32
  spaceGatewayUrl: didSpacesCoreUrl
35
33
  });
36
34
  setOpen(false);
37
35
  } catch (err) {
36
+ if (err instanceof axios.AxiosError && util.isCorsBlockedError(err)) {
37
+ err.message = t("storage.spaces.error.corsBlocked");
38
+ }
38
39
  console.error(err);
39
40
  setErrorMessage(err.message);
40
41
  } finally {
@@ -3,6 +3,7 @@ import { SpaceGateway, SpaceStatus } from '../../types';
3
3
  export type Action = React.ReactNode | ((props: {
4
4
  spaceGateway: SpaceGateway;
5
5
  spaceStatus: SpaceStatus;
6
+ errorCode: number;
6
7
  selected: boolean;
7
8
  compat: boolean;
8
9
  refresh: () => void;
@@ -9,6 +9,8 @@ const DidAddress = require('@arcblock/ux/lib/DID');
9
9
  const Theme = require('@arcblock/ux/lib/Theme');
10
10
  const React = require('react');
11
11
  const axios = require('axios');
12
+ const ahooks = require('ahooks');
13
+ const constants = require('../../libs/constants.js');
12
14
  const useMobile = require('../../hooks/use-mobile.js');
13
15
  const useSpaceInfo = require('../../hooks/use-space-info.js');
14
16
  const useLocale = require('../../hooks/use-locale.js');
@@ -23,61 +25,83 @@ const spaceConnectError = require('../../icons/space-connect-error.svg.js');
23
25
  function Status({
24
26
  spaceUrl,
25
27
  status,
26
- isError,
28
+ errorCode,
27
29
  refresh,
28
30
  sx,
29
31
  ...rest
30
32
  }) {
31
- const { t } = useLocale();
33
+ const { t, locale } = useLocale();
32
34
  const iconStyle = { marginRight: "4px" };
33
- let icon = null;
34
- let text = null;
35
- if (status === index.SpaceStatus.CONNECTED) {
36
- icon = /* @__PURE__ */ jsxRuntime.jsx(spaceConnected, { style: iconStyle });
37
- text = /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#047857" }, children: t("storage.spaces.connected.tag") });
38
- }
39
- if (status === index.SpaceStatus.DISCONNECTED) {
40
- icon = /* @__PURE__ */ jsxRuntime.jsx(spaceDisconnect, { style: iconStyle });
41
- text = /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#626a77" }, children: t("storage.spaces.disconnected.tag") });
42
- }
43
- if (status === index.SpaceStatus.EXPIRED) {
44
- icon = /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle });
45
- text = /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title: t("storage.spaces.error.expired"), placement: "top", children: /* @__PURE__ */ jsxRuntime.jsxs(
46
- material.Link,
47
- {
48
- href: ufo.withQuery(ufo.joinURL(spaceUrl, "overview"), { guide: 1 }),
49
- target: "_blank",
50
- underline: "hover",
51
- color: "error",
52
- sx: { display: "flex", alignItems: "center", color: "error.main" },
53
- children: [
54
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("storage.spaces.error.tag") }),
55
- /* @__PURE__ */ jsxRuntime.jsx(OpenInNewIcon, { sx: { fontSize: "14px", marginLeft: "4px" } })
56
- ]
35
+ const spaceGuideUrl = ufo.withQuery(ufo.joinURL(spaceUrl, "overview"), { guide: 1 });
36
+ const statusConfig = ahooks.useCreation(
37
+ () => ({
38
+ // 加载中
39
+ [index.SpaceStatus.LOADING]: {
40
+ icon: null,
41
+ text: null
42
+ },
43
+ // 已连接
44
+ [index.SpaceStatus.CONNECTED]: {
45
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceConnected, { style: iconStyle }),
46
+ text: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#047857" }, children: t("storage.spaces.connected.tag") })
47
+ },
48
+ // 未连接(未授权)
49
+ [index.SpaceStatus.DISCONNECTED]: {
50
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceDisconnect, { style: iconStyle }),
51
+ text: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#626a77" }, children: t("storage.spaces.disconnected.tag") })
57
52
  }
58
- ) });
59
- }
60
- if (status === index.SpaceStatus.CORS_BLOCKED) {
61
- icon = /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle });
62
- text = /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title: t("storage.spaces.error.corsBlocked"), placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { display: "flex", alignItems: "center", color: "error.main" }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("storage.spaces.error.tag") }) }) });
63
- }
64
- if (status === index.SpaceStatus.UNKNOWN) {
65
- icon = /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle });
66
- text = /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { color: "error.main" }, children: t("storage.spaces.error.networkError") });
67
- }
53
+ }),
54
+ [locale]
55
+ );
56
+ const errorStatusConfig = ahooks.useCreation(
57
+ () => ({
58
+ // 未知的网络错误(如超时)
59
+ [constants.SPACE_CONNECT_ERROR_CODE.NETWORK_ERROR]: {
60
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle }),
61
+ text: /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { color: "error.main" }, children: t("storage.spaces.error.networkError") })
62
+ },
63
+ // 订阅过期
64
+ [constants.SPACE_CONNECT_ERROR_CODE.EXPIRED]: {
65
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle }),
66
+ text: /* @__PURE__ */ jsxRuntime.jsx(ErrorLink, { title: t("storage.spaces.error.expired"), url: spaceGuideUrl })
67
+ },
68
+ // 订阅逾期
69
+ [constants.SPACE_CONNECT_ERROR_CODE.PAST_DUE]: {
70
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle }),
71
+ text: /* @__PURE__ */ jsxRuntime.jsx(ErrorLink, { title: t("storage.spaces.error.pastDue"), url: spaceGuideUrl })
72
+ },
73
+ // 订阅状态异常
74
+ [constants.SPACE_CONNECT_ERROR_CODE.INVALID]: {
75
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle }),
76
+ text: /* @__PURE__ */ jsxRuntime.jsx(ErrorLink, { title: t("storage.spaces.error.invalid"), url: spaceGuideUrl })
77
+ },
78
+ // 用量不足
79
+ [constants.SPACE_CONNECT_ERROR_CODE.UNIT_LIMIT]: {
80
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle }),
81
+ text: /* @__PURE__ */ jsxRuntime.jsx(ErrorLink, { title: t("storage.spaces.error.unitLimit"), url: spaceGuideUrl })
82
+ },
83
+ // CORS 拦截
84
+ [constants.SPACE_CONNECT_ERROR_CODE.CORS_BLOCKED]: {
85
+ icon: /* @__PURE__ */ jsxRuntime.jsx(spaceConnectError, { style: iconStyle }),
86
+ text: /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title: t("storage.spaces.error.corsBlocked"), placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { display: "flex", alignItems: "center", color: "error.main" }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("storage.spaces.error.tag") }) }) })
87
+ }
88
+ }),
89
+ [locale]
90
+ );
91
+ const { icon, text } = status === index.SpaceStatus.UNAVAILABLE ? errorStatusConfig[errorCode] : statusConfig[status];
68
92
  React.useEffect(() => {
69
93
  const handleVisibilityChange = () => {
70
94
  if (!document.hidden) {
71
95
  refresh();
72
96
  }
73
97
  };
74
- if (isError) {
98
+ if (status !== index.SpaceStatus.CONNECTED) {
75
99
  document.addEventListener("visibilitychange", handleVisibilityChange);
76
100
  } else {
77
101
  document.removeEventListener("visibilitychange", handleVisibilityChange);
78
102
  }
79
103
  return () => document.removeEventListener("visibilitychange", handleVisibilityChange);
80
- }, [isError, refresh]);
104
+ }, [status, refresh]);
81
105
  return /* @__PURE__ */ jsxRuntime.jsxs(
82
106
  material.Box,
83
107
  {
@@ -92,6 +116,23 @@ function Status({
92
116
  }
93
117
  );
94
118
  }
119
+ function ErrorLink({ title, url }) {
120
+ const { t } = useLocale();
121
+ return /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsxs(
122
+ material.Link,
123
+ {
124
+ href: url,
125
+ target: "_blank",
126
+ underline: "hover",
127
+ color: "error",
128
+ sx: { display: "flex", alignItems: "center", color: "error.main" },
129
+ children: [
130
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("storage.spaces.error.tag") }),
131
+ /* @__PURE__ */ jsxRuntime.jsx(OpenInNewIcon, { sx: { fontSize: "14px", marginLeft: "4px" } })
132
+ ]
133
+ }
134
+ ) });
135
+ }
95
136
  function SpaceCard({ endpoint, selected = false, compat, action, className, deps, ...rest }) {
96
137
  const isMobile = useMobile();
97
138
  const { t } = useLocale();
@@ -113,33 +154,30 @@ function SpaceCard({ endpoint, selected = false, compat, action, className, deps
113
154
  deps: [refreshSpaceInfo].concat(deps ?? [])
114
155
  });
115
156
  let spaceName = "";
116
- const hasPermission = spaceInfo?.hasPermission ?? false;
117
157
  const isAvailable = spaceInfo?.isAvailable ?? false;
118
- let isError = false;
119
158
  const spaceStatus = React.useRef(index.SpaceStatus.LOADING);
159
+ let errorCode = 0;
120
160
  if (loading) {
121
161
  spaceStatus.current = index.SpaceStatus.LOADING;
122
162
  spaceName = /* @__PURE__ */ jsxRuntime.jsx(material.Skeleton, { variant: "text", sx: { width: "180px", fontSize: "1rem" } });
123
163
  } else if (spaceInfo) {
124
164
  spaceName = spaceInfo.spaceName;
125
165
  if (!isAvailable) {
126
- spaceStatus.current = index.SpaceStatus.EXPIRED;
127
- isError = true;
128
- } else if (hasPermission) {
129
- spaceStatus.current = index.SpaceStatus.CONNECTED;
166
+ spaceStatus.current = index.SpaceStatus.UNAVAILABLE;
167
+ errorCode = spaceInfo.errorCode;
168
+ if (errorCode === constants.SPACE_CONNECT_ERROR_CODE.UNAUTHORIZED) {
169
+ spaceStatus.current = index.SpaceStatus.DISCONNECTED;
170
+ }
130
171
  } else {
131
- spaceStatus.current = index.SpaceStatus.DISCONNECTED;
172
+ spaceStatus.current = index.SpaceStatus.CONNECTED;
132
173
  }
133
174
  } else if (error instanceof axios.AxiosError) {
134
175
  spaceName = t("common.unknown");
135
- isError = true;
136
- if (!error.response && // 无响应
137
- error.message === "Network Error" && // 网络错误
138
- error.code !== "ECONNABORTED" && // 非超时引起
139
- new URL(error.config.url).origin !== window.location.origin) {
140
- spaceStatus.current = index.SpaceStatus.CORS_BLOCKED;
176
+ spaceStatus.current = index.SpaceStatus.UNAVAILABLE;
177
+ if (util.isCorsBlockedError(error)) {
178
+ errorCode = constants.SPACE_CONNECT_ERROR_CODE.CORS_BLOCKED;
141
179
  } else {
142
- spaceStatus.current = index.SpaceStatus.UNKNOWN;
180
+ errorCode = constants.SPACE_CONNECT_ERROR_CODE.NETWORK_ERROR;
143
181
  }
144
182
  }
145
183
  const renderAction = () => {
@@ -154,6 +192,7 @@ function SpaceCard({ endpoint, selected = false, compat, action, className, deps
154
192
  endpoint
155
193
  },
156
194
  spaceStatus: spaceStatus.current,
195
+ errorCode,
157
196
  selected,
158
197
  compat: isCompact,
159
198
  refresh
@@ -166,7 +205,7 @@ function SpaceCard({ endpoint, selected = false, compat, action, className, deps
166
205
  {
167
206
  className: util.classNames(className, {
168
207
  selected,
169
- error: isError
208
+ error: errorCode > 0
170
209
  }),
171
210
  ...rest,
172
211
  children: [
@@ -180,8 +219,8 @@ function SpaceCard({ endpoint, selected = false, compat, action, className, deps
180
219
  {
181
220
  spaceUrl,
182
221
  status: spaceStatus.current,
222
+ errorCode,
183
223
  refresh,
184
- isError,
185
224
  sx: { mr: 1 }
186
225
  }
187
226
  )
@@ -210,8 +249,8 @@ function SpaceCard({ endpoint, selected = false, compat, action, className, deps
210
249
  {
211
250
  spaceUrl,
212
251
  status: spaceStatus.current,
252
+ errorCode,
213
253
  refresh,
214
- isError,
215
254
  flexShrink: 0
216
255
  }
217
256
  ),
@@ -3,6 +3,8 @@ export default function useSpaceInfo({ endpoint, deps }: {
3
3
  deps?: any[];
4
4
  }): import("ahooks/lib/useRequest/src/types").Result<{
5
5
  spaceName: string;
6
- hasPermission: boolean;
6
+ subscriptionId: any;
7
7
  isAvailable: boolean;
8
+ errorMessage: string;
9
+ errorCode: number;
8
10
  } | undefined, []>;
@@ -11,13 +11,18 @@ function useSpaceInfo({ endpoint, deps = [] }) {
11
11
  return void 0;
12
12
  }
13
13
  const { headers } = await api.head(endpoint, {
14
- timeout: 1e3 * 30
14
+ timeout: 1e3 * 30,
15
+ params: {
16
+ withExtras: true
17
+ }
15
18
  });
16
19
  const spaceName = headers["x-space-name"];
17
20
  return {
18
21
  spaceName: spaceName ? decodeURIComponent(spaceName) : "",
19
- hasPermission: headers["x-listable"] === "true" && headers["x-readable"] === "true" && headers["x-writeable"] === "true",
20
- isAvailable: headers["x-space-is-available"] === "true"
22
+ subscriptionId: headers["x-subscription-id"],
23
+ isAvailable: headers["x-space-is-available"] === "true",
24
+ errorMessage: decodeURIComponent(headers["x-error-message"]),
25
+ errorCode: parseInt(headers["x-error-code"], 10)
21
26
  };
22
27
  },
23
28
  {
@@ -7,6 +7,7 @@ export * from './components/preview-space-nft';
7
7
  export * from './components/base-connect-to';
8
8
  export * from './components/auth-connect-to';
9
9
  export * from './components/session-connect-to';
10
+ export * from './libs/constants';
10
11
  export * from './libs/util';
11
12
  export * from './libs/gateway';
12
13
  export * from './locales';
package/dist/cjs/index.js CHANGED
@@ -9,6 +9,7 @@ const index$1 = require('./components/preview-space-nft/index.js');
9
9
  const index$2 = require('./components/base-connect-to/index.js');
10
10
  const index$3 = require('./components/auth-connect-to/index.js');
11
11
  const index$4 = require('./components/session-connect-to/index.js');
12
+ const constants = require('./libs/constants.js');
12
13
  const util = require('./libs/util.js');
13
14
  const gateway = require('./libs/gateway.js');
14
15
  const index$5 = require('./locales/index.js');
@@ -33,17 +34,22 @@ exports.PreviewSpaceNft = index$1.PreviewSpaceNft;
33
34
  exports.BaseConnectTo = index$2.BaseConnectTo;
34
35
  exports.AuthConnectTo = index$3.AuthConnectTo;
35
36
  exports.SessionConnectTo = index$4.SessionConnectTo;
37
+ exports.AUTHORIZE = constants.AUTHORIZE;
38
+ exports.SPACE_CONNECT_ERROR_CODE = constants.SPACE_CONNECT_ERROR_CODE;
39
+ exports.copyGatewayPageUrl = constants.copyGatewayPageUrl;
36
40
  exports.classNames = util.classNames;
37
41
  exports.decryptSpaceGateway = util.decryptSpaceGateway;
38
42
  exports.extraDIDSpacesCoreUrl = util.extraDIDSpacesCoreUrl;
39
43
  exports.getDIDSpaceDidFromEndpoint = util.getDIDSpaceDidFromEndpoint;
40
44
  exports.getDIDSpaceUrlFromEndpoint = util.getDIDSpaceUrlFromEndpoint;
41
45
  exports.getSpaceDidFromEndpoint = util.getSpaceDidFromEndpoint;
42
- exports.getSpaceDidFromGatewayUrl = util.getSpaceDidFromGatewayUrl;
46
+ exports.getSpaceDidFromSpaceUrl = util.getSpaceDidFromSpaceUrl;
43
47
  exports.getSpaceGatewayUrlFromEndpoint = util.getSpaceGatewayUrlFromEndpoint;
44
48
  exports.getSpaceNftDisplayUrlFromEndpoint = util.getSpaceNftDisplayUrlFromEndpoint;
49
+ exports.isCorsBlockedError = util.isCorsBlockedError;
50
+ exports.t = util.t;
45
51
  exports.getSpaceGatewayUrl = gateway.getSpaceGatewayUrl;
46
- exports.isValidSpaceGatewayUrl = gateway.isValidSpaceGatewayUrl;
52
+ exports.verifySpaceUrl = gateway.verifySpaceUrl;
47
53
  exports.translations = index$5.translations;
48
54
  exports.SpaceStatus = index$6.SpaceStatus;
49
55
  exports.EmptySpacesNFTIcon = emptySpaceNft;
@@ -1,3 +1,19 @@
1
+ export declare const SPACE_CONNECT_ERROR_CODE: {
2
+ /** 网络错误 */
3
+ NETWORK_ERROR: number;
4
+ /** 未授权 */
5
+ UNAUTHORIZED: number;
6
+ /** 订阅过期 */
7
+ EXPIRED: number;
8
+ /** 订阅逾期 */
9
+ PAST_DUE: number;
10
+ /** 订阅状态异常 */
11
+ INVALID: number;
12
+ /** 用量不足 */
13
+ UNIT_LIMIT: number;
14
+ /** 跨域限制 */
15
+ CORS_BLOCKED: number;
16
+ };
1
17
  export declare const AUTHORIZE: {
2
18
  DEFAULT_SCOPE: string;
3
19
  };
@@ -1,9 +1,26 @@
1
1
  'use strict';
2
2
 
3
+ const SPACE_CONNECT_ERROR_CODE = {
4
+ /** 网络错误 */
5
+ NETWORK_ERROR: 1001,
6
+ /** 未授权 */
7
+ UNAUTHORIZED: 1002,
8
+ /** 订阅过期 */
9
+ EXPIRED: 1003,
10
+ /** 订阅逾期 */
11
+ PAST_DUE: 1004,
12
+ /** 订阅状态异常 */
13
+ INVALID: 1005,
14
+ /** 用量不足 */
15
+ UNIT_LIMIT: 1006,
16
+ /** 跨域限制 */
17
+ CORS_BLOCKED: 1007
18
+ };
3
19
  const AUTHORIZE = {
4
20
  DEFAULT_SCOPE: "list:object read:object write:object"
5
21
  };
6
22
  const copyGatewayPageUrl = "https://www.arcblock.io/content/docs/did-spaces/how-to-obtain-space-gateway-url";
7
23
 
8
24
  exports.AUTHORIZE = AUTHORIZE;
25
+ exports.SPACE_CONNECT_ERROR_CODE = SPACE_CONNECT_ERROR_CODE;
9
26
  exports.copyGatewayPageUrl = copyGatewayPageUrl;
@@ -2,4 +2,8 @@ export declare function getSpaceGatewayUrl(anyUrl: string, options?: {
2
2
  timeout: number;
3
3
  withSearchParams: boolean;
4
4
  }): Promise<string>;
5
- export declare function isValidSpaceGatewayUrl(spaceGatewayUrl: string): Promise<boolean>;
5
+ export declare function verifySpaceUrl({ spaceGatewayUrl, spaceDid, locale, }: {
6
+ spaceGatewayUrl: string;
7
+ spaceDid?: string;
8
+ locale?: string;
9
+ }): Promise<void>;
@@ -4,6 +4,7 @@ const ufo = require('ufo');
4
4
  const isUrl = require('is-url');
5
5
  const isString = require('lodash/isString');
6
6
  const isObject = require('lodash/isObject');
7
+ const did = require('@arcblock/did');
7
8
  const api = require('./api.js');
8
9
  const util = require('./util.js');
9
10
 
@@ -26,22 +27,26 @@ async function getSpaceGatewayUrl(anyUrl, options = { timeout: 3e4, withSearchPa
26
27
  const spaceGatewayUrl = options.withSearchParams && u.searchParams.get("spaceDid") ? ufo.withQuery(didSpacesCoreUrl, { spaceDid: u.searchParams.get("spaceDid") }) : didSpacesCoreUrl;
27
28
  return spaceGatewayUrl;
28
29
  }
29
- async function isValidSpaceGatewayUrl(spaceGatewayUrl) {
30
- try {
31
- if (!isUrl(spaceGatewayUrl)) {
32
- return false;
33
- }
34
- const didSpacesCoreUrl = util.extraDIDSpacesCoreUrl(spaceGatewayUrl);
35
- const didConnectTokenUrl = ufo.joinURL(didSpacesCoreUrl, "space/api/did/one-click-authorization/token");
36
- const { status, data } = await api.get(didConnectTokenUrl, {
37
- timeout: 5e3
38
- });
39
- return status === 200 && isObject(data);
40
- } catch (error) {
41
- console.error(error);
42
- return false;
30
+ async function verifySpaceUrl({
31
+ spaceGatewayUrl,
32
+ spaceDid,
33
+ locale
34
+ }) {
35
+ if (!isUrl(spaceGatewayUrl)) {
36
+ throw new Error(util.t("common.invalidUrl", locale, { url: spaceGatewayUrl }));
37
+ }
38
+ if (!spaceDid || !did.isValid(spaceDid)) {
39
+ throw new Error(util.t("storage.spaces.gateway.add.invalidUrl", locale));
40
+ }
41
+ const didSpacesCoreUrl = util.extraDIDSpacesCoreUrl(spaceGatewayUrl);
42
+ const didConnectTokenUrl = ufo.joinURL(didSpacesCoreUrl, "space/api/did/one-click-authorization/token");
43
+ const { status, data } = await api.get(didConnectTokenUrl, {
44
+ timeout: 5e3
45
+ });
46
+ if (!(status === 200 && isObject(data))) {
47
+ throw new Error(util.t("storage.spaces.gateway.add.invalidUrl", locale));
43
48
  }
44
49
  }
45
50
 
46
51
  exports.getSpaceGatewayUrl = getSpaceGatewayUrl;
47
- exports.isValidSpaceGatewayUrl = isValidSpaceGatewayUrl;
52
+ exports.verifySpaceUrl = verifySpaceUrl;
@@ -1,3 +1,4 @@
1
+ import { type AxiosError } from 'axios';
1
2
  type ClassStr = string | undefined | null;
2
3
  /** classObj -> className
3
4
  * examples:
@@ -16,6 +17,9 @@ export declare function getSpaceNftDisplayUrlFromEndpoint(endpoint: string): str
16
17
  export declare function getSpaceDidFromEndpoint(endpoint: string): string | undefined;
17
18
  export declare function getSpaceGatewayUrlFromEndpoint(endpoint: string): string;
18
19
  export declare function extraDIDSpacesCoreUrl(url: string): string;
19
- export declare function getSpaceDidFromGatewayUrl(url: string): string | undefined;
20
+ export declare function getSpaceDidFromSpaceUrl(url: string): string | undefined;
20
21
  export declare function decryptSpaceGateway(response: Record<string, string>, decrypt: Function): any;
22
+ export declare function isCorsBlockedError(error: AxiosError): boolean;
23
+ export declare function t(key: string, locale?: string, data?: Record<string, any>): string;
24
+ export declare function t(key: string, data?: Record<string, any>): string;
21
25
  export {};
@@ -2,6 +2,8 @@
2
2
 
3
3
  const ufo = require('ufo');
4
4
  const isEmpty = require('lodash/isEmpty');
5
+ const util = require('@arcblock/ux/lib/Locale/util');
6
+ const index = require('../locales/index.js');
5
7
 
6
8
  function classNames(...classes) {
7
9
  const result = [];
@@ -54,7 +56,7 @@ function extraDIDSpacesCoreUrl(url) {
54
56
  return didSpacesCoreUrl;
55
57
  }
56
58
  const spaceDidRegex = /\/space\/([^/]+)/;
57
- function getSpaceDidFromGatewayUrl(url) {
59
+ function getSpaceDidFromSpaceUrl(url) {
58
60
  return new URL(url).pathname.match(spaceDidRegex)?.[1];
59
61
  }
60
62
  function decryptSpaceGateway(response, decrypt) {
@@ -70,6 +72,17 @@ function decryptSpaceGateway(response, decrypt) {
70
72
  ...space
71
73
  };
72
74
  }
75
+ function isCorsBlockedError(error) {
76
+ return !error.response && // 无响应
77
+ error.message === "Network Error" && // 是网络错误
78
+ error.code !== "ECONNABORTED" && // 非超时引起
79
+ new URL(error.config.url).origin !== window.location.origin;
80
+ }
81
+ function t(key, localeOrData, data = {}) {
82
+ const locale = typeof localeOrData === "string" ? localeOrData : "en";
83
+ const finalData = typeof localeOrData === "object" ? localeOrData : data;
84
+ return util.translate(index.translations, key, locale, "en", finalData);
85
+ }
73
86
 
74
87
  exports.classNames = classNames;
75
88
  exports.decryptSpaceGateway = decryptSpaceGateway;
@@ -77,6 +90,8 @@ exports.extraDIDSpacesCoreUrl = extraDIDSpacesCoreUrl;
77
90
  exports.getDIDSpaceDidFromEndpoint = getDIDSpaceDidFromEndpoint;
78
91
  exports.getDIDSpaceUrlFromEndpoint = getDIDSpaceUrlFromEndpoint;
79
92
  exports.getSpaceDidFromEndpoint = getSpaceDidFromEndpoint;
80
- exports.getSpaceDidFromGatewayUrl = getSpaceDidFromGatewayUrl;
93
+ exports.getSpaceDidFromSpaceUrl = getSpaceDidFromSpaceUrl;
81
94
  exports.getSpaceGatewayUrlFromEndpoint = getSpaceGatewayUrlFromEndpoint;
82
95
  exports.getSpaceNftDisplayUrlFromEndpoint = getSpaceNftDisplayUrlFromEndpoint;
96
+ exports.isCorsBlockedError = isCorsBlockedError;
97
+ exports.t = t;
@@ -9,7 +9,8 @@ const en = flat.flatten({
9
9
  delete: "Delete",
10
10
  error: "Error",
11
11
  open: "Open",
12
- unknown: "Unknown"
12
+ unknown: "Unknown",
13
+ invalidUrl: "Invalid url: {url}"
13
14
  },
14
15
  storage: {
15
16
  spaces: {
@@ -34,8 +35,11 @@ const en = flat.flatten({
34
35
  },
35
36
  error: {
36
37
  tag: "Need Attention",
37
- expired: "This DID spaces has expired, you can re-subscribe by opening this link",
38
- corsBlocked: "Connection requests may be blocked by CORS. Please check security settings in the DID Space dashboard.",
38
+ expired: "DID Spaces has expired, click this link to re-subscribe",
39
+ pastDue: "DID Spaces has unpaid bills, click this link to complete payment",
40
+ invalid: "DID Spaces subscription anomaly, click this link to check",
41
+ unitLimit: "DID Spaces free quota has been used up, click this link to pay for the upgrade",
42
+ corsBlocked: "Connection requests may be blocked by CORS. Please contact your DID Space administrator to check the settings",
39
43
  networkError: "Network error"
40
44
  },
41
45
  gateway: {
@@ -9,7 +9,8 @@ const zh = flat.flatten({
9
9
  delete: "\u5220\u9664",
10
10
  error: "\u9519\u8BEF",
11
11
  open: "\u6253\u5F00",
12
- unknown: "\u672A\u77E5"
12
+ unknown: "\u672A\u77E5",
13
+ invalidUrl: "\u65E0\u6548\u7684 url: {url}"
13
14
  },
14
15
  storage: {
15
16
  spaces: {
@@ -34,8 +35,11 @@ const zh = flat.flatten({
34
35
  },
35
36
  error: {
36
37
  tag: "\u9700\u8981\u5173\u6CE8",
37
- expired: "\u6B64 DID Spaces \u5DF2\u8FC7\u671F\uFF0C\u60A8\u53EF\u4EE5\u6253\u5F00\u6B64\u94FE\u63A5\u91CD\u65B0\u8BA2\u9605",
38
- corsBlocked: "\u8FDE\u63A5\u8BF7\u6C42\u53EF\u80FD\u88AB CORS \u963B\u6B62\u3002\u8BF7\u68C0\u67E5 DID Space \u63A7\u5236\u9762\u677F\u4E2D\u7684\u5B89\u5168\u8BBE\u7F6E\u3002",
38
+ expired: "DID Spaces \u5DF2\u8FC7\u671F\uFF0C\u70B9\u51FB\u6B64\u94FE\u63A5\u91CD\u65B0\u8BA2\u9605",
39
+ pastDue: "DID Spaces \u6709\u672A\u652F\u4ED8\u8D26\u5355\uFF0C\u70B9\u51FB\u6B64\u94FE\u63A5\u5B8C\u6210\u652F\u4ED8",
40
+ invalid: "DID Spaces \u8BA2\u9605\u5F02\u5E38\uFF0C\u70B9\u51FB\u6B64\u94FE\u63A5\u68C0\u67E5",
41
+ unitLimit: "DID Spaces \u514D\u8D39\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u70B9\u51FB\u6B64\u94FE\u63A5\u4ED8\u8D39\u5347\u7EA7",
42
+ corsBlocked: "\u8FDE\u63A5\u8BF7\u6C42\u53EF\u80FD\u88AB CORS \u9650\u5236\uFF0C\u8BF7\u8054\u7CFB DID Space \u7BA1\u7406\u5458\u68C0\u67E5\u76F8\u5173\u8BBE\u7F6E",
39
43
  networkError: "\u7F51\u7EDC\u9519\u8BEF"
40
44
  },
41
45
  gateway: {
@@ -20,9 +20,8 @@ export declare enum SpaceStatus {
20
20
  LOADING = "loading",
21
21
  CONNECTED = "connected",
22
22
  DISCONNECTED = "disconnected",
23
- EXPIRED = "expired",
24
- CORS_BLOCKED = "corsBlocked",
25
- UNKNOWN = "unknown"
23
+ /** 不可用,跟订阅状态相关,比如过期、逾期、用量不足等 */
24
+ UNAVAILABLE = "unavailable"
26
25
  }
27
26
  export interface SpaceGateway {
28
27
  did: string;
@@ -4,9 +4,7 @@ var SpaceStatus = /* @__PURE__ */ ((SpaceStatus2) => {
4
4
  SpaceStatus2["LOADING"] = "loading";
5
5
  SpaceStatus2["CONNECTED"] = "connected";
6
6
  SpaceStatus2["DISCONNECTED"] = "disconnected";
7
- SpaceStatus2["EXPIRED"] = "expired";
8
- SpaceStatus2["CORS_BLOCKED"] = "corsBlocked";
9
- SpaceStatus2["UNKNOWN"] = "unknown";
7
+ SpaceStatus2["UNAVAILABLE"] = "unavailable";
10
8
  return SpaceStatus2;
11
9
  })(SpaceStatus || {});
12
10
 
@@ -1,15 +1,15 @@
1
1
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
2
  import { useState } from 'react';
3
- import { isValid } from '@arcblock/did';
4
3
  import { Typography, CircularProgress, DialogContentText, TextField, Tooltip, Link } from '@mui/material';
5
4
  import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
6
5
  import Button from '@arcblock/ux/lib/Button';
7
6
  import SplitButton from '@arcblock/ux/lib/SplitButton';
8
7
  import Dialog from '@arcblock/ux/lib/Dialog';
9
8
  import { withQuery } from 'ufo';
9
+ import { AxiosError } from 'axios';
10
10
  import { copyGatewayPageUrl } from '../../libs/constants.js';
11
- import { extraDIDSpacesCoreUrl, getSpaceDidFromGatewayUrl } from '../../libs/util.js';
12
- import { getSpaceGatewayUrl, isValidSpaceGatewayUrl } from '../../libs/gateway.js';
11
+ import { extraDIDSpacesCoreUrl, getSpaceDidFromSpaceUrl, isCorsBlockedError } from '../../libs/util.js';
12
+ import { getSpaceGatewayUrl, verifySpaceUrl } from '../../libs/gateway.js';
13
13
  import useLocale from '../../hooks/use-locale.js';
14
14
 
15
15
  function BaseConnectTo({ style, onWalletClick, onGatewayConfirm, ...rest }) {
@@ -23,16 +23,17 @@ function BaseConnectTo({ style, onWalletClick, onGatewayConfirm, ...rest }) {
23
23
  setLoading(true);
24
24
  const spaceGatewayUrl = await getSpaceGatewayUrl(url);
25
25
  const didSpacesCoreUrl = extraDIDSpacesCoreUrl(spaceGatewayUrl);
26
- const spaceDid = getSpaceDidFromGatewayUrl(url);
27
- if (!isValid(spaceDid) || !await isValidSpaceGatewayUrl(didSpacesCoreUrl)) {
28
- throw new Error(t("storage.spaces.gateway.add.invalidUrl"));
29
- }
26
+ const spaceDid = getSpaceDidFromSpaceUrl(url);
27
+ await verifySpaceUrl({ spaceGatewayUrl, spaceDid, locale });
30
28
  onGatewayConfirm?.({
31
29
  spaceDid,
32
30
  spaceGatewayUrl: didSpacesCoreUrl
33
31
  });
34
32
  setOpen(false);
35
33
  } catch (err) {
34
+ if (err instanceof AxiosError && isCorsBlockedError(err)) {
35
+ err.message = t("storage.spaces.error.corsBlocked");
36
+ }
36
37
  console.error(err);
37
38
  setErrorMessage(err.message);
38
39
  } finally {