@abtnode/blocklet-services 1.8.3 → 1.8.4

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.
@@ -1,308 +1,33 @@
1
- /* eslint-disable arrow-parens */
2
- const get = require('lodash/get');
3
- const joinUrl = require('url-join');
4
-
5
- const { extractUserAvatar } = require('@abtnode/util/lib/user-avatar');
6
- const formatContext = require('@abtnode/util/lib/format-context');
7
- const {
8
- messages,
9
- getVCFromClaims,
10
- checkWalletVersion,
11
- getUser,
12
- getPassportStatusEndpoint,
13
- validatePassportStatus,
14
- } = require('@abtnode/auth/lib/auth');
15
- const {
16
- ROLES,
17
- VC_TYPE_GENERAL_PASSPORT,
18
- VC_TYPE_NODE_PASSPORT,
19
- NODE_SERVICES,
20
- WELLKNOWN_SERVICE_PATH_PREFIX,
21
- WHO_CAN_ACCESS,
22
- } = require('@abtnode/constant');
23
- const {
24
- createPassportVC,
25
- createPassport,
26
- validatePassport,
27
- isUserPassportRevoked,
28
- upsertToPassports,
29
- getRoleFromLocalPassport,
30
- getRoleFromExternalPassport,
31
- createUserPassport,
32
- } = require('@abtnode/auth/lib/passport');
33
1
  const logger = require('@abtnode/logger')(require('../../../../package.json').name);
34
2
 
35
- const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
36
-
37
- /**
38
- * @returns {Array} config
39
- * @returns {Boolean} config[0] is invited user only
40
- * @returns {String} config[1] default role
41
- * @returns {Boolean} config[2] issue passport
42
- */
43
- const isInvitedUserOnly = async (config, node, teamDid) => {
44
- const count = await node.getUsersCount({ teamDid });
45
-
46
- // issue owner passport for first login user
47
- if (count === 0) {
48
- return [false, ROLES.OWNER, true];
49
- }
3
+ const { login } = require('../../../libs/connect/session');
50
4
 
51
- if ([WHO_CAN_ACCESS.OWNER, WHO_CAN_ACCESS.INVITED].includes(config.whoCanAccess)) {
52
- return [true];
53
- }
54
-
55
- if ([WHO_CAN_ACCESS.ALL].includes(config.whoCanAccess)) {
56
- return [false, ROLES.GUEST];
57
- }
58
-
59
- return [false, ROLES.GUEST];
60
- };
5
+ const { onConnect, onApprove } = login;
61
6
 
62
7
  module.exports = function createRoutes(node, authenticator, createSessionToken) {
63
8
  return {
64
9
  action: 'login',
65
- onConnect: async ({ req, userDid }) => {
66
- const blocklet = await req.getBlocklet();
67
-
68
- const claims = {
69
- profile: async ({ extraParams, context }) => {
70
- const { locale } = extraParams;
71
-
72
- const config = await context.request.getServiceConfig(NODE_SERVICES.AUTH);
73
- const profileFields = get(config, 'profileFields');
74
-
75
- return {
76
- fields: profileFields || ['fullName', 'avatar'],
77
- description: messages.description[locale],
78
- };
79
- },
80
-
81
- verifiableCredential: async ({ context, extraParams: { locale, passportId = '' } }) => {
82
- const { request, didwallet } = context;
83
- const { wallet, did: teamDid } = await request.getBlockletInfo();
84
-
85
- checkWalletVersion({ didwallet, locale });
86
-
87
- const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
88
- const trustedIssuers = [wallet.address, ...trustedPassports].filter(Boolean);
89
-
90
- const config = (await request.getServiceConfig(NODE_SERVICES.AUTH)) || {};
91
- const [invitedUserOnly] = await isInvitedUserOnly(config, node, teamDid);
92
-
93
- const claim = {
94
- description: messages.requestPassport[locale],
95
- item: vcTypes,
96
- trustedIssuers,
97
- optional: !invitedUserOnly,
98
- };
99
- if (passportId) {
100
- claim.target = passportId;
101
- }
102
-
103
- return claim;
104
- },
105
- };
106
-
107
- const user = await node.getUser({ teamDid: blocklet.meta.did, user: { did: userDid } });
108
- if (user) {
109
- delete claims.profile;
110
- }
111
-
112
- return claims;
10
+ onConnect: async ({ req, userDid, extraParams: { locale, passportId = '' } }) => {
11
+ return onConnect({ node, request: req, userDid, locale, passportId });
113
12
  },
114
13
 
115
- // eslint-disable-next-line consistent-return
116
14
  onAuth: async ({ claims, challenge, userDid, userPk, updateSession, extraParams, req, baseUrl }) => {
117
- const { locale } = extraParams;
118
- const blocklet = await req.getBlocklet();
119
- const { wallet, name, passportColor, did: teamDid } = await req.getBlockletInfo();
120
- const teamAppDid = wallet.address;
121
-
122
- // check user approved
123
- const user = await getUser(node, teamDid, userDid);
124
- if (user && !user.approved) {
125
- throw new Error(messages.notAllowed[locale]);
126
- }
127
-
128
- // Get passport
129
- const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
130
- const trustedIssuers = [teamAppDid, ...trustedPassports].filter(Boolean);
131
- const { vc: inputVC } = await getVCFromClaims({
132
- claims,
133
- challenge,
134
- trustedIssuers,
135
- vcTypes,
136
- locale,
137
- });
138
-
139
- let vc = inputVC;
140
-
141
- const config = (await req.getServiceConfig(NODE_SERVICES.AUTH)) || {};
142
- const [invitedUserOnly, defaultRole, issuePassport] = await isInvitedUserOnly(config, node, teamDid);
143
-
144
- if (invitedUserOnly && !vc) {
145
- throw new Error(messages.missingCredentialClaim[locale]);
146
- }
147
-
148
- // issue passport for the first login user in a invite-only team
149
- if (issuePassport) {
150
- logger.info('issue passport to user at the login workflow', { role: defaultRole });
151
- const profile = claims.find((x) => x.type === 'profile');
152
- vc = createPassportVC({
153
- issuerName: name,
154
- issuerWallet: wallet,
155
- ownerDid: userDid,
156
- passport: await createPassport({
157
- name: defaultRole,
158
- node,
159
- teamDid,
160
- locale,
161
- endpoint: baseUrl,
162
- }),
163
- endpoint: getPassportStatusEndpoint({
164
- baseUrl: joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
165
- userDid,
166
- teamDid,
167
- }),
168
- ownerProfile: profile,
169
- preferredColor: passportColor,
170
- });
171
- }
172
-
173
- // Get user passport from vc
174
- let passport = vc ? createUserPassport(vc) : null;
175
- if (user && passport && isUserPassportRevoked(user, passport)) {
176
- throw new Error(messages.passportRevoked[locale](name));
177
- }
178
-
179
- // Get role
180
- let role = ROLES.GUEST;
181
- if (vc) {
182
- await validatePassport(get(vc, 'credentialSubject.passport'));
183
- const issuerId = get(vc, 'issuer.id');
184
- if (issuerId === teamAppDid) {
185
- role = getRoleFromLocalPassport(get(vc, 'credentialSubject.passport'));
186
- } else {
187
- // map external passport to local role
188
- const { mappings = [] } = (blocklet.trustedPassports || []).find((x) => x.issuerDid === issuerId) || {};
189
- role = await getRoleFromExternalPassport({
190
- passport: get(vc, 'credentialSubject.passport'),
191
- node,
192
- teamDid,
193
- locale,
194
- mappings,
195
- });
196
-
197
- // check status of external passport if passport has an endpoint
198
- const endpoint = get(vc, 'credentialStatus.id');
199
- if (endpoint) {
200
- await validatePassportStatus({ vcId: vc.id, endpoint, locale });
201
- }
202
- }
203
- }
204
-
205
- if (config.whoCanAccess === WHO_CAN_ACCESS.OWNER && role !== ROLES.OWNER) {
206
- throw new Error(
207
- {
208
- zh: '你不是该应用的所有者',
209
- en: 'You are not the owner of this application',
210
- }[locale]
211
- );
212
- }
213
-
214
- // Recreate passport with correct role
215
- passport = vc ? createUserPassport(vc, { role }) : null;
216
-
217
- // Update profile
218
15
  try {
219
- const passportForLog = passport || { name: 'Guest', role: 'guest' };
220
- if (user) {
221
- // Update user
222
- const doc = await node.updateUser({
223
- teamDid,
224
- user: {
225
- did: userDid,
226
- pk: userPk,
227
- locale,
228
- passports: upsertToPassports(user.passports || [], passport).filter(Boolean),
229
- lastLoginAt: new Date().toISOString(),
230
- },
231
- });
232
- await node.createAuditLog(
233
- {
234
- action: 'login',
235
- args: { teamDid, userDid, passport: passportForLog },
236
- context: formatContext(Object.assign(req, { user: doc })),
237
- result: doc,
238
- },
239
- node
240
- );
241
- } else {
242
- // Create user
243
- const profile = claims.find((x) => x.type === 'profile');
244
-
245
- const doc = await node.addUser({
246
- teamDid,
247
- user: {
248
- ...profile,
249
- avatar: await extractUserAvatar(get(profile, 'avatar'), {
250
- dataDir: blocklet.env.dataDir,
251
- }),
252
- did: userDid,
253
- pk: userPk,
254
- approved: true,
255
- locale,
256
- passports: [passport].filter(Boolean),
257
- firstLoginAt: new Date().toISOString(),
258
- lastLoginAt: new Date().toISOString(),
259
- },
260
- });
261
- await node.createAuditLog(
262
- {
263
- action: 'addUser',
264
- args: { teamDid, userDid, reason: `first login as ${passportForLog.role}` },
265
- context: formatContext(Object.assign(req, { user: doc })),
266
- result: doc,
267
- },
268
- node
269
- );
270
- }
271
-
272
- // Generate new session token that client can save to localStorage
273
- const sessionToken = await createSessionToken(userDid, { passport, role });
274
- await updateSession({ sessionToken }, true);
275
- logger.info('login.success', { userDid, role });
276
-
277
- if (
278
- // if user provides owner passport AND app does not have owner, set this user to owner
279
- (inputVC && role === ROLES.OWNER && !blocklet.settings?.owner) ||
280
- // if the user will receive a owner passport AND app does not have owner, set this user to owner
281
- (issuePassport && defaultRole === ROLES.OWNER && !blocklet.settings?.owner)
282
- ) {
283
- logger.info('Bind owner for blocklet', { teamDid, userDid });
284
- await node.setBlockletInitialized({ did: teamDid, owner: { did: userDid, pk: userPk } });
285
- }
286
-
287
- // issue passport for the first login user in a invite-only team
288
- if (issuePassport) {
289
- return {
290
- disposition: 'attachment',
291
- type: 'VerifiableCredential',
292
- data: vc,
293
- nextWorkflowData: {
294
- userDid,
295
- },
296
- };
297
- }
16
+ const result = await onApprove({
17
+ node,
18
+ request: req,
19
+ locale: extraParams.locale,
20
+ challenge,
21
+ userDid,
22
+ userPk,
23
+ baseUrl,
24
+ claims,
25
+ createSessionToken,
26
+ });
298
27
 
299
- // TODO set app owner
28
+ await updateSession({ sessionToken: result.sessionToken }, true);
300
29
 
301
- return {
302
- nextWorkflowData: {
303
- userDid,
304
- },
305
- };
30
+ return result;
306
31
  } catch (err) {
307
32
  logger.error('login.error', { error: err, userDid });
308
33
  throw new Error(err.message);
@@ -1,116 +1,31 @@
1
- const get = require('lodash/get');
2
- const formatContext = require('@abtnode/util/lib/format-context');
3
- const { messages, getVCFromClaims, getUser, validatePassportStatus } = require('@abtnode/auth/lib/auth');
4
- const { ROLES, VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT } = require('@abtnode/constant');
5
- const {
6
- validatePassport,
7
- isUserPassportRevoked,
8
- getRoleFromLocalPassport,
9
- getRoleFromExternalPassport,
10
- createUserPassport,
11
- } = require('@abtnode/auth/lib/passport');
1
+ const { switchPassport } = require('../../../libs/connect/session');
12
2
 
13
- const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
3
+ const { onConnect, onApprove } = switchPassport;
14
4
 
15
5
  module.exports = function createRoutes(node, authenticator, createSessionToken) {
16
6
  return {
17
7
  action: 'switch-passport',
18
8
  onConnect: async ({ req, userDid, extraParams: { locale, connectedDid } }) => {
19
- if (userDid && connectedDid && userDid !== connectedDid) {
20
- throw new Error(messages.userMismatch[locale]);
21
- }
22
-
23
- const { wallet, did: teamDid } = await req.getBlockletInfo();
24
- const user = await getUser(node, teamDid, userDid);
25
-
26
- if (!user) {
27
- throw new Error(messages.userNotFound[locale]);
28
- }
29
- if (!user.approved) {
30
- throw new Error(messages.notAuthorized[locale]);
31
- }
32
-
33
- return {
34
- verifiableCredential: async ({ context }) => {
35
- const { request } = context;
36
- const blocklet = await request.getBlocklet();
37
-
38
- const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
39
- const trustedIssuers = [wallet.address, ...trustedPassports].filter(Boolean);
40
-
41
- return {
42
- description: messages.requestPassport[locale],
43
- item: vcTypes,
44
- trustedIssuers,
45
- optional: false,
46
- };
47
- },
48
- };
9
+ return onConnect({
10
+ node,
11
+ request: req,
12
+ locale,
13
+ userDid,
14
+ previousUserDid: connectedDid,
15
+ });
49
16
  },
50
17
 
51
18
  onAuth: async ({ claims, challenge, userDid, updateSession, extraParams, req }) => {
52
- const { locale } = extraParams;
53
- const blocklet = await req.getBlocklet();
54
- const { wallet, name, did: teamDid } = await req.getBlockletInfo();
55
-
56
- // Validate user
57
- const user = await getUser(node, teamDid, userDid);
58
- if (!user) {
59
- throw new Error(messages.userNotFound[locale]);
60
- }
61
- if (!user.approved) {
62
- throw new Error(messages.notAuthorized[locale]);
63
- }
64
-
65
- // Get passport
66
- const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
67
- const trustedIssuers = [wallet.address, ...trustedPassports].filter(Boolean);
68
- const { vc } = await getVCFromClaims({ claims, challenge, trustedIssuers, vcTypes, locale });
69
-
70
- // Get user passport from vc
71
- let passport = createUserPassport(vc);
72
- if (passport && isUserPassportRevoked(user, passport)) {
73
- throw new Error(messages.passportRevoked[locale](name));
74
- }
75
-
76
- // Get role
77
- let role = ROLES.GUEST;
78
- await validatePassport(get(vc, 'credentialSubject.passport'));
79
- const issuerId = get(vc, 'issuer.id');
80
- if (issuerId === wallet.address) {
81
- role = getRoleFromLocalPassport(get(vc, 'credentialSubject.passport'));
82
- } else {
83
- // map external passport to local role
84
- const { mappings = [] } = (blocklet.trustedPassports || []).find((x) => x.issuerDid === issuerId) || {};
85
- role = await getRoleFromExternalPassport({
86
- passport: get(vc, 'credentialSubject.passport'),
87
- node,
88
- teamDid,
89
- locale,
90
- mappings,
91
- });
92
-
93
- // check status of external passport if passport has an endpoint
94
- const endpoint = get(vc, 'credentialStatus.id');
95
- if (endpoint) {
96
- await validatePassportStatus({ vcId: vc.id, endpoint, locale });
97
- }
98
- }
99
-
100
- // Recreate passport with correct role
101
- passport = createUserPassport(vc, { role });
102
- await node.createAuditLog(
103
- {
104
- action: 'switchPassport',
105
- args: { teamDid, userDid, passport },
106
- context: formatContext(Object.assign(req, { user })),
107
- result: {},
108
- },
109
- node
110
- );
19
+ const sessionToken = await onApprove({
20
+ node,
21
+ request: req,
22
+ challenge,
23
+ locale: extraParams.locale,
24
+ verifiableCredential: claims.find((x) => x.type === 'verifiableCredential'),
25
+ userDid,
26
+ createSessionToken,
27
+ });
111
28
 
112
- // Generate new session token that client can save to localStorage
113
- const sessionToken = await createSessionToken(userDid, { passport, role });
114
29
  await updateSession({ sessionToken }, true);
115
30
  },
116
31
  };
@@ -1,75 +1,29 @@
1
- const get = require('lodash/get');
2
- const formatContext = require('@abtnode/util/lib/format-context');
3
- const { messages, getUser } = require('@abtnode/auth/lib/auth');
4
- const { NODE_SERVICES } = require('@abtnode/constant');
5
- const { extractUserAvatar } = require('@abtnode/util/lib/user-avatar');
1
+ const { switchProfile } = require('../../../libs/connect/session');
2
+
3
+ const { onConnect, onApprove } = switchProfile;
6
4
 
7
5
  module.exports = function createRoutes(node) {
8
6
  return {
9
7
  action: 'switch-profile',
10
- onConnect: async ({ req, userDid, extraParams: { locale, connectedDid } }) => {
11
- if (userDid && connectedDid && userDid !== connectedDid) {
12
- throw new Error(messages.userMismatch[locale]);
13
- }
14
-
15
- const config = await req.getServiceConfig(NODE_SERVICES.AUTH);
16
- if (get(config, 'allowSwitchProfile', true) === false) {
17
- throw new Error(messages.actionForbidden[locale]);
18
- }
19
-
20
- const { did: teamDid } = await req.getBlockletInfo();
21
- const user = await getUser(node, teamDid, userDid);
22
-
23
- if (!user) {
24
- throw new Error(messages.userNotFound[locale]);
25
- }
26
- if (!user.approved) {
27
- throw new Error(messages.notAuthorized[locale]);
28
- }
29
-
30
- return {
31
- profile: {
32
- fields: get(config, 'profileFields') || ['fullName', 'avatar'],
33
- description: messages.description[locale],
34
- },
35
- };
8
+ onConnect: ({ req, userDid, extraParams: { locale, connectedDid } }) => {
9
+ return onConnect({
10
+ node,
11
+ request: req,
12
+ locale,
13
+ userDid,
14
+ previousUserDid: connectedDid,
15
+ });
36
16
  },
37
17
 
38
18
  onAuth: async ({ req, claims, userDid, extraParams: { locale } }) => {
39
- const blocklet = await req.getBlocklet();
40
- const teamDid = blocklet.meta.did;
41
-
42
- // check user approved
43
- const user = await getUser(node, teamDid, userDid);
44
- if (!user) {
45
- throw new Error(messages.userNotFound[locale]);
46
- }
47
- if (!user.approved) {
48
- throw new Error(messages.notAuthorized[locale]);
49
- }
50
-
51
- // Update user
52
19
  const profile = claims.find((x) => x.type === 'profile');
53
- const doc = await node.updateUser({
54
- teamDid,
55
- user: {
56
- ...user,
57
- ...profile,
58
- avatar: await extractUserAvatar(get(profile, 'avatar'), {
59
- dataDir: blocklet.env.dataDir,
60
- }),
61
- locale,
62
- },
20
+ return onApprove({
21
+ node,
22
+ request: req,
23
+ locale,
24
+ profile,
25
+ userDid,
63
26
  });
64
- await node.createAuditLog(
65
- {
66
- action: 'switchProfile',
67
- args: { teamDid, userDid, profile },
68
- context: formatContext(Object.assign(req, { user })),
69
- result: doc,
70
- },
71
- node
72
- );
73
27
  },
74
28
  };
75
29
  };
@@ -78,7 +78,10 @@ const onAuthenticate = async ({ channel, node }) => {
78
78
 
79
79
  const exist = await node.hasBlocklet({ did: appDid });
80
80
  if (!exist) {
81
- throw new Error(`App does not exist: ${appDid}`);
81
+ const nodeInfo = await node.getNodeInfo();
82
+ if (nodeInfo.did !== appDid) {
83
+ throw new Error(`App does not exist: ${appDid}`);
84
+ }
82
85
  }
83
86
  };
84
87
 
@@ -8,15 +8,15 @@
8
8
  "static/js/2.dc4d44c3.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/2.dc4d44c3.chunk.js.map",
9
9
  "main.js": "/.blocklet/proxy/blocklet-service/static/js/main.67b92d1a.chunk.js",
10
10
  "main.js.map": "/.blocklet/proxy/blocklet-service/static/js/main.67b92d1a.chunk.js.map",
11
- "runtime-main.js": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.7fadd252.js",
12
- "runtime-main.js.map": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.7fadd252.js.map",
11
+ "runtime-main.js": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.2227285f.js",
12
+ "runtime-main.js.map": "/.blocklet/proxy/blocklet-service/static/js/runtime-main.2227285f.js.map",
13
13
  "static/css/5.4db48a1d.chunk.css": "/.blocklet/proxy/blocklet-service/static/css/5.4db48a1d.chunk.css",
14
14
  "static/js/5.40b9123f.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/5.40b9123f.chunk.js",
15
15
  "static/js/5.40b9123f.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/5.40b9123f.chunk.js.map",
16
16
  "static/js/6.d8cacc55.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/6.d8cacc55.chunk.js",
17
17
  "static/js/6.d8cacc55.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/6.d8cacc55.chunk.js.map",
18
- "static/js/7.96fdf7e5.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/7.96fdf7e5.chunk.js",
19
- "static/js/7.96fdf7e5.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/7.96fdf7e5.chunk.js.map",
18
+ "static/js/7.b2428475.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/7.b2428475.chunk.js",
19
+ "static/js/7.b2428475.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/7.b2428475.chunk.js.map",
20
20
  "static/js/8.512a38a3.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/8.512a38a3.chunk.js",
21
21
  "static/js/8.512a38a3.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/8.512a38a3.chunk.js.map",
22
22
  "static/js/9.c10d6f6d.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/9.c10d6f6d.chunk.js",
@@ -25,8 +25,8 @@
25
25
  "static/js/10.7cdccc61.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/10.7cdccc61.chunk.js.map",
26
26
  "static/js/11.4647209f.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/11.4647209f.chunk.js",
27
27
  "static/js/11.4647209f.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/11.4647209f.chunk.js.map",
28
- "static/js/12.a879bfa6.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/12.a879bfa6.chunk.js",
29
- "static/js/12.a879bfa6.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/12.a879bfa6.chunk.js.map",
28
+ "static/js/12.0e874475.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/12.0e874475.chunk.js",
29
+ "static/js/12.0e874475.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/12.0e874475.chunk.js.map",
30
30
  "static/js/13.14a45622.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/13.14a45622.chunk.js",
31
31
  "static/js/13.14a45622.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/13.14a45622.chunk.js.map",
32
32
  "index.html": "/.blocklet/proxy/blocklet-service/index.html",
@@ -38,7 +38,7 @@
38
38
  "static/media/700.css": "/.blocklet/proxy/blocklet-service/static/media/lato-latin-ext-700-normal.9c8812ea.woff2"
39
39
  },
40
40
  "entrypoints": [
41
- "static/js/runtime-main.7fadd252.js",
41
+ "static/js/runtime-main.2227285f.js",
42
42
  "static/css/5.4db48a1d.chunk.css",
43
43
  "static/js/5.40b9123f.chunk.js",
44
44
  "static/js/main.67b92d1a.chunk.js"
package/build/index.html CHANGED
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/.well-known/service/static/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><script src=".well-known/service/api/env"></script><link href="/.blocklet/proxy/blocklet-service/static/css/5.4db48a1d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,u,i=t[0],l=t[1],f=t[2],s=t[3]||[],d=0,h=[];d<i.length;d++)u=i[d],Object.prototype.hasOwnProperty.call(o,u)&&o[u]&&h.push(o[u][0]),o[u]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t),a.push.apply(a,s);h.length;)h.shift()();return c.push.apply(c,f||[]),r()}function r(){for(var e,t=0;t<c.length;t++){for(var r=c[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(c.splice(t--,1),e=i(i.s=r[0]))}return 0===c.length&&(a.forEach((function(e){if(void 0===o[e]){o[e]=null;var t=document.createElement("link");i.nc&&t.setAttribute("nonce",i.nc),t.rel="prefetch",t.as="script",t.href=u(e),document.head.appendChild(t)}})),a.length=0),e}var n={},o={4:0},c=[],a=[];function u(e){return i.p+"static/js/"+({}[e]||e)+"."+{0:"125a8c91",1:"19473290",2:"dc4d44c3",6:"d8cacc55",7:"96fdf7e5",8:"512a38a3",9:"c10d6f6d",10:"7cdccc61",11:"4647209f",12:"a879bfa6",13:"14a45622"}[e]+".chunk.js"}function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var c,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=u(e);var l=new Error;c=function(t){a.onerror=a.onload=null,clearTimeout(f);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),c=t&&t.target&&t.target.src;l.message="Loading chunk "+e+" failed.\n("+n+": "+c+")",l.name="ChunkLoadError",l.type=n,l.request=c,r[1](l)}o[e]=void 0}};var f=setTimeout((function(){c({type:"timeout",target:a})}),12e4);a.onerror=a.onload=c,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/.blocklet/proxy/blocklet-service/",i.oe=function(e){throw console.error(e),e};var l=this["webpackJsonp@abtnode/blocklet-services"]=this["webpackJsonp@abtnode/blocklet-services"]||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var s=0;s<l.length;s++)t(l[s]);var p=f;r()}([])</script><script src="/.blocklet/proxy/blocklet-service/static/js/5.40b9123f.chunk.js"></script><script src="/.blocklet/proxy/blocklet-service/static/js/main.67b92d1a.chunk.js"></script></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/.well-known/service/static/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><script src=".well-known/service/api/env"></script><link href="/.blocklet/proxy/blocklet-service/static/css/5.4db48a1d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,u,i=t[0],l=t[1],f=t[2],s=t[3]||[],d=0,h=[];d<i.length;d++)u=i[d],Object.prototype.hasOwnProperty.call(o,u)&&o[u]&&h.push(o[u][0]),o[u]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t),a.push.apply(a,s);h.length;)h.shift()();return c.push.apply(c,f||[]),r()}function r(){for(var e,t=0;t<c.length;t++){for(var r=c[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(c.splice(t--,1),e=i(i.s=r[0]))}return 0===c.length&&(a.forEach((function(e){if(void 0===o[e]){o[e]=null;var t=document.createElement("link");i.nc&&t.setAttribute("nonce",i.nc),t.rel="prefetch",t.as="script",t.href=u(e),document.head.appendChild(t)}})),a.length=0),e}var n={},o={4:0},c=[],a=[];function u(e){return i.p+"static/js/"+({}[e]||e)+"."+{0:"125a8c91",1:"19473290",2:"dc4d44c3",6:"d8cacc55",7:"b2428475",8:"512a38a3",9:"c10d6f6d",10:"7cdccc61",11:"4647209f",12:"0e874475",13:"14a45622"}[e]+".chunk.js"}function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var c,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=u(e);var l=new Error;c=function(t){a.onerror=a.onload=null,clearTimeout(f);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),c=t&&t.target&&t.target.src;l.message="Loading chunk "+e+" failed.\n("+n+": "+c+")",l.name="ChunkLoadError",l.type=n,l.request=c,r[1](l)}o[e]=void 0}};var f=setTimeout((function(){c({type:"timeout",target:a})}),12e4);a.onerror=a.onload=c,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/.blocklet/proxy/blocklet-service/",i.oe=function(e){throw console.error(e),e};var l=this["webpackJsonp@abtnode/blocklet-services"]=this["webpackJsonp@abtnode/blocklet-services"]||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var s=0;s<l.length;s++)t(l[s]);var p=f;r()}([])</script><script src="/.blocklet/proxy/blocklet-service/static/js/5.40b9123f.chunk.js"></script><script src="/.blocklet/proxy/blocklet-service/static/js/main.67b92d1a.chunk.js"></script></body></html>