@shuvi/platform-shared 1.0.13 → 1.0.15
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/esm/shared/helper/getAppData.js +2 -2
- package/esm/shared/loader/loader.js +1 -1
- package/lib/node/route/matchSpec.d.ts +10 -4
- package/lib/node/route/matchSpec.js +76 -19
- package/lib/node/route/route.d.ts +16 -4
- package/lib/node/route/route.js +13 -9
- package/lib/shared/helper/getAppData.js +2 -2
- package/lib/shared/loader/loader.js +1 -1
- package/package.json +8 -8
|
@@ -9,7 +9,7 @@ export function getAppData() {
|
|
|
9
9
|
return {
|
|
10
10
|
ssr: false,
|
|
11
11
|
filesByRoutId: {},
|
|
12
|
-
publicPath: ''
|
|
12
|
+
publicPath: '/'
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
const el = document.getElementById(CLIENT_APPDATA_ID);
|
|
@@ -18,7 +18,7 @@ export function getAppData() {
|
|
|
18
18
|
ssr: false,
|
|
19
19
|
pageData: {},
|
|
20
20
|
filesByRoutId: {},
|
|
21
|
-
publicPath: ''
|
|
21
|
+
publicPath: '/'
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
return JSON.parse(el.textContent);
|
|
@@ -63,7 +63,7 @@ export function runInParallerAndBail(fns) {
|
|
|
63
63
|
}
|
|
64
64
|
function redirectHelper(to, status = 302) {
|
|
65
65
|
if (process.env.NODE_ENV === 'development') {
|
|
66
|
-
invariant(typeof to === 'string', `redirect
|
|
66
|
+
invariant(typeof to === 'string', `redirect's frist argument should be string, now is ${typeof to}`);
|
|
67
67
|
}
|
|
68
68
|
throw createRedirect(to, status);
|
|
69
69
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
export interface FileMatcherPatterns {
|
|
2
|
+
includePattern: string | undefined;
|
|
2
3
|
excludePattern: string | undefined;
|
|
3
4
|
}
|
|
4
|
-
export declare
|
|
5
|
-
export declare function
|
|
5
|
+
export declare type Usage = 'include' | 'exclude';
|
|
6
|
+
export declare function getRegularExpressionsForWildcards(specs: readonly string[] | undefined, basePath: string, usage: Usage): readonly string[] | undefined;
|
|
7
|
+
export declare function getRegularExpressionForWildcard(specs: readonly string[] | undefined, basePath: string, usage: Usage): string | undefined;
|
|
6
8
|
export declare function getRegexFromPattern(pattern: string, caseSensitive: boolean): RegExp;
|
|
7
|
-
export declare function getFileMatcherPatterns(basePath: string, excludes: readonly string[] | undefined): FileMatcherPatterns;
|
|
8
|
-
export declare function
|
|
9
|
+
export declare function getFileMatcherPatterns(basePath: string, includes: readonly string[] | undefined, excludes: readonly string[] | undefined): FileMatcherPatterns;
|
|
10
|
+
export declare function matchesSpecs(basePath: string, { includes, excludes, caseSensitive }: {
|
|
11
|
+
includes?: string[];
|
|
12
|
+
excludes?: string[];
|
|
13
|
+
caseSensitive: boolean;
|
|
14
|
+
}): (path: string) => boolean;
|
|
@@ -23,17 +23,21 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
26
|
+
exports.matchesSpecs = exports.getFileMatcherPatterns = exports.getRegexFromPattern = exports.getRegularExpressionForWildcard = exports.getRegularExpressionsForWildcards = void 0;
|
|
27
27
|
// port from typescript
|
|
28
28
|
const nodePath = __importStar(require("path"));
|
|
29
|
+
const CharacterCodes = {
|
|
30
|
+
asterisk: 42,
|
|
31
|
+
question: 63
|
|
32
|
+
};
|
|
29
33
|
const directorySeparator = '/';
|
|
30
34
|
// Reserved characters, forces escaping of any non-word (or digit), non-whitespace character.
|
|
31
35
|
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
|
|
32
36
|
// proof.
|
|
33
37
|
const reservedCharacterPattern = /[^\w\s\/]/g;
|
|
34
38
|
const commonPackageFolders = ['node_modules'];
|
|
35
|
-
// does not match centeain directories
|
|
36
|
-
const implicitExcludePathRegexPattern =
|
|
39
|
+
// does not match centeain directories like node_modules
|
|
40
|
+
const implicitExcludePathRegexPattern = `(?!(${commonPackageFolders.join('|')})(/|$))`;
|
|
37
41
|
function replaceWildcardCharacter(match, singleAsteriskRegexFragment) {
|
|
38
42
|
return match === '*'
|
|
39
43
|
? singleAsteriskRegexFragment
|
|
@@ -41,13 +45,29 @@ function replaceWildcardCharacter(match, singleAsteriskRegexFragment) {
|
|
|
41
45
|
? '[^/]'
|
|
42
46
|
: '\\' + match;
|
|
43
47
|
}
|
|
44
|
-
const
|
|
48
|
+
const includeMatcher = {
|
|
49
|
+
/**
|
|
50
|
+
* Matches any single directory segment except for directory separators.
|
|
51
|
+
*/
|
|
52
|
+
singleAsteriskRegexFragment: '[^/]*',
|
|
53
|
+
/**
|
|
54
|
+
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
|
|
55
|
+
* files or directories, does not match subdirectories that start with a . character
|
|
56
|
+
*/
|
|
57
|
+
doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`,
|
|
58
|
+
replaceWildcardCharacter: match => replaceWildcardCharacter(match, includeMatcher.singleAsteriskRegexFragment)
|
|
59
|
+
};
|
|
60
|
+
const excludeMatcher = {
|
|
45
61
|
singleAsteriskRegexFragment: '[^/]*',
|
|
46
62
|
doubleAsteriskRegexFragment: '(/.+?)?',
|
|
47
|
-
replaceWildcardCharacter: match => replaceWildcardCharacter(match,
|
|
63
|
+
replaceWildcardCharacter: match => replaceWildcardCharacter(match, excludeMatcher.singleAsteriskRegexFragment)
|
|
64
|
+
};
|
|
65
|
+
const wildcardMatchers = {
|
|
66
|
+
include: includeMatcher,
|
|
67
|
+
exclude: excludeMatcher
|
|
48
68
|
};
|
|
49
69
|
/**
|
|
50
|
-
* An "includes" path "foo" is implicitly a glob "foo/** /*" (without the space) if its last component has no extension,
|
|
70
|
+
* An "includes" or "exclude" path "foo" is implicitly a glob "foo/** /*" (without the space) if its last component has no extension,
|
|
51
71
|
* and does not contain any glob characters itself.
|
|
52
72
|
*/
|
|
53
73
|
function isImplicitGlob(lastPathComponent) {
|
|
@@ -65,7 +85,7 @@ function getNormalizedPathComponents(path, currentDirectory) {
|
|
|
65
85
|
comps.pop();
|
|
66
86
|
return comps;
|
|
67
87
|
}
|
|
68
|
-
function getSubPatternFromSpec(spec, basePath, { doubleAsteriskRegexFragment, replaceWildcardCharacter }) {
|
|
88
|
+
function getSubPatternFromSpec(spec, basePath, usage, { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }) {
|
|
69
89
|
let subpattern = '';
|
|
70
90
|
let hasWrittenComponent = false;
|
|
71
91
|
const components = getNormalizedPathComponents(spec, basePath);
|
|
@@ -83,20 +103,47 @@ function getSubPatternFromSpec(spec, basePath, { doubleAsteriskRegexFragment, re
|
|
|
83
103
|
if (hasWrittenComponent) {
|
|
84
104
|
subpattern += directorySeparator;
|
|
85
105
|
}
|
|
86
|
-
|
|
106
|
+
if (usage !== 'exclude') {
|
|
107
|
+
let componentPattern = '';
|
|
108
|
+
// The * and ? wildcards should not match directories or files that start with . if they
|
|
109
|
+
// appear first in a component. Dotted directories and files can be included explicitly
|
|
110
|
+
// like so: **/.*/.*
|
|
111
|
+
if (component.charCodeAt(0) === CharacterCodes.asterisk) {
|
|
112
|
+
componentPattern += '([^./]' + singleAsteriskRegexFragment + ')?';
|
|
113
|
+
component = component.substring(1);
|
|
114
|
+
}
|
|
115
|
+
else if (component.charCodeAt(0) === CharacterCodes.question) {
|
|
116
|
+
componentPattern += '[^./]';
|
|
117
|
+
component = component.substring(1);
|
|
118
|
+
}
|
|
119
|
+
componentPattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
|
|
120
|
+
// Patterns should not include subfolders like node_modules unless they are
|
|
121
|
+
// explicitly included as part of the path.
|
|
122
|
+
//
|
|
123
|
+
// As an optimization, if the component pattern is the same as the component,
|
|
124
|
+
// then there definitely were no wildcard characters and we do not need to
|
|
125
|
+
// add the exclusion pattern.
|
|
126
|
+
if (componentPattern !== component) {
|
|
127
|
+
subpattern += implicitExcludePathRegexPattern;
|
|
128
|
+
}
|
|
129
|
+
subpattern += componentPattern;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
|
|
133
|
+
}
|
|
87
134
|
}
|
|
88
135
|
hasWrittenComponent = true;
|
|
89
136
|
}
|
|
90
137
|
return subpattern;
|
|
91
138
|
}
|
|
92
|
-
function getRegularExpressionsForWildcards(specs, basePath) {
|
|
139
|
+
function getRegularExpressionsForWildcards(specs, basePath, usage) {
|
|
93
140
|
if (specs === undefined || specs.length === 0) {
|
|
94
141
|
return undefined;
|
|
95
142
|
}
|
|
96
143
|
const result = [];
|
|
97
144
|
for (const spec of specs) {
|
|
98
145
|
if (spec) {
|
|
99
|
-
let r = getSubPatternFromSpec(spec, basePath,
|
|
146
|
+
let r = getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage]);
|
|
100
147
|
if (r) {
|
|
101
148
|
result.push(r);
|
|
102
149
|
}
|
|
@@ -106,12 +153,12 @@ function getRegularExpressionsForWildcards(specs, basePath) {
|
|
|
106
153
|
}
|
|
107
154
|
exports.getRegularExpressionsForWildcards = getRegularExpressionsForWildcards;
|
|
108
155
|
function getRegularExpressionForWildcard(specs, basePath, usage) {
|
|
109
|
-
const patterns = getRegularExpressionsForWildcards(specs, basePath);
|
|
156
|
+
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
|
|
110
157
|
if (!patterns || !patterns.length) {
|
|
111
158
|
return undefined;
|
|
112
159
|
}
|
|
113
160
|
const pattern = patterns.map(pattern => `(${pattern})`).join('|');
|
|
114
|
-
// If excluding, match "foo/
|
|
161
|
+
// If excluding, match "foo/", but if including, only allow "foo".
|
|
115
162
|
const terminator = usage === 'exclude' ? '($|/)' : '$';
|
|
116
163
|
return `^(${pattern})${terminator}`;
|
|
117
164
|
}
|
|
@@ -120,19 +167,29 @@ function getRegexFromPattern(pattern, caseSensitive) {
|
|
|
120
167
|
return new RegExp(pattern, caseSensitive ? '' : 'i');
|
|
121
168
|
}
|
|
122
169
|
exports.getRegexFromPattern = getRegexFromPattern;
|
|
123
|
-
function getFileMatcherPatterns(basePath, excludes) {
|
|
170
|
+
function getFileMatcherPatterns(basePath, includes, excludes) {
|
|
124
171
|
const absolutePath = normalizePath(basePath);
|
|
125
172
|
return {
|
|
173
|
+
includePattern: getRegularExpressionForWildcard(includes, absolutePath, 'include'),
|
|
126
174
|
excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, 'exclude')
|
|
127
175
|
};
|
|
128
176
|
}
|
|
129
177
|
exports.getFileMatcherPatterns = getFileMatcherPatterns;
|
|
130
|
-
function
|
|
131
|
-
|
|
178
|
+
function matchesSpecs(basePath, { includes, excludes, caseSensitive }) {
|
|
179
|
+
const patterns = getFileMatcherPatterns(basePath, includes, excludes);
|
|
180
|
+
const includeRegex = patterns.includePattern &&
|
|
181
|
+
getRegexFromPattern(patterns.includePattern, caseSensitive);
|
|
132
182
|
const excludeRegex = patterns.excludePattern &&
|
|
133
183
|
getRegexFromPattern(patterns.excludePattern, caseSensitive);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
184
|
+
if (includeRegex) {
|
|
185
|
+
if (excludeRegex) {
|
|
186
|
+
return path => !(includeRegex.test(path) && !excludeRegex.test(path));
|
|
187
|
+
}
|
|
188
|
+
return path => !includeRegex.test(path);
|
|
189
|
+
}
|
|
190
|
+
if (excludeRegex) {
|
|
191
|
+
return path => excludeRegex.test(path);
|
|
192
|
+
}
|
|
193
|
+
return () => true;
|
|
137
194
|
}
|
|
138
|
-
exports.
|
|
195
|
+
exports.matchesSpecs = matchesSpecs;
|
|
@@ -28,7 +28,19 @@ export declare type PageRoutes = RouteResult<IPageRouteConfig>;
|
|
|
28
28
|
export declare type ApiRoutes = RouteResult<IApiRouteConfig>;
|
|
29
29
|
export declare type MiddlewareRoutes = RouteResult<IMiddlewareRouteConfig>;
|
|
30
30
|
export declare type RouteConfigType = IPageRouteConfig | IApiRouteConfig | IMiddlewareRouteConfig;
|
|
31
|
-
export declare const getRawRoutesFromDir: (dirname: string, excludes
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
export declare const getRawRoutesFromDir: (dirname: string, { includes, excludes }: {
|
|
32
|
+
includes?: string[] | undefined;
|
|
33
|
+
excludes?: string[] | undefined;
|
|
34
|
+
}) => Promise<RawRoutes>;
|
|
35
|
+
export declare const getPageRoutes: (dir: string | RawRoutes, { includes, excludes }?: {
|
|
36
|
+
includes?: string[] | undefined;
|
|
37
|
+
excludes?: string[] | undefined;
|
|
38
|
+
}) => Promise<PageRoutes>;
|
|
39
|
+
export declare const getApiRoutes: (dir: string | RawRoutes, { includes, excludes }?: {
|
|
40
|
+
includes?: string[] | undefined;
|
|
41
|
+
excludes?: string[] | undefined;
|
|
42
|
+
}) => Promise<ApiRoutes>;
|
|
43
|
+
export declare const getMiddlewareRoutes: (dir: string | RawRoutes, { includes, excludes }?: {
|
|
44
|
+
includes?: string[] | undefined;
|
|
45
|
+
excludes?: string[] | undefined;
|
|
46
|
+
}) => Promise<MiddlewareRoutes>;
|
package/lib/node/route/route.js
CHANGED
|
@@ -14,7 +14,7 @@ const path_1 = require("path");
|
|
|
14
14
|
const file_1 = require("@shuvi/utils/file");
|
|
15
15
|
const helpers_1 = require("./helpers");
|
|
16
16
|
const matchSpec_1 = require("./matchSpec");
|
|
17
|
-
const getRawRoutesFromDir = (dirname, excludes) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
const getRawRoutesFromDir = (dirname, { includes, excludes }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
18
|
const rootDirname = dirname;
|
|
19
19
|
if (!(yield (0, file_1.isDirectory)(rootDirname))) {
|
|
20
20
|
return {
|
|
@@ -26,7 +26,11 @@ const getRawRoutesFromDir = (dirname, excludes) => __awaiter(void 0, void 0, voi
|
|
|
26
26
|
const warnings = [];
|
|
27
27
|
const errors = [];
|
|
28
28
|
const routes = [];
|
|
29
|
-
const
|
|
29
|
+
const shouldExclude = (0, matchSpec_1.matchesSpecs)(rootDirname, {
|
|
30
|
+
includes: includes && includes.length > 0 ? includes : ['**/*'],
|
|
31
|
+
excludes,
|
|
32
|
+
caseSensitive: false
|
|
33
|
+
});
|
|
30
34
|
const visitDirectory = (dirname, routes, parentDir) => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
35
|
const files = yield (0, helpers_1.getAllowFilesAndDirs)(dirname);
|
|
32
36
|
if (!files.length) {
|
|
@@ -43,7 +47,7 @@ const getRawRoutesFromDir = (dirname, excludes) => __awaiter(void 0, void 0, voi
|
|
|
43
47
|
// this is required for matchFile to wrok properly
|
|
44
48
|
filepath = (0, path_1.join)(filepath, path_1.sep);
|
|
45
49
|
}
|
|
46
|
-
if (
|
|
50
|
+
if (shouldExclude(filepath)) {
|
|
47
51
|
continue;
|
|
48
52
|
}
|
|
49
53
|
const segment = parentDir === '' ? '/' : (0, helpers_1.normalizeRoutePath)(parentDir);
|
|
@@ -77,10 +81,10 @@ const getRawRoutesFromDir = (dirname, excludes) => __awaiter(void 0, void 0, voi
|
|
|
77
81
|
};
|
|
78
82
|
});
|
|
79
83
|
exports.getRawRoutesFromDir = getRawRoutesFromDir;
|
|
80
|
-
const getPageRoutes = (dir, excludes) => __awaiter(void 0, void 0, void 0, function* () {
|
|
84
|
+
const getPageRoutes = (dir, { includes, excludes } = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
85
|
let raw;
|
|
82
86
|
if (typeof dir === 'string') {
|
|
83
|
-
raw = yield (0, exports.getRawRoutesFromDir)(dir, excludes);
|
|
87
|
+
raw = yield (0, exports.getRawRoutesFromDir)(dir, { excludes });
|
|
84
88
|
}
|
|
85
89
|
else {
|
|
86
90
|
raw = dir;
|
|
@@ -124,10 +128,10 @@ const getPageRoutes = (dir, excludes) => __awaiter(void 0, void 0, void 0, funct
|
|
|
124
128
|
};
|
|
125
129
|
});
|
|
126
130
|
exports.getPageRoutes = getPageRoutes;
|
|
127
|
-
const getApiRoutes = (dir, excludes) => __awaiter(void 0, void 0, void 0, function* () {
|
|
131
|
+
const getApiRoutes = (dir, { includes, excludes } = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
128
132
|
let raw;
|
|
129
133
|
if (typeof dir === 'string') {
|
|
130
|
-
raw = yield (0, exports.getRawRoutesFromDir)(dir, excludes);
|
|
134
|
+
raw = yield (0, exports.getRawRoutesFromDir)(dir, { excludes });
|
|
131
135
|
}
|
|
132
136
|
else {
|
|
133
137
|
raw = dir;
|
|
@@ -177,10 +181,10 @@ const getApiRoutes = (dir, excludes) => __awaiter(void 0, void 0, void 0, functi
|
|
|
177
181
|
};
|
|
178
182
|
});
|
|
179
183
|
exports.getApiRoutes = getApiRoutes;
|
|
180
|
-
const getMiddlewareRoutes = (dir, excludes) => __awaiter(void 0, void 0, void 0, function* () {
|
|
184
|
+
const getMiddlewareRoutes = (dir, { includes, excludes } = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
181
185
|
let raw;
|
|
182
186
|
if (typeof dir === 'string') {
|
|
183
|
-
raw = yield (0, exports.getRawRoutesFromDir)(dir, excludes);
|
|
187
|
+
raw = yield (0, exports.getRawRoutesFromDir)(dir, { excludes });
|
|
184
188
|
}
|
|
185
189
|
else {
|
|
186
190
|
raw = dir;
|
|
@@ -12,7 +12,7 @@ function getAppData() {
|
|
|
12
12
|
return {
|
|
13
13
|
ssr: false,
|
|
14
14
|
filesByRoutId: {},
|
|
15
|
-
publicPath: ''
|
|
15
|
+
publicPath: '/'
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
const el = document.getElementById(constants_1.CLIENT_APPDATA_ID);
|
|
@@ -21,7 +21,7 @@ function getAppData() {
|
|
|
21
21
|
ssr: false,
|
|
22
22
|
pageData: {},
|
|
23
23
|
filesByRoutId: {},
|
|
24
|
-
publicPath: ''
|
|
24
|
+
publicPath: '/'
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
return JSON.parse(el.textContent);
|
|
@@ -70,7 +70,7 @@ function runInParallerAndBail(fns) {
|
|
|
70
70
|
exports.runInParallerAndBail = runInParallerAndBail;
|
|
71
71
|
function redirectHelper(to, status = 302) {
|
|
72
72
|
if (process.env.NODE_ENV === 'development') {
|
|
73
|
-
(0, invariant_1.default)(typeof to === 'string', `redirect
|
|
73
|
+
(0, invariant_1.default)(typeof to === 'string', `redirect's frist argument should be string, now is ${typeof to}`);
|
|
74
74
|
}
|
|
75
75
|
throw (0, response_1.redirect)(to, status);
|
|
76
76
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shuvi/platform-shared",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/shuvijs/shuvi.git",
|
|
@@ -83,17 +83,17 @@
|
|
|
83
83
|
"node": ">= 16.0.0"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@shuvi/hook": "1.0.
|
|
86
|
+
"@shuvi/hook": "1.0.15",
|
|
87
87
|
"doura": "0.0.7",
|
|
88
|
-
"@shuvi/router": "1.0.
|
|
89
|
-
"@shuvi/runtime": "1.0.
|
|
90
|
-
"@shuvi/shared": "1.0.
|
|
91
|
-
"@shuvi/toolpack": "1.0.
|
|
92
|
-
"@shuvi/utils": "1.0.
|
|
88
|
+
"@shuvi/router": "1.0.15",
|
|
89
|
+
"@shuvi/runtime": "1.0.15",
|
|
90
|
+
"@shuvi/shared": "1.0.15",
|
|
91
|
+
"@shuvi/toolpack": "1.0.15",
|
|
92
|
+
"@shuvi/utils": "1.0.15",
|
|
93
93
|
"redux": "4.1.2"
|
|
94
94
|
},
|
|
95
95
|
"peerDependencies": {
|
|
96
|
-
"@shuvi/service": "1.0.
|
|
96
|
+
"@shuvi/service": "1.0.15"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"@shuvi/service": "workspace:*",
|