@blocklet/meta 1.15.17 → 1.16.0-beta-8ee536d7
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/lib/channel.d.ts +32 -0
- package/lib/channel.js +54 -0
- package/lib/constants.d.ts +2 -0
- package/lib/constants.js +5 -152
- package/lib/did.d.ts +3 -0
- package/lib/did.js +9 -9
- package/lib/engine.d.ts +7 -0
- package/lib/engine.js +21 -25
- package/lib/entry.d.ts +3 -0
- package/lib/entry.js +51 -64
- package/lib/extension.d.ts +14 -0
- package/lib/extension.js +82 -77
- package/lib/file.d.ts +23 -0
- package/lib/file.js +51 -36
- package/lib/fix.d.ts +36 -0
- package/lib/fix.js +231 -228
- package/lib/get-component-process-id.d.ts +5 -0
- package/lib/get-component-process-id.js +16 -0
- package/lib/has-reserved-key.d.ts +3 -0
- package/lib/has-reserved-key.js +15 -0
- package/lib/index.d.ts +86 -0
- package/lib/index.js +55 -34
- package/lib/info.d.ts +15 -0
- package/lib/info.js +70 -38
- package/lib/name.d.ts +15 -0
- package/lib/name.js +41 -8
- package/lib/nft-templates.d.ts +86 -0
- package/lib/nft-templates.js +52 -0
- package/lib/parse-navigation-from-blocklet.d.ts +92 -0
- package/lib/parse-navigation-from-blocklet.js +539 -0
- package/lib/parse-navigation.d.ts +3 -0
- package/lib/parse-navigation.js +197 -0
- package/lib/parse.d.ts +22 -0
- package/lib/parse.js +100 -89
- package/lib/payment/index.d.ts +254 -0
- package/lib/payment/index.js +14 -0
- package/lib/payment/v1.d.ts +185 -0
- package/lib/payment/v1.js +84 -0
- package/lib/payment/v2.d.ts +242 -0
- package/lib/payment/v2.js +576 -0
- package/lib/schema.d.ts +63 -0
- package/lib/schema.js +669 -283
- package/lib/service.d.ts +27 -0
- package/lib/service.js +71 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +18 -0
- package/lib/types/schema.d.ts +284 -0
- package/lib/types/schema.js +3 -0
- package/lib/url-friendly.d.ts +6 -0
- package/lib/url-friendly.js +20 -0
- package/lib/util-meta.d.ts +42 -0
- package/lib/util-meta.js +146 -0
- package/lib/util.d.ts +201 -0
- package/lib/util.js +501 -82
- package/lib/validate.d.ts +13 -0
- package/lib/validate.js +37 -61
- package/lib/verify-multi-sig.d.ts +3 -0
- package/lib/verify-multi-sig.js +86 -59
- package/lib/wallet.d.ts +9 -0
- package/lib/wallet.js +19 -30
- package/package.json +59 -20
- package/lib/payment.js +0 -114
package/lib/schema.js
CHANGED
|
@@ -1,363 +1,749 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.authConfigSchema = exports.cacheableSchema = exports.statsSchema = exports.titleSchema = exports.themeSchema = exports.signatureSchema = exports.serviceSchema = exports.scriptsSchema = exports.personSchema = exports.navigationSchema = exports.navigationItemSchema = exports.updateMountPointSchema = exports.mountPointSchema = exports.logoSchema = exports.interfaceSchema = exports.environmentNameSchema = exports.environmentSchema = exports.engineSchema = exports.endpointSchema = exports.distSchema = exports.descriptionSchema = exports.createBlockletSchema = exports.componentSchema = exports.blockletNameSchema = exports.blockletMetaSchema = void 0;
|
|
30
|
+
const fs_1 = __importDefault(require("fs"));
|
|
31
|
+
const joi_1 = __importDefault(require("joi"));
|
|
32
|
+
const cjk_length_1 = __importDefault(require("cjk-length"));
|
|
33
|
+
const is_glob_1 = __importDefault(require("is-glob"));
|
|
34
|
+
const joi_extension_semver_1 = require("joi-extension-semver");
|
|
35
|
+
const is_var_name_1 = __importDefault(require("is-var-name"));
|
|
36
|
+
const constant_1 = require("@abtnode/constant");
|
|
37
|
+
const did_1 = require("@arcblock/did");
|
|
38
|
+
const did_2 = __importDefault(require("./did"));
|
|
39
|
+
const extension_1 = require("./extension");
|
|
40
|
+
const name_1 = require("./name");
|
|
41
|
+
const constants_1 = __importDefault(require("./constants"));
|
|
42
|
+
const parse_navigation_from_blocklet_1 = require("./parse-navigation-from-blocklet");
|
|
43
|
+
const url_friendly_1 = __importStar(require("./url-friendly"));
|
|
44
|
+
const cjkLength = cjk_length_1.default.default;
|
|
45
|
+
const { BLOCKLET_GROUPS, BLOCKLET_PLATFORMS, BLOCKLET_ARCHITECTURES, BLOCKLET_INTERFACE_TYPES, BLOCKLET_INTERFACE_PROTOCOLS, BLOCKLET_ENTRY_FILE, BLOCKLET_BUNDLE_FILE, BLOCKLET_DEFAULT_PORT_NAME, BLOCKLET_DYNAMIC_PATH_PREFIX, BlockletGroup, BLOCKLET_LATEST_REQUIREMENT_SERVER, BLOCKLET_INTERFACE_TYPE_WEB, BLOCKLET_INTERFACE_TYPE_WELLKNOWN, BLOCKLET_APP_SPACE_ENDPOINTS, BLOCKLET_CONFIGURABLE_KEY, } = constants_1.default;
|
|
25
46
|
const WELLKNOWN_PATH_PREFIX = '/.well-known';
|
|
47
|
+
const MAX_TITLE_LENGTH = 24;
|
|
48
|
+
const Joi = joi_1.default.extend(joi_extension_semver_1.semver)
|
|
49
|
+
.extend(joi_extension_semver_1.semverRange)
|
|
50
|
+
.extend(extension_1.fileExtension)
|
|
51
|
+
.extend(extension_1.didExtension);
|
|
52
|
+
const checkLinkHelper = (value, helper) => {
|
|
53
|
+
if ((0, parse_navigation_from_blocklet_1.checkLink)(value)) {
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
// @ts-expect-error
|
|
57
|
+
return helper.message(`Invalid navigation link: ${value}
|
|
58
|
+
|
|
59
|
+
A valid navigation link should be a relative url which start with '/' or a absolute url, such as:
|
|
60
|
+
- /en/home
|
|
61
|
+
- /zh/home
|
|
62
|
+
- https://www.arcblock.io`);
|
|
63
|
+
};
|
|
64
|
+
const checkId = (value, helper) => {
|
|
65
|
+
if (!value || (0, is_var_name_1.default)(value)) {
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
// @ts-expect-error
|
|
69
|
+
return helper.message(`Invalid navigation id: ${value}
|
|
26
70
|
|
|
27
|
-
|
|
71
|
+
A valid navigation id is should follow the rules of javascript variables, such as:
|
|
72
|
+
- foo
|
|
73
|
+
- fooBar
|
|
74
|
+
- foo123
|
|
28
75
|
|
|
76
|
+
see detail in https://www.npmjs.com/package/is-var-name`);
|
|
77
|
+
};
|
|
78
|
+
const titleSchema = Joi.string()
|
|
79
|
+
.trim()
|
|
80
|
+
.min(1)
|
|
81
|
+
.custom((value) => {
|
|
82
|
+
if (cjkLength(value) > MAX_TITLE_LENGTH) {
|
|
83
|
+
throw new Error(`title length should not exceed ${MAX_TITLE_LENGTH} (see: https://www.npmjs.com/package/cjk-length)`);
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
})
|
|
87
|
+
.meta({ className: 'TTitle' });
|
|
88
|
+
exports.titleSchema = titleSchema;
|
|
89
|
+
const descriptionSchema = Joi.string().trim().min(3).max(160).meta({ className: 'TDescription' });
|
|
90
|
+
exports.descriptionSchema = descriptionSchema;
|
|
91
|
+
const logoSchema = Joi.string()
|
|
92
|
+
.uri({ scheme: ['http', 'https'], allowRelative: true })
|
|
93
|
+
.allow('')
|
|
94
|
+
.custom((value, helper) => {
|
|
95
|
+
if (value.includes(constant_1.WELLKNOWN_BLOCKLET_LOGO_PATH)) {
|
|
96
|
+
// @ts-expect-error
|
|
97
|
+
return helper.message(`logo url should not include ${constant_1.WELLKNOWN_BLOCKLET_LOGO_PATH}`);
|
|
98
|
+
}
|
|
99
|
+
return value;
|
|
100
|
+
})
|
|
101
|
+
.meta({ className: 'TLogo' });
|
|
102
|
+
exports.logoSchema = logoSchema;
|
|
103
|
+
const baseMountPointSchema = Joi.string().trim().min(1);
|
|
104
|
+
const mountPointSchema = baseMountPointSchema
|
|
105
|
+
.meta({ className: 'TMountPoint' })
|
|
106
|
+
.custom((value, helper) => {
|
|
107
|
+
if ((0, url_friendly_1.isValidUrl)(value)) {
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
// @ts-expect-error
|
|
111
|
+
return helper.message('mountPoint cannot contain such characters space $*_+~.()\'"!:@\\');
|
|
112
|
+
});
|
|
113
|
+
exports.mountPointSchema = mountPointSchema;
|
|
114
|
+
const updateMountPointSchema = baseMountPointSchema
|
|
115
|
+
.meta({ className: 'TUpdateMountPoint' })
|
|
116
|
+
.custom((value) => (0, url_friendly_1.default)(value));
|
|
117
|
+
exports.updateMountPointSchema = updateMountPointSchema;
|
|
118
|
+
const blockletNameSchema = Joi.string()
|
|
119
|
+
.custom((value) => {
|
|
120
|
+
(0, name_1.validateName)(value);
|
|
121
|
+
return value;
|
|
122
|
+
})
|
|
123
|
+
.meta({ className: 'TBlockletName' });
|
|
124
|
+
exports.blockletNameSchema = blockletNameSchema;
|
|
125
|
+
const ENV_NAME_WHITE_LIST = [BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_WALLET_TYPE];
|
|
126
|
+
const environmentNameSchema = Joi.string()
|
|
127
|
+
.trim()
|
|
128
|
+
.min(1)
|
|
129
|
+
.max(50)
|
|
130
|
+
.required()
|
|
131
|
+
.custom((name, helper) => {
|
|
132
|
+
if (name.startsWith('BLOCKLET')) {
|
|
133
|
+
if (!ENV_NAME_WHITE_LIST.includes(name)) {
|
|
134
|
+
// @ts-expect-error
|
|
135
|
+
return helper.message('Env name can not start with BLOCKLET_');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (name.startsWith('COMPONENT')) {
|
|
139
|
+
// @ts-expect-error
|
|
140
|
+
return helper.message('Env name can not start with COMPONENT_');
|
|
141
|
+
}
|
|
142
|
+
if (name.startsWith('ABTNODE')) {
|
|
143
|
+
// @ts-expect-error
|
|
144
|
+
return helper.message('Env name can not start with ABTNODE_');
|
|
145
|
+
}
|
|
146
|
+
if (/[^\w]/.test(name)) {
|
|
147
|
+
// @ts-expect-error
|
|
148
|
+
return helper.message('Env name can include only numbers or letters or "_"');
|
|
149
|
+
}
|
|
150
|
+
return name;
|
|
151
|
+
})
|
|
152
|
+
.meta({
|
|
153
|
+
className: 'TEnvironmentName',
|
|
154
|
+
unknownType: 'any',
|
|
155
|
+
});
|
|
156
|
+
exports.environmentNameSchema = environmentNameSchema;
|
|
29
157
|
const environmentSchema = Joi.object({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
158
|
+
name: environmentNameSchema.required(),
|
|
159
|
+
description: Joi.string().trim().required(),
|
|
160
|
+
default: Joi.string().optional().allow('').default(''),
|
|
161
|
+
required: Joi.boolean().default(false),
|
|
162
|
+
secure: Joi.boolean().default(false),
|
|
163
|
+
validation: Joi.string().optional(),
|
|
164
|
+
shared: Joi.boolean().default((parent) => !parent.secure),
|
|
165
|
+
})
|
|
166
|
+
.custom((x, helper) => {
|
|
167
|
+
if (x.secure && x.default) {
|
|
168
|
+
// @ts-expect-error
|
|
169
|
+
return helper.message(`Cannot declare default value for secure env ${x.name}`);
|
|
170
|
+
}
|
|
171
|
+
return x;
|
|
172
|
+
})
|
|
173
|
+
.meta({
|
|
174
|
+
className: 'TEnvironment',
|
|
175
|
+
unknownType: 'any',
|
|
36
176
|
});
|
|
37
|
-
|
|
177
|
+
exports.environmentSchema = environmentSchema;
|
|
38
178
|
const scriptsSchema = Joi.object({
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
179
|
+
dev: Joi.string().trim().min(1),
|
|
180
|
+
e2eDev: Joi.string().trim().min(1),
|
|
181
|
+
preInstall: Joi.string().trim().min(1),
|
|
182
|
+
postInstall: Joi.string().trim().min(1),
|
|
183
|
+
preStart: Joi.string().trim().min(1),
|
|
184
|
+
postStart: Joi.string().trim().min(1),
|
|
185
|
+
preStop: Joi.string().trim().min(1),
|
|
186
|
+
preUninstall: Joi.string().trim().min(1),
|
|
187
|
+
preConfig: Joi.string().trim().min(1),
|
|
47
188
|
})
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
189
|
+
.rename('pre-install', 'preInstall')
|
|
190
|
+
.rename('post-install', 'postInstall')
|
|
191
|
+
.rename('pre-start', 'preStart')
|
|
192
|
+
.rename('post-start', 'postStart')
|
|
193
|
+
.rename('pre-stop', 'preStop')
|
|
194
|
+
.rename('pre-uninstall', 'preUninstall')
|
|
195
|
+
.rename('pre-config', 'preConfig')
|
|
196
|
+
.optional()
|
|
197
|
+
.meta({
|
|
198
|
+
className: 'TScripts',
|
|
199
|
+
unknownType: 'any',
|
|
200
|
+
});
|
|
201
|
+
exports.scriptsSchema = scriptsSchema;
|
|
57
202
|
// Different services have different config schema
|
|
58
203
|
// - Auth: https://github.com/ArcBlock/abtnode-docs/blob/master/src/developer/auth-service/index.md
|
|
59
204
|
const serviceSchema = Joi.object({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
63
|
-
|
|
205
|
+
name: Joi.string().required().trim(),
|
|
206
|
+
config: Joi.object().optional().default({}),
|
|
207
|
+
})
|
|
208
|
+
.unknown(true)
|
|
209
|
+
.meta({
|
|
210
|
+
className: 'TService',
|
|
211
|
+
unknownType: 'any',
|
|
212
|
+
});
|
|
213
|
+
exports.serviceSchema = serviceSchema;
|
|
64
214
|
const endpointSchema = Joi.object({
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
215
|
+
type: Joi.string().trim(true).min(1).required(),
|
|
216
|
+
path: Joi.string().required(),
|
|
217
|
+
meta: Joi.object({
|
|
218
|
+
vcType: Joi.string(),
|
|
219
|
+
payable: Joi.boolean(),
|
|
220
|
+
params: Joi.array().items({
|
|
221
|
+
name: Joi.string().required().trim(),
|
|
222
|
+
description: Joi.string().required().trim(),
|
|
223
|
+
}),
|
|
73
224
|
}),
|
|
74
|
-
|
|
225
|
+
}).meta({
|
|
226
|
+
className: 'TEndpoint',
|
|
227
|
+
unknownType: 'any',
|
|
75
228
|
});
|
|
76
|
-
|
|
229
|
+
exports.endpointSchema = endpointSchema;
|
|
230
|
+
const cacheableSchema = Joi.string()
|
|
231
|
+
.trim()
|
|
232
|
+
.custom((value, helpers) => {
|
|
233
|
+
const parts = value.split('/').filter(Boolean);
|
|
234
|
+
if (parts.length === 0) {
|
|
235
|
+
// @ts-ignore
|
|
236
|
+
return helpers.message('cacheable path must be a valid pathname that is not /');
|
|
237
|
+
}
|
|
238
|
+
return `/${parts.join('/')}`;
|
|
239
|
+
})
|
|
240
|
+
.meta({
|
|
241
|
+
className: 'TPathPrefix',
|
|
242
|
+
unknownType: 'any',
|
|
243
|
+
});
|
|
244
|
+
exports.cacheableSchema = cacheableSchema;
|
|
77
245
|
const interfaceSchema = Joi.object({
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.
|
|
94
|
-
|
|
95
|
-
.default('http'),
|
|
96
|
-
|
|
97
|
-
// Can be a string or an object
|
|
98
|
-
port: Joi.alternatives()
|
|
99
|
-
.try(
|
|
100
|
-
Joi.string().uppercase().default(BLOCKLET_DEFAULT_PORT_NAME),
|
|
101
|
-
Joi.object({
|
|
246
|
+
type: Joi.string()
|
|
247
|
+
.lowercase()
|
|
248
|
+
.valid(...BLOCKLET_INTERFACE_TYPES)
|
|
249
|
+
.required(),
|
|
250
|
+
// Human readable name of the interface, such as `public_url`
|
|
251
|
+
name: Joi.string().trim().required(),
|
|
252
|
+
// The path where the interface is served from the blocklet
|
|
253
|
+
path: Joi.string().trim().default('/'),
|
|
254
|
+
// `*` means the interface can be mounted at any path prefix
|
|
255
|
+
prefix: Joi.string().trim().min(1).default(BLOCKLET_DYNAMIC_PATH_PREFIX),
|
|
256
|
+
protocol: Joi.string()
|
|
257
|
+
.lowercase()
|
|
258
|
+
.valid(...BLOCKLET_INTERFACE_PROTOCOLS)
|
|
259
|
+
.default('http'),
|
|
260
|
+
// Can be a string or an object
|
|
261
|
+
port: Joi.alternatives()
|
|
262
|
+
.try(Joi.string().uppercase().default(BLOCKLET_DEFAULT_PORT_NAME), Joi.object({
|
|
102
263
|
internal: Joi.string().uppercase().required(),
|
|
103
264
|
external: Joi.number().port().required(),
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
265
|
+
}))
|
|
266
|
+
.default(BLOCKLET_DEFAULT_PORT_NAME),
|
|
267
|
+
cacheable: Joi.array().items(cacheableSchema).unique(),
|
|
268
|
+
services: Joi.array().items(serviceSchema).unique('name'),
|
|
269
|
+
endpoints: Joi.array().items(endpointSchema).unique('type'),
|
|
270
|
+
}).meta({
|
|
271
|
+
className: 'TInterface',
|
|
272
|
+
unknownType: 'any',
|
|
110
273
|
});
|
|
111
|
-
|
|
274
|
+
exports.interfaceSchema = interfaceSchema;
|
|
112
275
|
const engineSchema = Joi.object({
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
276
|
+
platform: Joi.string()
|
|
277
|
+
.valid(...BLOCKLET_PLATFORMS)
|
|
278
|
+
.optional(),
|
|
279
|
+
interpreter: Joi.string().valid('binary', 'node').default('node'),
|
|
280
|
+
script: Joi.string().required(),
|
|
281
|
+
args: Joi.array().items(Joi.string()).optional().default([]),
|
|
282
|
+
}).meta({
|
|
283
|
+
className: 'TEngine',
|
|
284
|
+
unknownType: 'any',
|
|
119
285
|
});
|
|
120
|
-
|
|
286
|
+
exports.engineSchema = engineSchema;
|
|
121
287
|
const personSchema = Joi.object({
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
288
|
+
name: Joi.string().min(1).required(),
|
|
289
|
+
email: Joi.string().email().optional(),
|
|
290
|
+
url: Joi.string().uri().optional(),
|
|
291
|
+
}).meta({
|
|
292
|
+
className: 'TPerson',
|
|
293
|
+
unknownType: 'any',
|
|
125
294
|
});
|
|
126
|
-
|
|
295
|
+
exports.personSchema = personSchema;
|
|
127
296
|
const distSchema = Joi.object({
|
|
128
|
-
|
|
129
|
-
|
|
297
|
+
tarball: Joi.alternatives().try(Joi.string().uri(), Joi.string()).required(),
|
|
298
|
+
integrity: Joi.string().required(),
|
|
299
|
+
size: Joi.number().optional(),
|
|
300
|
+
}).meta({
|
|
301
|
+
className: 'TDist',
|
|
302
|
+
unknownType: 'any',
|
|
130
303
|
});
|
|
131
|
-
|
|
304
|
+
exports.distSchema = distSchema;
|
|
132
305
|
const statsSchema = Joi.object({
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
306
|
+
downloads: Joi.number().integer().greater(-1),
|
|
307
|
+
star: Joi.number().default(0),
|
|
308
|
+
purchases: Joi.number().default(0),
|
|
309
|
+
}).meta({
|
|
310
|
+
className: 'TStats',
|
|
311
|
+
unknownType: 'any',
|
|
136
312
|
});
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
313
|
+
exports.statsSchema = statsSchema;
|
|
314
|
+
const urlListSchema = Joi.alternatives().try(Joi.string().uri(), Joi.array().items(Joi.string().uri()).min(1));
|
|
315
|
+
const componentSourceSchema = Joi.alternatives().try(Joi.object({
|
|
316
|
+
url: urlListSchema.required(),
|
|
317
|
+
// 虽然 url 无法像 store 一样根据 version 获取指定版本的 component, 但是 version 仍然可以用于限制 component 版本
|
|
318
|
+
version: Joi.alternatives().try(Joi.string().valid('latest'), Joi.semverRange().valid()),
|
|
319
|
+
}), Joi.object({
|
|
320
|
+
store: urlListSchema,
|
|
321
|
+
name: blockletNameSchema.required(),
|
|
322
|
+
// TODO 目前只能支持锁死的版本号,接下载需要支持自适应的版本号,比如 4.x
|
|
323
|
+
version: Joi.alternatives().try(Joi.string().valid('latest'), Joi.semverRange().valid()).default('latest'),
|
|
324
|
+
}));
|
|
325
|
+
const componentSchemaProps = {
|
|
326
|
+
source: componentSourceSchema.required(),
|
|
327
|
+
// Can the dynamic component be deleted before I delete myself
|
|
328
|
+
required: Joi.boolean(),
|
|
329
|
+
// These props in dynamic component is for suggestion only and can be changed by user or other dynamic component
|
|
330
|
+
title: titleSchema,
|
|
331
|
+
description: descriptionSchema,
|
|
332
|
+
mountPoint: mountPointSchema,
|
|
333
|
+
// backward compatible, useless
|
|
334
|
+
name: blockletNameSchema,
|
|
335
|
+
};
|
|
336
|
+
const staticComponentSchemaProps = {
|
|
337
|
+
source: componentSourceSchema.required(),
|
|
338
|
+
name: blockletNameSchema.required(),
|
|
339
|
+
title: titleSchema,
|
|
340
|
+
description: descriptionSchema,
|
|
341
|
+
mountPoint: mountPointSchema.required(),
|
|
342
|
+
};
|
|
343
|
+
const createComponentSchema = (schema, allowEmptyStore) => Joi.object(schema).custom((value, helper) => {
|
|
344
|
+
if (!allowEmptyStore && value.source && value.source.name && !value.source.store) {
|
|
345
|
+
// @ts-expect-error
|
|
346
|
+
return helper.message(`missing 'store' in source of component ${value.name}`);
|
|
347
|
+
}
|
|
348
|
+
return value;
|
|
156
349
|
});
|
|
157
|
-
|
|
350
|
+
const componentSchema = createComponentSchema(componentSchemaProps).meta({
|
|
351
|
+
className: 'TComponent',
|
|
352
|
+
unknownType: 'any',
|
|
353
|
+
});
|
|
354
|
+
exports.componentSchema = componentSchema;
|
|
355
|
+
const staticComponentSchema = createComponentSchema(staticComponentSchemaProps).meta({
|
|
356
|
+
className: 'TStaticComponent',
|
|
357
|
+
unknownType: 'any',
|
|
358
|
+
});
|
|
359
|
+
const componentSchemaWithoutStoreCheck = createComponentSchema(componentSchemaProps, true);
|
|
360
|
+
const staticComponentSchemaWithoutStoreCheck = createComponentSchema(staticComponentSchemaProps, true);
|
|
361
|
+
const componentsSchema = ({ isStatic, checkStore } = {}) => {
|
|
362
|
+
const arr = isStatic
|
|
363
|
+
? [staticComponentSchema, staticComponentSchemaWithoutStoreCheck]
|
|
364
|
+
: [componentSchema, componentSchemaWithoutStoreCheck];
|
|
365
|
+
let schema = Joi.array()
|
|
366
|
+
.items(checkStore ? arr[0] : arr[1])
|
|
367
|
+
.optional()
|
|
368
|
+
.custom((value, helper) => {
|
|
369
|
+
if (isStatic) {
|
|
370
|
+
const names = value.map((x) => x.name);
|
|
371
|
+
const duplicateName = names.find((x, i) => names.indexOf(x) !== i);
|
|
372
|
+
if (duplicateName) {
|
|
373
|
+
// @ts-expect-error
|
|
374
|
+
return helper.message(`find duplicate name "${duplicateName}" in components`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return value;
|
|
378
|
+
});
|
|
379
|
+
if (!isStatic) {
|
|
380
|
+
schema = schema.default([]);
|
|
381
|
+
}
|
|
382
|
+
return schema;
|
|
383
|
+
};
|
|
158
384
|
const signatureSchema = Joi.object({
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
385
|
+
type: Joi.string().required(),
|
|
386
|
+
name: Joi.string().required(),
|
|
387
|
+
signer: Joi.string().required(),
|
|
388
|
+
pk: Joi.string().required(),
|
|
389
|
+
created: Joi.string().isoDate().required(),
|
|
390
|
+
sig: Joi.string().required(),
|
|
391
|
+
excludes: Joi.array().items(Joi.string()).optional(),
|
|
392
|
+
appended: Joi.array().items(Joi.string()).optional(),
|
|
393
|
+
// delegation token 校验所需字段
|
|
394
|
+
delegatee: Joi.string(),
|
|
395
|
+
delegateePk: Joi.string(),
|
|
396
|
+
delegation: Joi.string(),
|
|
397
|
+
}).meta({
|
|
398
|
+
className: 'TSignature',
|
|
399
|
+
unknownType: 'any',
|
|
167
400
|
});
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
401
|
+
exports.signatureSchema = signatureSchema;
|
|
402
|
+
const localeList = ['en', 'zh', 'fr', 'ru', 'ar', 'es', 'de', 'pt', 'ja', 'hi'];
|
|
403
|
+
const navigationItemProps = {
|
|
404
|
+
id: Joi.string().custom(checkId),
|
|
405
|
+
title: Joi.alternatives()
|
|
406
|
+
.try(Joi.string().min(1).max(MAX_TITLE_LENGTH), Joi.object()
|
|
407
|
+
.min(1)
|
|
408
|
+
.pattern(Joi.string().valid(...localeList), Joi.string().min(1).max(MAX_TITLE_LENGTH)))
|
|
409
|
+
.required(),
|
|
410
|
+
link: Joi.alternatives().try(Joi.string().custom(checkLinkHelper), Joi.object()
|
|
411
|
+
.min(1)
|
|
412
|
+
.pattern(Joi.string().valid(...localeList), Joi.string().custom(checkLinkHelper))),
|
|
413
|
+
component: Joi.string().min(1),
|
|
414
|
+
section: Joi.array().items(Joi.string().min(1)).single(),
|
|
415
|
+
role: Joi.array().items(Joi.string().min(1)).single(),
|
|
416
|
+
icon: Joi.string().min(1),
|
|
417
|
+
visible: Joi.boolean(),
|
|
418
|
+
};
|
|
419
|
+
const navigationItemSchema = Joi.object({
|
|
420
|
+
...navigationItemProps,
|
|
421
|
+
items: Joi.array().items(Joi.object({ ...navigationItemProps }).rename('child', 'component')),
|
|
422
|
+
})
|
|
423
|
+
.rename('child', 'component')
|
|
424
|
+
.meta({
|
|
425
|
+
className: 'TNavigationItem',
|
|
426
|
+
unknownType: 'any',
|
|
427
|
+
});
|
|
428
|
+
exports.navigationItemSchema = navigationItemSchema;
|
|
429
|
+
const navigationSchema = Joi.array()
|
|
430
|
+
.items(navigationItemSchema)
|
|
431
|
+
.unique((a, b) => {
|
|
432
|
+
if (a.id && b.id) {
|
|
433
|
+
return a.id === b.id;
|
|
434
|
+
}
|
|
435
|
+
return false;
|
|
436
|
+
})
|
|
437
|
+
.meta({
|
|
438
|
+
className: 'TNavigation',
|
|
439
|
+
unknownType: 'any',
|
|
440
|
+
});
|
|
441
|
+
exports.navigationSchema = navigationSchema;
|
|
442
|
+
const themeSchema = Joi.object({
|
|
443
|
+
background: Joi.alternatives().try(Joi.string().min(1), Joi.object({
|
|
444
|
+
header: Joi.string().min(1),
|
|
445
|
+
footer: Joi.string().min(1),
|
|
446
|
+
default: Joi.string().min(1),
|
|
447
|
+
}).min(1)),
|
|
448
|
+
}).meta({
|
|
449
|
+
className: 'TTheme',
|
|
450
|
+
unknownType: 'any',
|
|
451
|
+
});
|
|
452
|
+
exports.themeSchema = themeSchema;
|
|
453
|
+
const authConfigSchema = Joi.object({
|
|
454
|
+
whoCanAccess: Joi.string().valid('owner', 'invited', 'all'),
|
|
455
|
+
profileFields: Joi.array().items(Joi.string().valid('fullName', 'email', 'avatar', 'phone')).unique(),
|
|
456
|
+
ignoreUrls: Joi.array().items(Joi.string().min(1)),
|
|
457
|
+
allowSwitchProfile: Joi.boolean(),
|
|
458
|
+
blockUnauthenticated: Joi.boolean(),
|
|
459
|
+
blockUnauthorized: Joi.boolean(),
|
|
460
|
+
})
|
|
461
|
+
.options({ stripUnknown: true })
|
|
462
|
+
.meta({
|
|
463
|
+
className: 'TAuthConfig',
|
|
464
|
+
unknownType: 'any',
|
|
465
|
+
});
|
|
466
|
+
exports.authConfigSchema = authConfigSchema;
|
|
467
|
+
const blockletMetaProps = {
|
|
179
468
|
did: Joi.DID().trim().required(),
|
|
180
469
|
version: Joi.semver().valid().required(),
|
|
181
|
-
name: Joi.string()
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
main: Joi.when('group', {
|
|
190
|
-
is: Joi.valid(BlockletGroup.gateway),
|
|
191
|
-
then: Joi.forbidden(),
|
|
192
|
-
otherwise: ensureMain ? Joi.file().exists({ baseDir }).required() : Joi.string().trim().required(),
|
|
193
|
-
}),
|
|
194
|
-
title: Joi.string().trim().optional().allow(''),
|
|
195
|
-
logo: ensureFiles ? Joi.file().trim().exists({ baseDir }).optional() : Joi.string().trim().optional(),
|
|
470
|
+
name: Joi.string().optional(),
|
|
471
|
+
description: descriptionSchema.required(),
|
|
472
|
+
group: Joi.string()
|
|
473
|
+
.valid(...BLOCKLET_GROUPS)
|
|
474
|
+
.required(),
|
|
475
|
+
main: Joi.string().trim().required(),
|
|
476
|
+
title: titleSchema.optional().allow(''),
|
|
477
|
+
logo: Joi.string().trim().optional(),
|
|
196
478
|
specVersion: Joi.semver().valid().gte('1.0.0').optional(),
|
|
197
|
-
|
|
198
479
|
author: personSchema.optional(),
|
|
199
480
|
contributors: Joi.array().items(personSchema).optional(),
|
|
200
481
|
maintainers: Joi.array().items(personSchema).optional(),
|
|
201
|
-
|
|
202
482
|
community: Joi.string().uri().optional().allow('').default(''),
|
|
203
483
|
documentation: Joi.string().uri().optional().allow('').default(''),
|
|
204
484
|
homepage: Joi.string().uri().optional().allow('').default(''),
|
|
205
485
|
license: Joi.string().optional().allow('').default(''),
|
|
206
486
|
support: Joi.alternatives().try(Joi.string().uri(), Joi.string().email()).optional(),
|
|
207
|
-
|
|
208
487
|
// which asset factory to mint blocklet purchase nft
|
|
209
488
|
// This is usually created and maintained by `blocklet publish` command
|
|
210
489
|
nftFactory: Joi.DID().optional().allow('').default(''),
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
.max(4)
|
|
219
|
-
.items(
|
|
220
|
-
Joi.object({
|
|
221
|
-
price: Joi.number().required(),
|
|
490
|
+
// Set the price and share of the blocklet
|
|
491
|
+
payment: Joi.object({
|
|
492
|
+
// Currently only supports 1 token
|
|
493
|
+
price: Joi.array()
|
|
494
|
+
.max(1)
|
|
495
|
+
.items(Joi.object({
|
|
496
|
+
value: Joi.number().greater(0).required(),
|
|
222
497
|
address: Joi.DID().required(), // token address
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
Joi.object({
|
|
498
|
+
}))
|
|
499
|
+
.default([]),
|
|
500
|
+
// List of beneficiaries that share the token earns from blocklet purchase
|
|
501
|
+
// If left empty, blocklet publish workflow will enforce both the developer and the registry account
|
|
502
|
+
// If not, the blocklet publish workflow will enforce the registry account
|
|
503
|
+
// In theory, the developer can split as many share as he wants
|
|
504
|
+
// Such as, some developers coauthored the blocklet, and their income get instant settlement on blocklet purchase
|
|
505
|
+
// For performance reasons, we need to set a hard limit for share count
|
|
506
|
+
share: Joi.array()
|
|
507
|
+
.max(4)
|
|
508
|
+
.items(Joi.object({
|
|
235
509
|
name: Joi.string().required(),
|
|
236
510
|
address: Joi.DID().required(),
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
511
|
+
value: Joi.number().greater(0).max(1).required(),
|
|
512
|
+
}))
|
|
513
|
+
.default([])
|
|
514
|
+
.custom((value) => {
|
|
515
|
+
// If share is not empty, the total value should be 1
|
|
516
|
+
if (value.length === 0) {
|
|
517
|
+
return value;
|
|
518
|
+
}
|
|
519
|
+
const total = value.reduce((acc, cur) => acc + cur.value, 0);
|
|
520
|
+
if (total !== 1) {
|
|
521
|
+
throw new Error(`Invalid blocklet payment share config: total share must be 1, got ${total}`);
|
|
522
|
+
}
|
|
523
|
+
return value;
|
|
524
|
+
}, 'invalid blocklet share'),
|
|
525
|
+
componentPrice: Joi.array()
|
|
526
|
+
.items(Joi.object({
|
|
527
|
+
parentPriceRange: Joi.array()
|
|
528
|
+
.items(Joi.number())
|
|
529
|
+
// FIXME
|
|
530
|
+
// 1. 有重叠的区间时
|
|
531
|
+
// 2. 区间不连续时
|
|
532
|
+
// 3. 区间边界
|
|
533
|
+
.custom((value, helper) => {
|
|
534
|
+
if (value.length !== 2) {
|
|
535
|
+
// @ts-ignore
|
|
536
|
+
return helper.message('length of range should be 2');
|
|
537
|
+
}
|
|
538
|
+
if (value[0] < 0) {
|
|
539
|
+
// @ts-ignore
|
|
540
|
+
return helper.message('the first value should not less than 0 in range');
|
|
541
|
+
}
|
|
542
|
+
if (value[1] <= value[0]) {
|
|
543
|
+
// @ts-ignore
|
|
544
|
+
return helper.message('the second value should greater than the first value in range');
|
|
545
|
+
}
|
|
546
|
+
return value;
|
|
547
|
+
}),
|
|
548
|
+
type: Joi.string().valid('fixed', 'percentage').required(),
|
|
549
|
+
value: Joi.number().greater(0).required(),
|
|
550
|
+
}))
|
|
551
|
+
.single(),
|
|
552
|
+
}).default({ price: [], share: [] }),
|
|
244
553
|
keywords: Joi.alternatives()
|
|
245
|
-
|
|
246
|
-
|
|
554
|
+
.try(Joi.string().trim().min(1), Joi.array().items(Joi.string().min(1)))
|
|
555
|
+
.optional(),
|
|
247
556
|
tags: Joi.alternatives()
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
557
|
+
.try(Joi.string().trim().min(1), Joi.array().items(Joi.string().min(1)))
|
|
558
|
+
.optional(),
|
|
251
559
|
gitHash: Joi.string().optional().allow(''),
|
|
252
560
|
repository: Joi.alternatives()
|
|
253
|
-
|
|
254
|
-
Joi.string().
|
|
255
|
-
Joi.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
})
|
|
260
|
-
)
|
|
261
|
-
.optional(),
|
|
262
|
-
|
|
561
|
+
.try(Joi.string().min(1), Joi.object({
|
|
562
|
+
type: Joi.string().valid('git', 'https', 'svn').required(),
|
|
563
|
+
url: Joi.string().uri().required(),
|
|
564
|
+
directory: Joi.string(),
|
|
565
|
+
}))
|
|
566
|
+
.optional(),
|
|
263
567
|
timeout: Joi.object({
|
|
264
|
-
|
|
568
|
+
start: Joi.number().min(10).max(600), // start check timeout, 10 seconds ~ 10 minutes
|
|
265
569
|
}).default({ start: 60 }),
|
|
266
|
-
|
|
267
570
|
requirements: Joi.object({
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
Joi.string().valid('*', ...BLOCKLET_PLATFORMS),
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
Joi.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
571
|
+
abtnode: Joi.semverRange().valid(),
|
|
572
|
+
server: Joi.semverRange().valid(),
|
|
573
|
+
os: Joi.alternatives().try(Joi.string().valid('*', ...BLOCKLET_PLATFORMS), Joi.array()
|
|
574
|
+
.items(Joi.string().valid(...BLOCKLET_PLATFORMS))
|
|
575
|
+
.min(1)),
|
|
576
|
+
cpu: Joi.alternatives().try(Joi.string().valid('*', ...BLOCKLET_ARCHITECTURES), Joi.array()
|
|
577
|
+
.items(Joi.string().valid(...BLOCKLET_ARCHITECTURES))
|
|
578
|
+
.min(1)),
|
|
579
|
+
fuels: Joi.array().items(Joi.object({
|
|
580
|
+
endpoint: Joi.string().trim().required(),
|
|
581
|
+
address: Joi.string().trim(),
|
|
582
|
+
value: Joi.string().trim().required(),
|
|
583
|
+
reason: Joi.string().trim().required(),
|
|
584
|
+
})),
|
|
585
|
+
nodejs: Joi.semverRange().valid(),
|
|
586
|
+
}).default({ server: BLOCKLET_LATEST_REQUIREMENT_SERVER, os: '*', cpu: '*', nodejs: '*' }),
|
|
283
587
|
// interfaces: https://github.com/blocklet/blocklet-specification/issues/2
|
|
284
588
|
interfaces: Joi.array()
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
589
|
+
.items(interfaceSchema)
|
|
590
|
+
.unique('name')
|
|
591
|
+
.min(1)
|
|
592
|
+
.custom((value, helper) => {
|
|
289
593
|
const webItems = value.filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
290
594
|
if (webItems.length > 1) {
|
|
291
|
-
|
|
595
|
+
// @ts-expect-error
|
|
596
|
+
return helper.message(`Only one ${BLOCKLET_INTERFACE_TYPE_WEB} interface can be declared`);
|
|
292
597
|
}
|
|
293
|
-
|
|
294
598
|
const wellknownItems = value.filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WELLKNOWN);
|
|
295
599
|
for (const x of wellknownItems) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
600
|
+
if (!x.prefix.startsWith(WELLKNOWN_PATH_PREFIX)) {
|
|
601
|
+
// @ts-expect-error
|
|
602
|
+
return helper.message(`Wellknown path prefix must start with: ${WELLKNOWN_PATH_PREFIX}`);
|
|
603
|
+
}
|
|
299
604
|
}
|
|
300
|
-
|
|
301
605
|
return value;
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
606
|
+
})
|
|
607
|
+
.default([]),
|
|
305
608
|
// environments
|
|
306
|
-
environments: Joi.array()
|
|
307
|
-
|
|
609
|
+
environments: Joi.array()
|
|
610
|
+
.items(environmentSchema)
|
|
611
|
+
.default([])
|
|
612
|
+
.optional()
|
|
613
|
+
.custom((data, helper) => {
|
|
614
|
+
if (data && data.length) {
|
|
615
|
+
const duplicates = data.filter((x, index) => data.findIndex((y) => y.name === x.name) !== index);
|
|
616
|
+
if (duplicates.length) {
|
|
617
|
+
// @ts-expect-error
|
|
618
|
+
return helper.message(`find duplicate environment names ${duplicates.map((x) => x.name).join(', ')}`);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return data;
|
|
622
|
+
}),
|
|
308
623
|
// scripts & hooks
|
|
309
624
|
scripts: scriptsSchema,
|
|
310
|
-
|
|
311
625
|
// capabilities
|
|
312
626
|
capabilities: Joi.object({
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
627
|
+
clusterMode: Joi.boolean().default(false),
|
|
628
|
+
// added in 1.2.2
|
|
629
|
+
component: Joi.boolean().default(true),
|
|
630
|
+
didSpace: Joi.string()
|
|
631
|
+
.valid(...Object.values(BLOCKLET_APP_SPACE_ENDPOINTS))
|
|
632
|
+
.optional(),
|
|
633
|
+
navigation: Joi.boolean().default(true), // Should blocklet join navigation auto-merge process
|
|
634
|
+
}).default({
|
|
635
|
+
clusterMode: false,
|
|
636
|
+
component: true,
|
|
637
|
+
}),
|
|
316
638
|
// Other contents to be included in the bundle
|
|
317
|
-
files: Joi.array()
|
|
318
|
-
.items(
|
|
319
|
-
ensureFiles
|
|
320
|
-
? // eslint-disable-next-line
|
|
321
|
-
Joi.file().exists({ baseDir, canSkip: (dir, name) => [BLOCKLET_ENTRY_FILE, BLOCKLET_BUNDLE_FILE].includes(name) || isGlob(name) }) // prettier-ignore
|
|
322
|
-
: Joi.string().trim()
|
|
323
|
-
)
|
|
324
|
-
.optional(),
|
|
325
|
-
|
|
639
|
+
files: Joi.array().items(Joi.string().trim()).optional(),
|
|
326
640
|
// TODO: this field should be refactored in future version
|
|
327
641
|
engine: Joi.alternatives().try(engineSchema, Joi.array().items(engineSchema)).optional(),
|
|
328
|
-
|
|
329
|
-
// TODO: following fields only exist for backward compatibility
|
|
330
|
-
publicUrl: Joi.string().optional().allow(''),
|
|
331
|
-
adminUrl: Joi.string().optional().allow(''),
|
|
332
|
-
configUrl: Joi.string().optional().allow(''),
|
|
333
|
-
docUrl: Joi.string().optional().allow(''),
|
|
334
|
-
|
|
335
642
|
// NOTE: following fields are appended by registry or bundling process
|
|
336
643
|
screenshots: Joi.array().items(Joi.string().min(1)).optional().default([]),
|
|
337
644
|
logoUrl: Joi.string().optional().allow(''),
|
|
338
|
-
dist:
|
|
645
|
+
dist: distSchema.optional(),
|
|
339
646
|
stats: statsSchema.optional(),
|
|
340
647
|
htmlAst: Joi.any().optional(),
|
|
341
648
|
path: Joi.string().optional(),
|
|
342
649
|
signatures: Joi.array().items(signatureSchema).optional(),
|
|
343
650
|
lastPublishedAt: Joi.string().isoDate().optional(),
|
|
344
|
-
|
|
345
651
|
// blocklet component support
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
.
|
|
352
|
-
|
|
353
|
-
|
|
652
|
+
components: componentsSchema(),
|
|
653
|
+
staticComponents: componentsSchema({ isStatic: true }),
|
|
654
|
+
// navigation & theme
|
|
655
|
+
navigation: navigationSchema,
|
|
656
|
+
theme: themeSchema,
|
|
657
|
+
copyright: Joi.object({
|
|
658
|
+
owner: Joi.string().min(1),
|
|
659
|
+
year: Joi.alternatives().try(Joi.string(), Joi.number()),
|
|
660
|
+
}),
|
|
661
|
+
// NOTE: following fields only exist in blocklet server and cannot be set manually
|
|
662
|
+
bundleName: Joi.string(),
|
|
663
|
+
bundleDid: Joi.DID().trim(),
|
|
664
|
+
storeId: Joi.string(),
|
|
354
665
|
};
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
666
|
+
const blockletMetaSchema = Joi.object(blockletMetaProps).options({ stripUnknown: true, noDefaults: false }).meta({
|
|
667
|
+
className: 'TBlockletMeta',
|
|
668
|
+
unknownType: 'any',
|
|
669
|
+
});
|
|
670
|
+
exports.blockletMetaSchema = blockletMetaSchema;
|
|
671
|
+
const createBlockletSchema = (baseDir, { ensureMain = false, ensureFiles = false, ensureDist = false, ensureComponentStore = true, ensureName = false, skipValidateDidName = false, ...schemaOptions } = {}) => {
|
|
672
|
+
if (!baseDir || !fs_1.default.existsSync(baseDir)) {
|
|
673
|
+
// eslint-disable-next-line no-param-reassign
|
|
674
|
+
ensureFiles = false;
|
|
675
|
+
}
|
|
676
|
+
return Joi.object({
|
|
677
|
+
...blockletMetaProps,
|
|
678
|
+
main: Joi.when('group', {
|
|
679
|
+
is: Joi.valid(BlockletGroup.gateway),
|
|
680
|
+
then: Joi.forbidden(),
|
|
681
|
+
otherwise: ensureMain ? Joi.file().exists({ baseDir }).required() : Joi.string().trim().required(),
|
|
682
|
+
}),
|
|
683
|
+
logo: ensureFiles ? Joi.file().trim().exists({ baseDir }).optional() : Joi.string().trim().optional(),
|
|
684
|
+
// Other contents to be included in the bundle
|
|
685
|
+
files: Joi.array()
|
|
686
|
+
.items(ensureFiles
|
|
687
|
+
? // eslint-disable-next-line
|
|
688
|
+
Joi.file().exists({ baseDir, canSkip: (dir, name) => [BLOCKLET_ENTRY_FILE, BLOCKLET_BUNDLE_FILE].includes(name) || (0, is_glob_1.default)(name) }) // prettier-ignore
|
|
689
|
+
: Joi.string().trim())
|
|
690
|
+
.optional(),
|
|
691
|
+
dist: ensureDist ? distSchema.required() : distSchema.optional(),
|
|
692
|
+
components: componentsSchema({ checkStore: ensureComponentStore }),
|
|
693
|
+
staticComponents: componentsSchema({ isStatic: true, checkStore: ensureComponentStore }),
|
|
694
|
+
name: ensureName ? Joi.string().optional() : Joi.string().required(),
|
|
695
|
+
})
|
|
696
|
+
.options({ stripUnknown: true, noDefaults: false, ...schemaOptions })
|
|
697
|
+
.rename('children', 'components')
|
|
698
|
+
.custom((data, helper) => {
|
|
699
|
+
const { did, name } = data;
|
|
700
|
+
let cacheError;
|
|
701
|
+
if ((0, did_1.isValid)(did)) {
|
|
702
|
+
try {
|
|
703
|
+
(0, name_1.validateNewDid)(did);
|
|
704
|
+
return data;
|
|
705
|
+
}
|
|
706
|
+
catch (e) {
|
|
707
|
+
cacheError = e;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
/* ------------- 兼容旧的逻辑,旧逻辑使用 name 生成一个 did ------------- */
|
|
711
|
+
// 此时 name 必须存在
|
|
712
|
+
if (name) {
|
|
713
|
+
(0, name_1.validateName)(name, { checkDid: !skipValidateDidName });
|
|
714
|
+
const expectDid = (0, did_2.default)(name);
|
|
715
|
+
if (expectDid !== did) {
|
|
716
|
+
// @ts-ignore
|
|
717
|
+
return helper.message(`The did of name "${name}" should be "${expectDid}"`);
|
|
718
|
+
}
|
|
719
|
+
return data;
|
|
720
|
+
/* ------------------------------------------------------ */
|
|
721
|
+
}
|
|
722
|
+
if (cacheError) {
|
|
723
|
+
return helper.message(cacheError.message);
|
|
724
|
+
}
|
|
725
|
+
return data;
|
|
726
|
+
});
|
|
727
|
+
};
|
|
728
|
+
exports.createBlockletSchema = createBlockletSchema;
|
|
729
|
+
exports.default = {
|
|
730
|
+
blockletNameSchema,
|
|
731
|
+
componentSchema,
|
|
732
|
+
endpointSchema,
|
|
733
|
+
serviceSchema,
|
|
734
|
+
createBlockletSchema,
|
|
735
|
+
interfaceSchema,
|
|
736
|
+
environmentSchema,
|
|
737
|
+
environmentNameSchema,
|
|
738
|
+
scriptsSchema,
|
|
739
|
+
personSchema,
|
|
740
|
+
distSchema,
|
|
741
|
+
titleSchema,
|
|
742
|
+
descriptionSchema,
|
|
743
|
+
logoSchema,
|
|
744
|
+
navigationSchema,
|
|
745
|
+
themeSchema,
|
|
746
|
+
mountPointSchema,
|
|
747
|
+
updateMountPointSchema,
|
|
748
|
+
authConfigSchema,
|
|
363
749
|
};
|