@blocklet/launcher-workflow 2.4.4 → 2.4.6
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/components/in-progress-session.js +1 -1
- package/es/components/launch-serverless/allocate.js +181 -0
- package/es/components/launch-serverless/install.js +203 -0
- package/es/components/launch-serverless/shared/base-serverless-layout.js +53 -0
- package/es/components/launch-serverless/shared/common-components.js +605 -0
- package/es/components/launch-serverless/shared/loading-display-layout.js +122 -0
- package/es/components/launch-serverless/shared/retry-error-message.js +45 -0
- package/es/components/launch-serverless/start-app.js +356 -0
- package/es/contexts/request.js +2 -2
- package/es/hooks/use-serial-polling.js +43 -0
- package/es/install.js +28 -0
- package/es/launch.js +1 -1
- package/es/locales/en.js +71 -14
- package/es/locales/zh.js +68 -12
- package/es/paid.js +1 -1
- package/es/prepare.js +1 -1
- package/es/start-app.js +28 -0
- package/es/util.js +181 -2
- package/lib/components/in-progress-session.js +3 -3
- package/lib/components/launch-serverless/allocate.js +198 -0
- package/lib/components/launch-serverless/install.js +223 -0
- package/lib/components/launch-serverless/shared/base-serverless-layout.js +59 -0
- package/lib/components/launch-serverless/shared/common-components.js +635 -0
- package/lib/components/launch-serverless/shared/loading-display-layout.js +131 -0
- package/lib/components/launch-serverless/shared/retry-error-message.js +52 -0
- package/lib/components/launch-serverless/start-app.js +369 -0
- package/lib/contexts/request.js +2 -2
- package/lib/hooks/use-serial-polling.js +49 -0
- package/lib/install.js +35 -0
- package/lib/launch.js +2 -2
- package/lib/locales/en.js +71 -14
- package/lib/locales/zh.js +68 -12
- package/lib/paid.js +2 -2
- package/lib/prepare.js +2 -2
- package/lib/start-app.js +35 -0
- package/lib/util.js +214 -11
- package/package.json +16 -13
- package/es/components/launch-serverless.js +0 -115
- package/lib/components/launch-serverless.js +0 -89
package/es/locales/en.js
CHANGED
|
@@ -39,15 +39,15 @@ export default {
|
|
|
39
39
|
},
|
|
40
40
|
prepare: {
|
|
41
41
|
serverless: {
|
|
42
|
-
preparing: '
|
|
43
|
-
prepared: '
|
|
44
|
-
prepareFailed: 'Failed to
|
|
42
|
+
preparing: 'Setting up your space...',
|
|
43
|
+
prepared: 'Space is ready! Installing your blocklet...',
|
|
44
|
+
prepareFailed: 'Failed to set up your space!'
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
launch: {
|
|
48
48
|
pageTitle: 'Preparing Space',
|
|
49
49
|
invalidFftId: 'Invalid Purchase NFT ID',
|
|
50
|
-
launchApp: 'Launch
|
|
50
|
+
launchApp: 'Launch Blocklet',
|
|
51
51
|
launching: 'Your Blocklet Space is being baked, please be patient, it usually takes about 5 minutes',
|
|
52
52
|
launched: 'Your Blocklet Space is up and running',
|
|
53
53
|
launchSuccess: 'Blocklet Space is successfully launched',
|
|
@@ -55,11 +55,11 @@ export default {
|
|
|
55
55
|
waitingForLaunching: 'Your Blocklet Space launch request is being processed, please be patient, it usually takes about 5 minutes',
|
|
56
56
|
accessServer: 'Access Blocklet Space',
|
|
57
57
|
waiting: {
|
|
58
|
-
starting: 'Starting Blocklet Space',
|
|
59
|
-
securing: 'Securing Network',
|
|
60
|
-
prepare: 'Prepare Storage',
|
|
61
|
-
waiting: 'Waiting for Ready',
|
|
62
|
-
done: 'Blocklet Space is Ready'
|
|
58
|
+
starting: 'Starting Blocklet Space...',
|
|
59
|
+
securing: 'Securing Network...',
|
|
60
|
+
prepare: 'Prepare Storage...',
|
|
61
|
+
waiting: 'Waiting for Ready...',
|
|
62
|
+
done: 'Blocklet Space is Ready...'
|
|
63
63
|
},
|
|
64
64
|
dialog: {
|
|
65
65
|
title: 'Launch Blocklet Space',
|
|
@@ -74,6 +74,63 @@ export default {
|
|
|
74
74
|
notFoundDescription: 'You can launch the Space by clicking the button below'
|
|
75
75
|
}
|
|
76
76
|
},
|
|
77
|
+
install: {
|
|
78
|
+
pageTitle: 'Install Blocklet',
|
|
79
|
+
waiting: {
|
|
80
|
+
verifying: 'Verifying blocklet metadata...',
|
|
81
|
+
downloading: 'Downloading blocklet...',
|
|
82
|
+
extracting: 'Extracting blocklet data...',
|
|
83
|
+
downloadingComponent: 'Downloading {name}',
|
|
84
|
+
extractingComponent: 'Extracting {name}',
|
|
85
|
+
installing: 'Installing blocklet components...',
|
|
86
|
+
installed: 'Blocklet is installed'
|
|
87
|
+
},
|
|
88
|
+
installing: 'Installing Blocklet...',
|
|
89
|
+
installed: 'Blocklet is installed',
|
|
90
|
+
installFailed: 'Install Blocklet Failed!'
|
|
91
|
+
},
|
|
92
|
+
startApp: {
|
|
93
|
+
pageTitle: 'Start Blocklet',
|
|
94
|
+
starting: 'Starting Blocklet...',
|
|
95
|
+
started: 'Blocklet is ready to use!',
|
|
96
|
+
startedDescription: 'Your blocklet has been successfully started and is now ready to use.',
|
|
97
|
+
startFailed: 'Start Blocklet Failed',
|
|
98
|
+
installFailed: 'Install Blocklet Failed',
|
|
99
|
+
visit: 'Visit Blocklet',
|
|
100
|
+
dashboard: 'View Blocklet Dashboard',
|
|
101
|
+
subscription: 'Manage Subscription',
|
|
102
|
+
unknownApp: 'Unknown Blocklet',
|
|
103
|
+
appInfo: 'Blocklet Information',
|
|
104
|
+
appDid: 'Blocklet DID',
|
|
105
|
+
serverUrl: 'Server URL',
|
|
106
|
+
status: 'Status',
|
|
107
|
+
version: 'Version',
|
|
108
|
+
running: 'Running',
|
|
109
|
+
myOrders: 'My Orders',
|
|
110
|
+
myOrdersDesc: 'View and manage all your orders',
|
|
111
|
+
projectName: 'Project Name',
|
|
112
|
+
visitUrl: 'Visit URL',
|
|
113
|
+
visitApp: 'Visit Blocklet',
|
|
114
|
+
visitAppDesc: 'Open your blocklet homepage',
|
|
115
|
+
dashboardDesc: 'View monitoring status and resource usage',
|
|
116
|
+
subscriptionDesc: 'Manage stake amount and renewal settings',
|
|
117
|
+
appManagement: 'Blocklet Management',
|
|
118
|
+
appManagementDesc: 'Change configuration and blocklet settings',
|
|
119
|
+
waiting: {
|
|
120
|
+
starting: 'Starting blocklet...',
|
|
121
|
+
parsing: 'Parsing blocklet metadata...',
|
|
122
|
+
initializing: 'Initializing blocklet configuration...',
|
|
123
|
+
initializingOwner: 'Initializing blocklet owner...',
|
|
124
|
+
creatingSecurityRules: 'Creating default security rules...',
|
|
125
|
+
assigningDomain: 'Assigning default domain name...',
|
|
126
|
+
waitingForDomain: 'Waiting for default domain name...'
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
loading: {
|
|
130
|
+
completed: 'completed',
|
|
131
|
+
retry: 'Retry',
|
|
132
|
+
remainingTime: 'About {time} remaining'
|
|
133
|
+
},
|
|
77
134
|
start: {
|
|
78
135
|
title: 'Starting Space',
|
|
79
136
|
error: {
|
|
@@ -108,10 +165,10 @@ export default {
|
|
|
108
165
|
morePlanPrompt: 'Flip the page to see more plans',
|
|
109
166
|
redeem: 'Select purchased space',
|
|
110
167
|
noProducts: 'No products available for purchase, please check your payment-kit config',
|
|
111
|
-
serverlessNotSupported: 'This
|
|
168
|
+
serverlessNotSupported: 'This blocklet is not allowed in sigular and on-demand space, please select dedicated space',
|
|
112
169
|
componentCount: '{count} Component Included',
|
|
113
170
|
componentsCount: '{count} Components Included',
|
|
114
|
-
onDemandNotSupport: 'This
|
|
171
|
+
onDemandNotSupport: 'This blocklet does not support installation in on-demand space, please purchase dedicated space or install in your own dedicated space',
|
|
115
172
|
dialog: {
|
|
116
173
|
title: 'Purchase Blocklet Space NFT',
|
|
117
174
|
scan: 'Scan the QR code below with your DID wallet to complete purchase',
|
|
@@ -120,7 +177,7 @@ export default {
|
|
|
120
177
|
},
|
|
121
178
|
serverlessDialog: {
|
|
122
179
|
title: 'Purchase successfully',
|
|
123
|
-
redirectToStoreButton: 'Go to install the
|
|
180
|
+
redirectToStoreButton: 'Go to install the blocklet →',
|
|
124
181
|
purchaseServerlessSuccess: 'The purchase of Running Space is successful and you can go ahead and install Blocklet.'
|
|
125
182
|
},
|
|
126
183
|
inProgress: {
|
|
@@ -141,7 +198,7 @@ export default {
|
|
|
141
198
|
paid: 'Current order has been paid',
|
|
142
199
|
paidDescription: 'The current order has been paid, you can choose to purchase a new space or continue the launch process.',
|
|
143
200
|
installed: 'Order has been installed',
|
|
144
|
-
installedDescription: 'The current order has been successfully installed, you can choose to purchase a new space or jump to the current
|
|
201
|
+
installedDescription: 'The current order has been successfully installed, you can choose to purchase a new space or jump to the current blocklet.',
|
|
145
202
|
expired: 'Order has been expired',
|
|
146
203
|
expiredDescription: 'The current order has expired, you can choose to purchase a new space.'
|
|
147
204
|
}
|
|
@@ -156,7 +213,7 @@ export default {
|
|
|
156
213
|
agreement: '{name} User Agreement',
|
|
157
214
|
estimatedCost: 'Estimated Cost',
|
|
158
215
|
estimatedCostFreeTrial: 'Estimated Cost After The Trial ends',
|
|
159
|
-
estimatedCostHint: 'The total cost will vary depending on the actual number and duration of components used in the
|
|
216
|
+
estimatedCostHint: 'The total cost will vary depending on the actual number and duration of components used in the blocklet. The calculation method is: Unit price of component * Number of components * Duration.',
|
|
160
217
|
freeTrial: 'Free Trial',
|
|
161
218
|
freeTrialHint: 'Free trial for {duration}',
|
|
162
219
|
stakeAmount: 'Stake Amount',
|
package/es/locales/zh.js
CHANGED
|
@@ -47,7 +47,7 @@ export default {
|
|
|
47
47
|
launch: {
|
|
48
48
|
pageTitle: '准备空间',
|
|
49
49
|
invalidFftId: '无效的购买凭证',
|
|
50
|
-
launchApp: '
|
|
50
|
+
launchApp: '启动 Blocklet',
|
|
51
51
|
launching: '空间正在启动中, 大约需要 5 分钟',
|
|
52
52
|
launched: '空间已启动',
|
|
53
53
|
launchSuccess: '创建空间成功',
|
|
@@ -55,11 +55,11 @@ export default {
|
|
|
55
55
|
waitingForLaunching: '空间正在启动中,大约需要 5 分钟',
|
|
56
56
|
accessServer: '访问空间',
|
|
57
57
|
waiting: {
|
|
58
|
-
starting: '
|
|
59
|
-
securing: '
|
|
60
|
-
prepare: '
|
|
61
|
-
waiting: '
|
|
62
|
-
done: '
|
|
58
|
+
starting: '启动空间...',
|
|
59
|
+
securing: '确保空间的网络安全...',
|
|
60
|
+
prepare: '准备好空间存储...',
|
|
61
|
+
waiting: '等待空间就绪...',
|
|
62
|
+
done: '空间已准备就绪...'
|
|
63
63
|
},
|
|
64
64
|
dialog: {
|
|
65
65
|
title: '创建空间',
|
|
@@ -74,6 +74,62 @@ export default {
|
|
|
74
74
|
notFoundDescription: '您可以点击下面按钮启动空间'
|
|
75
75
|
}
|
|
76
76
|
},
|
|
77
|
+
install: {
|
|
78
|
+
pageTitle: '安装 Blocklet',
|
|
79
|
+
waiting: {
|
|
80
|
+
verifying: '验证 Blocklet 元数据...',
|
|
81
|
+
downloading: '下载 Blocklet...',
|
|
82
|
+
extracting: '提取 Blocklet 数据...',
|
|
83
|
+
downloadingComponent: '下载 {name}',
|
|
84
|
+
extractingComponent: '提取 {name}',
|
|
85
|
+
installing: '安装 Blocklet 组件...',
|
|
86
|
+
installed: 'Blocklet 已安装'
|
|
87
|
+
},
|
|
88
|
+
installing: '正在安装 Blocklet...',
|
|
89
|
+
installFailed: '安装 Blocklet 失败!'
|
|
90
|
+
},
|
|
91
|
+
startApp: {
|
|
92
|
+
pageTitle: '启动 Blocklet',
|
|
93
|
+
starting: '正在启动 Blocklet...',
|
|
94
|
+
started: 'Blocklet 启动成功',
|
|
95
|
+
startedDescription: '您的 Blocklet 已成功启动并准备就绪,现在可以开始使用了。',
|
|
96
|
+
startFailed: '启动 Blocklet 失败',
|
|
97
|
+
installFailed: '安装 Blocklet 失败',
|
|
98
|
+
visit: '访问 Blocklet',
|
|
99
|
+
dashboard: '查看 Blocklet 仪表盘',
|
|
100
|
+
subscription: '管理订阅',
|
|
101
|
+
unknownApp: '未知 Blocklet',
|
|
102
|
+
appInfo: 'Blocklet 信息',
|
|
103
|
+
appDid: 'Blocklet DID',
|
|
104
|
+
serverUrl: '服务器地址',
|
|
105
|
+
status: '状态',
|
|
106
|
+
version: '版本',
|
|
107
|
+
running: '运行中',
|
|
108
|
+
myOrders: '我的订单',
|
|
109
|
+
myOrdersDesc: '查看和管理您的所有订单',
|
|
110
|
+
projectName: '项目名称',
|
|
111
|
+
visitUrl: '访问地址',
|
|
112
|
+
visitApp: '访问 Blocklet',
|
|
113
|
+
visitAppDesc: '打开您的 Blocklet 主页面',
|
|
114
|
+
dashboardDesc: '查看监控状态和资源使用',
|
|
115
|
+
subscriptionDesc: '管理质押金额和续费设置',
|
|
116
|
+
appManagement: 'Blocklet 管理',
|
|
117
|
+
appManagementDesc: '更改配置和 Blocklet 设置',
|
|
118
|
+
waiting: {
|
|
119
|
+
starting: '正在启动 Blocklet...',
|
|
120
|
+
parsing: '正在解析 Blocklet 元数据...',
|
|
121
|
+
initializing: '正在初始化 Blocklet 配置...',
|
|
122
|
+
initializingOwner: '正在初始化 Blocklet 所有者...',
|
|
123
|
+
creatingSecurityRules: '正在创建默认安全规则...',
|
|
124
|
+
assigningDomain: '正在为 Blocklet 分配默认域名...',
|
|
125
|
+
waitingForDomain: '正在等待默认域名生效...'
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
loading: {
|
|
129
|
+
completed: '完成',
|
|
130
|
+
retry: '重试',
|
|
131
|
+
remainingTime: '大约需要 {time}'
|
|
132
|
+
},
|
|
77
133
|
start: {
|
|
78
134
|
title: '启动空间',
|
|
79
135
|
error: {
|
|
@@ -108,10 +164,10 @@ export default {
|
|
|
108
164
|
noPlan: '选择套餐以继续',
|
|
109
165
|
hasPlan: '选用{name}',
|
|
110
166
|
noProducts: '没有可购买的商品,请检查 PaymentKit 的配置',
|
|
111
|
-
serverlessNotSupported: '
|
|
167
|
+
serverlessNotSupported: '该 Blocklet 被禁止能在单 Blocklet 或者按需空间中运行,请选择专用空间',
|
|
112
168
|
componentCount: '共 {count} 个组件',
|
|
113
169
|
componentsCount: '共 {count} 个组件',
|
|
114
|
-
onDemandNotSupport: '
|
|
170
|
+
onDemandNotSupport: '该 Blocklet 不支持安装在按需空间中,请购买专用空间,或者安装在自己已有的专用空间中',
|
|
115
171
|
dialog: {
|
|
116
172
|
title: '购买 Blocklet Server NFT',
|
|
117
173
|
scan: '用您的 DID 钱包扫描下面的二维码完成购买',
|
|
@@ -120,8 +176,8 @@ export default {
|
|
|
120
176
|
},
|
|
121
177
|
serverlessDialog: {
|
|
122
178
|
title: '购买成功',
|
|
123
|
-
redirectToStoreButton: '
|
|
124
|
-
purchaseServerlessSuccess: '
|
|
179
|
+
redirectToStoreButton: '去安装 Blocklet →',
|
|
180
|
+
purchaseServerlessSuccess: '购买运行空间成功,您可以去安装 Blocklet.'
|
|
125
181
|
},
|
|
126
182
|
inProgress: {
|
|
127
183
|
title: '未完成的订单',
|
|
@@ -141,7 +197,7 @@ export default {
|
|
|
141
197
|
paid: '订单已支付',
|
|
142
198
|
paidDescription: '检测当前订单已经支付,您可以选择购买新的空间,或者继续启动流程',
|
|
143
199
|
installed: '订单已安装',
|
|
144
|
-
installedDescription: '
|
|
200
|
+
installedDescription: '检测当前订单已经安装成功,您可以选择购买新的空间,或者跳转到当前 Blocklet。',
|
|
145
201
|
expired: '订单已过期',
|
|
146
202
|
expiredDescription: '检测当前订单已经过期,您可以选择购买新的空间。'
|
|
147
203
|
}
|
|
@@ -156,7 +212,7 @@ export default {
|
|
|
156
212
|
agreement: '{name} 用户协议',
|
|
157
213
|
estimatedCostFreeTrial: '试用结束后估算成本',
|
|
158
214
|
estimatedCost: '估算成本',
|
|
159
|
-
estimatedCostHint: '
|
|
215
|
+
estimatedCostHint: '总成本会根据 Blocklet 实际使用的组件数量和时长而变化,计算方式为: 组件单价*组件数量*时长',
|
|
160
216
|
freeTrial: '免费试用',
|
|
161
217
|
freeTrialHint: '免费试用{duration}',
|
|
162
218
|
stakeAmount: '质押金额',
|
package/es/paid.js
CHANGED
|
@@ -4,7 +4,7 @@ import CircularProgress from '@mui/material/CircularProgress';
|
|
|
4
4
|
import { useRequest } from 'ahooks';
|
|
5
5
|
import { useEffect } from 'react';
|
|
6
6
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
|
7
|
-
import joinURL from '
|
|
7
|
+
import { joinURL } from 'ufo';
|
|
8
8
|
import { useLocaleContext } from './contexts/locale';
|
|
9
9
|
import useRequestContext from './contexts/request';
|
|
10
10
|
import { useWorkflowContext } from './contexts/workflow';
|
package/es/prepare.js
CHANGED
|
@@ -17,7 +17,7 @@ import { useCallback, useEffect, useMemo } from 'react';
|
|
|
17
17
|
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
|
18
18
|
import useAsync from 'react-use/lib/useAsync';
|
|
19
19
|
import useSetState from 'react-use/lib/useSetState';
|
|
20
|
-
import joinURL from '
|
|
20
|
+
import { joinURL } from 'ufo';
|
|
21
21
|
import ConfirmDialog from './components/confirm';
|
|
22
22
|
import Body from './components/layout/body';
|
|
23
23
|
import Header from './components/layout/header';
|
package/es/start-app.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useParams } from 'react-router-dom';
|
|
3
|
+
import StartAppServerless from './components/launch-serverless/start-app';
|
|
4
|
+
import { useSessionContext } from './contexts/session';
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
export default function Launch() {
|
|
7
|
+
const {
|
|
8
|
+
sessionId
|
|
9
|
+
} = useParams();
|
|
10
|
+
const {
|
|
11
|
+
session
|
|
12
|
+
} = useSessionContext();
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!session.user) {
|
|
15
|
+
return session.login(() => {
|
|
16
|
+
session.refresh();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return () => {};
|
|
20
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21
|
+
}, [session.user]);
|
|
22
|
+
if (!session.user) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
return /*#__PURE__*/_jsx(StartAppServerless, {
|
|
26
|
+
sessionId: sessionId
|
|
27
|
+
});
|
|
28
|
+
}
|
package/es/util.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { WELLKNOWN_PATH_PREFIX, WELLKNOWN_PING_PREFIX } from '@abtnode/constant';
|
|
2
|
+
import axios from '@abtnode/util/lib/axios';
|
|
3
|
+
import normalizePathPrefix from '@abtnode/util/lib/normalize-path-prefix';
|
|
4
|
+
import tryWithTimeout from '@abtnode/util/lib/try-with-timeout';
|
|
5
|
+
import { evaluateURLs } from '@abtnode/util/lib/url-evaluation';
|
|
6
|
+
import checkAccessible from '@abtnode/util/lib/url-evaluation/check-accessible-browser';
|
|
1
7
|
import { create as createRequestInstance } from '@blocklet/launcher-util/es/api';
|
|
2
8
|
import { getFromQuery } from '@blocklet/launcher-ux/lib/util';
|
|
3
9
|
import get from 'lodash.get';
|
|
4
10
|
import noop from 'lodash.noop';
|
|
5
11
|
import pick from 'lodash.pick';
|
|
6
|
-
import joinURL from '
|
|
12
|
+
import { joinURL } from 'ufo';
|
|
7
13
|
export const BLOCKLET_STORE_URL = get(window, 'blocklet.LAUNCHER_BLOCKLET_STORE_URL') || 'https://store.blocklet.dev';
|
|
8
14
|
export function getBlockletMetaUrl(registry, did) {
|
|
9
15
|
return joinURL(registry, `/api/blocklets/${did}/blocklet.json?source=webapp`);
|
|
@@ -162,4 +168,177 @@ export const launchSession = {
|
|
|
162
168
|
done(err);
|
|
163
169
|
});
|
|
164
170
|
}
|
|
165
|
-
};
|
|
171
|
+
};
|
|
172
|
+
export function sleep(t) {
|
|
173
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
174
|
+
return new Promise(resolve => setTimeout(resolve, t));
|
|
175
|
+
}
|
|
176
|
+
export const isUrlAccessible = url => checkAccessible(joinURL(new URL(url).origin, WELLKNOWN_PING_PREFIX));
|
|
177
|
+
export const checkBlockletAccessible = async (url, timeout = 5000, controller = null) => {
|
|
178
|
+
try {
|
|
179
|
+
const urlObj = new URL(url);
|
|
180
|
+
urlObj.protocol = 'https';
|
|
181
|
+
const res = await axios.get(joinURL(urlObj.toString(), '/api/__blocklet__.js?type=json'), {
|
|
182
|
+
timeout,
|
|
183
|
+
signal: controller?.signal,
|
|
184
|
+
validateStatus: status => {
|
|
185
|
+
return status >= 200 && status < 400 || status === 503; // 503 是 not running, 可以访问 blocklet service
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
return res.data;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
export const checkUrlAccessible = async (url, timeout = 30 * 1000, controller = null) => {
|
|
194
|
+
try {
|
|
195
|
+
return await tryWithTimeout(async () => {
|
|
196
|
+
let res = null;
|
|
197
|
+
do {
|
|
198
|
+
res = await checkBlockletAccessible(url, 5000, controller);
|
|
199
|
+
await sleep(2000);
|
|
200
|
+
} while (!res && !controller?.signal?.aborted);
|
|
201
|
+
return res;
|
|
202
|
+
}, timeout);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(error);
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
export const waitingForRaceAccessible = async (urls, timeout = 30 * 1000) => {
|
|
209
|
+
// Create an AbortController for each request
|
|
210
|
+
const controllers = urls.map(() => new AbortController());
|
|
211
|
+
try {
|
|
212
|
+
const tasks = urls.map((url, index) => checkUrlAccessible(url, timeout, controllers[index]).then(res => [url, res]).catch(error => {
|
|
213
|
+
// If this request failed but wasn't aborted, we should still propagate the error
|
|
214
|
+
if (error.name !== 'AbortError') {
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}));
|
|
219
|
+
|
|
220
|
+
// Add a timeout promise to the race
|
|
221
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
222
|
+
setTimeout(() => reject(new Error('All requests timed out')), timeout);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Race all tasks including the timeout
|
|
226
|
+
const result = await Promise.race([
|
|
227
|
+
// Wait for the first successful response
|
|
228
|
+
...tasks, timeoutPromise]);
|
|
229
|
+
|
|
230
|
+
// Cancel all other requests
|
|
231
|
+
controllers.forEach(controller => controller.abort());
|
|
232
|
+
return result;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
// Cancel all requests on error
|
|
235
|
+
controllers.forEach(controller => controller.abort());
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const waitingForAccessible = async (urls, timeout = 30 * 1000) => {
|
|
240
|
+
const tasks = await urls.map(url => checkUrlAccessible(url, timeout));
|
|
241
|
+
const result = await Promise.all(tasks);
|
|
242
|
+
return result;
|
|
243
|
+
};
|
|
244
|
+
export const sortUrls = urls => {
|
|
245
|
+
return evaluateURLs(urls, {
|
|
246
|
+
checkAccessible: null
|
|
247
|
+
}).then(items => items.map(item => item.url));
|
|
248
|
+
};
|
|
249
|
+
export const getAccessibleUrl = async urls => {
|
|
250
|
+
try {
|
|
251
|
+
await waitingForAccessible(urls);
|
|
252
|
+
const res = await evaluateURLs(urls, {
|
|
253
|
+
checkAccessible: checkBlockletAccessible
|
|
254
|
+
});
|
|
255
|
+
return res[0].url;
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.warn('get accessible url failed', error);
|
|
258
|
+
return '';
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* get access url
|
|
264
|
+
* auto fix http/https, port, query
|
|
265
|
+
* docker friendly
|
|
266
|
+
*/
|
|
267
|
+
export function getAccessUrl(hostname, path = '', params = undefined) {
|
|
268
|
+
if (!hostname) {
|
|
269
|
+
return '';
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
let port = '';
|
|
273
|
+
const browserPort = Number(window.location.port);
|
|
274
|
+
if (process.env.NODE_ENV !== 'development' && browserPort && ![80, 443].includes(browserPort)) {
|
|
275
|
+
port = `:${browserPort}`;
|
|
276
|
+
}
|
|
277
|
+
const urlObj = new URL(`${window.location.protocol}//${hostname}${port}`);
|
|
278
|
+
urlObj.pathname = path;
|
|
279
|
+
const url = urlObj.href.replace(/\/$/, '');
|
|
280
|
+
if (!params || !Object.keys(params)) {
|
|
281
|
+
return url;
|
|
282
|
+
}
|
|
283
|
+
const searchParams = new URLSearchParams();
|
|
284
|
+
Object.keys(params).forEach(key => {
|
|
285
|
+
searchParams.append(key, params[key]);
|
|
286
|
+
});
|
|
287
|
+
return `${url}${urlObj.pathname === '/' ? '/' : ''}?${searchParams.toString()}`;
|
|
288
|
+
} catch (err) {
|
|
289
|
+
console.error(err);
|
|
290
|
+
return '';
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function getBlockletUrl({
|
|
294
|
+
blocklet,
|
|
295
|
+
domain: inputDomain,
|
|
296
|
+
mountPoint: inputMountPoint,
|
|
297
|
+
params
|
|
298
|
+
} = {}) {
|
|
299
|
+
const {
|
|
300
|
+
site
|
|
301
|
+
} = blocklet;
|
|
302
|
+
if (!site) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const domain = inputDomain || (site.domainAliases || [])[0];
|
|
306
|
+
if (!domain) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
let mountPoint = inputMountPoint;
|
|
310
|
+
if (!mountPoint) {
|
|
311
|
+
const rule = site.rules.filter(x => !x.from.pathPrefix.startsWith(WELLKNOWN_PATH_PREFIX))[0];
|
|
312
|
+
mountPoint = rule ? rule.from.pathPrefix : '/';
|
|
313
|
+
}
|
|
314
|
+
return getAccessUrl(domain.value, mountPoint, params);
|
|
315
|
+
}
|
|
316
|
+
export function getBlockletUrls({
|
|
317
|
+
blocklet,
|
|
318
|
+
mountPoint: inputMountPoint,
|
|
319
|
+
params
|
|
320
|
+
} = {}) {
|
|
321
|
+
const {
|
|
322
|
+
site
|
|
323
|
+
} = blocklet;
|
|
324
|
+
if (!site) {
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
327
|
+
const domains = site.domainAliases || [];
|
|
328
|
+
if (!domains.length) {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
331
|
+
let mountPoint = inputMountPoint;
|
|
332
|
+
if (!mountPoint) {
|
|
333
|
+
const rules = site.rules.filter(x => !x.from.pathPrefix.startsWith(WELLKNOWN_PATH_PREFIX));
|
|
334
|
+
let rule = rules[0];
|
|
335
|
+
if (rule?.from?.pathPrefix !== '/') {
|
|
336
|
+
const rootRule = rules.find(x => x.from?.pathPrefix === '/');
|
|
337
|
+
if (rootRule) {
|
|
338
|
+
rule = rootRule;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
mountPoint = normalizePathPrefix(rule?.from?.pathPrefix || '/');
|
|
342
|
+
}
|
|
343
|
+
return domains.map(domain => getAccessUrl(domain.value, mountPoint, params));
|
|
344
|
+
}
|
|
@@ -11,7 +11,7 @@ var _Box = _interopRequireDefault(require("@mui/material/Box"));
|
|
|
11
11
|
var _Link = _interopRequireDefault(require("@mui/material/Link"));
|
|
12
12
|
var _react = require("react");
|
|
13
13
|
var _useAsync = _interopRequireDefault(require("react-use/lib/useAsync"));
|
|
14
|
-
var
|
|
14
|
+
var _ufo = require("ufo");
|
|
15
15
|
var _locale = require("../contexts/locale");
|
|
16
16
|
var _request = _interopRequireDefault(require("../contexts/request"));
|
|
17
17
|
var _workflow = require("../contexts/workflow");
|
|
@@ -36,7 +36,7 @@ function InProgressSession() {
|
|
|
36
36
|
const state = (0, _useAsync.default)(async () => {
|
|
37
37
|
const {
|
|
38
38
|
data
|
|
39
|
-
} = await api.get((0,
|
|
39
|
+
} = await api.get((0, _ufo.joinURL)(routerPrefix, '/launches/in-progress'));
|
|
40
40
|
if (data.launch) {
|
|
41
41
|
if (localStorage.getItem(IGNORE_LAUNCH_SESSION_KEY) === data.launch.id) {
|
|
42
42
|
return null;
|
|
@@ -59,7 +59,7 @@ function InProgressSession() {
|
|
|
59
59
|
let continueBaseURL = '';
|
|
60
60
|
try {
|
|
61
61
|
continueBaseURL = (0, _util.getContinueLaunchURL)({
|
|
62
|
-
baseURL: (0,
|
|
62
|
+
baseURL: (0, _ufo.joinURL)(window.location.origin, baseURL),
|
|
63
63
|
launch: state.value
|
|
64
64
|
});
|
|
65
65
|
} catch (error) {
|