@blocklet/launcher-util 2.2.3 → 2.2.5
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/constant.js +169 -0
- package/es/format-error.js +25 -0
- package/es/get-asset.js +45 -0
- package/es/locale/en.js +43 -0
- package/es/locale/index.js +17 -0
- package/es/locale/zh.js +45 -0
- package/es/middleware.js +66 -0
- package/es/notification/index.js +29 -0
- package/es/permission.js +5 -0
- package/es/util.js +132 -0
- package/es/validator.js +10 -0
- package/package.json +3 -2
package/es/constant.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
const INSTANCE_STATUS = Object.freeze({
|
|
2
|
+
error: 0,
|
|
3
|
+
waiting: 5,
|
|
4
|
+
pending: 10,
|
|
5
|
+
starting: 20,
|
|
6
|
+
running: 30,
|
|
7
|
+
restarting: 40,
|
|
8
|
+
stopping: 50,
|
|
9
|
+
stopped: 60,
|
|
10
|
+
terminated: 70,
|
|
11
|
+
expired: 80,
|
|
12
|
+
underMaintenance: 90
|
|
13
|
+
});
|
|
14
|
+
const PLAN_STATUS = Object.freeze({
|
|
15
|
+
draft: 10,
|
|
16
|
+
published: 20,
|
|
17
|
+
dropped: 30
|
|
18
|
+
// 已下架
|
|
19
|
+
});
|
|
20
|
+
const LAUNCH_STATUS = Object.freeze({
|
|
21
|
+
created: 0,
|
|
22
|
+
selected: 10,
|
|
23
|
+
connected: 20,
|
|
24
|
+
paid: 30,
|
|
25
|
+
allocated: 40,
|
|
26
|
+
installed: 50,
|
|
27
|
+
expired: 60,
|
|
28
|
+
terminated: 70,
|
|
29
|
+
timeout: 80,
|
|
30
|
+
transferred: 90
|
|
31
|
+
});
|
|
32
|
+
const LAUNCH_ACTIVITY_TYPE = Object.freeze({
|
|
33
|
+
created: "created",
|
|
34
|
+
selected: "selected",
|
|
35
|
+
connected: "connected",
|
|
36
|
+
paid: "paid",
|
|
37
|
+
allocated: "allocated",
|
|
38
|
+
installed: "installed",
|
|
39
|
+
timeout: "timeout",
|
|
40
|
+
expired: "expired",
|
|
41
|
+
terminated: "terminated",
|
|
42
|
+
transferred: "transferred"
|
|
43
|
+
});
|
|
44
|
+
const SERVER_ACTIVITY_TYPE = Object.freeze({
|
|
45
|
+
purchase: "purchase",
|
|
46
|
+
launch: "launch",
|
|
47
|
+
createFailed: "createFailed",
|
|
48
|
+
created: "created",
|
|
49
|
+
start: "start",
|
|
50
|
+
started: "started",
|
|
51
|
+
startFailed: "startFailed",
|
|
52
|
+
stop: "stop",
|
|
53
|
+
stopped: "stopped",
|
|
54
|
+
stopFailed: "stopFailed",
|
|
55
|
+
restart: "restart",
|
|
56
|
+
restarted: "restarted",
|
|
57
|
+
restartFailed: "restartFailed",
|
|
58
|
+
expired: "expired",
|
|
59
|
+
terminate: "terminate",
|
|
60
|
+
terminated: "terminated",
|
|
61
|
+
terminateFailed: "terminateFailed",
|
|
62
|
+
renewaled: "renewaled",
|
|
63
|
+
transferred: "transferred",
|
|
64
|
+
replacement: "replacement"
|
|
65
|
+
});
|
|
66
|
+
const SERVERLESS_INSTANCE_STATUS = {
|
|
67
|
+
launching: 10,
|
|
68
|
+
running: 20,
|
|
69
|
+
expired: 30,
|
|
70
|
+
terminated: 40
|
|
71
|
+
};
|
|
72
|
+
const toMap = (staus) => Object.keys(staus).reduce((acc, cur) => {
|
|
73
|
+
acc[staus[cur]] = cur;
|
|
74
|
+
return acc;
|
|
75
|
+
}, {});
|
|
76
|
+
const fromStatus = (map) => (status) => map[status];
|
|
77
|
+
const statusInstanceMap = toMap(INSTANCE_STATUS);
|
|
78
|
+
const planStatusMap = toMap(PLAN_STATUS);
|
|
79
|
+
const fromInstanceStatus = fromStatus(statusInstanceMap);
|
|
80
|
+
const fromPlanStatus = fromStatus(planStatusMap);
|
|
81
|
+
const NFT_TYPE_SERVERLESS = "BlockletServerServerlessNFT";
|
|
82
|
+
const BLOCKLET_SERVER_OWNERSHIP_NFT = "BlockletServerOwnershipNFT";
|
|
83
|
+
const TIME_LOCALE = {
|
|
84
|
+
en: {
|
|
85
|
+
h: "hour",
|
|
86
|
+
hs: "hours",
|
|
87
|
+
d: " day",
|
|
88
|
+
ds: " days",
|
|
89
|
+
m: " month",
|
|
90
|
+
ms: " months",
|
|
91
|
+
y: " year",
|
|
92
|
+
ys: " years"
|
|
93
|
+
},
|
|
94
|
+
zh: {
|
|
95
|
+
h: "小时",
|
|
96
|
+
hs: "小时",
|
|
97
|
+
d: "天",
|
|
98
|
+
ds: "天",
|
|
99
|
+
m: "个月",
|
|
100
|
+
ms: "个月",
|
|
101
|
+
y: "年",
|
|
102
|
+
ys: "年"
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const APP_TYPE = Object.freeze({
|
|
106
|
+
serverless: "serverless",
|
|
107
|
+
dedicated: "dedicated"
|
|
108
|
+
});
|
|
109
|
+
const SKU_STATUS = Object.freeze({
|
|
110
|
+
DISABLED: 0,
|
|
111
|
+
ENABLED: 1
|
|
112
|
+
});
|
|
113
|
+
const PAYMENT_STATUS = Object.freeze({
|
|
114
|
+
unpaid: 10,
|
|
115
|
+
paid: 20,
|
|
116
|
+
done: 30,
|
|
117
|
+
expired: 40,
|
|
118
|
+
canceled: 60,
|
|
119
|
+
failed: 70
|
|
120
|
+
});
|
|
121
|
+
const PAYMENT_TYPES = {
|
|
122
|
+
purchase: "purchase",
|
|
123
|
+
renewal: "renewal",
|
|
124
|
+
autoRenewal: "auto-renewal"
|
|
125
|
+
};
|
|
126
|
+
const PAYMENT_METHODS = Object.freeze({
|
|
127
|
+
crypto: "crypto",
|
|
128
|
+
stripe: "stripe",
|
|
129
|
+
fiat: "fiat"
|
|
130
|
+
// TODO: 区分支付货币和支付方式
|
|
131
|
+
});
|
|
132
|
+
const DID_DOMAIN_SUFFIX = "did.abtnet.io";
|
|
133
|
+
const REDEEM_NFT_ID = "redeem";
|
|
134
|
+
const INSTANCE_MAX_NAME_LENGTH = 30;
|
|
135
|
+
const INSTANCE_MAX_DESC_LENGTH = 50;
|
|
136
|
+
const LAUNCH_TYPE = {
|
|
137
|
+
instant: "instant",
|
|
138
|
+
redeem: "redeem"
|
|
139
|
+
};
|
|
140
|
+
const CURRENCY_TYPE = {
|
|
141
|
+
fiat: "fiat",
|
|
142
|
+
crypto: "crypto"
|
|
143
|
+
};
|
|
144
|
+
const SERVERLESS_RETAIN_DAYS = 30;
|
|
145
|
+
export {
|
|
146
|
+
APP_TYPE,
|
|
147
|
+
BLOCKLET_SERVER_OWNERSHIP_NFT,
|
|
148
|
+
CURRENCY_TYPE,
|
|
149
|
+
DID_DOMAIN_SUFFIX,
|
|
150
|
+
INSTANCE_MAX_DESC_LENGTH,
|
|
151
|
+
INSTANCE_MAX_NAME_LENGTH,
|
|
152
|
+
INSTANCE_STATUS,
|
|
153
|
+
LAUNCH_ACTIVITY_TYPE,
|
|
154
|
+
LAUNCH_STATUS,
|
|
155
|
+
LAUNCH_TYPE,
|
|
156
|
+
NFT_TYPE_SERVERLESS,
|
|
157
|
+
PAYMENT_METHODS,
|
|
158
|
+
PAYMENT_STATUS,
|
|
159
|
+
PAYMENT_TYPES,
|
|
160
|
+
PLAN_STATUS,
|
|
161
|
+
REDEEM_NFT_ID,
|
|
162
|
+
SERVERLESS_INSTANCE_STATUS,
|
|
163
|
+
SERVERLESS_RETAIN_DAYS,
|
|
164
|
+
SERVER_ACTIVITY_TYPE,
|
|
165
|
+
SKU_STATUS,
|
|
166
|
+
TIME_LOCALE,
|
|
167
|
+
fromInstanceStatus,
|
|
168
|
+
fromPlanStatus
|
|
169
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const formatError = (err) => {
|
|
2
|
+
var _a;
|
|
3
|
+
if (!err) {
|
|
4
|
+
return err;
|
|
5
|
+
}
|
|
6
|
+
const { details, errors, response } = err;
|
|
7
|
+
if (Array.isArray(errors)) {
|
|
8
|
+
return errors.map((x) => x.message).join("\n");
|
|
9
|
+
}
|
|
10
|
+
if (Array.isArray(details)) {
|
|
11
|
+
const formatted = details.map((e) => {
|
|
12
|
+
const errorMessage = e.message.replace(/["]/g, "'");
|
|
13
|
+
const errorPath = e.path.join(".");
|
|
14
|
+
return `${errorPath}: ${errorMessage}`;
|
|
15
|
+
});
|
|
16
|
+
return `Validate failed: ${formatted.join(";")}`;
|
|
17
|
+
}
|
|
18
|
+
if (response) {
|
|
19
|
+
return ((_a = response.data) == null ? void 0 : _a.error) || `Request failed: ${response.status} ${response.statusText}: ${JSON.stringify(response.data)}`;
|
|
20
|
+
}
|
|
21
|
+
return err.message || err;
|
|
22
|
+
};
|
|
23
|
+
export {
|
|
24
|
+
formatError as default
|
|
25
|
+
};
|
package/es/get-asset.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import joinUrl from "url-join";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import get from "lodash.get";
|
|
4
|
+
const getAsset = async (chainHost, address) => {
|
|
5
|
+
const url = joinUrl(new URL(chainHost).origin, "/api/gql/");
|
|
6
|
+
const result = await axios.post(
|
|
7
|
+
url,
|
|
8
|
+
JSON.stringify({
|
|
9
|
+
query: `{
|
|
10
|
+
getAssetState(address: "${address}") {
|
|
11
|
+
state {
|
|
12
|
+
address
|
|
13
|
+
data {
|
|
14
|
+
typeUrl
|
|
15
|
+
value
|
|
16
|
+
}
|
|
17
|
+
display {
|
|
18
|
+
type
|
|
19
|
+
content
|
|
20
|
+
}
|
|
21
|
+
issuer
|
|
22
|
+
owner
|
|
23
|
+
parent
|
|
24
|
+
tags
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}`
|
|
28
|
+
}),
|
|
29
|
+
{
|
|
30
|
+
headers: {
|
|
31
|
+
"Content-Type": "application/json",
|
|
32
|
+
Accept: "application/json"
|
|
33
|
+
},
|
|
34
|
+
timeout: 60 * 1e3
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
const state = get(result, "data.data.getAssetState.state");
|
|
38
|
+
if (state && state.data.typeUrl === "json") {
|
|
39
|
+
state.data.value = JSON.parse(state.data.value);
|
|
40
|
+
}
|
|
41
|
+
return state;
|
|
42
|
+
};
|
|
43
|
+
export {
|
|
44
|
+
getAsset as default
|
|
45
|
+
};
|
package/es/locale/en.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import flat from "flat";
|
|
2
|
+
import { SERVERLESS_INSTANCE_STATUS, INSTANCE_STATUS, PAYMENT_METHODS, CURRENCY_TYPE } from "../constant";
|
|
3
|
+
const en = flat({
|
|
4
|
+
common: {
|
|
5
|
+
app: "App",
|
|
6
|
+
billing: "Billing",
|
|
7
|
+
duration: "Duration",
|
|
8
|
+
spaceName: "Space Name"
|
|
9
|
+
},
|
|
10
|
+
serverlessInstance: {
|
|
11
|
+
appStatus: {
|
|
12
|
+
[SERVERLESS_INSTANCE_STATUS.launching]: "Launching",
|
|
13
|
+
[SERVERLESS_INSTANCE_STATUS.running]: "Running",
|
|
14
|
+
[SERVERLESS_INSTANCE_STATUS.expired]: "Expired",
|
|
15
|
+
[SERVERLESS_INSTANCE_STATUS.terminated]: "Terminated"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
dedicatedInstance: {
|
|
19
|
+
appStatus: {
|
|
20
|
+
[INSTANCE_STATUS.unknown]: "Unknown",
|
|
21
|
+
[INSTANCE_STATUS.pending]: "Pending",
|
|
22
|
+
[INSTANCE_STATUS.starting]: "Starting",
|
|
23
|
+
[INSTANCE_STATUS.running]: "Running",
|
|
24
|
+
[INSTANCE_STATUS.restarting]: "Restarting",
|
|
25
|
+
[INSTANCE_STATUS.stopping]: "Stopping",
|
|
26
|
+
[INSTANCE_STATUS.stopped]: "Stopped",
|
|
27
|
+
[INSTANCE_STATUS.terminated]: "Terminated",
|
|
28
|
+
[INSTANCE_STATUS.expired]: "Expired",
|
|
29
|
+
[INSTANCE_STATUS.error]: "Error",
|
|
30
|
+
[INSTANCE_STATUS.waiting]: "Waiting",
|
|
31
|
+
[INSTANCE_STATUS.underMaintenance]: "Under-Maintenance"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
paymentMethod: {
|
|
35
|
+
[PAYMENT_METHODS.crypto]: "Crypto",
|
|
36
|
+
[PAYMENT_METHODS.stripe]: "Credit",
|
|
37
|
+
[CURRENCY_TYPE.fiat]: "Credit",
|
|
38
|
+
[CURRENCY_TYPE.crypto]: "Crypto"
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
export {
|
|
42
|
+
en as default
|
|
43
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const index = (locales) => {
|
|
2
|
+
const replace = (template, data) => (template || "").replace(
|
|
3
|
+
/{(\w*)}/g,
|
|
4
|
+
(_, key) => Object.prototype.hasOwnProperty.call(data || {}, key) ? data[key] : ""
|
|
5
|
+
);
|
|
6
|
+
const translate = (key, locale, params) => {
|
|
7
|
+
if (!locales[locale]) {
|
|
8
|
+
locale = "en";
|
|
9
|
+
}
|
|
10
|
+
return replace(locales[locale][key], params) || key;
|
|
11
|
+
};
|
|
12
|
+
const createTranslateFunc = (locale) => (key, params) => translate(key, locale || "en", params);
|
|
13
|
+
return { translate, createTranslateFunc };
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
index as default
|
|
17
|
+
};
|
package/es/locale/zh.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import flat from "flat";
|
|
2
|
+
import { SERVERLESS_INSTANCE_STATUS, INSTANCE_STATUS, PAYMENT_METHODS, CURRENCY_TYPE } from "../constant";
|
|
3
|
+
const zh = flat({
|
|
4
|
+
common: {
|
|
5
|
+
app: "应用",
|
|
6
|
+
billing: "账单",
|
|
7
|
+
duration: "时长",
|
|
8
|
+
spaceName: "应用空间"
|
|
9
|
+
},
|
|
10
|
+
serverlessInstance: {
|
|
11
|
+
appStatus: {
|
|
12
|
+
[SERVERLESS_INSTANCE_STATUS.launching]: "启动中",
|
|
13
|
+
[SERVERLESS_INSTANCE_STATUS.running]: "运行中",
|
|
14
|
+
[SERVERLESS_INSTANCE_STATUS.expired]: "已过期",
|
|
15
|
+
[SERVERLESS_INSTANCE_STATUS.terminated]: "已终止"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
dedicatedInstance: {
|
|
19
|
+
appStatus: {
|
|
20
|
+
[INSTANCE_STATUS.unknown]: "未知",
|
|
21
|
+
[INSTANCE_STATUS.pending]: "待处理",
|
|
22
|
+
[INSTANCE_STATUS.starting]: "启动中",
|
|
23
|
+
[INSTANCE_STATUS.running]: "运行中",
|
|
24
|
+
[INSTANCE_STATUS.restarting]: "重启中",
|
|
25
|
+
[INSTANCE_STATUS.stopping]: "停止中",
|
|
26
|
+
[INSTANCE_STATUS.stopped]: "已停止",
|
|
27
|
+
[INSTANCE_STATUS.terminated]: "已终止",
|
|
28
|
+
[INSTANCE_STATUS.expired]: "已过期",
|
|
29
|
+
[INSTANCE_STATUS.error]: "错误",
|
|
30
|
+
[INSTANCE_STATUS.waiting]: "等待中",
|
|
31
|
+
[INSTANCE_STATUS.underMaintenance]: "维护中"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
paymentMethod: {
|
|
35
|
+
[PAYMENT_METHODS.crypto]: "加密货币",
|
|
36
|
+
[PAYMENT_METHODS.stripe]: "信用卡",
|
|
37
|
+
[CURRENCY_TYPE.fiat]: "信用卡",
|
|
38
|
+
// TODO: 统一管理支付方式和货币类型
|
|
39
|
+
[CURRENCY_TYPE.crypto]: "加密货币"
|
|
40
|
+
// TODO: 统一管理支付方式和货币类型
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
export {
|
|
44
|
+
zh as default
|
|
45
|
+
};
|
package/es/middleware.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import pick from "lodash.pick";
|
|
2
|
+
import { getSort } from "./util";
|
|
3
|
+
const MAX_PAGING_SIZE = 100;
|
|
4
|
+
const DEFAULT_PAGING_SIZE = MAX_PAGING_SIZE;
|
|
5
|
+
const DEFAULT_PAGE = 1;
|
|
6
|
+
const pagination = (req, res, next) => {
|
|
7
|
+
const paging = {
|
|
8
|
+
page: DEFAULT_PAGE,
|
|
9
|
+
size: DEFAULT_PAGING_SIZE
|
|
10
|
+
};
|
|
11
|
+
req.paging = paging;
|
|
12
|
+
if (!Number.isNaN(Number(req.query.page))) {
|
|
13
|
+
paging.page = Number(req.query.page);
|
|
14
|
+
}
|
|
15
|
+
if (!Number.isNaN(Number(req.query.size))) {
|
|
16
|
+
const size = Number(req.query.size);
|
|
17
|
+
paging.size = size <= MAX_PAGING_SIZE ? size : MAX_PAGING_SIZE;
|
|
18
|
+
}
|
|
19
|
+
paging.sort = getSort(req.query.sortby, req.query.sortdir);
|
|
20
|
+
next();
|
|
21
|
+
};
|
|
22
|
+
const validate = (schema, option = {}) => (req, res, next) => {
|
|
23
|
+
const { error, value } = schema.validate(req.body, {
|
|
24
|
+
errors: { language: req.query.locale || "en" },
|
|
25
|
+
...option
|
|
26
|
+
});
|
|
27
|
+
if (error) {
|
|
28
|
+
res.status(400).json({ error: error.message });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
req.data = value;
|
|
32
|
+
next();
|
|
33
|
+
};
|
|
34
|
+
const createAuditMiddleware = ({ baseURL, writer, formatterMap }) => (req, res, next) => {
|
|
35
|
+
if (["PUT", "POST", "PATCH", "DELETE"].includes(req.method)) {
|
|
36
|
+
const originalResponse = res.end.bind(res);
|
|
37
|
+
const wrappedResponse = (...args) => {
|
|
38
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
39
|
+
const key = `${req.baseUrl}${req.route.path}`.replace(baseURL, req.method.toLowerCase());
|
|
40
|
+
const formater = formatterMap[key];
|
|
41
|
+
if (formater) {
|
|
42
|
+
const data = {
|
|
43
|
+
user: { ...pick(req.user, ["did", "role", "fullName"]) },
|
|
44
|
+
id: formater.id,
|
|
45
|
+
resource: formater.resource,
|
|
46
|
+
payload: formater.format({ req, res }),
|
|
47
|
+
ip: req.get("x-Real-ip", ""),
|
|
48
|
+
ua: req.get("user-agent", "")
|
|
49
|
+
};
|
|
50
|
+
writer(data);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return originalResponse(...args);
|
|
54
|
+
};
|
|
55
|
+
res.end = wrappedResponse;
|
|
56
|
+
}
|
|
57
|
+
next();
|
|
58
|
+
};
|
|
59
|
+
export {
|
|
60
|
+
DEFAULT_PAGE,
|
|
61
|
+
DEFAULT_PAGING_SIZE,
|
|
62
|
+
MAX_PAGING_SIZE,
|
|
63
|
+
createAuditMiddleware,
|
|
64
|
+
pagination,
|
|
65
|
+
validate
|
|
66
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import BlockletNotification from "@blocklet/sdk/service/notification";
|
|
2
|
+
class Notification {
|
|
3
|
+
constructor({ logger, auth }) {
|
|
4
|
+
this.auth = auth;
|
|
5
|
+
this.logger = logger || { info: console.info, error: console.error };
|
|
6
|
+
}
|
|
7
|
+
async sendNotification({ to, title, message, actions, attachments = [], assetAddress }) {
|
|
8
|
+
try {
|
|
9
|
+
const payload = { title, body: message, actions: actions || [], attachments: [...attachments] };
|
|
10
|
+
if (typeof assetAddress !== "undefined") {
|
|
11
|
+
payload.attachments.push({
|
|
12
|
+
type: "asset",
|
|
13
|
+
data: {
|
|
14
|
+
chainHost: this.auth.chainHost,
|
|
15
|
+
did: assetAddress
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
await BlockletNotification.sendToUser(to, payload);
|
|
20
|
+
this.logger.info("text message was sent", { to, payload: JSON.stringify(payload, null, 2) });
|
|
21
|
+
} catch (error) {
|
|
22
|
+
this.logger.error("send text message failed", { error, to, message, actions, attachments });
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
Notification as default
|
|
29
|
+
};
|
package/es/permission.js
ADDED
package/es/util.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import "moment-timezone";
|
|
2
|
+
import "moment/locale/zh-cn";
|
|
3
|
+
import moment from "moment";
|
|
4
|
+
import joinURL from "url-join";
|
|
5
|
+
import get from "lodash.get";
|
|
6
|
+
import { TIME_LOCALE, LAUNCH_STATUS } from "./constant";
|
|
7
|
+
const formatPeriod = (duration) => {
|
|
8
|
+
const value = Number(duration.slice(0, duration.length - 1));
|
|
9
|
+
const unit = duration[duration.length - 1];
|
|
10
|
+
return { value, unit };
|
|
11
|
+
};
|
|
12
|
+
const prettyDurationUnit = ({ value, unit }, locale) => {
|
|
13
|
+
if (!Object.keys(TIME_LOCALE).includes(locale)) {
|
|
14
|
+
locale = "en";
|
|
15
|
+
}
|
|
16
|
+
const localeKey = value > 1 ? `${unit}s` : unit;
|
|
17
|
+
return TIME_LOCALE[locale][localeKey.toLowerCase()];
|
|
18
|
+
};
|
|
19
|
+
const prettyDuration = (duration, locale) => {
|
|
20
|
+
if (!duration) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
const { value, unit } = duration;
|
|
24
|
+
return `${value}${prettyDurationUnit({ value, unit }, locale)}`;
|
|
25
|
+
};
|
|
26
|
+
const formatDatetime = (time, locale = "en-us", timezone = Intl.DateTimeFormat().resolvedOptions().timeZone) => {
|
|
27
|
+
if (!time) {
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
locale = locale || "en-us";
|
|
31
|
+
if (locale === "zh") {
|
|
32
|
+
locale = "zh-cn";
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return moment(time).locale(locale).tz(timezone).format("LLL zz");
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(`formate date time "${time}" error`, error);
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const formatUtcDatetime = (time, locale = "en-us") => formatDatetime(time, locale, "UTC");
|
|
42
|
+
const sortArrayByDate = (array, asc = true, field = void 0) => (array || []).sort((x, y) => {
|
|
43
|
+
let v1 = x;
|
|
44
|
+
let v2 = y;
|
|
45
|
+
if (typeof field !== "undefined") {
|
|
46
|
+
v1 = v1[field];
|
|
47
|
+
v2 = v2[field];
|
|
48
|
+
}
|
|
49
|
+
if (v1 === v2) {
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
const directionResult = asc ? 1 : -1;
|
|
53
|
+
if (moment(v1).diff(moment(v2)) > 0) {
|
|
54
|
+
return directionResult;
|
|
55
|
+
}
|
|
56
|
+
return -1 * directionResult;
|
|
57
|
+
});
|
|
58
|
+
const getSort = (sortby, sortdir) => {
|
|
59
|
+
if (sortby && sortby !== "undefined") {
|
|
60
|
+
return { [sortby]: sortdir };
|
|
61
|
+
}
|
|
62
|
+
return { createdAt: -1 };
|
|
63
|
+
};
|
|
64
|
+
const getExplorerUrl = ({ address, type = "txs", chainHost }) => {
|
|
65
|
+
return `https://explorer.abtnetwork.io/explorer/${type}/${address}?host=${chainHost}`;
|
|
66
|
+
};
|
|
67
|
+
const getBlockletDisplayName = (blocklet) => get(blocklet, "title") || get(blocklet, "name") || "";
|
|
68
|
+
const getBlockletAdminURL = (appURL) => joinURL(appURL, "/.well-known/service/admin/overview");
|
|
69
|
+
const isDateExpired = (expirationDate) => !!expirationDate && new Date(expirationDate).getTime() <= Date.now();
|
|
70
|
+
const getContinueLaunchURL = ({ baseURL, launch }) => {
|
|
71
|
+
const urlObject = new URL(baseURL);
|
|
72
|
+
if (launch.status < LAUNCH_STATUS.paid) {
|
|
73
|
+
urlObject.searchParams.set("sessionId", launch._id);
|
|
74
|
+
urlObject.searchParams.set("blocklet_meta_url", launch.blockletMetaUrl);
|
|
75
|
+
return urlObject.href;
|
|
76
|
+
}
|
|
77
|
+
if (launch.status >= LAUNCH_STATUS.paid && launch.status < LAUNCH_STATUS.installed) {
|
|
78
|
+
urlObject.pathname = joinURL(urlObject.pathname, `/launch/${launch.nftDid}`);
|
|
79
|
+
urlObject.searchParams.set("sessionId", launch._id);
|
|
80
|
+
urlObject.searchParams.set("blocklet_meta_url", launch.blockletMetaUrl);
|
|
81
|
+
urlObject.searchParams.set("launchType", launch.type);
|
|
82
|
+
if (launch.from) {
|
|
83
|
+
urlObject.searchParams.set("from", launch.from);
|
|
84
|
+
}
|
|
85
|
+
return urlObject.href;
|
|
86
|
+
}
|
|
87
|
+
return "";
|
|
88
|
+
};
|
|
89
|
+
const getBlockletMetaUrlFromQuery = (query) => {
|
|
90
|
+
const url = (query.get("blocklet_meta_url") || query.get("meta_url") || "").trim();
|
|
91
|
+
return decodeURIComponent(url);
|
|
92
|
+
};
|
|
93
|
+
const getRegistryUrlFromBlockletMetaUrl = (blockletMetaUrl) => {
|
|
94
|
+
try {
|
|
95
|
+
return blockletMetaUrl ? new URL(blockletMetaUrl).origin : "";
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error("get registry url from blocklet meta url error:", error);
|
|
98
|
+
return "";
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const formatRegistryLogoPath = (did, asset) => {
|
|
102
|
+
if (asset.startsWith("/assets")) {
|
|
103
|
+
return asset;
|
|
104
|
+
}
|
|
105
|
+
return `/assets/${did}/${asset}`;
|
|
106
|
+
};
|
|
107
|
+
const getBlockletLogoUrl = ({ did, baseUrl, logoPath }) => {
|
|
108
|
+
if (logoPath && logoPath.startsWith("http")) {
|
|
109
|
+
return logoPath;
|
|
110
|
+
}
|
|
111
|
+
if (baseUrl.startsWith("http") && logoPath) {
|
|
112
|
+
return joinURL(baseUrl, formatRegistryLogoPath(did, logoPath));
|
|
113
|
+
}
|
|
114
|
+
return "";
|
|
115
|
+
};
|
|
116
|
+
export {
|
|
117
|
+
formatDatetime,
|
|
118
|
+
formatPeriod,
|
|
119
|
+
formatUtcDatetime,
|
|
120
|
+
getBlockletAdminURL,
|
|
121
|
+
getBlockletDisplayName,
|
|
122
|
+
getBlockletLogoUrl,
|
|
123
|
+
getBlockletMetaUrlFromQuery,
|
|
124
|
+
getContinueLaunchURL,
|
|
125
|
+
getExplorerUrl,
|
|
126
|
+
getRegistryUrlFromBlockletMetaUrl,
|
|
127
|
+
getSort,
|
|
128
|
+
isDateExpired,
|
|
129
|
+
prettyDuration,
|
|
130
|
+
prettyDurationUnit,
|
|
131
|
+
sortArrayByDate
|
|
132
|
+
};
|
package/es/validator.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/launcher-util",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.5",
|
|
4
4
|
"description": "Common constants",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"constant"
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"main": "lib/util.js",
|
|
12
12
|
"files": [
|
|
13
13
|
"lib",
|
|
14
|
+
"es",
|
|
14
15
|
"LICENSE",
|
|
15
16
|
"package.json",
|
|
16
17
|
"README.md"
|
|
@@ -50,5 +51,5 @@
|
|
|
50
51
|
"vite": "^4.4.9",
|
|
51
52
|
"vite-plugin-build": "^0.10.0"
|
|
52
53
|
},
|
|
53
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "fab4f0dd5e6475b7e96104219aec4da5262df3ef"
|
|
54
55
|
}
|