silgi 0.24.15 → 0.24.17
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/dist/cli/build/prepare.mjs +43 -0
- package/dist/cli/{dev.mjs → commands/dev.mjs} +4 -43
- package/dist/cli/commands/env.mjs +40 -0
- package/dist/cli/{install.mjs → commands/install.mjs} +3 -37
- package/dist/cli/commands/prepare.mjs +66 -0
- package/dist/cli/{prepare.mjs → commands/run.mjs} +9 -82
- package/dist/cli/config/defaults.mjs +129 -0
- package/dist/cli/config/index.mjs +2 -16
- package/dist/cli/config/loader.mjs +97 -0
- package/dist/cli/config/resolvers/compatibility.mjs +90 -0
- package/dist/cli/config/resolvers/imports.mjs +96 -0
- package/dist/cli/config/resolvers/paths.mjs +167 -0
- package/dist/cli/config/resolvers/storage.mjs +25 -0
- package/dist/cli/config/resolvers/url.mjs +7 -0
- package/dist/cli/config/types.mjs +191 -0
- package/dist/cli/core/app.mjs +92 -0
- package/dist/cli/core/devServer.mjs +8 -0
- package/dist/cli/core/env.mjs +76 -0
- package/dist/cli/core/installPackage.mjs +31 -0
- package/dist/cli/core/prepare.mjs +7 -0
- package/dist/cli/core/runtimeConfig.mjs +14 -0
- package/dist/cli/core/scan.mjs +39 -0
- package/dist/cli/core/silgi.mjs +125 -0
- package/dist/cli/core/templates.mjs +31 -0
- package/dist/cli/framework/emptyFramework.mjs +9 -0
- package/dist/cli/framework/h3.mjs +89 -0
- package/dist/cli/framework/index.mjs +8 -0
- package/dist/cli/framework/nitro.mjs +106 -0
- package/dist/cli/framework/nuxt.mjs +9 -0
- package/dist/cli/index.mjs +6 -9
- package/dist/cli/module/exportScan.mjs +130 -0
- package/dist/cli/module/install.mjs +59 -0
- package/dist/cli/module/scan.mjs +227 -0
- package/dist/cli/scan/commands.mjs +47 -0
- package/dist/cli/scan/prepareConfigs.mjs +46 -0
- package/dist/cli/scan/prepareCoreFile.mjs +166 -0
- package/dist/cli/scan/prepareFramework.mjs +73 -0
- package/dist/cli/scan/prepareSchema.mjs +177 -0
- package/dist/cli/scan/prepareServerFiles.mjs +119 -0
- package/dist/cli/scan/scanExportFile.mjs +155 -0
- package/dist/cli/scan/writeCoreFile.mjs +34 -0
- package/dist/cli/scan/writeScanFiles.mjs +30 -0
- package/dist/cli/scan/writeTypesAndFiles.mjs +109 -0
- package/dist/cli/utils/build-uri-map.mjs +39 -0
- package/dist/cli/utils/common.mjs +13 -0
- package/dist/cli/{compatibility.mjs → utils/compatibility.mjs} +1 -1
- package/dist/cli/utils/generateRouterDTS.mjs +80 -0
- package/dist/cli/utils/ignore.mjs +46 -0
- package/dist/cli/utils/parser.mjs +168 -0
- package/dist/cli/utils/readScanFile.mjs +79 -0
- package/dist/cli/utils/storage.mjs +25 -0
- package/dist/core/createSilgi.mjs +76 -0
- package/dist/core/error.mjs +227 -0
- package/dist/core/index.mjs +8 -0
- package/dist/core/routeRules.mjs +288 -0
- package/dist/core/silgi.mjs +128 -0
- package/dist/core/silgiApp.mjs +25 -0
- package/dist/core/storage.mjs +15 -0
- package/dist/core/unctx.mjs +27 -0
- package/dist/core/uris/uri.mjs +33 -0
- package/dist/core/uris/utils.mjs +130 -0
- package/dist/core/utils/event.mjs +15 -0
- package/dist/core/utils/merge.mjs +29 -0
- package/dist/core/utils/runtime.mjs +22 -0
- package/dist/core/utils/schema.mjs +5 -0
- package/dist/core/utils/service.mjs +5 -0
- package/dist/core/utils/shared.mjs +5 -0
- package/dist/core/utils/storage.mjs +72 -0
- package/dist/index.mjs +20 -793
- package/dist/kit/errors.mjs +11 -0
- package/dist/kit/esm.mjs +14 -0
- package/dist/kit/fs.mjs +30 -0
- package/dist/kit/gen.mjs +44 -0
- package/dist/kit/hash.mjs +8 -0
- package/dist/kit/index.mjs +15 -528
- package/dist/kit/isFramework.mjs +25 -0
- package/dist/kit/logger.mjs +7 -0
- package/dist/kit/module.mjs +73 -0
- package/dist/kit/parseServices.mjs +57 -0
- package/dist/kit/path.mjs +34 -0
- package/dist/kit/preset.mjs +6 -0
- package/dist/kit/resolve.mjs +80 -0
- package/dist/kit/template.mjs +49 -0
- package/dist/kit/useRequest.mjs +91 -0
- package/dist/kit/utils.mjs +43 -0
- package/dist/package.json.mjs +5 -0
- package/dist/types/index.d.mts +1 -1
- package/package.json +1 -1
- package/dist/_chunks/silgiApp.mjs +0 -2682
- package/dist/cli/types.mjs +0 -772
- /package/dist/cli/{init.mjs → commands/init.mjs} +0 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
var HttpStatus = /* @__PURE__ */ ((HttpStatus2) => {
|
|
2
|
+
HttpStatus2[HttpStatus2["CONTINUE"] = 100] = "CONTINUE";
|
|
3
|
+
HttpStatus2[HttpStatus2["SWITCHING_PROTOCOLS"] = 101] = "SWITCHING_PROTOCOLS";
|
|
4
|
+
HttpStatus2[HttpStatus2["PROCESSING"] = 102] = "PROCESSING";
|
|
5
|
+
HttpStatus2[HttpStatus2["EARLY_HINTS"] = 103] = "EARLY_HINTS";
|
|
6
|
+
HttpStatus2[HttpStatus2["OK"] = 200] = "OK";
|
|
7
|
+
HttpStatus2[HttpStatus2["CREATED"] = 201] = "CREATED";
|
|
8
|
+
HttpStatus2[HttpStatus2["ACCEPTED"] = 202] = "ACCEPTED";
|
|
9
|
+
HttpStatus2[HttpStatus2["NON_AUTHORITATIVE_INFORMATION"] = 203] = "NON_AUTHORITATIVE_INFORMATION";
|
|
10
|
+
HttpStatus2[HttpStatus2["NO_CONTENT"] = 204] = "NO_CONTENT";
|
|
11
|
+
HttpStatus2[HttpStatus2["RESET_CONTENT"] = 205] = "RESET_CONTENT";
|
|
12
|
+
HttpStatus2[HttpStatus2["PARTIAL_CONTENT"] = 206] = "PARTIAL_CONTENT";
|
|
13
|
+
HttpStatus2[HttpStatus2["MULTI_STATUS"] = 207] = "MULTI_STATUS";
|
|
14
|
+
HttpStatus2[HttpStatus2["ALREADY_REPORTED"] = 208] = "ALREADY_REPORTED";
|
|
15
|
+
HttpStatus2[HttpStatus2["IM_USED"] = 226] = "IM_USED";
|
|
16
|
+
HttpStatus2[HttpStatus2["MULTIPLE_CHOICES"] = 300] = "MULTIPLE_CHOICES";
|
|
17
|
+
HttpStatus2[HttpStatus2["MOVED_PERMANENTLY"] = 301] = "MOVED_PERMANENTLY";
|
|
18
|
+
HttpStatus2[HttpStatus2["FOUND"] = 302] = "FOUND";
|
|
19
|
+
HttpStatus2[HttpStatus2["SEE_OTHER"] = 303] = "SEE_OTHER";
|
|
20
|
+
HttpStatus2[HttpStatus2["NOT_MODIFIED"] = 304] = "NOT_MODIFIED";
|
|
21
|
+
HttpStatus2[HttpStatus2["USE_PROXY"] = 305] = "USE_PROXY";
|
|
22
|
+
HttpStatus2[HttpStatus2["TEMPORARY_REDIRECT"] = 307] = "TEMPORARY_REDIRECT";
|
|
23
|
+
HttpStatus2[HttpStatus2["PERMANENT_REDIRECT"] = 308] = "PERMANENT_REDIRECT";
|
|
24
|
+
HttpStatus2[HttpStatus2["BAD_REQUEST"] = 400] = "BAD_REQUEST";
|
|
25
|
+
HttpStatus2[HttpStatus2["UNAUTHORIZED"] = 401] = "UNAUTHORIZED";
|
|
26
|
+
HttpStatus2[HttpStatus2["PAYMENT_REQUIRED"] = 402] = "PAYMENT_REQUIRED";
|
|
27
|
+
HttpStatus2[HttpStatus2["FORBIDDEN"] = 403] = "FORBIDDEN";
|
|
28
|
+
HttpStatus2[HttpStatus2["NOT_FOUND"] = 404] = "NOT_FOUND";
|
|
29
|
+
HttpStatus2[HttpStatus2["METHOD_NOT_ALLOWED"] = 405] = "METHOD_NOT_ALLOWED";
|
|
30
|
+
HttpStatus2[HttpStatus2["NOT_ACCEPTABLE"] = 406] = "NOT_ACCEPTABLE";
|
|
31
|
+
HttpStatus2[HttpStatus2["PROXY_AUTHENTICATION_REQUIRED"] = 407] = "PROXY_AUTHENTICATION_REQUIRED";
|
|
32
|
+
HttpStatus2[HttpStatus2["REQUEST_TIMEOUT"] = 408] = "REQUEST_TIMEOUT";
|
|
33
|
+
HttpStatus2[HttpStatus2["CONFLICT"] = 409] = "CONFLICT";
|
|
34
|
+
HttpStatus2[HttpStatus2["GONE"] = 410] = "GONE";
|
|
35
|
+
HttpStatus2[HttpStatus2["LENGTH_REQUIRED"] = 411] = "LENGTH_REQUIRED";
|
|
36
|
+
HttpStatus2[HttpStatus2["PRECONDITION_FAILED"] = 412] = "PRECONDITION_FAILED";
|
|
37
|
+
HttpStatus2[HttpStatus2["PAYLOAD_TOO_LARGE"] = 413] = "PAYLOAD_TOO_LARGE";
|
|
38
|
+
HttpStatus2[HttpStatus2["URI_TOO_LONG"] = 414] = "URI_TOO_LONG";
|
|
39
|
+
HttpStatus2[HttpStatus2["UNSUPPORTED_MEDIA_TYPE"] = 415] = "UNSUPPORTED_MEDIA_TYPE";
|
|
40
|
+
HttpStatus2[HttpStatus2["RANGE_NOT_SATISFIABLE"] = 416] = "RANGE_NOT_SATISFIABLE";
|
|
41
|
+
HttpStatus2[HttpStatus2["EXPECTATION_FAILED"] = 417] = "EXPECTATION_FAILED";
|
|
42
|
+
HttpStatus2[HttpStatus2["IM_A_TEAPOT"] = 418] = "IM_A_TEAPOT";
|
|
43
|
+
HttpStatus2[HttpStatus2["MISDIRECTED_REQUEST"] = 421] = "MISDIRECTED_REQUEST";
|
|
44
|
+
HttpStatus2[HttpStatus2["UNPROCESSABLE_ENTITY"] = 422] = "UNPROCESSABLE_ENTITY";
|
|
45
|
+
HttpStatus2[HttpStatus2["LOCKED"] = 423] = "LOCKED";
|
|
46
|
+
HttpStatus2[HttpStatus2["FAILED_DEPENDENCY"] = 424] = "FAILED_DEPENDENCY";
|
|
47
|
+
HttpStatus2[HttpStatus2["TOO_EARLY"] = 425] = "TOO_EARLY";
|
|
48
|
+
HttpStatus2[HttpStatus2["UPGRADE_REQUIRED"] = 426] = "UPGRADE_REQUIRED";
|
|
49
|
+
HttpStatus2[HttpStatus2["PRECONDITION_REQUIRED"] = 428] = "PRECONDITION_REQUIRED";
|
|
50
|
+
HttpStatus2[HttpStatus2["TOO_MANY_REQUESTS"] = 429] = "TOO_MANY_REQUESTS";
|
|
51
|
+
HttpStatus2[HttpStatus2["REQUEST_HEADER_FIELDS_TOO_LARGE"] = 431] = "REQUEST_HEADER_FIELDS_TOO_LARGE";
|
|
52
|
+
HttpStatus2[HttpStatus2["UNAVAILABLE_FOR_LEGAL_REASONS"] = 451] = "UNAVAILABLE_FOR_LEGAL_REASONS";
|
|
53
|
+
HttpStatus2[HttpStatus2["INTERNAL_SERVER_ERROR"] = 500] = "INTERNAL_SERVER_ERROR";
|
|
54
|
+
HttpStatus2[HttpStatus2["NOT_IMPLEMENTED"] = 501] = "NOT_IMPLEMENTED";
|
|
55
|
+
HttpStatus2[HttpStatus2["BAD_GATEWAY"] = 502] = "BAD_GATEWAY";
|
|
56
|
+
HttpStatus2[HttpStatus2["SERVICE_UNAVAILABLE"] = 503] = "SERVICE_UNAVAILABLE";
|
|
57
|
+
HttpStatus2[HttpStatus2["GATEWAY_TIMEOUT"] = 504] = "GATEWAY_TIMEOUT";
|
|
58
|
+
HttpStatus2[HttpStatus2["HTTP_VERSION_NOT_SUPPORTED"] = 505] = "HTTP_VERSION_NOT_SUPPORTED";
|
|
59
|
+
HttpStatus2[HttpStatus2["VARIANT_ALSO_NEGOTIATES"] = 506] = "VARIANT_ALSO_NEGOTIATES";
|
|
60
|
+
HttpStatus2[HttpStatus2["INSUFFICIENT_STORAGE"] = 507] = "INSUFFICIENT_STORAGE";
|
|
61
|
+
HttpStatus2[HttpStatus2["LOOP_DETECTED"] = 508] = "LOOP_DETECTED";
|
|
62
|
+
HttpStatus2[HttpStatus2["NOT_EXTENDED"] = 510] = "NOT_EXTENDED";
|
|
63
|
+
HttpStatus2[HttpStatus2["NETWORK_AUTHENTICATION_REQUIRED"] = 511] = "NETWORK_AUTHENTICATION_REQUIRED";
|
|
64
|
+
return HttpStatus2;
|
|
65
|
+
})(HttpStatus || {});
|
|
66
|
+
var ErrorSeverity = /* @__PURE__ */ ((ErrorSeverity2) => {
|
|
67
|
+
ErrorSeverity2["DEBUG"] = "DEBUG";
|
|
68
|
+
ErrorSeverity2["INFO"] = "INFO";
|
|
69
|
+
ErrorSeverity2["WARNING"] = "WARNING";
|
|
70
|
+
ErrorSeverity2["ERROR"] = "ERROR";
|
|
71
|
+
ErrorSeverity2["CRITICAL"] = "CRITICAL";
|
|
72
|
+
return ErrorSeverity2;
|
|
73
|
+
})(ErrorSeverity || {});
|
|
74
|
+
var ErrorCategory = /* @__PURE__ */ ((ErrorCategory2) => {
|
|
75
|
+
ErrorCategory2["AUTHENTICATION"] = "auth";
|
|
76
|
+
ErrorCategory2["AUTHORIZATION"] = "authorization";
|
|
77
|
+
ErrorCategory2["VALIDATION"] = "validation";
|
|
78
|
+
ErrorCategory2["BUSINESS"] = "business";
|
|
79
|
+
ErrorCategory2["INFRASTRUCTURE"] = "infrastructure";
|
|
80
|
+
ErrorCategory2["EXTERNAL"] = "external";
|
|
81
|
+
ErrorCategory2["UNKNOWN"] = "unknown";
|
|
82
|
+
return ErrorCategory2;
|
|
83
|
+
})(ErrorCategory || {});
|
|
84
|
+
class ErrorFactory {
|
|
85
|
+
static createMetadata(metadata) {
|
|
86
|
+
return {
|
|
87
|
+
timestamp: Date.now(),
|
|
88
|
+
...metadata
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
static create(options) {
|
|
92
|
+
return new SilgiError({
|
|
93
|
+
code: options.code ?? options.httpStatus ?? 500 /* INTERNAL_SERVER_ERROR */,
|
|
94
|
+
message: options.message,
|
|
95
|
+
category: options.category ?? "unknown" /* UNKNOWN */,
|
|
96
|
+
severity: options.severity ?? "ERROR" /* ERROR */,
|
|
97
|
+
httpStatus: options.httpStatus ?? 500 /* INTERNAL_SERVER_ERROR */,
|
|
98
|
+
metadata: this.createMetadata(options.metadata),
|
|
99
|
+
cause: options.cause,
|
|
100
|
+
context: options.context
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Predefined error creators
|
|
104
|
+
static authenticationError(message, context) {
|
|
105
|
+
return this.create({
|
|
106
|
+
message,
|
|
107
|
+
code: 401,
|
|
108
|
+
category: "auth" /* AUTHENTICATION */,
|
|
109
|
+
severity: "ERROR" /* ERROR */,
|
|
110
|
+
httpStatus: 401 /* UNAUTHORIZED */,
|
|
111
|
+
context
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
static authorizationError(message, context) {
|
|
115
|
+
return this.create({
|
|
116
|
+
message,
|
|
117
|
+
code: 403,
|
|
118
|
+
category: "authorization" /* AUTHORIZATION */,
|
|
119
|
+
severity: "ERROR" /* ERROR */,
|
|
120
|
+
httpStatus: 403 /* FORBIDDEN */,
|
|
121
|
+
context
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
static validationError(message, context) {
|
|
125
|
+
return this.create({
|
|
126
|
+
message,
|
|
127
|
+
code: 400,
|
|
128
|
+
category: "validation" /* VALIDATION */,
|
|
129
|
+
severity: "WARNING" /* WARNING */,
|
|
130
|
+
httpStatus: 400 /* BAD_REQUEST */,
|
|
131
|
+
context
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
static notFoundError(message, context) {
|
|
135
|
+
return this.create({
|
|
136
|
+
message,
|
|
137
|
+
code: 404,
|
|
138
|
+
category: "business" /* BUSINESS */,
|
|
139
|
+
severity: "WARNING" /* WARNING */,
|
|
140
|
+
httpStatus: 404 /* NOT_FOUND */,
|
|
141
|
+
context
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
static internalError(message, cause) {
|
|
145
|
+
return this.create({
|
|
146
|
+
message,
|
|
147
|
+
code: 500,
|
|
148
|
+
category: "infrastructure" /* INFRASTRUCTURE */,
|
|
149
|
+
severity: "CRITICAL" /* CRITICAL */,
|
|
150
|
+
httpStatus: 500 /* INTERNAL_SERVER_ERROR */,
|
|
151
|
+
cause
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
class SilgiError extends Error {
|
|
156
|
+
code;
|
|
157
|
+
category;
|
|
158
|
+
severity;
|
|
159
|
+
httpStatus;
|
|
160
|
+
metadata;
|
|
161
|
+
context;
|
|
162
|
+
cause;
|
|
163
|
+
constructor(error) {
|
|
164
|
+
super(error.message);
|
|
165
|
+
this.name = "SilgiError";
|
|
166
|
+
this.code = error.code;
|
|
167
|
+
this.category = error.category;
|
|
168
|
+
this.severity = error.severity;
|
|
169
|
+
this.httpStatus = error.httpStatus;
|
|
170
|
+
this.metadata = error.metadata ?? { timestamp: Date.now() };
|
|
171
|
+
this.context = error.context;
|
|
172
|
+
this.cause = error.cause;
|
|
173
|
+
if (Error.captureStackTrace) {
|
|
174
|
+
Error.captureStackTrace(this, this.constructor);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
toString() {
|
|
178
|
+
let str = `${this.name} [${this.code}] ${this.severity}: ${this.message}`;
|
|
179
|
+
str += `
|
|
180
|
+
Category: ${this.category}`;
|
|
181
|
+
str += `
|
|
182
|
+
HTTP Status: ${this.httpStatus}`;
|
|
183
|
+
if (this.context) {
|
|
184
|
+
str += `
|
|
185
|
+
Context: ${JSON.stringify(this.context, null, 2)}`;
|
|
186
|
+
}
|
|
187
|
+
if (this.metadata) {
|
|
188
|
+
str += `
|
|
189
|
+
Metadata: ${JSON.stringify(this.metadata, null, 2)}`;
|
|
190
|
+
}
|
|
191
|
+
if (this.stack) {
|
|
192
|
+
str += `
|
|
193
|
+
${this.stack}`;
|
|
194
|
+
}
|
|
195
|
+
return str;
|
|
196
|
+
}
|
|
197
|
+
toJSON() {
|
|
198
|
+
return {
|
|
199
|
+
name: this.name,
|
|
200
|
+
code: this.code,
|
|
201
|
+
message: this.message,
|
|
202
|
+
category: this.category,
|
|
203
|
+
severity: this.severity,
|
|
204
|
+
httpStatus: this.httpStatus,
|
|
205
|
+
metadata: this.metadata,
|
|
206
|
+
context: this.context,
|
|
207
|
+
stack: this.stack
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
static isError(error) {
|
|
211
|
+
return error instanceof SilgiError || typeof error === "object" && error !== null && "name" in error && error.name === "SilgiError";
|
|
212
|
+
}
|
|
213
|
+
static from(error) {
|
|
214
|
+
if (error instanceof SilgiError) {
|
|
215
|
+
return error;
|
|
216
|
+
}
|
|
217
|
+
return ErrorFactory.internalError(
|
|
218
|
+
error instanceof Error ? error.message : String(error),
|
|
219
|
+
error instanceof Error ? error : void 0
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function isBaseError(error) {
|
|
224
|
+
return typeof error === "object" && error !== null && "code" in error && "message" in error && "category" in error && "severity" in error && "httpStatus" in error;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export { ErrorCategory, ErrorFactory, ErrorSeverity, HttpStatus, SilgiError, isBaseError };
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { withoutTrailingSlash, withLeadingSlash } from 'ufo';
|
|
2
|
+
|
|
3
|
+
function patternToRegex(pattern) {
|
|
4
|
+
let regexStr = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
5
|
+
regexStr = regexStr.replace(/\*\*/g, ".+");
|
|
6
|
+
regexStr = regexStr.replace(/\*/g, "[^/]+");
|
|
7
|
+
regexStr = regexStr.replace(/:([^/]+)/g, "([^/]+)");
|
|
8
|
+
return new RegExp(`^${regexStr}$`);
|
|
9
|
+
}
|
|
10
|
+
function extractParams(url, pattern) {
|
|
11
|
+
url = withoutTrailingSlash(withLeadingSlash(url));
|
|
12
|
+
pattern = withoutTrailingSlash(withLeadingSlash(pattern));
|
|
13
|
+
if (!pattern.includes(":"))
|
|
14
|
+
return null;
|
|
15
|
+
const paramNames = [];
|
|
16
|
+
const patternRegex = pattern.replace(/:([^/]+)/g, (_, name) => {
|
|
17
|
+
paramNames.push(name);
|
|
18
|
+
return "([^/]+)";
|
|
19
|
+
});
|
|
20
|
+
const regex = new RegExp(`^${patternRegex}$`);
|
|
21
|
+
const matches = url.match(regex);
|
|
22
|
+
if (!matches)
|
|
23
|
+
return null;
|
|
24
|
+
const params = {};
|
|
25
|
+
paramNames.forEach((name, i) => {
|
|
26
|
+
params[name] = matches[i + 1];
|
|
27
|
+
});
|
|
28
|
+
return Object.keys(params).length > 0 ? params : null;
|
|
29
|
+
}
|
|
30
|
+
function matchesPattern(url, pattern) {
|
|
31
|
+
url = withoutTrailingSlash(withLeadingSlash(url));
|
|
32
|
+
pattern = withoutTrailingSlash(withLeadingSlash(pattern));
|
|
33
|
+
if (url === pattern)
|
|
34
|
+
return true;
|
|
35
|
+
if (pattern.endsWith("/**")) {
|
|
36
|
+
const basePath = pattern.slice(0, -3);
|
|
37
|
+
return url === basePath || url.startsWith(`${basePath}/`);
|
|
38
|
+
}
|
|
39
|
+
const urlParts = url.split("/");
|
|
40
|
+
const patternParts = pattern.split("/");
|
|
41
|
+
if (!pattern.includes("**") && urlParts.length !== patternParts.length) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (pattern.includes("/**/")) {
|
|
45
|
+
const [prefix, ...suffixParts] = pattern.split("/**/");
|
|
46
|
+
const suffix = suffixParts.join("/");
|
|
47
|
+
return url.startsWith(prefix) && (!suffix || url.endsWith(`/${suffix}`));
|
|
48
|
+
}
|
|
49
|
+
return patternToRegex(pattern).test(url);
|
|
50
|
+
}
|
|
51
|
+
function deepClone(obj) {
|
|
52
|
+
if (obj === null || typeof obj !== "object")
|
|
53
|
+
return obj;
|
|
54
|
+
if (typeof obj === "function")
|
|
55
|
+
return obj;
|
|
56
|
+
if (Array.isArray(obj))
|
|
57
|
+
return obj.map(deepClone);
|
|
58
|
+
const cloned = {};
|
|
59
|
+
for (const key in obj) {
|
|
60
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
61
|
+
cloned[key] = deepClone(obj[key]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return cloned;
|
|
65
|
+
}
|
|
66
|
+
function mergeConfigs(...configs) {
|
|
67
|
+
const result = {};
|
|
68
|
+
for (const config of configs) {
|
|
69
|
+
if (!config)
|
|
70
|
+
continue;
|
|
71
|
+
for (const key in config) {
|
|
72
|
+
const value = config[key];
|
|
73
|
+
if (value && typeof value === "object" && !Array.isArray(value) && result[key] && typeof result[key] === "object" && typeof result[key] !== "function") {
|
|
74
|
+
const resultValue = result[key];
|
|
75
|
+
const valueToMerge = value;
|
|
76
|
+
result[key] = mergeConfigs(resultValue, valueToMerge);
|
|
77
|
+
} else {
|
|
78
|
+
result[key] = value;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
function createRouteRules() {
|
|
85
|
+
let _rules = {};
|
|
86
|
+
let _mergedRules = {};
|
|
87
|
+
let _rulesModified = false;
|
|
88
|
+
function getRules() {
|
|
89
|
+
return deepClone(_rules);
|
|
90
|
+
}
|
|
91
|
+
function importRules(config) {
|
|
92
|
+
const normalizedConfig = {};
|
|
93
|
+
for (const pattern in config) {
|
|
94
|
+
normalizedConfig[withoutTrailingSlash(withLeadingSlash(pattern))] = deepClone(config[pattern]);
|
|
95
|
+
}
|
|
96
|
+
_rules = normalizedConfig;
|
|
97
|
+
_rulesModified = true;
|
|
98
|
+
updateMergeRules();
|
|
99
|
+
}
|
|
100
|
+
function exportRules() {
|
|
101
|
+
return deepClone(_rules);
|
|
102
|
+
}
|
|
103
|
+
function addRule(pattern, config) {
|
|
104
|
+
_rules[withoutTrailingSlash(withLeadingSlash(pattern))] = deepClone(config);
|
|
105
|
+
_rulesModified = true;
|
|
106
|
+
updateMergeRules();
|
|
107
|
+
}
|
|
108
|
+
function updateRule(pattern, config) {
|
|
109
|
+
const normalizedPattern = withoutTrailingSlash(withLeadingSlash(pattern));
|
|
110
|
+
if (_rules[normalizedPattern]) {
|
|
111
|
+
_rules[normalizedPattern] = { ..._rules[normalizedPattern], ...deepClone(config) };
|
|
112
|
+
} else {
|
|
113
|
+
_rules[normalizedPattern] = deepClone(config);
|
|
114
|
+
}
|
|
115
|
+
_rulesModified = true;
|
|
116
|
+
updateMergeRules();
|
|
117
|
+
}
|
|
118
|
+
function removeRule(pattern) {
|
|
119
|
+
delete _rules[withoutTrailingSlash(withLeadingSlash(pattern))];
|
|
120
|
+
_rulesModified = true;
|
|
121
|
+
updateMergeRules();
|
|
122
|
+
}
|
|
123
|
+
function matchesRule(url, pattern) {
|
|
124
|
+
return matchesPattern(withoutTrailingSlash(withLeadingSlash(url)), withoutTrailingSlash(withLeadingSlash(pattern)));
|
|
125
|
+
}
|
|
126
|
+
function getMatchingPatterns(url) {
|
|
127
|
+
const normalizedUrl = withoutTrailingSlash(withLeadingSlash(url));
|
|
128
|
+
return Object.keys(_rules).filter((pattern) => matchesPattern(normalizedUrl, pattern)).sort((a, b) => {
|
|
129
|
+
if (a === url)
|
|
130
|
+
return -1;
|
|
131
|
+
if (b === url)
|
|
132
|
+
return 1;
|
|
133
|
+
const aSegments = a.split("/").filter(Boolean).length;
|
|
134
|
+
const bSegments = b.split("/").filter(Boolean).length;
|
|
135
|
+
if (aSegments !== bSegments)
|
|
136
|
+
return bSegments - aSegments;
|
|
137
|
+
const aWildcards = (a.match(/\*/g) || []).length;
|
|
138
|
+
const bWildcards = (b.match(/\*/g) || []).length;
|
|
139
|
+
if (aWildcards !== bWildcards)
|
|
140
|
+
return aWildcards - bWildcards;
|
|
141
|
+
const aDoubleWildcards = (a.match(/\*\*/g) || []).length;
|
|
142
|
+
const bDoubleWildcards = (b.match(/\*\*/g) || []).length;
|
|
143
|
+
if (aDoubleWildcards !== bDoubleWildcards)
|
|
144
|
+
return aDoubleWildcards - bDoubleWildcards;
|
|
145
|
+
return b.length - a.length;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function getConfig(url) {
|
|
149
|
+
const normalizedUrl = withoutTrailingSlash(withLeadingSlash(url));
|
|
150
|
+
if (_rulesModified) {
|
|
151
|
+
updateMergeRules();
|
|
152
|
+
}
|
|
153
|
+
if (_mergedRules[normalizedUrl]) {
|
|
154
|
+
return deepClone(_mergedRules[normalizedUrl]);
|
|
155
|
+
}
|
|
156
|
+
const patterns = getMatchingPatterns(normalizedUrl);
|
|
157
|
+
if (!patterns.length)
|
|
158
|
+
return null;
|
|
159
|
+
const mergedConfig = {};
|
|
160
|
+
for (let i = patterns.length - 1; i >= 0; i--) {
|
|
161
|
+
const pattern = patterns[i];
|
|
162
|
+
const patternConfig = _mergedRules[pattern] || _rules[pattern];
|
|
163
|
+
Object.assign(mergedConfig, deepClone(patternConfig));
|
|
164
|
+
}
|
|
165
|
+
_mergedRules[normalizedUrl] = deepClone(mergedConfig);
|
|
166
|
+
return mergedConfig;
|
|
167
|
+
}
|
|
168
|
+
function computeMergedConfig(url, patterns) {
|
|
169
|
+
const normalizedUrl = withoutTrailingSlash(withLeadingSlash(url));
|
|
170
|
+
const matchingPatterns = patterns || getMatchingPatterns(normalizedUrl);
|
|
171
|
+
if (!matchingPatterns.length)
|
|
172
|
+
return {};
|
|
173
|
+
const allPatternsHaveCache = matchingPatterns.every((pattern) => !!_mergedRules[pattern]);
|
|
174
|
+
if (allPatternsHaveCache) {
|
|
175
|
+
return matchingPatterns.reduceRight((result, pattern) => mergeConfigs(result, deepClone(_mergedRules[pattern])), {});
|
|
176
|
+
}
|
|
177
|
+
return matchingPatterns.reduceRight((result, pattern) => mergeConfigs(result, deepClone(_rules[pattern])), {});
|
|
178
|
+
}
|
|
179
|
+
function getParams(url, pattern) {
|
|
180
|
+
return extractParams(withoutTrailingSlash(withLeadingSlash(url)), withoutTrailingSlash(withLeadingSlash(pattern)));
|
|
181
|
+
}
|
|
182
|
+
function match(url) {
|
|
183
|
+
const normalizedUrl = withoutTrailingSlash(withLeadingSlash(url));
|
|
184
|
+
const patterns = getMatchingPatterns(normalizedUrl);
|
|
185
|
+
if (!patterns.length)
|
|
186
|
+
return null;
|
|
187
|
+
const bestPattern = patterns[0];
|
|
188
|
+
return {
|
|
189
|
+
pattern: bestPattern,
|
|
190
|
+
config: deepClone(_rules[bestPattern]),
|
|
191
|
+
params: getParams(normalizedUrl, bestPattern)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function clear() {
|
|
195
|
+
_rules = {};
|
|
196
|
+
clearMergedRules();
|
|
197
|
+
_rulesModified = false;
|
|
198
|
+
}
|
|
199
|
+
function clearMergedRules() {
|
|
200
|
+
_mergedRules = {};
|
|
201
|
+
_rulesModified = true;
|
|
202
|
+
}
|
|
203
|
+
function precomputeMergedRules(urls) {
|
|
204
|
+
if (_rulesModified) {
|
|
205
|
+
updateMergeRules();
|
|
206
|
+
}
|
|
207
|
+
for (const url of urls) {
|
|
208
|
+
const normalizedUrl = withoutTrailingSlash(withLeadingSlash(url));
|
|
209
|
+
if (!_mergedRules[normalizedUrl]) {
|
|
210
|
+
const patterns = getMatchingPatterns(normalizedUrl);
|
|
211
|
+
if (patterns.length) {
|
|
212
|
+
_mergedRules[normalizedUrl] = computeMergedConfig(normalizedUrl, patterns);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function setMergedRule(url, config) {
|
|
218
|
+
const normalizedUrl = withoutTrailingSlash(withLeadingSlash(url));
|
|
219
|
+
_mergedRules[normalizedUrl] = deepClone(config);
|
|
220
|
+
if (url.includes("*") || url.includes(":")) {
|
|
221
|
+
_rulesModified = false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function getMergedRules() {
|
|
225
|
+
return deepClone(_mergedRules);
|
|
226
|
+
}
|
|
227
|
+
function configure(config) {
|
|
228
|
+
importRules(config);
|
|
229
|
+
}
|
|
230
|
+
function updateMergeRules() {
|
|
231
|
+
if (!_rulesModified) {
|
|
232
|
+
return _mergedRules;
|
|
233
|
+
}
|
|
234
|
+
_mergedRules = {};
|
|
235
|
+
const rulePatterns = Object.keys(_rules);
|
|
236
|
+
for (const pattern of rulePatterns) {
|
|
237
|
+
const patterns = getMatchingPatterns(pattern);
|
|
238
|
+
_mergedRules[pattern] = computeMergedConfig(pattern, patterns);
|
|
239
|
+
}
|
|
240
|
+
for (const pattern of rulePatterns) {
|
|
241
|
+
if (pattern.includes("/:")) {
|
|
242
|
+
const segments = pattern.split("/");
|
|
243
|
+
let partialPath = "";
|
|
244
|
+
for (const segment of segments) {
|
|
245
|
+
if (segment) {
|
|
246
|
+
partialPath += `/${segment}`;
|
|
247
|
+
if (segment.startsWith(":") && partialPath !== pattern) {
|
|
248
|
+
const samplePath = partialPath.replace(/:\w+/g, "sample");
|
|
249
|
+
const patterns = getMatchingPatterns(samplePath);
|
|
250
|
+
_mergedRules[samplePath] = computeMergedConfig(samplePath, patterns);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
_rulesModified = false;
|
|
257
|
+
return _mergedRules;
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
// Public getters that return a cloned version to prevent direct modification
|
|
261
|
+
get rules() {
|
|
262
|
+
return getRules();
|
|
263
|
+
},
|
|
264
|
+
get mergedRules() {
|
|
265
|
+
return getMergedRules();
|
|
266
|
+
},
|
|
267
|
+
// API methods
|
|
268
|
+
importRules,
|
|
269
|
+
exportRules,
|
|
270
|
+
addRule,
|
|
271
|
+
updateRule,
|
|
272
|
+
removeRule,
|
|
273
|
+
matchesRule,
|
|
274
|
+
getMatchingPatterns,
|
|
275
|
+
getConfig,
|
|
276
|
+
getParams,
|
|
277
|
+
match,
|
|
278
|
+
clear,
|
|
279
|
+
clearMergedRules,
|
|
280
|
+
precomputeMergedRules,
|
|
281
|
+
setMergedRule,
|
|
282
|
+
getMergedRules,
|
|
283
|
+
configure,
|
|
284
|
+
updateMergeRules
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export { createRouteRules };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { defu } from 'defu';
|
|
2
|
+
import { ErrorFactory, HttpStatus, SilgiError } from './error.mjs';
|
|
3
|
+
import { useSilgi, normalizeResult } from './unctx.mjs';
|
|
4
|
+
import { parseURI } from './uris/utils.mjs';
|
|
5
|
+
import { useSilgiStorage, generateStorageKey } from './utils/storage.mjs';
|
|
6
|
+
|
|
7
|
+
function silgi(event) {
|
|
8
|
+
return {
|
|
9
|
+
execute: (uriString, input, source, queryParams) => {
|
|
10
|
+
return execute(uriString, input, event, source, queryParams);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function execute(uriString, input, event, source, queryParams) {
|
|
15
|
+
const silgiCtx = useSilgi();
|
|
16
|
+
const config = {
|
|
17
|
+
returnNull: false
|
|
18
|
+
};
|
|
19
|
+
try {
|
|
20
|
+
const operation = parseURI(uriString, silgiCtx.uris);
|
|
21
|
+
if (!operation) {
|
|
22
|
+
throw ErrorFactory.create({ message: "Invalid URI", httpStatus: HttpStatus.BAD_REQUEST });
|
|
23
|
+
}
|
|
24
|
+
let success = false;
|
|
25
|
+
let cached = false;
|
|
26
|
+
let result;
|
|
27
|
+
const handler = silgiCtx.scannedHandlers.get(operation.uri);
|
|
28
|
+
if (!handler) {
|
|
29
|
+
throw ErrorFactory.create({
|
|
30
|
+
message: "execute not found",
|
|
31
|
+
httpStatus: HttpStatus.NOT_FOUND,
|
|
32
|
+
context: {
|
|
33
|
+
uri: uriString
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
await silgiCtx.callHook("execute:before", {
|
|
38
|
+
operation,
|
|
39
|
+
input,
|
|
40
|
+
event,
|
|
41
|
+
modules: handler.modules,
|
|
42
|
+
source,
|
|
43
|
+
config
|
|
44
|
+
});
|
|
45
|
+
if (config.returnNull) {
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
const cacheData = await cacheExecute(input, operation, handler, event);
|
|
49
|
+
if (cacheData?.success) {
|
|
50
|
+
result = cacheData.data;
|
|
51
|
+
success = cacheData.success;
|
|
52
|
+
cached = cacheData.cached;
|
|
53
|
+
} else {
|
|
54
|
+
let parameters = defu(operation.routerParams, operation.query) || {};
|
|
55
|
+
if (queryParams) {
|
|
56
|
+
parameters = defu(queryParams, parameters);
|
|
57
|
+
}
|
|
58
|
+
silgiCtx.shared.silgi = silgi(event);
|
|
59
|
+
result = await handler?.handler(
|
|
60
|
+
defu(input, { parameters }),
|
|
61
|
+
silgiCtx.shared,
|
|
62
|
+
event,
|
|
63
|
+
source
|
|
64
|
+
);
|
|
65
|
+
success = true;
|
|
66
|
+
}
|
|
67
|
+
await silgiCtx.callHook("execute:after", {
|
|
68
|
+
operation,
|
|
69
|
+
input,
|
|
70
|
+
event,
|
|
71
|
+
result,
|
|
72
|
+
success,
|
|
73
|
+
source,
|
|
74
|
+
modules: handler.modules,
|
|
75
|
+
config
|
|
76
|
+
});
|
|
77
|
+
if (!cached) {
|
|
78
|
+
if (success && cacheData?.cachedKey && handler.storage) {
|
|
79
|
+
await useSilgiStorage(handler.storage.base).setItem(cacheData.cachedKey, result, handler.storage.options);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
} catch (err) {
|
|
84
|
+
await silgiCtx.callHook("execute:error", {
|
|
85
|
+
input,
|
|
86
|
+
event,
|
|
87
|
+
source,
|
|
88
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
config
|
|
91
|
+
});
|
|
92
|
+
silgiCtx.captureError(SilgiError.from(err), {
|
|
93
|
+
event,
|
|
94
|
+
tags: ["execute"]
|
|
95
|
+
});
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function cacheExecute(input, operation, handler, event) {
|
|
100
|
+
if (!handler.storage)
|
|
101
|
+
return;
|
|
102
|
+
const cacheKey = handler.storage ? await generateStorageKey({
|
|
103
|
+
operation,
|
|
104
|
+
input,
|
|
105
|
+
keyGenerator: handler.storage.key,
|
|
106
|
+
storageOptions: handler.storage,
|
|
107
|
+
requestId: event?.requestId
|
|
108
|
+
}) : null;
|
|
109
|
+
if (cacheKey) {
|
|
110
|
+
const cachedResult = await useSilgiStorage(handler.storage.base).getItem(cacheKey);
|
|
111
|
+
if (cachedResult !== null) {
|
|
112
|
+
return {
|
|
113
|
+
success: true,
|
|
114
|
+
data: normalizeResult(cachedResult),
|
|
115
|
+
cached: true,
|
|
116
|
+
cachedKey: cacheKey
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
success: false,
|
|
122
|
+
data: null,
|
|
123
|
+
cached: false,
|
|
124
|
+
cachedKey: cacheKey
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { execute, silgi };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import consola from 'consola';
|
|
2
|
+
import { createContext } from 'unctx';
|
|
3
|
+
|
|
4
|
+
const silgiCLICtx = createContext();
|
|
5
|
+
function useSilgiCLI() {
|
|
6
|
+
const instance = silgiCLICtx.tryUse();
|
|
7
|
+
if (!instance) {
|
|
8
|
+
throw new Error("Silgi instance is unavailable!");
|
|
9
|
+
}
|
|
10
|
+
return instance;
|
|
11
|
+
}
|
|
12
|
+
async function silgiCLIIClose() {
|
|
13
|
+
const silgi = silgiCLICtx.tryUse();
|
|
14
|
+
if (!silgi) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
await silgi.close();
|
|
18
|
+
await silgi.callHook("close", silgi);
|
|
19
|
+
consola.withTag("silgi").success("Process terminated");
|
|
20
|
+
}
|
|
21
|
+
function tryUseSilgiCLI() {
|
|
22
|
+
return silgiCLICtx.tryUse();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { silgiCLICtx, silgiCLIIClose, tryUseSilgiCLI, useSilgiCLI };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useSilgi } from './unctx.mjs';
|
|
2
|
+
|
|
3
|
+
function storageMount(silgi) {
|
|
4
|
+
const _silgi = silgi || useSilgi();
|
|
5
|
+
return (base, driver) => {
|
|
6
|
+
const existingStorage = _silgi.storage.getMount(base);
|
|
7
|
+
if (existingStorage) {
|
|
8
|
+
return existingStorage.driver;
|
|
9
|
+
}
|
|
10
|
+
const storage = _silgi.storage.mount(base, driver);
|
|
11
|
+
return storage;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { storageMount };
|