@abtnode/blocklet-services 1.16.8-beta-0c0c5eb2 → 1.16.8-beta-b3039c78

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.
Files changed (40) hide show
  1. package/api/cache.js +32 -1
  2. package/api/emails/components/actions.js +23 -0
  3. package/api/emails/components/article.js +9 -0
  4. package/api/emails/components/asset.js +29 -0
  5. package/api/emails/components/attachments.js +55 -0
  6. package/api/emails/components/compose.js +27 -0
  7. package/api/emails/components/content.js +22 -0
  8. package/api/emails/components/copyright.js +14 -0
  9. package/api/emails/components/dapp.js +8 -0
  10. package/api/emails/components/footer.js +24 -0
  11. package/api/emails/components/header.js +20 -0
  12. package/api/emails/components/layout.js +15 -0
  13. package/api/emails/components/token.js +31 -0
  14. package/api/emails/components/transaction.js +16 -0
  15. package/api/emails/libs/config.js +256 -0
  16. package/api/emails/libs/constant.js +112 -0
  17. package/api/emails/libs/explorer-url.js +52 -0
  18. package/api/emails/libs/func.js +5 -0
  19. package/api/emails/libs/highlight.js +109 -0
  20. package/api/emails/libs/util.js +19 -0
  21. package/api/emails/pages/notification.js +26 -0
  22. package/api/emails/test.js +166 -0
  23. package/api/emails/types.js +2 -0
  24. package/api/index.js +1 -0
  25. package/api/libs/email.js +68 -0
  26. package/api/services/auth/connect/receive-transfer-app-owner.js +1 -1
  27. package/api/socket/channel/did.js +44 -26
  28. package/build/asset-manifest.json +11 -11
  29. package/build/index.html +1 -1
  30. package/build/static/css/{286.97b3dab6.chunk.css → 290.07ab3f1e.chunk.css} +1 -1
  31. package/build/static/js/{286.af946efa.chunk.js → 290.8692063d.chunk.js} +3 -3
  32. package/build/static/js/343.6fc2089d.chunk.js +2 -0
  33. package/build/static/js/460.df719a3e.chunk.js +2 -0
  34. package/build/static/js/main.94c49b7d.js +3 -0
  35. package/package.json +29 -22
  36. package/build/static/js/343.0b145b64.chunk.js +0 -2
  37. package/build/static/js/460.4763afe0.chunk.js +0 -2
  38. package/build/static/js/main.0006cb61.js +0 -3
  39. /package/build/static/js/{286.af946efa.chunk.js.LICENSE.txt → 290.8692063d.chunk.js.LICENSE.txt} +0 -0
  40. /package/build/static/js/{main.0006cb61.js.LICENSE.txt → main.94c49b7d.js.LICENSE.txt} +0 -0
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KEY_PAIR_APP_ID = exports.DEFAULT_TOKEN_ADDRESS = exports.loadingKeys = exports.ChainTxType = exports.VERSION_KEY = exports.TEST_OPENSEA_PROFILE = exports.MAIN_OPENSEA_PROFILE = exports.ENUM_SEND_TYPE = exports.INIT_GENERATE_DEFAULT = exports.INIT_CONNECT_SOCKET = exports.INIT_WALLET_TITLE = exports.INIT_WALLET = exports.CURRENT_VERSION = exports.EVM_DEFAULT_TOKEN_ADDRESS = exports.INFURA_PROJECT_ID = exports.TX_SEND_STATUS = exports.DEFAULT_IPFS_GATEWAY = exports.DEFAULT_IPFS_GATEWAY_HOST = exports.HIDE_PRICE = exports.HIDE_TEST_CHAINS = exports.CURRENT_UNIT = exports.BASE_RATE = exports.DEFAULT_DECIMAL = exports.GWEI = exports.DEFAULT_WITHDRAW_GAS_LIMIT = exports.CONTRACT_GAS_LIMIT = exports.DEFAULT_ERC20_GAS_LIMIT = exports.DEFAULT_GAS_LIMIT = exports.DEFAULT_ETH_TOKEN = exports.DEFAULT_CHAIN_TOKEN = exports.ETH_MAIN_CHAIN_ID = exports.BATE_CHAIN = exports.ASSET_CHAIN_ID = exports.ABT_TOKEN_ADDRESS = exports.ARCBLOCK_TOKEN_CONTRACT_ADDRESS = exports.TOKEN_SWAP_CHAIN_HOSTS = exports.DEFAULT_BATE_HOST = exports.DEFAULT_MAIN_HOST = exports.BLACK_LIST_CHAIN_HOST = exports.IGNORE_CHAIN = exports.NONE_FLAG = exports.ASSETS_TYPES = exports.SUPPORT_TX_TYPES = exports.DEFAULT_AVATAR = void 0;
4
+ exports.DEFAULT_AVATAR = 'https://web.abtwallet.io/static/images/public_default_avatar.png';
5
+ exports.SUPPORT_TX_TYPES = [
6
+ 'Transfer',
7
+ 'TransferV2',
8
+ 'Exchange',
9
+ 'ExchangeV2',
10
+ 'AcquireAssetV2',
11
+ 'Delegate',
12
+ 'RevokeStake',
13
+ 'ClaimStake',
14
+ 'CreateAsset',
15
+ 'CreateFactory',
16
+ 'CreateToken',
17
+ 'ConsumeAsset',
18
+ ];
19
+ exports.ASSETS_TYPES = {
20
+ WALLET: 'WALLET',
21
+ VC_BADGE: 'VC_BADGE',
22
+ VC_CREDENTIAL: 'VC_CREDENTIAL',
23
+ VC_CERTIFICATION: 'VC_CERTIFICATION',
24
+ VC_TICKET: 'VC_TICKET',
25
+ VC_PASSPORT: 'VC_PASSPORT',
26
+ UNKNOWN: 'UNKNOWN',
27
+ NFT_COMMON_DISPLAY: 'NFT_COMMON_DISPLAY',
28
+ };
29
+ exports.NONE_FLAG = 'none';
30
+ exports.IGNORE_CHAIN = [exports.NONE_FLAG, 'abtnode', 'eth', 'playground'];
31
+ exports.BLACK_LIST_CHAIN_HOST = [
32
+ 'lbd.abtnetwork.io',
33
+ 'zinc.network.arcblockio.cn',
34
+ 'app.didconnect.io',
35
+ 'ausd.abtnetwork.io',
36
+ 'zinc.abtnetwork.io',
37
+ ];
38
+ exports.DEFAULT_MAIN_HOST = 'https://main.abtnetwork.io/api/';
39
+ exports.DEFAULT_BATE_HOST = 'https://beta.abtnetwork.io/api/';
40
+ exports.TOKEN_SWAP_CHAIN_HOSTS = ['xenon.abtnetwork.io', 'xenon.network.arcblockio.cn', 'main.abtnetwork.io'];
41
+ exports.ARCBLOCK_TOKEN_CONTRACT_ADDRESS = '0xB98d4C97425d9908E66E53A6fDf673ACcA0BE986';
42
+ exports.ABT_TOKEN_ADDRESS = 'z35nNRvYxBoHitx9yZ5ATS88psfShzPPBLxYD';
43
+ exports.ASSET_CHAIN_ID = 'xenon-2020-01-15';
44
+ exports.BATE_CHAIN = 'beta';
45
+ exports.ETH_MAIN_CHAIN_ID = 'evm-1';
46
+ exports.DEFAULT_CHAIN_TOKEN = 'ABT';
47
+ exports.DEFAULT_ETH_TOKEN = 'ETH';
48
+ exports.DEFAULT_GAS_LIMIT = 25200;
49
+ exports.DEFAULT_ERC20_GAS_LIMIT = 80000;
50
+ exports.CONTRACT_GAS_LIMIT = 40000;
51
+ exports.DEFAULT_WITHDRAW_GAS_LIMIT = 100000;
52
+ exports.GWEI = 10 ** 9;
53
+ exports.DEFAULT_DECIMAL = 18;
54
+ exports.BASE_RATE = 10000;
55
+ exports.CURRENT_UNIT = 'price-unit';
56
+ exports.HIDE_TEST_CHAINS = 'hide-test-chains';
57
+ exports.HIDE_PRICE = 'hide-balance-price';
58
+ exports.DEFAULT_IPFS_GATEWAY_HOST = 'default-ipfs-gateway-host';
59
+ exports.DEFAULT_IPFS_GATEWAY = 'default-ipfs-gateway';
60
+ exports.TX_SEND_STATUS = {
61
+ WAITING: 'WAITING',
62
+ PENDING: 'PENDING',
63
+ OK: 'OK',
64
+ REPLACED: 'replaced',
65
+ FAIL_BEFORE_SEND: 'fail-before-send',
66
+ FAIL: 'fail',
67
+ };
68
+ exports.INFURA_PROJECT_ID = 'ffa38bc49bc64c9c94df039a626aeeaf';
69
+ exports.EVM_DEFAULT_TOKEN_ADDRESS = 'default';
70
+ exports.CURRENT_VERSION = '4.0';
71
+ exports.INIT_WALLET = 'init-wallet';
72
+ exports.INIT_WALLET_TITLE = 'wallet-title';
73
+ exports.INIT_CONNECT_SOCKET = 'have-checked-connect-socket';
74
+ exports.INIT_GENERATE_DEFAULT = 'default-information-has-been-generated';
75
+ exports.ENUM_SEND_TYPE = {
76
+ EVM_ASSET: 'evm-asset',
77
+ OCAP_ASSET: 'ocap-asset',
78
+ EVM_TOKEN: 'evm-token',
79
+ OCAP_TOKEN: 'ocap-token',
80
+ };
81
+ exports.MAIN_OPENSEA_PROFILE = 'https://opensea.io/account';
82
+ exports.TEST_OPENSEA_PROFILE = 'https://testnets.opensea.io/account';
83
+ exports.VERSION_KEY = 'local-wallet-version';
84
+ exports.ChainTxType = {
85
+ Transfer: 'transfer',
86
+ TransferV2: 'transfer_v2',
87
+ TransferV3: 'transfer_v3',
88
+ ExchangeV2: 'exchange_v2',
89
+ Stake: 'stake',
90
+ RevokeStake: 'revoke_stake',
91
+ ClaimStake: 'claim_stake',
92
+ CreateFactory: 'create_factory',
93
+ CreateToken: 'create_token',
94
+ CreateAsset: 'create_asset',
95
+ AcquireAssetV2: 'acquire_asset_v2',
96
+ AcquireAssetV3: 'acquire_asset_v3',
97
+ WithdrawTokenV2: 'withdraw_token_v2',
98
+ DepositTokenV2: 'deposit_token_v2',
99
+ Delegate: 'delegate',
100
+ RevokeDelegate: 'revoke_delegate',
101
+ SlashStake: 'slash_stake',
102
+ MintAsset: 'mint_asset',
103
+ };
104
+ exports.loadingKeys = {
105
+ migration: 'migrationProviderLoading',
106
+ generate: 'generateProviderLoading',
107
+ states: 'statesProviderLoading',
108
+ importData: 'isImportBackupFile',
109
+ security: 'securityPassword',
110
+ };
111
+ exports.DEFAULT_TOKEN_ADDRESS = [exports.NONE_FLAG, exports.EVM_DEFAULT_TOKEN_ADDRESS];
112
+ exports.KEY_PAIR_APP_ID = 'zfffffffffffffffffffffffffffffffff';
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const url_join_1 = __importDefault(require("url-join"));
7
+ const mcrypto_1 = require("@ocap/mcrypto");
8
+ const did_1 = require("@arcblock/did");
9
+ const config_1 = require("./config");
10
+ const util_1 = require("./util");
11
+ const { RoleType } = mcrypto_1.types;
12
+ const baseUrl = 'https://explorer.abtnetwork.io/explorer/';
13
+ function explorerUrl({ hash, asset, rollup, address, token, stake, chainId = '', }) {
14
+ if ((0, util_1.isEVMChain)(chainId)) {
15
+ const url = (0, util_1.getExplorerUrl)(chainId);
16
+ if (hash) {
17
+ return (0, url_join_1.default)(url, `tx/${hash}`);
18
+ }
19
+ if (asset) {
20
+ return (0, url_join_1.default)(url, `token/${asset}`);
21
+ }
22
+ return (0, url_join_1.default)(url, `address/${address}`);
23
+ }
24
+ const chain = config_1.arcChainConfig[chainId];
25
+ const chainHost = chain === null || chain === void 0 ? void 0 : chain.defaultRPC;
26
+ const host = chainHost ? `?host=${chainHost}` : '';
27
+ // rollup
28
+ if (rollup && (0, did_1.toTypeInfo)(rollup).role === RoleType.ROLE_ROLLUP) {
29
+ if (hash) {
30
+ return (0, url_join_1.default)(baseUrl, `rollups/${rollup}/moves/${hash}`, host);
31
+ }
32
+ return (0, url_join_1.default)(baseUrl, `rollups/${rollup}`, host);
33
+ }
34
+ // asset
35
+ if (asset) {
36
+ return (0, url_join_1.default)(baseUrl, `assets/${asset}`, host);
37
+ }
38
+ // tx
39
+ if (hash) {
40
+ return (0, url_join_1.default)(baseUrl, `txs/${hash}`, host);
41
+ }
42
+ // tx
43
+ if (token) {
44
+ return (0, url_join_1.default)(baseUrl, `tokens/${token}/tx`, host);
45
+ }
46
+ if (stake) {
47
+ return (0, url_join_1.default)(baseUrl, `stakes/${stake}`, host);
48
+ }
49
+ // account
50
+ return (0, url_join_1.default)(baseUrl, `accounts/${address}`, host);
51
+ }
52
+ exports.default = explorerUrl;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isSameAddr = void 0;
4
+ const isSameAddr = (addr1, addr2) => String(addr1).toLowerCase() === String(addr2).toLowerCase();
5
+ exports.isSameAddr = isSameAddr;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.toClickableSpan = void 0;
7
+ const explorer_url_1 = __importDefault(require("./explorer-url"));
8
+ const func_1 = require("./func");
9
+ class Link {
10
+ constructor({ type, did, chainId, text }) {
11
+ this.text = text;
12
+ this.did = did;
13
+ this.type = type;
14
+ this.chainId = chainId;
15
+ }
16
+ }
17
+ const toClickableSpan = (str, isHighLight = true) => {
18
+ const textList = toTextList(str);
19
+ return textList
20
+ .map((item) => {
21
+ if (item instanceof Link) {
22
+ if (isHighLight) {
23
+ let url;
24
+ const { type, chainId, did } = item;
25
+ if ((0, func_1.isSameAddr)(type, 'link')) {
26
+ url = `${chainId}:${did}`;
27
+ }
28
+ else if ((0, func_1.isSameAddr)(type, 'tx')) {
29
+ url = (0, explorer_url_1.default)({ hash: did, chainId });
30
+ }
31
+ else if ((0, func_1.isSameAddr)(type, 'stake')) {
32
+ url = (0, explorer_url_1.default)({ stake: did, chainId });
33
+ }
34
+ else if ((0, func_1.isSameAddr)(type, 'nft')) {
35
+ url = (0, explorer_url_1.default)({ asset: did, chainId });
36
+ }
37
+ else if ((0, func_1.isSameAddr)(type, 'token')) {
38
+ url = (0, explorer_url_1.default)({ token: did, chainId });
39
+ }
40
+ else if ((0, func_1.isSameAddr)(type, 'did')) {
41
+ url = (0, explorer_url_1.default)({ address: did, chainId });
42
+ }
43
+ // HACK: 邮件中无法支持 dapp 的展示,缺少 dapp 链接,只能作为加粗展示
44
+ if ((0, func_1.isSameAddr)(type, 'dapp')) {
45
+ return `<em data-type="${type}" data-chain-id="${chainId}" data-did="${did}">${item.text}</em>`;
46
+ }
47
+ if (url) {
48
+ return `<a target="_blank" href="${url}">${item.text}</a>`;
49
+ }
50
+ // 默认展示为加粗
51
+ return `<em data-type="${type}" data-chain-id="${chainId}" data-did="${did}">${item.text}</em>`;
52
+ }
53
+ return item.text;
54
+ }
55
+ return item;
56
+ })
57
+ .join('');
58
+ };
59
+ exports.toClickableSpan = toClickableSpan;
60
+ function toTextList(str) {
61
+ var _a;
62
+ const arr = [];
63
+ try {
64
+ let startPoint = 0;
65
+ const pattern = /<(.+?)\(?[tx|nft|token|stake|did|dapp|link]+[:](.+?)\)?>/gi; // 匹配 <asdad(did:abt:xxx)>
66
+ const matches = str.matchAll(pattern);
67
+ for (const match of matches) {
68
+ const didPattern = /\([tx|nft|token|stake|did|dapp|link]+[:](.+?)\)/gi; // 匹配 (did:abt:xxx)
69
+ const oriHit = match[0];
70
+ const matchIndex = match.index || startPoint;
71
+ const endPoint = matchIndex + oriHit.length;
72
+ const didMatcherLength = oriHit.matchAll(didPattern);
73
+ if ([...didMatcherLength].length > 1) {
74
+ return [str];
75
+ }
76
+ let showName = '';
77
+ const didMatcher = didPattern.exec(oriHit);
78
+ let hit = '';
79
+ if (didMatcher) {
80
+ const didGroup = didMatcher[0];
81
+ showName = oriHit.replace(didGroup, '').replace(/^</, '').replace(/(>)$/, '');
82
+ hit = didGroup.replace(/\)$/, '').replace(/^\(/, '');
83
+ }
84
+ else {
85
+ hit = oriHit;
86
+ }
87
+ const address = hit.split(':');
88
+ const didType = (_a = (address[0] || '').replace(/^</, '').replace(/^\(/, '')) === null || _a === void 0 ? void 0 : _a.toUpperCase();
89
+ const chainId = (address[1] || '').replace(/>$/, '').replace(/\)$/, '');
90
+ const did = (address[address.length - 1] || '').replace(/>$/, '').replace(/\)$/, '');
91
+ arr.push(str.substring(startPoint, matchIndex));
92
+ arr.push(new Link({
93
+ type: didType,
94
+ chainId,
95
+ did,
96
+ text: showName || didType,
97
+ }));
98
+ startPoint = endPoint;
99
+ }
100
+ if (startPoint < str.length) {
101
+ arr.push(str.substring(startPoint));
102
+ }
103
+ return arr;
104
+ }
105
+ catch (error) {
106
+ console.error(error === null || error === void 0 ? void 0 : error.message);
107
+ return [str];
108
+ }
109
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getExplorerUrl = exports.isEVMChain = void 0;
4
+ const config_1 = require("./config");
5
+ const isEVMChain = (chainId) => {
6
+ if (!chainId) {
7
+ return false;
8
+ }
9
+ return chainId.startsWith(config_1.EVM_PREFIX);
10
+ };
11
+ exports.isEVMChain = isEVMChain;
12
+ const getExplorerUrl = (chainId) => {
13
+ const chain = (0, config_1.getConfigByChainId)(chainId);
14
+ if (chain) {
15
+ return chain.explorer;
16
+ }
17
+ return '';
18
+ };
19
+ exports.getExplorerUrl = getExplorerUrl;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NotificationEmail = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const components_1 = require("@react-email/components");
9
+ const footer_1 = __importDefault(require("../components/footer"));
10
+ const content_1 = __importDefault(require("../components/content"));
11
+ const layout_1 = __importDefault(require("../components/layout"));
12
+ const header_1 = __importDefault(require("../components/header"));
13
+ const NotificationEmail = ({ title, body = '', attachments = [], actions = [], appInfo, locale = 'en', }) => {
14
+ return ((0, jsx_runtime_1.jsxs)(layout_1.default, Object.assign({ mainStyle: main }, { children: [(0, jsx_runtime_1.jsx)(components_1.Preview, { children: title }), (0, jsx_runtime_1.jsx)(header_1.default, { appInfo: appInfo }), (0, jsx_runtime_1.jsx)(content_1.default, { style: container, title: title, content: body, attachments: attachments, actions: actions, locale: locale }), (0, jsx_runtime_1.jsx)(footer_1.default, { showCopyright: false, showBlocklet: true, appInfo: appInfo })] })));
15
+ };
16
+ exports.NotificationEmail = NotificationEmail;
17
+ exports.default = exports.NotificationEmail;
18
+ const fontFamily = 'HelveticaNeue,Helvetica,Arial,sans-serif';
19
+ const main = {
20
+ fontFamily,
21
+ };
22
+ const container = {
23
+ margin: '30px auto',
24
+ backgroundColor: '#ffffff',
25
+ padding: '5px 50px 10px 60px',
26
+ };
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const notification_1 = __importDefault(require("./pages/notification"));
8
+ function Test() {
9
+ const title = 'Blocklet Server is about to expire';
10
+ const body = 'User <DAMINGZHAO(did:abt:z1Y313EXfBK9FePjDh5cZy6sNY97TneEemB)> has a <Transaction(tx:beta:D20C566BB46A7B6B4DDEA0B42EB3996F0213C1C27C54533F3D40D7B5C6DA59FD)> and it will give your a <Badge (nft:beta:zjdivheWGgy6ucvsYYqP34hVeUgx6743GEfx)> on the DApp <OCAP Playground(dapp:beta:zNKeLKixvCM32TkVM1zmRDdAU3bvm3dTtAcM)>';
11
+ const attachments = [
12
+ {
13
+ type: 'token',
14
+ data: {
15
+ address: 'abcdefghjikl',
16
+ decimal: 18,
17
+ amount: 10000,
18
+ chianHost: 'beta',
19
+ symbol: 'TBA',
20
+ },
21
+ },
22
+ {
23
+ type: 'nft',
24
+ data: {
25
+ chianHost: 'beta',
26
+ did: 'abcdefghijkl',
27
+ },
28
+ },
29
+ // {
30
+ // type: 'vc',
31
+ // data: {
32
+ // credential: '',
33
+ // tag: '',
34
+ // },
35
+ // },
36
+ {
37
+ type: 'text',
38
+ data: {
39
+ type: 'plain',
40
+ text: '哈哈哈哈哈',
41
+ color: 'red',
42
+ },
43
+ },
44
+ {
45
+ type: 'image',
46
+ data: {
47
+ url: 'https://picsum.photos/100/100',
48
+ alt: 'beta',
49
+ },
50
+ },
51
+ {
52
+ type: 'divider',
53
+ },
54
+ {
55
+ type: 'transaction',
56
+ data: {
57
+ hash: 'asdasdasasd',
58
+ chainId: 'beta',
59
+ },
60
+ },
61
+ {
62
+ type: 'dapp',
63
+ data: {
64
+ url: 'https://token-prize-pool-bfg-18-180-145-193.ip.abtnet.io/',
65
+ appDID: 'zNKuEeFscqBDfaS5RMrmFKdQmucpcQkPEJgi',
66
+ logo: 'https://picsum.photos/50/50',
67
+ title: 'Token Prize',
68
+ desc: '奖金池开启,速来瓜分🏃🏻🏃🏻🏃🏻~\n[测试] 使用 DID 钱包 + Twitter 账户即可参与奖池瓜分,更有机会直接赢走 50% 奖池数额,快来参加吧!!!',
69
+ },
70
+ },
71
+ {
72
+ type: 'link',
73
+ data: {
74
+ url: 'https://token-prize-pool-bfg-18-180-145-193.ip.abtnet.io/',
75
+ image: 'https://picsum.photos/50/50',
76
+ title: 'Token Prize',
77
+ description: '奖金池开启,速来瓜分🏃🏻🏃🏻🏃🏻~\n[测试] 使用 DID 钱包 + Twitter 账户即可参与奖池瓜分,更有机会直接赢走 50% 奖池数额,快来参加吧!!!',
78
+ },
79
+ },
80
+ {
81
+ type: 'section',
82
+ fileds: [
83
+ {
84
+ type: 'text',
85
+ data: {
86
+ type: 'plain',
87
+ color: '#9397A1',
88
+ text: '当前余额',
89
+ },
90
+ },
91
+ {
92
+ type: 'text',
93
+ data: {
94
+ type: 'plain',
95
+ color: '#DE9E37',
96
+ text: '+ 100 ABT',
97
+ },
98
+ },
99
+ {
100
+ type: 'text',
101
+ data: {
102
+ type: 'plain',
103
+ color: '#9397A1',
104
+ text: '扣费日期',
105
+ },
106
+ },
107
+ {
108
+ type: 'text',
109
+ data: {
110
+ type: 'plain',
111
+ text: '2023年1月3日 上午8:00',
112
+ },
113
+ },
114
+ {
115
+ type: 'text',
116
+ data: {
117
+ type: 'plain',
118
+ color: '#9397A1',
119
+ text: '下月扣除',
120
+ },
121
+ },
122
+ {
123
+ type: 'text',
124
+ data: {
125
+ type: 'plain',
126
+ text: '200 ABT',
127
+ },
128
+ },
129
+ {
130
+ type: 'text',
131
+ data: {
132
+ type: 'plain',
133
+ color: '#9397A1',
134
+ text: '本月支出',
135
+ },
136
+ },
137
+ {
138
+ type: 'text',
139
+ data: {
140
+ type: 'plain',
141
+ text: '-200 ABT',
142
+ },
143
+ },
144
+ ],
145
+ },
146
+ ];
147
+ const actions = [
148
+ {
149
+ name: 'Launch',
150
+ url: '',
151
+ },
152
+ {
153
+ name: 'Dashboard',
154
+ url: '',
155
+ },
156
+ ];
157
+ const appInfo = {
158
+ title: 'Blocklet Email Test',
159
+ logo: 'https://picsum.photos/200/100',
160
+ url: 'https://www.arcblock.io',
161
+ description: 'This is a test blocklet for email test only',
162
+ version: '1.0.0',
163
+ };
164
+ return (0, jsx_runtime_1.jsx)(notification_1.default, { title: title, body: body, attachments: attachments, actions: actions, appInfo: appInfo });
165
+ }
166
+ exports.default = Test;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/api/index.js CHANGED
@@ -128,6 +128,7 @@ module.exports = function createServer(node, serverOptions = {}) {
128
128
  logger.info('delete blocklet cache on update', { did, pid: process.pid });
129
129
  cache.del(cache.keyFns.blocklet(did));
130
130
  cache.del(cache.keyFns.blockletInfo(did));
131
+ cache.del(cache.keyFns.notificationConfig(did));
131
132
  }
132
133
 
133
134
  // structV1Did is just for migration purpose and should be removed in the future
@@ -0,0 +1,68 @@
1
+ const { Joi } = require('@arcblock/validator');
2
+ const { render } = require('@react-email/components');
3
+ const { getSafeEnv } = require('@abtnode/core/lib/util');
4
+ const { getRuntimeEnvironments } = require('@abtnode/core/lib/util/blocklet');
5
+ const { emailConfigSchema } = require('@blocklet/sdk/lib/validators/email');
6
+
7
+ const { NotificationEmail } = require('../emails/pages/notification');
8
+ const cache = require('../cache');
9
+
10
+ const schemaEmail = Joi.string().email().required();
11
+
12
+ const validateEmail = schemaEmail.validateAsync.bind(schemaEmail);
13
+
14
+ async function sendEmail(receiver, notification, { teamDid, node }) {
15
+ if (!receiver) {
16
+ throw new Error('receiver is required');
17
+ }
18
+
19
+ if (!notification.title && !notification.body) {
20
+ throw new Error('notification is required');
21
+ }
22
+
23
+ const blocklet = await node.getBlocklet({ did: teamDid, attachRuntimeInfo: false });
24
+ const config = blocklet.settings?.notification?.email || {};
25
+
26
+ if (!config.enabled) {
27
+ // skip send email
28
+ return;
29
+ }
30
+ delete config.enabled;
31
+
32
+ const { error, value: emailConfig } = emailConfigSchema.validate(config);
33
+ if (error) {
34
+ throw new Error(error.message);
35
+ }
36
+
37
+ const nodeEnvironments = await node.states.node.getEnvironments();
38
+ const env = getSafeEnv(getRuntimeEnvironments(blocklet, nodeEnvironments));
39
+
40
+ const url = env?.BLOCKLET_APP_URL;
41
+ // logo 采用顺序:横板 logo -> 正方形 logo -> blocklet.yml 指定的 logo
42
+ const logo =
43
+ env?.BLOCKLET_APP_LOGO_RECT || env?.BLOCKLET_APP_LOGO_SQUARE || `${url}/.well-known/service/blocklet/logo/`;
44
+
45
+ const appInfo = {
46
+ logo,
47
+ description: blocklet?.meta?.description,
48
+ title: blocklet?.meta?.title || blocklet?.meta?.name,
49
+ version: blocklet?.meta?.version,
50
+ url,
51
+ };
52
+
53
+ const html = render(NotificationEmail({ ...notification, appInfo }));
54
+ const emailData = {
55
+ from: emailConfig.from,
56
+ to: receiver,
57
+ title: notification.title,
58
+ subject: notification.title,
59
+ html,
60
+ };
61
+ const transporter = cache.getTransport({ did: teamDid, config: emailConfig });
62
+ await transporter.sendMail(emailData);
63
+ }
64
+
65
+ module.exports = {
66
+ validateEmail,
67
+ sendEmail,
68
+ };
@@ -171,7 +171,7 @@ module.exports = function createRoutes(node, _, createSessionToken) {
171
171
  throw new Error(`keyPair.secret is empty: ${appDid}`);
172
172
  }
173
173
 
174
- const blocklet = await node.getBlocklet({ did: appDid, attachRuntimeInfo: false });
174
+ const blocklet = await node.getBlocklet({ did: appDid });
175
175
  if (!blocklet) {
176
176
  throw new Error(messages.invalidBlocklet[locale]);
177
177
  }