@devbro/pashmak 0.1.55 → 0.1.57
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/cjs/app/console/DefaultCommand.js +52 -0
- package/dist/cjs/app/console/KeyGenerateCommand.js +52 -0
- package/dist/cjs/app/console/StartCommand.js +52 -0
- package/dist/cjs/app/console/generate/GenerateApiDocsCommand.js +52 -0
- package/dist/cjs/app/console/generate/GenerateControllerCommand.js +52 -0
- package/dist/cjs/app/console/generate/index.js +52 -0
- package/dist/cjs/app/console/index.js +320 -70
- package/dist/cjs/app/console/migrate/GenerateMigrateCommand.js +52 -0
- package/dist/cjs/app/console/migrate/MigrateCommand.js +52 -0
- package/dist/cjs/app/console/migrate/MigrateRollbackCommand.js +52 -0
- package/dist/cjs/app/console/migrate/index.js +52 -0
- package/dist/cjs/app/console/project/CreateProjectCommand.js +263 -65
- package/dist/cjs/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
- package/dist/cjs/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
- package/dist/cjs/app/console/project/base_project/src/config/default.mts.tpl +13 -20
- package/dist/cjs/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
- package/dist/cjs/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
- package/dist/cjs/app/console/project/base_project/src/initialize.ts.tpl +48 -16
- package/dist/cjs/app/console/project/base_project/src/routes.ts.tpl +2 -2
- package/dist/cjs/app/console/queue/GenerateQueueMigrateCommand.js +52 -0
- package/dist/cjs/bin/pashmak_cli.js +265 -66
- package/dist/cjs/cache/MultiCache.js +71 -0
- package/dist/cjs/{cache.js → cache/cache.js} +54 -2
- package/dist/cjs/facades.js +52 -0
- package/dist/cjs/factories.js +52 -0
- package/dist/cjs/http.js +52 -0
- package/dist/cjs/index.js +1900 -2056
- package/dist/cjs/middlewares.js +112 -2
- package/dist/cjs/queue.js +52 -0
- package/dist/esm/app/console/project/CreateProjectCommand.d.mts +15 -2
- package/dist/esm/app/console/project/CreateProjectCommand.mjs +265 -67
- package/dist/esm/app/console/project/CreateProjectCommand.mjs.map +1 -1
- package/dist/esm/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
- package/dist/esm/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
- package/dist/esm/app/console/project/base_project/src/config/default.mts.tpl +13 -20
- package/dist/esm/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
- package/dist/esm/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
- package/dist/esm/app/console/project/base_project/src/initialize.ts.tpl +48 -16
- package/dist/esm/app/console/project/base_project/src/routes.ts.tpl +2 -2
- package/dist/esm/bin/pashmak_cli.mjs +2 -1
- package/dist/esm/bin/pashmak_cli.mjs.map +1 -1
- package/dist/esm/cache/MultiCache.d.mts +14 -0
- package/dist/esm/cache/MultiCache.mjs +47 -0
- package/dist/esm/cache/MultiCache.mjs.map +1 -0
- package/dist/esm/{cache.mjs → cache/cache.mjs} +1 -1
- package/dist/esm/cache/cache.mjs.map +1 -0
- package/dist/esm/config.mjs.map +1 -1
- package/dist/esm/factories.mjs +9 -0
- package/dist/esm/factories.mjs.map +1 -1
- package/dist/esm/index.d.mts +1 -7
- package/dist/esm/index.mjs +1 -32
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/middlewares.d.mts +12 -1
- package/dist/esm/middlewares.mjs +52 -0
- package/dist/esm/middlewares.mjs.map +1 -1
- package/package.json +4 -2
- package/dist/cjs/app/console/project/base_project/package.json.tpl +0 -74
- package/dist/cjs/app/console/project/base_project/src/config/test.ts.tpl +0 -1
- package/dist/esm/app/console/project/base_project/package.json.tpl +0 -74
- package/dist/esm/app/console/project/base_project/src/config/test.ts.tpl +0 -1
- package/dist/esm/cache.mjs.map +0 -1
- /package/dist/cjs/app/console/project/base_project/src/config/{mailer.ts.tpl → mailers.ts.tpl} +0 -0
- /package/dist/esm/app/console/project/base_project/src/config/{mailer.ts.tpl → mailers.ts.tpl} +0 -0
- /package/dist/esm/{cache.d.mts → cache/cache.d.mts} +0 -0
package/dist/cjs/index.js
CHANGED
|
@@ -6,9 +6,6 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
-
var __esm = (fn, res) => function __init() {
|
|
10
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
-
};
|
|
12
9
|
var __commonJS = (cb, mod) => function __require() {
|
|
13
10
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
14
11
|
};
|
|
@@ -33,1134 +30,70 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
30
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
31
|
mod
|
|
35
32
|
));
|
|
36
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
-
|
|
38
|
-
// ../neko-router/dist/esm/types.mjs
|
|
39
|
-
var init_types = __esm({
|
|
40
|
-
"../neko-router/dist/esm/types.mjs"() {
|
|
41
|
-
"use strict";
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// ../neko-router/dist/esm/Middleware.mjs
|
|
46
|
-
var Middleware;
|
|
47
|
-
var init_Middleware = __esm({
|
|
48
|
-
"../neko-router/dist/esm/Middleware.mjs"() {
|
|
49
|
-
"use strict";
|
|
50
|
-
Middleware = class {
|
|
51
|
-
static {
|
|
52
|
-
__name(this, "Middleware");
|
|
53
|
-
}
|
|
54
|
-
constructor(params = {}) {
|
|
55
|
-
}
|
|
56
|
-
static getInstance(params) {
|
|
57
|
-
throw new Error("Method not implemented. Please implement a static getInstance method.");
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// ../neko-router/dist/esm/MiddlewareFactory.mjs
|
|
64
|
-
var MiddlewareFactory;
|
|
65
|
-
var init_MiddlewareFactory = __esm({
|
|
66
|
-
"../neko-router/dist/esm/MiddlewareFactory.mjs"() {
|
|
67
|
-
"use strict";
|
|
68
|
-
init_Middleware();
|
|
69
|
-
MiddlewareFactory = class {
|
|
70
|
-
static {
|
|
71
|
-
__name(this, "MiddlewareFactory");
|
|
72
|
-
}
|
|
73
|
-
static create(func) {
|
|
74
|
-
const cls = class extends Middleware {
|
|
75
|
-
static {
|
|
76
|
-
__name(this, "cls");
|
|
77
|
-
}
|
|
78
|
-
call(req, res, next) {
|
|
79
|
-
return func(req, res, next);
|
|
80
|
-
}
|
|
81
|
-
constructor(params = {}) {
|
|
82
|
-
super(params);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
return new cls();
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// ../neko-router/dist/esm/CompiledRoute.mjs
|
|
92
|
-
var import_stream, import_neko_helper, CompiledRoute;
|
|
93
|
-
var init_CompiledRoute = __esm({
|
|
94
|
-
"../neko-router/dist/esm/CompiledRoute.mjs"() {
|
|
95
|
-
"use strict";
|
|
96
|
-
import_stream = require("stream");
|
|
97
|
-
init_Middleware();
|
|
98
|
-
init_MiddlewareFactory();
|
|
99
|
-
import_neko_helper = require("@devbro/neko-helper");
|
|
100
|
-
CompiledRoute = class {
|
|
101
|
-
static {
|
|
102
|
-
__name(this, "CompiledRoute");
|
|
103
|
-
}
|
|
104
|
-
constructor(route, request, response, globalMiddlewares = []) {
|
|
105
|
-
this.route = route;
|
|
106
|
-
this.request = request;
|
|
107
|
-
this.response = response;
|
|
108
|
-
this.globalMiddlewares = globalMiddlewares;
|
|
109
|
-
this.prepareMiddlewares();
|
|
110
|
-
}
|
|
111
|
-
middlewares = [];
|
|
112
|
-
getMiddlewares() {
|
|
113
|
-
return this.middlewares;
|
|
114
|
-
}
|
|
115
|
-
prepareMiddlewares() {
|
|
116
|
-
this.middlewares = [];
|
|
117
|
-
for (const middleware of [...this.globalMiddlewares, ...this.route.getMiddlewares()]) {
|
|
118
|
-
if (middleware instanceof Middleware) {
|
|
119
|
-
this.middlewares.push(middleware);
|
|
120
|
-
} else if ((0, import_neko_helper.isClass)(middleware)) {
|
|
121
|
-
this.middlewares.push(middleware.getInstance({}));
|
|
122
|
-
} else if (typeof middleware === "function") {
|
|
123
|
-
this.middlewares.push(MiddlewareFactory.create(middleware));
|
|
124
|
-
} else {
|
|
125
|
-
throw new Error("Invalid middleware type");
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
async run() {
|
|
130
|
-
return await this.runMiddlewares(this.middlewares, this.request, this.response);
|
|
131
|
-
}
|
|
132
|
-
prepareOutputJsonFormat(obj) {
|
|
133
|
-
function traverse(value) {
|
|
134
|
-
if (value === void 0 || value === null) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
if (!value || typeof value !== "object") {
|
|
138
|
-
return value;
|
|
139
|
-
}
|
|
140
|
-
if (typeof value.toJson === "function") {
|
|
141
|
-
return traverse(value.toJson());
|
|
142
|
-
}
|
|
143
|
-
if (typeof value.toJSON === "function") {
|
|
144
|
-
return traverse(value.toJSON());
|
|
145
|
-
}
|
|
146
|
-
if (Array.isArray(value)) {
|
|
147
|
-
return value.map(traverse);
|
|
148
|
-
}
|
|
149
|
-
const result = {};
|
|
150
|
-
for (const key in value) {
|
|
151
|
-
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
152
|
-
result[key] = traverse(value[key]);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return result;
|
|
156
|
-
}
|
|
157
|
-
__name(traverse, "traverse");
|
|
158
|
-
return traverse(obj);
|
|
159
|
-
}
|
|
160
|
-
convertToString(obj) {
|
|
161
|
-
if (typeof obj === "string") {
|
|
162
|
-
return obj;
|
|
163
|
-
} else if (obj instanceof Buffer) {
|
|
164
|
-
return obj.toString();
|
|
165
|
-
} else if (typeof obj === "object") {
|
|
166
|
-
return JSON.stringify(this.prepareOutputJsonFormat(obj));
|
|
167
|
-
}
|
|
168
|
-
return String(obj);
|
|
169
|
-
}
|
|
170
|
-
async processResponseBody(res, controller_rc) {
|
|
171
|
-
if (controller_rc && res.writableEnded) {
|
|
172
|
-
throw new Error("cannot write to response, response has already ended");
|
|
173
|
-
}
|
|
174
|
-
if (res.writableEnded) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
if (controller_rc) {
|
|
178
|
-
const header_content_type = res.getHeader("Content-Type");
|
|
179
|
-
if (controller_rc instanceof import_stream.Stream || Buffer.isBuffer(controller_rc)) {
|
|
180
|
-
await this.writeAsync(res, controller_rc);
|
|
181
|
-
} else if (!header_content_type && typeof controller_rc === "object") {
|
|
182
|
-
res.setHeader("Content-Type", "application/json");
|
|
183
|
-
res.write(this.convertToString(controller_rc));
|
|
184
|
-
} else if (!header_content_type) {
|
|
185
|
-
res.setHeader("Content-Type", "text/plain");
|
|
186
|
-
res.write(this.convertToString(controller_rc));
|
|
187
|
-
} else {
|
|
188
|
-
res.write(this.convertToString(controller_rc));
|
|
189
|
-
}
|
|
190
|
-
return;
|
|
191
|
-
} else {
|
|
192
|
-
res.statusCode = [200].includes(res.statusCode) ? 204 : res.statusCode;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
async writeAsync(res, chunk) {
|
|
196
|
-
return new Promise((resolve, reject) => {
|
|
197
|
-
const ok = res.write(chunk, (err) => {
|
|
198
|
-
if (err) reject(err);
|
|
199
|
-
});
|
|
200
|
-
if (ok) {
|
|
201
|
-
resolve(0);
|
|
202
|
-
} else {
|
|
203
|
-
res.once("drain", resolve);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
async runMiddlewares(middlewares, req, res) {
|
|
208
|
-
let index = 0;
|
|
209
|
-
const me = this;
|
|
210
|
-
async function next() {
|
|
211
|
-
if (index >= middlewares.length) {
|
|
212
|
-
const controller_rc = await me.route.callHanlder(req, res);
|
|
213
|
-
await me.processResponseBody(res, controller_rc);
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
const middleware = middlewares[index++];
|
|
217
|
-
if (middleware instanceof Middleware) {
|
|
218
|
-
await middleware.call(req, res, next);
|
|
219
|
-
} else if (typeof middleware === "function") {
|
|
220
|
-
await middleware(req, res, next);
|
|
221
|
-
} else {
|
|
222
|
-
throw new Error("does not know how to run middleware");
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
__name(next, "next");
|
|
226
|
-
await next();
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// ../neko-router/dist/esm/Controller.mjs
|
|
233
|
-
var init_Controller = __esm({
|
|
234
|
-
"../neko-router/dist/esm/Controller.mjs"() {
|
|
235
|
-
"use strict";
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
33
|
|
|
239
|
-
// ../
|
|
240
|
-
var
|
|
241
|
-
|
|
242
|
-
"../neko-router/dist/esm/Route.mjs"() {
|
|
34
|
+
// ../node_modules/typanion/lib/index.js
|
|
35
|
+
var require_lib = __commonJS({
|
|
36
|
+
"../node_modules/typanion/lib/index.js"(exports2) {
|
|
243
37
|
"use strict";
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
i = start;
|
|
275
|
-
} else if (char === "*") {
|
|
276
|
-
let start = i + 1;
|
|
277
|
-
while (start < path10.length && /[a-zA-Z0-9_]/.test(path10[start])) {
|
|
278
|
-
start++;
|
|
279
|
-
}
|
|
280
|
-
tokens.push({ type: "WILDCARD", value: path10.slice(i + 1, start) });
|
|
281
|
-
i = start;
|
|
282
|
-
} else {
|
|
283
|
-
let start = i;
|
|
284
|
-
while (start < path10.length && !["/", ":", "*"].includes(path10[start])) {
|
|
285
|
-
start++;
|
|
286
|
-
}
|
|
287
|
-
tokens.push({ type: "TEXT", value: path10.slice(i, start) });
|
|
288
|
-
i = start;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return tokens;
|
|
292
|
-
}
|
|
293
|
-
tokensToRegex(tokens) {
|
|
294
|
-
const regexParts = [];
|
|
295
|
-
for (const token of tokens) {
|
|
296
|
-
if (token.type === "SLASH") {
|
|
297
|
-
regexParts.push("\\/");
|
|
298
|
-
} else if (token.type === "PARAM") {
|
|
299
|
-
regexParts.push(`(?<${token.value}>[^\\/]+)`);
|
|
300
|
-
} else if (token.type === "WILDCARD") {
|
|
301
|
-
regexParts.push("(.+)");
|
|
302
|
-
} else if (token.type === "TEXT") {
|
|
303
|
-
regexParts.push(token.value.replace(/[-\/\\^$.*+?()[\]{}|]/g, "\\$&"));
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (regexParts.length > 0 && regexParts[regexParts.length - 1] === "\\/") {
|
|
307
|
-
regexParts[regexParts.length - 1] = "\\/?";
|
|
308
|
-
} else {
|
|
309
|
-
regexParts.push("\\/?");
|
|
310
|
-
}
|
|
311
|
-
return new RegExp(`^${regexParts.join("")}$`);
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* to evaluadate if request is a match for this route
|
|
315
|
-
* @param request http request
|
|
316
|
-
* @returns return true if route is a match for this request
|
|
317
|
-
*/
|
|
318
|
-
test(request) {
|
|
319
|
-
if (this.methods.indexOf(request.method) === -1) {
|
|
320
|
-
return false;
|
|
321
|
-
}
|
|
322
|
-
const url = new URL(request.url || "/", "http://localhost");
|
|
323
|
-
return this.testPath(url.pathname);
|
|
324
|
-
}
|
|
325
|
-
testPath(pathname) {
|
|
326
|
-
return this.urlRegex.test(pathname);
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* returns details of the match, otherwise it returns false
|
|
330
|
-
* @param request the request to match
|
|
331
|
-
* @returns object cotaining details of match including matched params
|
|
332
|
-
*/
|
|
333
|
-
match(request) {
|
|
334
|
-
if (this.methods.indexOf(request.method) === -1) {
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
const url = new URL(request.url || "/", "http://localhost");
|
|
338
|
-
const r = this.urlRegex.exec(url.pathname);
|
|
339
|
-
if (!r) {
|
|
340
|
-
return false;
|
|
341
|
-
}
|
|
342
|
-
return {
|
|
343
|
-
url,
|
|
344
|
-
params: r.groups || {}
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
prependMiddleware(middlewares) {
|
|
348
|
-
this.middlewares = [].concat(middlewares, this.middlewares);
|
|
349
|
-
return this;
|
|
350
|
-
}
|
|
351
|
-
addMiddleware(middlewares) {
|
|
352
|
-
this.middlewares = this.middlewares.concat(middlewares);
|
|
353
|
-
return this;
|
|
354
|
-
}
|
|
355
|
-
getMiddlewares() {
|
|
356
|
-
return this.middlewares;
|
|
357
|
-
}
|
|
358
|
-
callHanlder(request, response) {
|
|
359
|
-
return this.handler(request, response);
|
|
38
|
+
Object.defineProperty(exports2, "__esModule", {
|
|
39
|
+
value: true
|
|
40
|
+
});
|
|
41
|
+
var simpleKeyRegExp = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
42
|
+
function getPrintable(value) {
|
|
43
|
+
if (value === null) return `null`;
|
|
44
|
+
if (value === void 0) return `undefined`;
|
|
45
|
+
if (value === ``) return `an empty string`;
|
|
46
|
+
if (typeof value === "symbol") return `<${value.toString()}>`;
|
|
47
|
+
if (Array.isArray(value)) return `an array`;
|
|
48
|
+
return JSON.stringify(value);
|
|
49
|
+
}
|
|
50
|
+
__name(getPrintable, "getPrintable");
|
|
51
|
+
function getPrintableArray(value, conjunction) {
|
|
52
|
+
if (value.length === 0) return `nothing`;
|
|
53
|
+
if (value.length === 1) return getPrintable(value[0]);
|
|
54
|
+
const rest = value.slice(0, -1);
|
|
55
|
+
const trailing = value[value.length - 1];
|
|
56
|
+
const separator = value.length > 2 ? `, ${conjunction} ` : ` ${conjunction} `;
|
|
57
|
+
return `${rest.map((value2) => getPrintable(value2)).join(`, `)}${separator}${getPrintable(trailing)}`;
|
|
58
|
+
}
|
|
59
|
+
__name(getPrintableArray, "getPrintableArray");
|
|
60
|
+
function computeKey(state, key) {
|
|
61
|
+
var _a, _b, _c;
|
|
62
|
+
if (typeof key === `number`) {
|
|
63
|
+
return `${(_a = state === null || state === void 0 ? void 0 : state.p) !== null && _a !== void 0 ? _a : `.`}[${key}]`;
|
|
64
|
+
} else if (simpleKeyRegExp.test(key)) {
|
|
65
|
+
return `${(_b = state === null || state === void 0 ? void 0 : state.p) !== null && _b !== void 0 ? _b : ``}.${key}`;
|
|
66
|
+
} else {
|
|
67
|
+
return `${(_c = state === null || state === void 0 ? void 0 : state.p) !== null && _c !== void 0 ? _c : `.`}[${JSON.stringify(key)}]`;
|
|
360
68
|
}
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
// ../node_modules/url-join/lib/url-join.js
|
|
366
|
-
function normalize(strArray) {
|
|
367
|
-
var resultArray = [];
|
|
368
|
-
if (strArray.length === 0) {
|
|
369
|
-
return "";
|
|
370
|
-
}
|
|
371
|
-
if (typeof strArray[0] !== "string") {
|
|
372
|
-
throw new TypeError("Url must be a string. Received " + strArray[0]);
|
|
373
|
-
}
|
|
374
|
-
if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
|
|
375
|
-
var first = strArray.shift();
|
|
376
|
-
strArray[0] = first + strArray[0];
|
|
377
|
-
}
|
|
378
|
-
if (strArray[0].match(/^file:\/\/\//)) {
|
|
379
|
-
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///");
|
|
380
|
-
} else {
|
|
381
|
-
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://");
|
|
382
|
-
}
|
|
383
|
-
for (var i = 0; i < strArray.length; i++) {
|
|
384
|
-
var component = strArray[i];
|
|
385
|
-
if (typeof component !== "string") {
|
|
386
|
-
throw new TypeError("Url must be a string. Received " + component);
|
|
387
69
|
}
|
|
388
|
-
|
|
389
|
-
|
|
70
|
+
__name(computeKey, "computeKey");
|
|
71
|
+
function plural(n, singular, plural2) {
|
|
72
|
+
return n === 1 ? singular : plural2;
|
|
390
73
|
}
|
|
391
|
-
|
|
392
|
-
|
|
74
|
+
__name(plural, "plural");
|
|
75
|
+
var colorStringRegExp = /^#[0-9a-f]{6}$/i;
|
|
76
|
+
var colorStringAlphaRegExp = /^#[0-9a-f]{6}([0-9a-f]{2})?$/i;
|
|
77
|
+
var base64RegExp = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
78
|
+
var uuid4RegExp = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i;
|
|
79
|
+
var iso8601RegExp = /^(?:[1-9]\d{3}(-?)(?:(?:0[1-9]|1[0-2])\1(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])\1(?:29|30)|(?:0[13578]|1[02])(?:\1)31|00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[0-5]))|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\2)29|-?366))T(?:[01]\d|2[0-3])(:?)[0-5]\d(?:\3[0-5]\d)?(?:Z|[+-][01]\d(?:\3[0-5]\d)?)$/;
|
|
80
|
+
function pushError({ errors, p } = {}, message) {
|
|
81
|
+
errors === null || errors === void 0 ? void 0 : errors.push(`${p !== null && p !== void 0 ? p : `.`}: ${message}`);
|
|
82
|
+
return false;
|
|
393
83
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
84
|
+
__name(pushError, "pushError");
|
|
85
|
+
function makeSetter(target, key) {
|
|
86
|
+
return (v) => {
|
|
87
|
+
target[key] = v;
|
|
88
|
+
};
|
|
398
89
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
function urlJoin() {
|
|
408
|
-
var input;
|
|
409
|
-
if (typeof arguments[0] === "object") {
|
|
410
|
-
input = arguments[0];
|
|
411
|
-
} else {
|
|
412
|
-
input = [].slice.call(arguments);
|
|
413
|
-
}
|
|
414
|
-
return normalize(input);
|
|
415
|
-
}
|
|
416
|
-
var init_url_join = __esm({
|
|
417
|
-
"../node_modules/url-join/lib/url-join.js"() {
|
|
418
|
-
"use strict";
|
|
419
|
-
__name(normalize, "normalize");
|
|
420
|
-
__name(urlJoin, "urlJoin");
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
// ../neko-router/dist/esm/Router.mjs
|
|
425
|
-
var import_path, Router;
|
|
426
|
-
var init_Router = __esm({
|
|
427
|
-
"../neko-router/dist/esm/Router.mjs"() {
|
|
428
|
-
"use strict";
|
|
429
|
-
init_CompiledRoute();
|
|
430
|
-
init_Route();
|
|
431
|
-
import_path = __toESM(require("path"), 1);
|
|
432
|
-
init_url_join();
|
|
433
|
-
Router = class {
|
|
434
|
-
static {
|
|
435
|
-
__name(this, "Router");
|
|
436
|
-
}
|
|
437
|
-
middlewares = [];
|
|
438
|
-
routes = [];
|
|
439
|
-
addRoute(methods, path22, handler) {
|
|
440
|
-
const route = new Route(methods, path22, handler);
|
|
441
|
-
this.routes.push(route);
|
|
442
|
-
return route;
|
|
443
|
-
}
|
|
444
|
-
getMiddlewares() {
|
|
445
|
-
return [...this.middlewares];
|
|
446
|
-
}
|
|
447
|
-
addController(controller) {
|
|
448
|
-
const basePath = controller.basePath || "";
|
|
449
|
-
for (const route of controller.routes) {
|
|
450
|
-
const urlPath = import_path.default.join(basePath, route.path);
|
|
451
|
-
this.addRoute(route.methods, urlPath, async (req, res) => {
|
|
452
|
-
const controllerInstance = controller.getInstance();
|
|
453
|
-
return await controllerInstance[route.handler]();
|
|
454
|
-
}).addMiddleware([...controller.baseMiddlewares, ...route.middlewares]);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
addRouter(path22, router2) {
|
|
458
|
-
for (const route of router2.routes) {
|
|
459
|
-
let path222 = urlJoin("/", path22, route.path);
|
|
460
|
-
this.addRoute(route.methods, path222, route.handler).addMiddleware(router2.getMiddlewares()).addMiddleware(route.getMiddlewares());
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
addGlobalMiddleware(middlewares) {
|
|
464
|
-
this.middlewares = this.middlewares.concat(middlewares);
|
|
465
|
-
}
|
|
466
|
-
resolve(request) {
|
|
467
|
-
for (const route of this.routes) {
|
|
468
|
-
if (route.test(request)) {
|
|
469
|
-
return route;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
return void 0;
|
|
473
|
-
}
|
|
474
|
-
resolveMultiple(request) {
|
|
475
|
-
const rc = [];
|
|
476
|
-
const url = new URL(request.url || "/", "http://localhost");
|
|
477
|
-
for (const route of this.routes) {
|
|
478
|
-
if (route.testPath(url.pathname)) {
|
|
479
|
-
rc.push(route);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return rc;
|
|
483
|
-
}
|
|
484
|
-
getCompiledRoute(request, response) {
|
|
485
|
-
const route = this.resolve(request);
|
|
486
|
-
if (!route) {
|
|
487
|
-
return void 0;
|
|
488
|
-
}
|
|
489
|
-
const match = route.match(request);
|
|
490
|
-
if (!match) {
|
|
491
|
-
return void 0;
|
|
492
|
-
}
|
|
493
|
-
request.params = match.params;
|
|
494
|
-
return new CompiledRoute(route, request, response, this.middlewares);
|
|
495
|
-
}
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
// ../neko-router/dist/esm/helpers.mjs
|
|
501
|
-
async function runNext(middlewares, req, res, final) {
|
|
502
|
-
let index = 0;
|
|
503
|
-
async function next() {
|
|
504
|
-
if (index >= middlewares.length) {
|
|
505
|
-
return await final(req, res);
|
|
506
|
-
}
|
|
507
|
-
const middleware = middlewares[index++];
|
|
508
|
-
if (middleware instanceof Middleware) {
|
|
509
|
-
await middleware.call(req, res, next);
|
|
510
|
-
} else if (typeof middleware === "function") {
|
|
511
|
-
await middleware(req, res, next);
|
|
512
|
-
} else {
|
|
513
|
-
throw new Error("does not know how to run middleware");
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
__name(next, "next");
|
|
517
|
-
await next();
|
|
518
|
-
}
|
|
519
|
-
var init_helpers = __esm({
|
|
520
|
-
"../neko-router/dist/esm/helpers.mjs"() {
|
|
521
|
-
"use strict";
|
|
522
|
-
init_Middleware();
|
|
523
|
-
__name(runNext, "runNext");
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
// ../neko-router/dist/esm/index.mjs
|
|
528
|
-
var init_esm = __esm({
|
|
529
|
-
"../neko-router/dist/esm/index.mjs"() {
|
|
530
|
-
"use strict";
|
|
531
|
-
init_types();
|
|
532
|
-
init_CompiledRoute();
|
|
533
|
-
init_Controller();
|
|
534
|
-
init_Route();
|
|
535
|
-
init_Router();
|
|
536
|
-
init_Middleware();
|
|
537
|
-
init_MiddlewareFactory();
|
|
538
|
-
init_helpers();
|
|
539
|
-
}
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
// src/router.mts
|
|
543
|
-
var import_neko_context, import_errors;
|
|
544
|
-
var init_router = __esm({
|
|
545
|
-
"src/router.mts"() {
|
|
546
|
-
"use strict";
|
|
547
|
-
import_neko_context = require("@devbro/neko-context");
|
|
548
|
-
import_errors = require("@devbro/neko-http/errors");
|
|
549
|
-
init_esm();
|
|
550
|
-
init_esm();
|
|
551
|
-
}
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
// src/http.mts
|
|
555
|
-
var http_exports = {};
|
|
556
|
-
__export(http_exports, {
|
|
557
|
-
handleHttpErrors: () => handleHttpErrors
|
|
558
|
-
});
|
|
559
|
-
async function handleHttpErrors(err, req, res) {
|
|
560
|
-
if (err instanceof import_neko_http.HttpError) {
|
|
561
|
-
res.writeHead(err.statusCode, { "Content-Type": "application/json" });
|
|
562
|
-
res.write(JSON.stringify({ message: err.message, error: err.code }));
|
|
563
|
-
logger().warn({ msg: "HttpError: " + err.message, err });
|
|
564
|
-
return;
|
|
565
|
-
} else {
|
|
566
|
-
logger().error({ msg: "Error: " + err.message, err });
|
|
567
|
-
}
|
|
568
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
569
|
-
res.write(JSON.stringify({ error: "Internal Server Error" }));
|
|
570
|
-
}
|
|
571
|
-
var import_neko_http;
|
|
572
|
-
var init_http = __esm({
|
|
573
|
-
"src/http.mts"() {
|
|
574
|
-
"use strict";
|
|
575
|
-
import_neko_http = require("@devbro/neko-http");
|
|
576
|
-
init_facades();
|
|
577
|
-
__reExport(http_exports, require("@devbro/neko-http"));
|
|
578
|
-
__name(handleHttpErrors, "handleHttpErrors");
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
// src/queue.mts
|
|
583
|
-
var queue_exports = {};
|
|
584
|
-
__export(queue_exports, {
|
|
585
|
-
DatabaseTransport: () => DatabaseTransport
|
|
586
|
-
});
|
|
587
|
-
var import_neko_helper2, import_neko_context2, DatabaseTransport;
|
|
588
|
-
var init_queue = __esm({
|
|
589
|
-
"src/queue.mts"() {
|
|
590
|
-
"use strict";
|
|
591
|
-
__reExport(queue_exports, require("@devbro/neko-queue"));
|
|
592
|
-
init_facades();
|
|
593
|
-
import_neko_helper2 = require("@devbro/neko-helper");
|
|
594
|
-
import_neko_context2 = require("@devbro/neko-context");
|
|
595
|
-
DatabaseTransport = class {
|
|
596
|
-
static {
|
|
597
|
-
__name(this, "DatabaseTransport");
|
|
598
|
-
}
|
|
599
|
-
config = {
|
|
600
|
-
queue_table: "queue_messages",
|
|
601
|
-
db_connection: "default",
|
|
602
|
-
listen_interval: 60,
|
|
603
|
-
// seconds
|
|
604
|
-
message_limit: 10,
|
|
605
|
-
// messages per each fetch
|
|
606
|
-
max_retry_count: 5
|
|
607
|
-
// maximum retry count for failed messages
|
|
608
|
-
};
|
|
609
|
-
channels = /* @__PURE__ */ new Map();
|
|
610
|
-
messageQueues = [];
|
|
611
|
-
repeater;
|
|
612
|
-
processMessage = /* @__PURE__ */ __name(async () => {
|
|
613
|
-
await import_neko_context2.context_provider.run(async () => {
|
|
614
|
-
const conn = db(this.config.db_connection);
|
|
615
|
-
try {
|
|
616
|
-
let q = conn.getQuery();
|
|
617
|
-
let messages = await conn.getQuery().table(this.config.queue_table).whereOp("channel", "in", Array.from(this.channels.keys())).whereOp("status", "in", ["pending", "failed"]).whereOp("retried_count", "<", this.config.max_retry_count).limit(this.config.message_limit).orderBy("last_tried_at", "asc").get();
|
|
618
|
-
for (let msg of messages) {
|
|
619
|
-
try {
|
|
620
|
-
await conn.getQuery().table(this.config.queue_table).whereOp("id", "=", msg.id).update({
|
|
621
|
-
status: "processing",
|
|
622
|
-
updated_at: /* @__PURE__ */ new Date(),
|
|
623
|
-
last_tried_at: /* @__PURE__ */ new Date(),
|
|
624
|
-
retried_count: (msg.retried_count || 0) + 1
|
|
625
|
-
});
|
|
626
|
-
let callback = this.channels.get(msg.channel);
|
|
627
|
-
await callback(msg.message);
|
|
628
|
-
await conn.getQuery().table(this.config.queue_table).whereOp("id", "=", msg.id).update({
|
|
629
|
-
status: "processed",
|
|
630
|
-
updated_at: /* @__PURE__ */ new Date()
|
|
631
|
-
});
|
|
632
|
-
} catch (error) {
|
|
633
|
-
logger().error("Error processing message:", {
|
|
634
|
-
error,
|
|
635
|
-
message_id: msg.id,
|
|
636
|
-
channel: msg.channel
|
|
637
|
-
});
|
|
638
|
-
await q.table(this.config.queue_table).whereOp("id", "=", msg.id).update({
|
|
639
|
-
status: "failed",
|
|
640
|
-
updated_at: /* @__PURE__ */ new Date(),
|
|
641
|
-
process_message: error.message || "Error processing message"
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
} catch (error) {
|
|
646
|
-
logger().error("Error in DatabaseTransport listen interval:", {
|
|
647
|
-
error
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
});
|
|
651
|
-
}, "processMessage");
|
|
652
|
-
constructor(config11 = {}) {
|
|
653
|
-
this.config = { ...this.config, ...config11 };
|
|
654
|
-
this.repeater = (0, import_neko_helper2.createRepeater)(
|
|
655
|
-
this.processMessage,
|
|
656
|
-
this.config.listen_interval * 1e3
|
|
657
|
-
);
|
|
658
|
-
}
|
|
659
|
-
async dispatch(channel, message) {
|
|
660
|
-
const conn = db(this.config.db_connection);
|
|
661
|
-
let schema = conn.getSchema();
|
|
662
|
-
if (await schema.tableExists(this.config.queue_table) === false) {
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
let q = conn.getQuery();
|
|
666
|
-
await q.table(this.config.queue_table).insert({
|
|
667
|
-
channel,
|
|
668
|
-
message,
|
|
669
|
-
created_at: /* @__PURE__ */ new Date(),
|
|
670
|
-
updated_at: /* @__PURE__ */ new Date(),
|
|
671
|
-
last_tried_at: null,
|
|
672
|
-
process_message: "",
|
|
673
|
-
retried_count: 0,
|
|
674
|
-
status: "pending"
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
async registerListener(channel, callback) {
|
|
678
|
-
this.channels.set(channel, callback);
|
|
679
|
-
}
|
|
680
|
-
async startListening() {
|
|
681
|
-
this.repeater.start();
|
|
682
|
-
}
|
|
683
|
-
async stopListening() {
|
|
684
|
-
this.repeater.stop();
|
|
685
|
-
}
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
// src/factories.mts
|
|
691
|
-
var import_neko_mailer, import_neko_queue, import_neko_cache, import_neko_storage, FlexibleFactory, CacheProviderFactory;
|
|
692
|
-
var init_factories = __esm({
|
|
693
|
-
"src/factories.mts"() {
|
|
694
|
-
"use strict";
|
|
695
|
-
import_neko_mailer = require("@devbro/neko-mailer");
|
|
696
|
-
import_neko_queue = require("@devbro/neko-queue");
|
|
697
|
-
init_queue();
|
|
698
|
-
import_neko_cache = require("@devbro/neko-cache");
|
|
699
|
-
import_neko_storage = require("@devbro/neko-storage");
|
|
700
|
-
FlexibleFactory = class {
|
|
701
|
-
static {
|
|
702
|
-
__name(this, "FlexibleFactory");
|
|
703
|
-
}
|
|
704
|
-
registry = /* @__PURE__ */ new Map();
|
|
705
|
-
register(key, ctor) {
|
|
706
|
-
this.registry.set(key, ctor);
|
|
707
|
-
}
|
|
708
|
-
create(key, ...args) {
|
|
709
|
-
const ctor = this.registry.get(key);
|
|
710
|
-
if (!ctor) {
|
|
711
|
-
throw new Error(`No factory registered for key: ${key}`);
|
|
712
|
-
}
|
|
713
|
-
return ctor(...args);
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
import_neko_mailer.MailerProviderFactory.register("ses", (opt) => {
|
|
717
|
-
return new import_neko_mailer.SESProvider(opt);
|
|
718
|
-
});
|
|
719
|
-
import_neko_mailer.MailerProviderFactory.register("smtp", (opt) => {
|
|
720
|
-
return new import_neko_mailer.SMTPProvider(opt);
|
|
721
|
-
});
|
|
722
|
-
import_neko_mailer.MailerProviderFactory.register("memory", (opt) => {
|
|
723
|
-
return new import_neko_mailer.MemoryProvider();
|
|
724
|
-
});
|
|
725
|
-
import_neko_queue.QueueTransportFactory.register("database", (opt) => {
|
|
726
|
-
return new DatabaseTransport(opt);
|
|
727
|
-
});
|
|
728
|
-
import_neko_queue.QueueTransportFactory.register("memory", (opt) => {
|
|
729
|
-
return new import_neko_queue.MemoryTransport(opt);
|
|
730
|
-
});
|
|
731
|
-
import_neko_queue.QueueTransportFactory.register("sqs", (opt) => {
|
|
732
|
-
return new import_neko_queue.AwsSqsTransport(opt);
|
|
733
|
-
});
|
|
734
|
-
import_neko_queue.QueueTransportFactory.register("amqp", (opt) => {
|
|
735
|
-
return new import_neko_queue.AmqpTransport(opt);
|
|
736
|
-
});
|
|
737
|
-
import_neko_queue.QueueTransportFactory.register("redis", (opt) => {
|
|
738
|
-
return new import_neko_queue.RedisTransport(opt);
|
|
739
|
-
});
|
|
740
|
-
import_neko_queue.QueueTransportFactory.register("async", (opt) => {
|
|
741
|
-
return new import_neko_queue.AsyncTransport();
|
|
742
|
-
});
|
|
743
|
-
import_neko_queue.QueueTransportFactory.register("azure_service_bus", (opt) => {
|
|
744
|
-
return new import_neko_queue.AzureServiceBusTransport(opt);
|
|
745
|
-
});
|
|
746
|
-
import_neko_queue.QueueTransportFactory.register("google_pubsub", (opt) => {
|
|
747
|
-
return new import_neko_queue.GooglePubSubTransport(opt);
|
|
748
|
-
});
|
|
749
|
-
CacheProviderFactory = class _CacheProviderFactory {
|
|
750
|
-
static {
|
|
751
|
-
__name(this, "CacheProviderFactory");
|
|
752
|
-
}
|
|
753
|
-
static instance = new FlexibleFactory();
|
|
754
|
-
static register(key, factory) {
|
|
755
|
-
_CacheProviderFactory.instance.register(key, factory);
|
|
756
|
-
}
|
|
757
|
-
static create(key, ...args) {
|
|
758
|
-
return _CacheProviderFactory.instance.create(key, ...args);
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
CacheProviderFactory.register("memory", (opt) => {
|
|
762
|
-
return new import_neko_cache.MemoryCacheProvider(opt);
|
|
763
|
-
});
|
|
764
|
-
CacheProviderFactory.register("redis", (opt) => {
|
|
765
|
-
return new import_neko_cache.RedisCacheProvider(opt);
|
|
766
|
-
});
|
|
767
|
-
CacheProviderFactory.register("file", (opt) => {
|
|
768
|
-
return new import_neko_cache.FileCacheProvider(opt);
|
|
769
|
-
});
|
|
770
|
-
CacheProviderFactory.register("disabled", (opt) => {
|
|
771
|
-
return new import_neko_cache.DisabledCacheProvider();
|
|
772
|
-
});
|
|
773
|
-
import_neko_storage.StorageProviderFactory.register("local", (opt) => {
|
|
774
|
-
return new import_neko_storage.LocalStorageProvider(opt);
|
|
775
|
-
});
|
|
776
|
-
import_neko_storage.StorageProviderFactory.register("s3", (opt) => {
|
|
777
|
-
return new import_neko_storage.AWSS3StorageProvider(opt);
|
|
778
|
-
});
|
|
779
|
-
import_neko_storage.StorageProviderFactory.register("gcp", (opt) => {
|
|
780
|
-
return new import_neko_storage.GCPStorageProvider(opt);
|
|
781
|
-
});
|
|
782
|
-
import_neko_storage.StorageProviderFactory.register("azure", (opt) => {
|
|
783
|
-
return new import_neko_storage.AzureBlobStorageProvider(opt);
|
|
784
|
-
});
|
|
785
|
-
import_neko_storage.StorageProviderFactory.register("ftp", (opt) => {
|
|
786
|
-
return new import_neko_storage.FTPStorageProvider(opt);
|
|
787
|
-
});
|
|
788
|
-
import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
|
|
789
|
-
return new import_neko_storage.SFTPStorageProvider(opt);
|
|
790
|
-
});
|
|
791
|
-
}
|
|
792
|
-
});
|
|
793
|
-
|
|
794
|
-
// src/facades.mts
|
|
795
|
-
function wrapSingletonWithAccessors(singletonFn) {
|
|
796
|
-
let methodsInitialized = false;
|
|
797
|
-
const initializeMethods = /* @__PURE__ */ __name(() => {
|
|
798
|
-
if (methodsInitialized) return;
|
|
799
|
-
const defaultInstance = singletonFn();
|
|
800
|
-
const prototype = Object.getPrototypeOf(defaultInstance);
|
|
801
|
-
const methodNames = Object.getOwnPropertyNames(prototype).filter(
|
|
802
|
-
(name) => name !== "constructor" && typeof prototype[name] === "function"
|
|
803
|
-
);
|
|
804
|
-
for (const methodName of methodNames) {
|
|
805
|
-
singletonFn[methodName] = (...args) => {
|
|
806
|
-
const instance = singletonFn();
|
|
807
|
-
return instance[methodName](...args);
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
methodsInitialized = true;
|
|
811
|
-
}, "initializeMethods");
|
|
812
|
-
return new Proxy(singletonFn, {
|
|
813
|
-
get(target, prop, receiver) {
|
|
814
|
-
if (typeof prop === "string" && !Reflect.has(target, prop)) {
|
|
815
|
-
initializeMethods();
|
|
816
|
-
}
|
|
817
|
-
return Reflect.get(target, prop, receiver);
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
var import_neko_scheduler, import_neko_helper3, import_neko_context3, import_neko_storage2, import_neko_mailer2, import_neko_config, import_clipanion, import_neko_logger, import_neko_cache2, import_neko_queue2, router, scheduler, db, storage, cli, httpServer, logger, mailer, queue, cache;
|
|
822
|
-
var init_facades = __esm({
|
|
823
|
-
"src/facades.mts"() {
|
|
824
|
-
"use strict";
|
|
825
|
-
init_router();
|
|
826
|
-
import_neko_scheduler = require("@devbro/neko-scheduler");
|
|
827
|
-
import_neko_helper3 = require("@devbro/neko-helper");
|
|
828
|
-
import_neko_context3 = require("@devbro/neko-context");
|
|
829
|
-
import_neko_storage2 = require("@devbro/neko-storage");
|
|
830
|
-
import_neko_mailer2 = require("@devbro/neko-mailer");
|
|
831
|
-
import_neko_config = require("@devbro/neko-config");
|
|
832
|
-
import_clipanion = require("clipanion");
|
|
833
|
-
init_http();
|
|
834
|
-
import_neko_logger = require("@devbro/neko-logger");
|
|
835
|
-
init_factories();
|
|
836
|
-
import_neko_cache2 = require("@devbro/neko-cache");
|
|
837
|
-
import_neko_queue2 = require("@devbro/neko-queue");
|
|
838
|
-
__name(wrapSingletonWithAccessors, "wrapSingletonWithAccessors");
|
|
839
|
-
router = (0, import_neko_helper3.createSingleton)(() => new Router());
|
|
840
|
-
scheduler = wrapSingletonWithAccessors(
|
|
841
|
-
(0, import_neko_helper3.createSingleton)(() => {
|
|
842
|
-
const rc = new import_neko_scheduler.Scheduler();
|
|
843
|
-
rc.setErrorHandler((err, job) => {
|
|
844
|
-
logger().error({
|
|
845
|
-
msg: "Scheduled job error",
|
|
846
|
-
err,
|
|
847
|
-
job_name: job.getName()
|
|
848
|
-
});
|
|
849
|
-
});
|
|
850
|
-
return rc;
|
|
851
|
-
})
|
|
852
|
-
);
|
|
853
|
-
db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
|
|
854
|
-
storage = wrapSingletonWithAccessors(
|
|
855
|
-
(0, import_neko_helper3.createSingleton)((label = "default") => {
|
|
856
|
-
let storage_config = import_neko_config.config.get(["storages", label].join("."));
|
|
857
|
-
const provider = import_neko_storage2.StorageProviderFactory.create(
|
|
858
|
-
storage_config.provider,
|
|
859
|
-
storage_config.config
|
|
860
|
-
);
|
|
861
|
-
return new import_neko_storage2.Storage(provider);
|
|
862
|
-
})
|
|
863
|
-
);
|
|
864
|
-
cli = (0, import_neko_helper3.createSingleton)(() => {
|
|
865
|
-
const [node, app, ...args] = process.argv;
|
|
866
|
-
return new import_clipanion.Cli({
|
|
867
|
-
binaryLabel: `My Application`,
|
|
868
|
-
binaryName: `${node} ${app}`,
|
|
869
|
-
binaryVersion: `1.0.0`
|
|
870
|
-
});
|
|
871
|
-
});
|
|
872
|
-
httpServer = (0, import_neko_helper3.createSingleton)(() => {
|
|
873
|
-
const server = new http_exports.HttpServer();
|
|
874
|
-
server.setErrorHandler(handleHttpErrors);
|
|
875
|
-
server.setRouter(router());
|
|
876
|
-
return server;
|
|
877
|
-
});
|
|
878
|
-
logger = wrapSingletonWithAccessors(
|
|
879
|
-
(0, import_neko_helper3.createSingleton)((label) => {
|
|
880
|
-
const logger_config = import_neko_config.config.get(["loggers", label].join("."));
|
|
881
|
-
const rc = new import_neko_logger.Logger(logger_config);
|
|
882
|
-
rc.setExtrasFunction((message) => {
|
|
883
|
-
message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
|
|
884
|
-
return message;
|
|
885
|
-
});
|
|
886
|
-
return rc;
|
|
887
|
-
})
|
|
888
|
-
);
|
|
889
|
-
mailer = wrapSingletonWithAccessors(
|
|
890
|
-
(0, import_neko_helper3.createSingleton)((label) => {
|
|
891
|
-
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
892
|
-
const provider = import_neko_mailer2.MailerProviderFactory.create(
|
|
893
|
-
mailer_config.provider,
|
|
894
|
-
mailer_config.config
|
|
895
|
-
);
|
|
896
|
-
const rc = new import_neko_mailer2.Mailer(provider);
|
|
897
|
-
return rc;
|
|
898
|
-
})
|
|
899
|
-
);
|
|
900
|
-
queue = wrapSingletonWithAccessors(
|
|
901
|
-
(0, import_neko_helper3.createSingleton)((label) => {
|
|
902
|
-
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
903
|
-
if (!queue_config) {
|
|
904
|
-
throw new Error(`Queue configuration for '${label}' not found`);
|
|
905
|
-
}
|
|
906
|
-
const provider = import_neko_queue2.QueueTransportFactory.create(
|
|
907
|
-
queue_config.provider,
|
|
908
|
-
queue_config.config
|
|
909
|
-
);
|
|
910
|
-
return new import_neko_queue2.QueueConnection(provider);
|
|
911
|
-
})
|
|
912
|
-
);
|
|
913
|
-
cache = wrapSingletonWithAccessors(
|
|
914
|
-
(0, import_neko_helper3.createSingleton)((label) => {
|
|
915
|
-
const cache_config = import_neko_config.config.get(["caches", label].join("."));
|
|
916
|
-
if (!cache_config) {
|
|
917
|
-
throw new Error(`Cache configuration for '${label}' not found`);
|
|
918
|
-
}
|
|
919
|
-
const provider = CacheProviderFactory.create(
|
|
920
|
-
cache_config.provider,
|
|
921
|
-
cache_config.config
|
|
922
|
-
);
|
|
923
|
-
return new import_neko_cache2.Cache(provider);
|
|
924
|
-
})
|
|
925
|
-
);
|
|
926
|
-
}
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
// src/app/console/migrate/MigrateCommand.mts
|
|
930
|
-
var import_clipanion2, import_neko_context4, import_path2, import_promises, import_neko_config2, MigrateCommand;
|
|
931
|
-
var init_MigrateCommand = __esm({
|
|
932
|
-
"src/app/console/migrate/MigrateCommand.mts"() {
|
|
933
|
-
"use strict";
|
|
934
|
-
init_facades();
|
|
935
|
-
import_clipanion2 = require("clipanion");
|
|
936
|
-
import_neko_context4 = require("@devbro/neko-context");
|
|
937
|
-
import_path2 = __toESM(require("path"), 1);
|
|
938
|
-
import_promises = __toESM(require("fs/promises"), 1);
|
|
939
|
-
import_neko_config2 = require("@devbro/neko-config");
|
|
940
|
-
MigrateCommand = class extends import_clipanion2.Command {
|
|
941
|
-
static {
|
|
942
|
-
__name(this, "MigrateCommand");
|
|
943
|
-
}
|
|
944
|
-
static paths = [[`migrate`]];
|
|
945
|
-
fresh = import_clipanion2.Option.Boolean(`--fresh`, false, {
|
|
946
|
-
description: `whether to delete and recreate database`
|
|
947
|
-
});
|
|
948
|
-
refresh = import_clipanion2.Option.Boolean(`--refresh`, false, {
|
|
949
|
-
description: `whether to drop all tables before running migrations by using rollback function`
|
|
950
|
-
});
|
|
951
|
-
async execute() {
|
|
952
|
-
await import_neko_context4.context_provider.run(async () => {
|
|
953
|
-
const db2 = db();
|
|
954
|
-
const schema = db2.getSchema();
|
|
955
|
-
if (this.fresh) {
|
|
956
|
-
await db2.dropDatabase(import_neko_config2.config.get("databases.default.database"));
|
|
957
|
-
await db2.createDatabase(import_neko_config2.config.get("databases.default.database"));
|
|
958
|
-
logger().info("database dropped and created fresh!");
|
|
959
|
-
}
|
|
960
|
-
if (this.refresh && await schema.tableExists("migrations")) {
|
|
961
|
-
logger().info("reverting all migrations!!");
|
|
962
|
-
const existing_migrations = await db2.runQuery({
|
|
963
|
-
sql: "select * from migrations order by created_at DESC",
|
|
964
|
-
parts: [],
|
|
965
|
-
bindings: []
|
|
966
|
-
});
|
|
967
|
-
const migrationsDir2 = import_neko_config2.config.get("migration.path");
|
|
968
|
-
for (const migration_record of existing_migrations) {
|
|
969
|
-
logger().info(`rolling back ${migration_record.filename}`);
|
|
970
|
-
try {
|
|
971
|
-
const MigrationClass = (await import(import_path2.default.join(migrationsDir2, migration_record.filename))).default;
|
|
972
|
-
const migrationInstance = new MigrationClass();
|
|
973
|
-
await migrationInstance.down(db2.getSchema());
|
|
974
|
-
await db2.runQuery({
|
|
975
|
-
sql: "delete from migrations where filename = $1",
|
|
976
|
-
parts: [],
|
|
977
|
-
bindings: [migration_record.filename]
|
|
978
|
-
});
|
|
979
|
-
} catch (error) {
|
|
980
|
-
logger().error(
|
|
981
|
-
`Failed to rollback migration ${migration_record.filename}: ${error}`
|
|
982
|
-
);
|
|
983
|
-
throw error;
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
logger().info(
|
|
987
|
-
`rolled back ${existing_migrations.length} migrations successfully!`
|
|
988
|
-
);
|
|
989
|
-
}
|
|
990
|
-
if (!await schema.tableExists("migrations")) {
|
|
991
|
-
await schema.createTable("migrations", (blueprint) => {
|
|
992
|
-
blueprint.id();
|
|
993
|
-
blueprint.timestamps();
|
|
994
|
-
blueprint.string("filename");
|
|
995
|
-
blueprint.integer("batch");
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
|
-
const migrationsDir = import_neko_config2.config.get("migration.path");
|
|
999
|
-
let files = [];
|
|
1000
|
-
const dirEntries = await import_promises.default.readdir(migrationsDir);
|
|
1001
|
-
files = dirEntries.filter((entry) => entry.endsWith(".ts") || entry.endsWith(".js")).sort();
|
|
1002
|
-
let batch_number = await db2.runQuery({
|
|
1003
|
-
sql: "select max(batch) as next_batch from migrations",
|
|
1004
|
-
parts: [],
|
|
1005
|
-
bindings: []
|
|
1006
|
-
});
|
|
1007
|
-
batch_number = batch_number[0].next_batch || 0;
|
|
1008
|
-
batch_number++;
|
|
1009
|
-
const migrations = await db2.runQuery({
|
|
1010
|
-
sql: "select * from migrations order by created_at ASC",
|
|
1011
|
-
parts: [],
|
|
1012
|
-
bindings: []
|
|
1013
|
-
});
|
|
1014
|
-
const completed_migrations = migrations.map((r) => r.filename);
|
|
1015
|
-
const pending_migrations = files.filter(
|
|
1016
|
-
(file) => !completed_migrations.includes(file)
|
|
1017
|
-
);
|
|
1018
|
-
let migrated_count = 0;
|
|
1019
|
-
for (const class_to_migrate of pending_migrations) {
|
|
1020
|
-
logger().info(`migrating up ${class_to_migrate}`);
|
|
1021
|
-
const ClassToMigrate = (await import(import_path2.default.join(migrationsDir, class_to_migrate))).default;
|
|
1022
|
-
const c = new ClassToMigrate();
|
|
1023
|
-
await c.up(db2.getSchema());
|
|
1024
|
-
await db2.runQuery({
|
|
1025
|
-
sql: "insert into migrations (filename, batch) values ($1,$2)",
|
|
1026
|
-
parts: [],
|
|
1027
|
-
bindings: [class_to_migrate, batch_number]
|
|
1028
|
-
});
|
|
1029
|
-
migrated_count++;
|
|
1030
|
-
}
|
|
1031
|
-
if (migrated_count === 0) {
|
|
1032
|
-
logger().warn("no migrations to run!");
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
logger().info(`migrated ${migrated_count} migrations successfully!`);
|
|
1036
|
-
return;
|
|
1037
|
-
});
|
|
1038
|
-
}
|
|
1039
|
-
};
|
|
1040
|
-
cli().register(MigrateCommand);
|
|
1041
|
-
}
|
|
1042
|
-
});
|
|
1043
|
-
|
|
1044
|
-
// src/app/console/migrate/GenerateMigrateCommand.mts
|
|
1045
|
-
var import_clipanion3, import_change_case_all, import_path3, fs2, import_neko_config3, import_handlebars, import_url, import_meta, GenerateMigrateCommand;
|
|
1046
|
-
var init_GenerateMigrateCommand = __esm({
|
|
1047
|
-
"src/app/console/migrate/GenerateMigrateCommand.mts"() {
|
|
1048
|
-
"use strict";
|
|
1049
|
-
init_facades();
|
|
1050
|
-
import_clipanion3 = require("clipanion");
|
|
1051
|
-
import_change_case_all = require("change-case-all");
|
|
1052
|
-
import_path3 = __toESM(require("path"), 1);
|
|
1053
|
-
fs2 = __toESM(require("fs/promises"), 1);
|
|
1054
|
-
import_neko_config3 = require("@devbro/neko-config");
|
|
1055
|
-
import_handlebars = __toESM(require("handlebars"), 1);
|
|
1056
|
-
import_url = require("url");
|
|
1057
|
-
import_meta = {};
|
|
1058
|
-
GenerateMigrateCommand = class extends import_clipanion3.Command {
|
|
1059
|
-
static {
|
|
1060
|
-
__name(this, "GenerateMigrateCommand");
|
|
1061
|
-
}
|
|
1062
|
-
static paths = [
|
|
1063
|
-
[`generate`, `migrate`],
|
|
1064
|
-
["generate", "migration"]
|
|
1065
|
-
];
|
|
1066
|
-
name = import_clipanion3.Option.String({ required: true });
|
|
1067
|
-
async execute() {
|
|
1068
|
-
const date = /* @__PURE__ */ new Date();
|
|
1069
|
-
const year = date.getFullYear();
|
|
1070
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
1071
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
1072
|
-
const secondsOfDay = String(
|
|
1073
|
-
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
1074
|
-
).padStart(5, "0");
|
|
1075
|
-
const fixed_name = import_change_case_all.Case.snake(this.name);
|
|
1076
|
-
const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;
|
|
1077
|
-
this.context.stdout.write(`creating migration file ${filename}
|
|
1078
|
-
`);
|
|
1079
|
-
await fs2.mkdir(import_neko_config3.config.get("migration.path"), { recursive: true });
|
|
1080
|
-
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
1081
|
-
if (!dirname) {
|
|
1082
|
-
dirname = import_path3.default.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
1083
|
-
}
|
|
1084
|
-
const compiledTemplate = import_handlebars.default.compile(
|
|
1085
|
-
(await fs2.readFile(import_path3.default.join(dirname, "./make_migration.tpl"))).toString()
|
|
1086
|
-
);
|
|
1087
|
-
const template = await compiledTemplate({
|
|
1088
|
-
className: import_change_case_all.Case.pascal(this.name) + "Migration",
|
|
1089
|
-
tableName: import_change_case_all.Case.snake(this.name)
|
|
1090
|
-
});
|
|
1091
|
-
await fs2.writeFile(
|
|
1092
|
-
import_path3.default.join(import_neko_config3.config.get("migration.path"), filename),
|
|
1093
|
-
template
|
|
1094
|
-
);
|
|
1095
|
-
}
|
|
1096
|
-
};
|
|
1097
|
-
cli().register(GenerateMigrateCommand);
|
|
1098
|
-
}
|
|
1099
|
-
});
|
|
1100
|
-
|
|
1101
|
-
// ../node_modules/typanion/lib/index.js
|
|
1102
|
-
var require_lib = __commonJS({
|
|
1103
|
-
"../node_modules/typanion/lib/index.js"(exports2) {
|
|
1104
|
-
"use strict";
|
|
1105
|
-
Object.defineProperty(exports2, "__esModule", {
|
|
1106
|
-
value: true
|
|
1107
|
-
});
|
|
1108
|
-
var simpleKeyRegExp = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
1109
|
-
function getPrintable(value) {
|
|
1110
|
-
if (value === null) return `null`;
|
|
1111
|
-
if (value === void 0) return `undefined`;
|
|
1112
|
-
if (value === ``) return `an empty string`;
|
|
1113
|
-
if (typeof value === "symbol") return `<${value.toString()}>`;
|
|
1114
|
-
if (Array.isArray(value)) return `an array`;
|
|
1115
|
-
return JSON.stringify(value);
|
|
1116
|
-
}
|
|
1117
|
-
__name(getPrintable, "getPrintable");
|
|
1118
|
-
function getPrintableArray(value, conjunction) {
|
|
1119
|
-
if (value.length === 0) return `nothing`;
|
|
1120
|
-
if (value.length === 1) return getPrintable(value[0]);
|
|
1121
|
-
const rest = value.slice(0, -1);
|
|
1122
|
-
const trailing = value[value.length - 1];
|
|
1123
|
-
const separator = value.length > 2 ? `, ${conjunction} ` : ` ${conjunction} `;
|
|
1124
|
-
return `${rest.map((value2) => getPrintable(value2)).join(`, `)}${separator}${getPrintable(trailing)}`;
|
|
1125
|
-
}
|
|
1126
|
-
__name(getPrintableArray, "getPrintableArray");
|
|
1127
|
-
function computeKey(state, key) {
|
|
1128
|
-
var _a, _b, _c;
|
|
1129
|
-
if (typeof key === `number`) {
|
|
1130
|
-
return `${(_a = state === null || state === void 0 ? void 0 : state.p) !== null && _a !== void 0 ? _a : `.`}[${key}]`;
|
|
1131
|
-
} else if (simpleKeyRegExp.test(key)) {
|
|
1132
|
-
return `${(_b = state === null || state === void 0 ? void 0 : state.p) !== null && _b !== void 0 ? _b : ``}.${key}`;
|
|
1133
|
-
} else {
|
|
1134
|
-
return `${(_c = state === null || state === void 0 ? void 0 : state.p) !== null && _c !== void 0 ? _c : `.`}[${JSON.stringify(key)}]`;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
__name(computeKey, "computeKey");
|
|
1138
|
-
function plural(n, singular, plural2) {
|
|
1139
|
-
return n === 1 ? singular : plural2;
|
|
1140
|
-
}
|
|
1141
|
-
__name(plural, "plural");
|
|
1142
|
-
var colorStringRegExp = /^#[0-9a-f]{6}$/i;
|
|
1143
|
-
var colorStringAlphaRegExp = /^#[0-9a-f]{6}([0-9a-f]{2})?$/i;
|
|
1144
|
-
var base64RegExp = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
1145
|
-
var uuid4RegExp = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i;
|
|
1146
|
-
var iso8601RegExp = /^(?:[1-9]\d{3}(-?)(?:(?:0[1-9]|1[0-2])\1(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])\1(?:29|30)|(?:0[13578]|1[02])(?:\1)31|00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[0-5]))|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\2)29|-?366))T(?:[01]\d|2[0-3])(:?)[0-5]\d(?:\3[0-5]\d)?(?:Z|[+-][01]\d(?:\3[0-5]\d)?)$/;
|
|
1147
|
-
function pushError({ errors, p } = {}, message) {
|
|
1148
|
-
errors === null || errors === void 0 ? void 0 : errors.push(`${p !== null && p !== void 0 ? p : `.`}: ${message}`);
|
|
1149
|
-
return false;
|
|
1150
|
-
}
|
|
1151
|
-
__name(pushError, "pushError");
|
|
1152
|
-
function makeSetter(target, key) {
|
|
1153
|
-
return (v) => {
|
|
1154
|
-
target[key] = v;
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
__name(makeSetter, "makeSetter");
|
|
1158
|
-
function makeCoercionFn(target, key) {
|
|
1159
|
-
return (v) => {
|
|
1160
|
-
const previous = target[key];
|
|
1161
|
-
target[key] = v;
|
|
1162
|
-
return makeCoercionFn(target, key).bind(null, previous);
|
|
1163
|
-
};
|
|
90
|
+
__name(makeSetter, "makeSetter");
|
|
91
|
+
function makeCoercionFn(target, key) {
|
|
92
|
+
return (v) => {
|
|
93
|
+
const previous = target[key];
|
|
94
|
+
target[key] = v;
|
|
95
|
+
return makeCoercionFn(target, key).bind(null, previous);
|
|
96
|
+
};
|
|
1164
97
|
}
|
|
1165
98
|
__name(makeCoercionFn, "makeCoercionFn");
|
|
1166
99
|
function makeLazyCoercionFn(fn2, orig, generator) {
|
|
@@ -2159,432 +1092,1354 @@ var require_lib = __commonJS({
|
|
|
2159
1092
|
}, "test")
|
|
2160
1093
|
});
|
|
2161
1094
|
}
|
|
2162
|
-
__name(hasMutuallyExclusiveKeys, "hasMutuallyExclusiveKeys");
|
|
2163
|
-
(function(KeyRelationship) {
|
|
2164
|
-
KeyRelationship["Forbids"] = "Forbids";
|
|
2165
|
-
KeyRelationship["Requires"] = "Requires";
|
|
2166
|
-
})(exports2.KeyRelationship || (exports2.KeyRelationship = {}));
|
|
2167
|
-
var keyRelationships = {
|
|
2168
|
-
[exports2.KeyRelationship.Forbids]: {
|
|
2169
|
-
expect: false,
|
|
2170
|
-
message: `forbids using`
|
|
2171
|
-
},
|
|
2172
|
-
[exports2.KeyRelationship.Requires]: {
|
|
2173
|
-
expect: true,
|
|
2174
|
-
message: `requires using`
|
|
1095
|
+
__name(hasMutuallyExclusiveKeys, "hasMutuallyExclusiveKeys");
|
|
1096
|
+
(function(KeyRelationship) {
|
|
1097
|
+
KeyRelationship["Forbids"] = "Forbids";
|
|
1098
|
+
KeyRelationship["Requires"] = "Requires";
|
|
1099
|
+
})(exports2.KeyRelationship || (exports2.KeyRelationship = {}));
|
|
1100
|
+
var keyRelationships = {
|
|
1101
|
+
[exports2.KeyRelationship.Forbids]: {
|
|
1102
|
+
expect: false,
|
|
1103
|
+
message: `forbids using`
|
|
1104
|
+
},
|
|
1105
|
+
[exports2.KeyRelationship.Requires]: {
|
|
1106
|
+
expect: true,
|
|
1107
|
+
message: `requires using`
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
function hasKeyRelationship(subject, relationship, others, options) {
|
|
1111
|
+
var _a, _b;
|
|
1112
|
+
const skipped = new Set((_a = options === null || options === void 0 ? void 0 : options.ignore) !== null && _a !== void 0 ? _a : []);
|
|
1113
|
+
const check = checks[(_b = options === null || options === void 0 ? void 0 : options.missingIf) !== null && _b !== void 0 ? _b : "missing"];
|
|
1114
|
+
const otherSet = new Set(others);
|
|
1115
|
+
const spec = keyRelationships[relationship];
|
|
1116
|
+
const conjunction = relationship === exports2.KeyRelationship.Forbids ? `or` : `and`;
|
|
1117
|
+
return makeValidator({
|
|
1118
|
+
test: /* @__PURE__ */ __name((value, state) => {
|
|
1119
|
+
const keys = new Set(Object.keys(value));
|
|
1120
|
+
if (!check(keys, subject, value) || skipped.has(value[subject])) return true;
|
|
1121
|
+
const problems = [];
|
|
1122
|
+
for (const key of otherSet) if ((check(keys, key, value) && !skipped.has(value[key])) !== spec.expect) problems.push(key);
|
|
1123
|
+
if (problems.length >= 1) return pushError(state, `Property "${subject}" ${spec.message} ${plural(problems.length, `property`, `properties`)} ${getPrintableArray(problems, conjunction)}`);
|
|
1124
|
+
return true;
|
|
1125
|
+
}, "test")
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
__name(hasKeyRelationship, "hasKeyRelationship");
|
|
1129
|
+
exports2.TypeAssertionError = TypeAssertionError;
|
|
1130
|
+
exports2.applyCascade = applyCascade;
|
|
1131
|
+
exports2.as = as;
|
|
1132
|
+
exports2.assert = assert;
|
|
1133
|
+
exports2.assertWithErrors = assertWithErrors;
|
|
1134
|
+
exports2.cascade = cascade;
|
|
1135
|
+
exports2.fn = fn;
|
|
1136
|
+
exports2.hasAtLeastOneKey = hasAtLeastOneKey;
|
|
1137
|
+
exports2.hasExactLength = hasExactLength;
|
|
1138
|
+
exports2.hasForbiddenKeys = hasForbiddenKeys;
|
|
1139
|
+
exports2.hasKeyRelationship = hasKeyRelationship;
|
|
1140
|
+
exports2.hasMaxLength = hasMaxLength;
|
|
1141
|
+
exports2.hasMinLength = hasMinLength;
|
|
1142
|
+
exports2.hasMutuallyExclusiveKeys = hasMutuallyExclusiveKeys;
|
|
1143
|
+
exports2.hasRequiredKeys = hasRequiredKeys;
|
|
1144
|
+
exports2.hasUniqueItems = hasUniqueItems;
|
|
1145
|
+
exports2.isArray = isArray;
|
|
1146
|
+
exports2.isAtLeast = isAtLeast;
|
|
1147
|
+
exports2.isAtMost = isAtMost;
|
|
1148
|
+
exports2.isBase64 = isBase64;
|
|
1149
|
+
exports2.isBoolean = isBoolean;
|
|
1150
|
+
exports2.isDate = isDate;
|
|
1151
|
+
exports2.isDict = isDict;
|
|
1152
|
+
exports2.isEnum = isEnum;
|
|
1153
|
+
exports2.isHexColor = isHexColor;
|
|
1154
|
+
exports2.isISO8601 = isISO8601;
|
|
1155
|
+
exports2.isInExclusiveRange = isInExclusiveRange;
|
|
1156
|
+
exports2.isInInclusiveRange = isInInclusiveRange;
|
|
1157
|
+
exports2.isInstanceOf = isInstanceOf;
|
|
1158
|
+
exports2.isInteger = isInteger;
|
|
1159
|
+
exports2.isJSON = isJSON;
|
|
1160
|
+
exports2.isLiteral = isLiteral;
|
|
1161
|
+
exports2.isLowerCase = isLowerCase;
|
|
1162
|
+
exports2.isMap = isMap;
|
|
1163
|
+
exports2.isNegative = isNegative;
|
|
1164
|
+
exports2.isNullable = isNullable;
|
|
1165
|
+
exports2.isNumber = isNumber2;
|
|
1166
|
+
exports2.isObject = isObject;
|
|
1167
|
+
exports2.isOneOf = isOneOf;
|
|
1168
|
+
exports2.isOptional = isOptional;
|
|
1169
|
+
exports2.isPartial = isPartial;
|
|
1170
|
+
exports2.isPayload = isPayload;
|
|
1171
|
+
exports2.isPositive = isPositive;
|
|
1172
|
+
exports2.isRecord = isRecord;
|
|
1173
|
+
exports2.isSet = isSet;
|
|
1174
|
+
exports2.isString = isString;
|
|
1175
|
+
exports2.isTuple = isTuple;
|
|
1176
|
+
exports2.isUUID4 = isUUID4;
|
|
1177
|
+
exports2.isUnknown = isUnknown;
|
|
1178
|
+
exports2.isUpperCase = isUpperCase;
|
|
1179
|
+
exports2.makeTrait = makeTrait;
|
|
1180
|
+
exports2.makeValidator = makeValidator;
|
|
1181
|
+
exports2.matchesRegExp = matchesRegExp;
|
|
1182
|
+
exports2.softAssert = softAssert;
|
|
1183
|
+
}
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
// src/router.mts
|
|
1187
|
+
var import_neko_context = require("@devbro/neko-context");
|
|
1188
|
+
var import_errors = require("@devbro/neko-http/errors");
|
|
1189
|
+
|
|
1190
|
+
// ../neko-router/dist/esm/CompiledRoute.mjs
|
|
1191
|
+
var import_stream = require("stream");
|
|
1192
|
+
|
|
1193
|
+
// ../neko-router/dist/esm/Middleware.mjs
|
|
1194
|
+
var Middleware = class {
|
|
1195
|
+
static {
|
|
1196
|
+
__name(this, "Middleware");
|
|
1197
|
+
}
|
|
1198
|
+
constructor(params = {}) {
|
|
1199
|
+
}
|
|
1200
|
+
static getInstance(params) {
|
|
1201
|
+
throw new Error("Method not implemented. Please implement a static getInstance method.");
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
// ../neko-router/dist/esm/MiddlewareFactory.mjs
|
|
1206
|
+
var MiddlewareFactory = class {
|
|
1207
|
+
static {
|
|
1208
|
+
__name(this, "MiddlewareFactory");
|
|
1209
|
+
}
|
|
1210
|
+
static create(func) {
|
|
1211
|
+
const cls = class extends Middleware {
|
|
1212
|
+
static {
|
|
1213
|
+
__name(this, "cls");
|
|
1214
|
+
}
|
|
1215
|
+
call(req, res, next) {
|
|
1216
|
+
return func(req, res, next);
|
|
1217
|
+
}
|
|
1218
|
+
constructor(params = {}) {
|
|
1219
|
+
super(params);
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
return new cls();
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
// ../neko-router/dist/esm/CompiledRoute.mjs
|
|
1227
|
+
var import_neko_helper = require("@devbro/neko-helper");
|
|
1228
|
+
var CompiledRoute = class {
|
|
1229
|
+
static {
|
|
1230
|
+
__name(this, "CompiledRoute");
|
|
1231
|
+
}
|
|
1232
|
+
constructor(route, request, response, globalMiddlewares = []) {
|
|
1233
|
+
this.route = route;
|
|
1234
|
+
this.request = request;
|
|
1235
|
+
this.response = response;
|
|
1236
|
+
this.globalMiddlewares = globalMiddlewares;
|
|
1237
|
+
this.prepareMiddlewares();
|
|
1238
|
+
}
|
|
1239
|
+
middlewares = [];
|
|
1240
|
+
getMiddlewares() {
|
|
1241
|
+
return this.middlewares;
|
|
1242
|
+
}
|
|
1243
|
+
prepareMiddlewares() {
|
|
1244
|
+
this.middlewares = [];
|
|
1245
|
+
for (const middleware of [...this.globalMiddlewares, ...this.route.getMiddlewares()]) {
|
|
1246
|
+
if (middleware instanceof Middleware) {
|
|
1247
|
+
this.middlewares.push(middleware);
|
|
1248
|
+
} else if ((0, import_neko_helper.isClass)(middleware)) {
|
|
1249
|
+
this.middlewares.push(middleware.getInstance({}));
|
|
1250
|
+
} else if (typeof middleware === "function") {
|
|
1251
|
+
this.middlewares.push(MiddlewareFactory.create(middleware));
|
|
1252
|
+
} else {
|
|
1253
|
+
throw new Error("Invalid middleware type");
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
async run() {
|
|
1258
|
+
return await this.runMiddlewares(this.middlewares, this.request, this.response);
|
|
1259
|
+
}
|
|
1260
|
+
prepareOutputJsonFormat(obj) {
|
|
1261
|
+
function traverse(value) {
|
|
1262
|
+
if (value === void 0 || value === null) {
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1265
|
+
if (!value || typeof value !== "object") {
|
|
1266
|
+
return value;
|
|
1267
|
+
}
|
|
1268
|
+
if (typeof value.toJson === "function") {
|
|
1269
|
+
return traverse(value.toJson());
|
|
1270
|
+
}
|
|
1271
|
+
if (typeof value.toJSON === "function") {
|
|
1272
|
+
return traverse(value.toJSON());
|
|
1273
|
+
}
|
|
1274
|
+
if (Array.isArray(value)) {
|
|
1275
|
+
return value.map(traverse);
|
|
1276
|
+
}
|
|
1277
|
+
const result = {};
|
|
1278
|
+
for (const key in value) {
|
|
1279
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
1280
|
+
result[key] = traverse(value[key]);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
return result;
|
|
1284
|
+
}
|
|
1285
|
+
__name(traverse, "traverse");
|
|
1286
|
+
return traverse(obj);
|
|
1287
|
+
}
|
|
1288
|
+
convertToString(obj) {
|
|
1289
|
+
if (typeof obj === "string") {
|
|
1290
|
+
return obj;
|
|
1291
|
+
} else if (obj instanceof Buffer) {
|
|
1292
|
+
return obj.toString();
|
|
1293
|
+
} else if (typeof obj === "object") {
|
|
1294
|
+
return JSON.stringify(this.prepareOutputJsonFormat(obj));
|
|
1295
|
+
}
|
|
1296
|
+
return String(obj);
|
|
1297
|
+
}
|
|
1298
|
+
async processResponseBody(res, controller_rc) {
|
|
1299
|
+
if (controller_rc && res.writableEnded) {
|
|
1300
|
+
throw new Error("cannot write to response, response has already ended");
|
|
1301
|
+
}
|
|
1302
|
+
if (res.writableEnded) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
if (controller_rc) {
|
|
1306
|
+
const header_content_type = res.getHeader("Content-Type");
|
|
1307
|
+
if (controller_rc instanceof import_stream.Stream || Buffer.isBuffer(controller_rc)) {
|
|
1308
|
+
await this.writeAsync(res, controller_rc);
|
|
1309
|
+
} else if (!header_content_type && typeof controller_rc === "object") {
|
|
1310
|
+
res.setHeader("Content-Type", "application/json");
|
|
1311
|
+
res.write(this.convertToString(controller_rc));
|
|
1312
|
+
} else if (!header_content_type) {
|
|
1313
|
+
res.setHeader("Content-Type", "text/plain");
|
|
1314
|
+
res.write(this.convertToString(controller_rc));
|
|
1315
|
+
} else {
|
|
1316
|
+
res.write(this.convertToString(controller_rc));
|
|
1317
|
+
}
|
|
1318
|
+
return;
|
|
1319
|
+
} else {
|
|
1320
|
+
res.statusCode = [200].includes(res.statusCode) ? 204 : res.statusCode;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
async writeAsync(res, chunk) {
|
|
1324
|
+
return new Promise((resolve, reject) => {
|
|
1325
|
+
const ok = res.write(chunk, (err) => {
|
|
1326
|
+
if (err) reject(err);
|
|
1327
|
+
});
|
|
1328
|
+
if (ok) {
|
|
1329
|
+
resolve(0);
|
|
1330
|
+
} else {
|
|
1331
|
+
res.once("drain", resolve);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
async runMiddlewares(middlewares, req, res) {
|
|
1336
|
+
let index = 0;
|
|
1337
|
+
const me = this;
|
|
1338
|
+
async function next() {
|
|
1339
|
+
if (index >= middlewares.length) {
|
|
1340
|
+
const controller_rc = await me.route.callHanlder(req, res);
|
|
1341
|
+
await me.processResponseBody(res, controller_rc);
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
const middleware = middlewares[index++];
|
|
1345
|
+
if (middleware instanceof Middleware) {
|
|
1346
|
+
await middleware.call(req, res, next);
|
|
1347
|
+
} else if (typeof middleware === "function") {
|
|
1348
|
+
await middleware(req, res, next);
|
|
1349
|
+
} else {
|
|
1350
|
+
throw new Error("does not know how to run middleware");
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
__name(next, "next");
|
|
1354
|
+
await next();
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
|
|
1358
|
+
// ../neko-router/dist/esm/Route.mjs
|
|
1359
|
+
var Route = class {
|
|
1360
|
+
static {
|
|
1361
|
+
__name(this, "Route");
|
|
1362
|
+
}
|
|
1363
|
+
constructor(methods, path10, handler) {
|
|
1364
|
+
this.methods = methods;
|
|
1365
|
+
this.path = path10;
|
|
1366
|
+
this.handler = handler;
|
|
1367
|
+
this.urlRegex = this.pathToRegex(path10);
|
|
1368
|
+
}
|
|
1369
|
+
middlewares = [];
|
|
1370
|
+
urlRegex;
|
|
1371
|
+
pathToRegex(path10) {
|
|
1372
|
+
const lex = this.lexUrlPath(path10);
|
|
1373
|
+
return this.tokensToRegex(lex);
|
|
1374
|
+
}
|
|
1375
|
+
lexUrlPath(path10) {
|
|
1376
|
+
const tokens = [];
|
|
1377
|
+
let i = 0;
|
|
1378
|
+
while (i < path10.length) {
|
|
1379
|
+
const char = path10[i];
|
|
1380
|
+
if (char === "/") {
|
|
1381
|
+
tokens.push({ type: "SLASH", value: "/" });
|
|
1382
|
+
i++;
|
|
1383
|
+
} else if (char === ":") {
|
|
1384
|
+
let start = i + 1;
|
|
1385
|
+
while (start < path10.length && /[a-zA-Z0-9_]/.test(path10[start])) {
|
|
1386
|
+
start++;
|
|
1387
|
+
}
|
|
1388
|
+
tokens.push({ type: "PARAM", value: path10.slice(i + 1, start) });
|
|
1389
|
+
i = start;
|
|
1390
|
+
} else if (char === "*") {
|
|
1391
|
+
let start = i + 1;
|
|
1392
|
+
while (start < path10.length && /[a-zA-Z0-9_]/.test(path10[start])) {
|
|
1393
|
+
start++;
|
|
1394
|
+
}
|
|
1395
|
+
tokens.push({ type: "WILDCARD", value: path10.slice(i + 1, start) });
|
|
1396
|
+
i = start;
|
|
1397
|
+
} else {
|
|
1398
|
+
let start = i;
|
|
1399
|
+
while (start < path10.length && !["/", ":", "*"].includes(path10[start])) {
|
|
1400
|
+
start++;
|
|
1401
|
+
}
|
|
1402
|
+
tokens.push({ type: "TEXT", value: path10.slice(i, start) });
|
|
1403
|
+
i = start;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
return tokens;
|
|
1407
|
+
}
|
|
1408
|
+
tokensToRegex(tokens) {
|
|
1409
|
+
const regexParts = [];
|
|
1410
|
+
for (const token of tokens) {
|
|
1411
|
+
if (token.type === "SLASH") {
|
|
1412
|
+
regexParts.push("\\/");
|
|
1413
|
+
} else if (token.type === "PARAM") {
|
|
1414
|
+
regexParts.push(`(?<${token.value}>[^\\/]+)`);
|
|
1415
|
+
} else if (token.type === "WILDCARD") {
|
|
1416
|
+
regexParts.push("(.+)");
|
|
1417
|
+
} else if (token.type === "TEXT") {
|
|
1418
|
+
regexParts.push(token.value.replace(/[-\/\\^$.*+?()[\]{}|]/g, "\\$&"));
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
if (regexParts.length > 0 && regexParts[regexParts.length - 1] === "\\/") {
|
|
1422
|
+
regexParts[regexParts.length - 1] = "\\/?";
|
|
1423
|
+
} else {
|
|
1424
|
+
regexParts.push("\\/?");
|
|
1425
|
+
}
|
|
1426
|
+
return new RegExp(`^${regexParts.join("")}$`);
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* to evaluadate if request is a match for this route
|
|
1430
|
+
* @param request http request
|
|
1431
|
+
* @returns return true if route is a match for this request
|
|
1432
|
+
*/
|
|
1433
|
+
test(request) {
|
|
1434
|
+
if (this.methods.indexOf(request.method) === -1) {
|
|
1435
|
+
return false;
|
|
1436
|
+
}
|
|
1437
|
+
const url = new URL(request.url || "/", "http://localhost");
|
|
1438
|
+
return this.testPath(url.pathname);
|
|
1439
|
+
}
|
|
1440
|
+
testPath(pathname) {
|
|
1441
|
+
return this.urlRegex.test(pathname);
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* returns details of the match, otherwise it returns false
|
|
1445
|
+
* @param request the request to match
|
|
1446
|
+
* @returns object cotaining details of match including matched params
|
|
1447
|
+
*/
|
|
1448
|
+
match(request) {
|
|
1449
|
+
if (this.methods.indexOf(request.method) === -1) {
|
|
1450
|
+
return false;
|
|
1451
|
+
}
|
|
1452
|
+
const url = new URL(request.url || "/", "http://localhost");
|
|
1453
|
+
const r = this.urlRegex.exec(url.pathname);
|
|
1454
|
+
if (!r) {
|
|
1455
|
+
return false;
|
|
1456
|
+
}
|
|
1457
|
+
return {
|
|
1458
|
+
url,
|
|
1459
|
+
params: r.groups || {}
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
prependMiddleware(middlewares) {
|
|
1463
|
+
this.middlewares = [].concat(middlewares, this.middlewares);
|
|
1464
|
+
return this;
|
|
1465
|
+
}
|
|
1466
|
+
addMiddleware(middlewares) {
|
|
1467
|
+
this.middlewares = this.middlewares.concat(middlewares);
|
|
1468
|
+
return this;
|
|
1469
|
+
}
|
|
1470
|
+
getMiddlewares() {
|
|
1471
|
+
return this.middlewares;
|
|
1472
|
+
}
|
|
1473
|
+
callHanlder(request, response) {
|
|
1474
|
+
return this.handler(request, response);
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
|
|
1478
|
+
// ../neko-router/dist/esm/Router.mjs
|
|
1479
|
+
var import_path = __toESM(require("path"), 1);
|
|
1480
|
+
|
|
1481
|
+
// ../node_modules/url-join/lib/url-join.js
|
|
1482
|
+
function normalize(strArray) {
|
|
1483
|
+
var resultArray = [];
|
|
1484
|
+
if (strArray.length === 0) {
|
|
1485
|
+
return "";
|
|
1486
|
+
}
|
|
1487
|
+
if (typeof strArray[0] !== "string") {
|
|
1488
|
+
throw new TypeError("Url must be a string. Received " + strArray[0]);
|
|
1489
|
+
}
|
|
1490
|
+
if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
|
|
1491
|
+
var first = strArray.shift();
|
|
1492
|
+
strArray[0] = first + strArray[0];
|
|
1493
|
+
}
|
|
1494
|
+
if (strArray[0].match(/^file:\/\/\//)) {
|
|
1495
|
+
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///");
|
|
1496
|
+
} else {
|
|
1497
|
+
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://");
|
|
1498
|
+
}
|
|
1499
|
+
for (var i = 0; i < strArray.length; i++) {
|
|
1500
|
+
var component = strArray[i];
|
|
1501
|
+
if (typeof component !== "string") {
|
|
1502
|
+
throw new TypeError("Url must be a string. Received " + component);
|
|
1503
|
+
}
|
|
1504
|
+
if (component === "") {
|
|
1505
|
+
continue;
|
|
1506
|
+
}
|
|
1507
|
+
if (i > 0) {
|
|
1508
|
+
component = component.replace(/^[\/]+/, "");
|
|
1509
|
+
}
|
|
1510
|
+
if (i < strArray.length - 1) {
|
|
1511
|
+
component = component.replace(/[\/]+$/, "");
|
|
1512
|
+
} else {
|
|
1513
|
+
component = component.replace(/[\/]+$/, "/");
|
|
1514
|
+
}
|
|
1515
|
+
resultArray.push(component);
|
|
1516
|
+
}
|
|
1517
|
+
var str = resultArray.join("/");
|
|
1518
|
+
str = str.replace(/\/(\?|&|#[^!])/g, "$1");
|
|
1519
|
+
var parts = str.split("?");
|
|
1520
|
+
str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&");
|
|
1521
|
+
return str;
|
|
1522
|
+
}
|
|
1523
|
+
__name(normalize, "normalize");
|
|
1524
|
+
function urlJoin() {
|
|
1525
|
+
var input2;
|
|
1526
|
+
if (typeof arguments[0] === "object") {
|
|
1527
|
+
input2 = arguments[0];
|
|
1528
|
+
} else {
|
|
1529
|
+
input2 = [].slice.call(arguments);
|
|
1530
|
+
}
|
|
1531
|
+
return normalize(input2);
|
|
1532
|
+
}
|
|
1533
|
+
__name(urlJoin, "urlJoin");
|
|
1534
|
+
|
|
1535
|
+
// ../neko-router/dist/esm/Router.mjs
|
|
1536
|
+
var Router = class {
|
|
1537
|
+
static {
|
|
1538
|
+
__name(this, "Router");
|
|
1539
|
+
}
|
|
1540
|
+
middlewares = [];
|
|
1541
|
+
routes = [];
|
|
1542
|
+
addRoute(methods, path22, handler) {
|
|
1543
|
+
const route = new Route(methods, path22, handler);
|
|
1544
|
+
this.routes.push(route);
|
|
1545
|
+
return route;
|
|
1546
|
+
}
|
|
1547
|
+
getMiddlewares() {
|
|
1548
|
+
return [...this.middlewares];
|
|
1549
|
+
}
|
|
1550
|
+
addController(controller) {
|
|
1551
|
+
const basePath = controller.basePath || "";
|
|
1552
|
+
for (const route of controller.routes) {
|
|
1553
|
+
const urlPath = import_path.default.join(basePath, route.path);
|
|
1554
|
+
this.addRoute(route.methods, urlPath, async (req, res) => {
|
|
1555
|
+
const controllerInstance = controller.getInstance();
|
|
1556
|
+
return await controllerInstance[route.handler]();
|
|
1557
|
+
}).addMiddleware([...controller.baseMiddlewares, ...route.middlewares]);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
addRouter(path22, router2) {
|
|
1561
|
+
for (const route of router2.routes) {
|
|
1562
|
+
let path222 = urlJoin("/", path22, route.path);
|
|
1563
|
+
this.addRoute(route.methods, path222, route.handler).addMiddleware(router2.getMiddlewares()).addMiddleware(route.getMiddlewares());
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
addGlobalMiddleware(middlewares) {
|
|
1567
|
+
this.middlewares = this.middlewares.concat(middlewares);
|
|
1568
|
+
}
|
|
1569
|
+
resolve(request) {
|
|
1570
|
+
for (const route of this.routes) {
|
|
1571
|
+
if (route.test(request)) {
|
|
1572
|
+
return route;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
return void 0;
|
|
1576
|
+
}
|
|
1577
|
+
resolveMultiple(request) {
|
|
1578
|
+
const rc = [];
|
|
1579
|
+
const url = new URL(request.url || "/", "http://localhost");
|
|
1580
|
+
for (const route of this.routes) {
|
|
1581
|
+
if (route.testPath(url.pathname)) {
|
|
1582
|
+
rc.push(route);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
return rc;
|
|
1586
|
+
}
|
|
1587
|
+
getCompiledRoute(request, response) {
|
|
1588
|
+
const route = this.resolve(request);
|
|
1589
|
+
if (!route) {
|
|
1590
|
+
return void 0;
|
|
1591
|
+
}
|
|
1592
|
+
const match = route.match(request);
|
|
1593
|
+
if (!match) {
|
|
1594
|
+
return void 0;
|
|
1595
|
+
}
|
|
1596
|
+
request.params = match.params;
|
|
1597
|
+
return new CompiledRoute(route, request, response, this.middlewares);
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1600
|
+
|
|
1601
|
+
// src/facades.mts
|
|
1602
|
+
var import_neko_scheduler = require("@devbro/neko-scheduler");
|
|
1603
|
+
var import_neko_helper3 = require("@devbro/neko-helper");
|
|
1604
|
+
var import_neko_context3 = require("@devbro/neko-context");
|
|
1605
|
+
var import_neko_storage2 = require("@devbro/neko-storage");
|
|
1606
|
+
var import_neko_mailer2 = require("@devbro/neko-mailer");
|
|
1607
|
+
var import_neko_config = require("@devbro/neko-config");
|
|
1608
|
+
var import_clipanion = require("clipanion");
|
|
1609
|
+
|
|
1610
|
+
// src/http.mts
|
|
1611
|
+
var http_exports = {};
|
|
1612
|
+
__export(http_exports, {
|
|
1613
|
+
handleHttpErrors: () => handleHttpErrors
|
|
1614
|
+
});
|
|
1615
|
+
var import_neko_http = require("@devbro/neko-http");
|
|
1616
|
+
__reExport(http_exports, require("@devbro/neko-http"));
|
|
1617
|
+
async function handleHttpErrors(err, req, res) {
|
|
1618
|
+
if (err instanceof import_neko_http.HttpError) {
|
|
1619
|
+
res.writeHead(err.statusCode, { "Content-Type": "application/json" });
|
|
1620
|
+
res.write(JSON.stringify({ message: err.message, error: err.code }));
|
|
1621
|
+
logger().warn({ msg: "HttpError: " + err.message, err });
|
|
1622
|
+
return;
|
|
1623
|
+
} else {
|
|
1624
|
+
logger().error({ msg: "Error: " + err.message, err });
|
|
1625
|
+
}
|
|
1626
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1627
|
+
res.write(JSON.stringify({ error: "Internal Server Error" }));
|
|
1628
|
+
}
|
|
1629
|
+
__name(handleHttpErrors, "handleHttpErrors");
|
|
1630
|
+
|
|
1631
|
+
// src/facades.mts
|
|
1632
|
+
var import_neko_logger = require("@devbro/neko-logger");
|
|
1633
|
+
|
|
1634
|
+
// src/factories.mts
|
|
1635
|
+
var import_neko_mailer = require("@devbro/neko-mailer");
|
|
1636
|
+
var import_neko_queue = require("@devbro/neko-queue");
|
|
1637
|
+
|
|
1638
|
+
// src/queue.mts
|
|
1639
|
+
var queue_exports = {};
|
|
1640
|
+
__export(queue_exports, {
|
|
1641
|
+
DatabaseTransport: () => DatabaseTransport
|
|
1642
|
+
});
|
|
1643
|
+
__reExport(queue_exports, require("@devbro/neko-queue"));
|
|
1644
|
+
var import_neko_helper2 = require("@devbro/neko-helper");
|
|
1645
|
+
var import_neko_context2 = require("@devbro/neko-context");
|
|
1646
|
+
var DatabaseTransport = class {
|
|
1647
|
+
static {
|
|
1648
|
+
__name(this, "DatabaseTransport");
|
|
1649
|
+
}
|
|
1650
|
+
config = {
|
|
1651
|
+
queue_table: "queue_messages",
|
|
1652
|
+
db_connection: "default",
|
|
1653
|
+
listen_interval: 60,
|
|
1654
|
+
// seconds
|
|
1655
|
+
message_limit: 10,
|
|
1656
|
+
// messages per each fetch
|
|
1657
|
+
max_retry_count: 5
|
|
1658
|
+
// maximum retry count for failed messages
|
|
1659
|
+
};
|
|
1660
|
+
channels = /* @__PURE__ */ new Map();
|
|
1661
|
+
messageQueues = [];
|
|
1662
|
+
repeater;
|
|
1663
|
+
processMessage = /* @__PURE__ */ __name(async () => {
|
|
1664
|
+
await import_neko_context2.context_provider.run(async () => {
|
|
1665
|
+
const conn = db(this.config.db_connection);
|
|
1666
|
+
try {
|
|
1667
|
+
let q = conn.getQuery();
|
|
1668
|
+
let messages = await conn.getQuery().table(this.config.queue_table).whereOp("channel", "in", Array.from(this.channels.keys())).whereOp("status", "in", ["pending", "failed"]).whereOp("retried_count", "<", this.config.max_retry_count).limit(this.config.message_limit).orderBy("last_tried_at", "asc").get();
|
|
1669
|
+
for (let msg of messages) {
|
|
1670
|
+
try {
|
|
1671
|
+
await conn.getQuery().table(this.config.queue_table).whereOp("id", "=", msg.id).update({
|
|
1672
|
+
status: "processing",
|
|
1673
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
1674
|
+
last_tried_at: /* @__PURE__ */ new Date(),
|
|
1675
|
+
retried_count: (msg.retried_count || 0) + 1
|
|
1676
|
+
});
|
|
1677
|
+
let callback = this.channels.get(msg.channel);
|
|
1678
|
+
await callback(msg.message);
|
|
1679
|
+
await conn.getQuery().table(this.config.queue_table).whereOp("id", "=", msg.id).update({
|
|
1680
|
+
status: "processed",
|
|
1681
|
+
updated_at: /* @__PURE__ */ new Date()
|
|
1682
|
+
});
|
|
1683
|
+
} catch (error) {
|
|
1684
|
+
logger().error("Error processing message:", {
|
|
1685
|
+
error,
|
|
1686
|
+
message_id: msg.id,
|
|
1687
|
+
channel: msg.channel
|
|
1688
|
+
});
|
|
1689
|
+
await q.table(this.config.queue_table).whereOp("id", "=", msg.id).update({
|
|
1690
|
+
status: "failed",
|
|
1691
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
1692
|
+
process_message: error.message || "Error processing message"
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
} catch (error) {
|
|
1697
|
+
logger().error("Error in DatabaseTransport listen interval:", {
|
|
1698
|
+
error
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
}, "processMessage");
|
|
1703
|
+
constructor(config9 = {}) {
|
|
1704
|
+
this.config = { ...this.config, ...config9 };
|
|
1705
|
+
this.repeater = (0, import_neko_helper2.createRepeater)(
|
|
1706
|
+
this.processMessage,
|
|
1707
|
+
this.config.listen_interval * 1e3
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
async dispatch(channel, message) {
|
|
1711
|
+
const conn = db(this.config.db_connection);
|
|
1712
|
+
let schema = conn.getSchema();
|
|
1713
|
+
if (await schema.tableExists(this.config.queue_table) === false) {
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
let q = conn.getQuery();
|
|
1717
|
+
await q.table(this.config.queue_table).insert({
|
|
1718
|
+
channel,
|
|
1719
|
+
message,
|
|
1720
|
+
created_at: /* @__PURE__ */ new Date(),
|
|
1721
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
1722
|
+
last_tried_at: null,
|
|
1723
|
+
process_message: "",
|
|
1724
|
+
retried_count: 0,
|
|
1725
|
+
status: "pending"
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
async registerListener(channel, callback) {
|
|
1729
|
+
this.channels.set(channel, callback);
|
|
1730
|
+
}
|
|
1731
|
+
async startListening() {
|
|
1732
|
+
this.repeater.start();
|
|
1733
|
+
}
|
|
1734
|
+
async stopListening() {
|
|
1735
|
+
this.repeater.stop();
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
// src/factories.mts
|
|
1740
|
+
var import_neko_cache = require("@devbro/neko-cache");
|
|
1741
|
+
var import_neko_storage = require("@devbro/neko-storage");
|
|
1742
|
+
|
|
1743
|
+
// src/cache/MultiCache.mts
|
|
1744
|
+
var MultiCache = class {
|
|
1745
|
+
constructor(caches) {
|
|
1746
|
+
this.caches = caches;
|
|
1747
|
+
}
|
|
1748
|
+
static {
|
|
1749
|
+
__name(this, "MultiCache");
|
|
1750
|
+
}
|
|
1751
|
+
async get(key) {
|
|
1752
|
+
for (const cache2 of this.caches) {
|
|
1753
|
+
const value = await cache2.get(key);
|
|
1754
|
+
if (value !== void 0) {
|
|
1755
|
+
return value;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
return void 0;
|
|
1759
|
+
}
|
|
1760
|
+
async put(key, value, ttl) {
|
|
1761
|
+
await Promise.all(this.caches.map((cache2) => cache2.put(key, value, ttl)));
|
|
1762
|
+
}
|
|
1763
|
+
async delete(key) {
|
|
1764
|
+
await Promise.all(this.caches.map((cache2) => cache2.delete(key)));
|
|
1765
|
+
}
|
|
1766
|
+
async has(key) {
|
|
1767
|
+
for (const cache2 of this.caches) {
|
|
1768
|
+
if (await cache2.has(key)) {
|
|
1769
|
+
return true;
|
|
2175
1770
|
}
|
|
2176
|
-
};
|
|
2177
|
-
function hasKeyRelationship(subject, relationship, others, options) {
|
|
2178
|
-
var _a, _b;
|
|
2179
|
-
const skipped = new Set((_a = options === null || options === void 0 ? void 0 : options.ignore) !== null && _a !== void 0 ? _a : []);
|
|
2180
|
-
const check = checks[(_b = options === null || options === void 0 ? void 0 : options.missingIf) !== null && _b !== void 0 ? _b : "missing"];
|
|
2181
|
-
const otherSet = new Set(others);
|
|
2182
|
-
const spec = keyRelationships[relationship];
|
|
2183
|
-
const conjunction = relationship === exports2.KeyRelationship.Forbids ? `or` : `and`;
|
|
2184
|
-
return makeValidator({
|
|
2185
|
-
test: /* @__PURE__ */ __name((value, state) => {
|
|
2186
|
-
const keys = new Set(Object.keys(value));
|
|
2187
|
-
if (!check(keys, subject, value) || skipped.has(value[subject])) return true;
|
|
2188
|
-
const problems = [];
|
|
2189
|
-
for (const key of otherSet) if ((check(keys, key, value) && !skipped.has(value[key])) !== spec.expect) problems.push(key);
|
|
2190
|
-
if (problems.length >= 1) return pushError(state, `Property "${subject}" ${spec.message} ${plural(problems.length, `property`, `properties`)} ${getPrintableArray(problems, conjunction)}`);
|
|
2191
|
-
return true;
|
|
2192
|
-
}, "test")
|
|
2193
|
-
});
|
|
2194
1771
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
1772
|
+
return false;
|
|
1773
|
+
}
|
|
1774
|
+
async increment(key, amount) {
|
|
1775
|
+
let rc = void 0;
|
|
1776
|
+
for (const cache2 of this.caches) {
|
|
1777
|
+
let rc2 = await cache2.increment(key, amount);
|
|
1778
|
+
if (rc === void 0) {
|
|
1779
|
+
rc = rc2;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
return rc;
|
|
1783
|
+
}
|
|
1784
|
+
};
|
|
1785
|
+
|
|
1786
|
+
// src/factories.mts
|
|
1787
|
+
var FlexibleFactory = class {
|
|
1788
|
+
static {
|
|
1789
|
+
__name(this, "FlexibleFactory");
|
|
1790
|
+
}
|
|
1791
|
+
registry = /* @__PURE__ */ new Map();
|
|
1792
|
+
register(key, ctor) {
|
|
1793
|
+
this.registry.set(key, ctor);
|
|
1794
|
+
}
|
|
1795
|
+
create(key, ...args) {
|
|
1796
|
+
const ctor = this.registry.get(key);
|
|
1797
|
+
if (!ctor) {
|
|
1798
|
+
throw new Error(`No factory registered for key: ${key}`);
|
|
1799
|
+
}
|
|
1800
|
+
return ctor(...args);
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
import_neko_mailer.MailerProviderFactory.register("ses", (opt) => {
|
|
1804
|
+
return new import_neko_mailer.SESProvider(opt);
|
|
1805
|
+
});
|
|
1806
|
+
import_neko_mailer.MailerProviderFactory.register("smtp", (opt) => {
|
|
1807
|
+
return new import_neko_mailer.SMTPProvider(opt);
|
|
1808
|
+
});
|
|
1809
|
+
import_neko_mailer.MailerProviderFactory.register("memory", (opt) => {
|
|
1810
|
+
return new import_neko_mailer.MemoryProvider();
|
|
1811
|
+
});
|
|
1812
|
+
import_neko_queue.QueueTransportFactory.register("database", (opt) => {
|
|
1813
|
+
return new DatabaseTransport(opt);
|
|
1814
|
+
});
|
|
1815
|
+
import_neko_queue.QueueTransportFactory.register("memory", (opt) => {
|
|
1816
|
+
return new import_neko_queue.MemoryTransport(opt);
|
|
1817
|
+
});
|
|
1818
|
+
import_neko_queue.QueueTransportFactory.register("sqs", (opt) => {
|
|
1819
|
+
return new import_neko_queue.AwsSqsTransport(opt);
|
|
1820
|
+
});
|
|
1821
|
+
import_neko_queue.QueueTransportFactory.register("amqp", (opt) => {
|
|
1822
|
+
return new import_neko_queue.AmqpTransport(opt);
|
|
1823
|
+
});
|
|
1824
|
+
import_neko_queue.QueueTransportFactory.register("redis", (opt) => {
|
|
1825
|
+
return new import_neko_queue.RedisTransport(opt);
|
|
1826
|
+
});
|
|
1827
|
+
import_neko_queue.QueueTransportFactory.register("async", (opt) => {
|
|
1828
|
+
return new import_neko_queue.AsyncTransport();
|
|
1829
|
+
});
|
|
1830
|
+
import_neko_queue.QueueTransportFactory.register("azure_service_bus", (opt) => {
|
|
1831
|
+
return new import_neko_queue.AzureServiceBusTransport(opt);
|
|
1832
|
+
});
|
|
1833
|
+
import_neko_queue.QueueTransportFactory.register("google_pubsub", (opt) => {
|
|
1834
|
+
return new import_neko_queue.GooglePubSubTransport(opt);
|
|
1835
|
+
});
|
|
1836
|
+
var CacheProviderFactory = class _CacheProviderFactory {
|
|
1837
|
+
static {
|
|
1838
|
+
__name(this, "CacheProviderFactory");
|
|
1839
|
+
}
|
|
1840
|
+
static instance = new FlexibleFactory();
|
|
1841
|
+
static register(key, factory) {
|
|
1842
|
+
_CacheProviderFactory.instance.register(key, factory);
|
|
1843
|
+
}
|
|
1844
|
+
static create(key, ...args) {
|
|
1845
|
+
return _CacheProviderFactory.instance.create(key, ...args);
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
CacheProviderFactory.register("memory", (opt) => {
|
|
1849
|
+
return new import_neko_cache.MemoryCacheProvider(opt);
|
|
1850
|
+
});
|
|
1851
|
+
CacheProviderFactory.register("redis", (opt) => {
|
|
1852
|
+
return new import_neko_cache.RedisCacheProvider(opt);
|
|
1853
|
+
});
|
|
1854
|
+
CacheProviderFactory.register("file", (opt) => {
|
|
1855
|
+
return new import_neko_cache.FileCacheProvider(opt);
|
|
1856
|
+
});
|
|
1857
|
+
CacheProviderFactory.register("multi", (opt) => {
|
|
1858
|
+
const caches = [];
|
|
1859
|
+
for (const c of opt.caches) {
|
|
1860
|
+
caches.push(cache(c));
|
|
2250
1861
|
}
|
|
1862
|
+
return new MultiCache(caches);
|
|
1863
|
+
});
|
|
1864
|
+
CacheProviderFactory.register("disabled", (opt) => {
|
|
1865
|
+
return new import_neko_cache.DisabledCacheProvider();
|
|
1866
|
+
});
|
|
1867
|
+
import_neko_storage.StorageProviderFactory.register("local", (opt) => {
|
|
1868
|
+
return new import_neko_storage.LocalStorageProvider(opt);
|
|
1869
|
+
});
|
|
1870
|
+
import_neko_storage.StorageProviderFactory.register("s3", (opt) => {
|
|
1871
|
+
return new import_neko_storage.AWSS3StorageProvider(opt);
|
|
1872
|
+
});
|
|
1873
|
+
import_neko_storage.StorageProviderFactory.register("gcp", (opt) => {
|
|
1874
|
+
return new import_neko_storage.GCPStorageProvider(opt);
|
|
1875
|
+
});
|
|
1876
|
+
import_neko_storage.StorageProviderFactory.register("azure", (opt) => {
|
|
1877
|
+
return new import_neko_storage.AzureBlobStorageProvider(opt);
|
|
1878
|
+
});
|
|
1879
|
+
import_neko_storage.StorageProviderFactory.register("ftp", (opt) => {
|
|
1880
|
+
return new import_neko_storage.FTPStorageProvider(opt);
|
|
1881
|
+
});
|
|
1882
|
+
import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
|
|
1883
|
+
return new import_neko_storage.SFTPStorageProvider(opt);
|
|
2251
1884
|
});
|
|
2252
1885
|
|
|
2253
|
-
// src/
|
|
2254
|
-
var
|
|
2255
|
-
var
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
1886
|
+
// src/facades.mts
|
|
1887
|
+
var import_neko_cache2 = require("@devbro/neko-cache");
|
|
1888
|
+
var import_neko_queue2 = require("@devbro/neko-queue");
|
|
1889
|
+
function wrapSingletonWithAccessors(singletonFn) {
|
|
1890
|
+
let methodsInitialized = false;
|
|
1891
|
+
const initializeMethods = /* @__PURE__ */ __name(() => {
|
|
1892
|
+
if (methodsInitialized) return;
|
|
1893
|
+
const defaultInstance = singletonFn();
|
|
1894
|
+
const prototype = Object.getPrototypeOf(defaultInstance);
|
|
1895
|
+
const methodNames = Object.getOwnPropertyNames(prototype).filter(
|
|
1896
|
+
(name) => name !== "constructor" && typeof prototype[name] === "function"
|
|
1897
|
+
);
|
|
1898
|
+
for (const methodName of methodNames) {
|
|
1899
|
+
singletonFn[methodName] = (...args) => {
|
|
1900
|
+
const instance = singletonFn();
|
|
1901
|
+
return instance[methodName](...args);
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
methodsInitialized = true;
|
|
1905
|
+
}, "initializeMethods");
|
|
1906
|
+
return new Proxy(singletonFn, {
|
|
1907
|
+
get(target, prop, receiver) {
|
|
1908
|
+
if (typeof prop === "string" && !Reflect.has(target, prop)) {
|
|
1909
|
+
initializeMethods();
|
|
2268
1910
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
1911
|
+
return Reflect.get(target, prop, receiver);
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
__name(wrapSingletonWithAccessors, "wrapSingletonWithAccessors");
|
|
1916
|
+
var router = (0, import_neko_helper3.createSingleton)(() => new Router());
|
|
1917
|
+
var scheduler = wrapSingletonWithAccessors(
|
|
1918
|
+
(0, import_neko_helper3.createSingleton)(() => {
|
|
1919
|
+
const rc = new import_neko_scheduler.Scheduler();
|
|
1920
|
+
rc.setErrorHandler((err, job) => {
|
|
1921
|
+
logger().error({
|
|
1922
|
+
msg: "Scheduled job error",
|
|
1923
|
+
err,
|
|
1924
|
+
job_name: job.getName()
|
|
2273
1925
|
});
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
1926
|
+
});
|
|
1927
|
+
return rc;
|
|
1928
|
+
})
|
|
1929
|
+
);
|
|
1930
|
+
var db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
|
|
1931
|
+
var storage = wrapSingletonWithAccessors(
|
|
1932
|
+
(0, import_neko_helper3.createSingleton)((label = "default") => {
|
|
1933
|
+
let storage_config = import_neko_config.config.get(["storages", label].join("."));
|
|
1934
|
+
const provider = import_neko_storage2.StorageProviderFactory.create(
|
|
1935
|
+
storage_config.provider,
|
|
1936
|
+
storage_config.config
|
|
1937
|
+
);
|
|
1938
|
+
return new import_neko_storage2.Storage(provider);
|
|
1939
|
+
})
|
|
1940
|
+
);
|
|
1941
|
+
var cli = (0, import_neko_helper3.createSingleton)(() => {
|
|
1942
|
+
const [node, app, ...args] = process.argv;
|
|
1943
|
+
return new import_clipanion.Cli({
|
|
1944
|
+
binaryLabel: `My Application`,
|
|
1945
|
+
binaryName: `${node} ${app}`,
|
|
1946
|
+
binaryVersion: `1.0.0`
|
|
1947
|
+
});
|
|
1948
|
+
});
|
|
1949
|
+
var httpServer = (0, import_neko_helper3.createSingleton)(() => {
|
|
1950
|
+
const server = new http_exports.HttpServer();
|
|
1951
|
+
server.setErrorHandler(handleHttpErrors);
|
|
1952
|
+
server.setRouter(router());
|
|
1953
|
+
return server;
|
|
1954
|
+
});
|
|
1955
|
+
var logger = wrapSingletonWithAccessors(
|
|
1956
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1957
|
+
const logger_config = import_neko_config.config.get(["loggers", label].join("."));
|
|
1958
|
+
const rc = new import_neko_logger.Logger(logger_config);
|
|
1959
|
+
rc.setExtrasFunction((message) => {
|
|
1960
|
+
message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
|
|
1961
|
+
return message;
|
|
1962
|
+
});
|
|
1963
|
+
return rc;
|
|
1964
|
+
})
|
|
1965
|
+
);
|
|
1966
|
+
var mailer = wrapSingletonWithAccessors(
|
|
1967
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1968
|
+
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
1969
|
+
const provider = import_neko_mailer2.MailerProviderFactory.create(
|
|
1970
|
+
mailer_config.provider,
|
|
1971
|
+
mailer_config.config
|
|
1972
|
+
);
|
|
1973
|
+
const rc = new import_neko_mailer2.Mailer(provider);
|
|
1974
|
+
return rc;
|
|
1975
|
+
})
|
|
1976
|
+
);
|
|
1977
|
+
var queue = wrapSingletonWithAccessors(
|
|
1978
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1979
|
+
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
1980
|
+
if (!queue_config) {
|
|
1981
|
+
throw new Error(`Queue configuration for '${label}' not found`);
|
|
1982
|
+
}
|
|
1983
|
+
const provider = import_neko_queue2.QueueTransportFactory.create(
|
|
1984
|
+
queue_config.provider,
|
|
1985
|
+
queue_config.config
|
|
1986
|
+
);
|
|
1987
|
+
return new import_neko_queue2.QueueConnection(provider);
|
|
1988
|
+
})
|
|
1989
|
+
);
|
|
1990
|
+
var cache = wrapSingletonWithAccessors(
|
|
1991
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1992
|
+
const cache_config = import_neko_config.config.get(["caches", label].join("."));
|
|
1993
|
+
if (!cache_config) {
|
|
1994
|
+
throw new Error(`Cache configuration for '${label}' not found`);
|
|
1995
|
+
}
|
|
1996
|
+
const provider = CacheProviderFactory.create(
|
|
1997
|
+
cache_config.provider,
|
|
1998
|
+
cache_config.config
|
|
1999
|
+
);
|
|
2000
|
+
return new import_neko_cache2.Cache(provider);
|
|
2001
|
+
})
|
|
2002
|
+
);
|
|
2003
|
+
|
|
2004
|
+
// src/app/console/migrate/MigrateCommand.mts
|
|
2005
|
+
var import_clipanion2 = require("clipanion");
|
|
2006
|
+
var import_neko_context4 = require("@devbro/neko-context");
|
|
2007
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
2008
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
2009
|
+
var import_neko_config2 = require("@devbro/neko-config");
|
|
2010
|
+
var MigrateCommand = class extends import_clipanion2.Command {
|
|
2011
|
+
static {
|
|
2012
|
+
__name(this, "MigrateCommand");
|
|
2013
|
+
}
|
|
2014
|
+
static paths = [[`migrate`]];
|
|
2015
|
+
fresh = import_clipanion2.Option.Boolean(`--fresh`, false, {
|
|
2016
|
+
description: `whether to delete and recreate database`
|
|
2017
|
+
});
|
|
2018
|
+
refresh = import_clipanion2.Option.Boolean(`--refresh`, false, {
|
|
2019
|
+
description: `whether to drop all tables before running migrations by using rollback function`
|
|
2020
|
+
});
|
|
2021
|
+
async execute() {
|
|
2022
|
+
await import_neko_context4.context_provider.run(async () => {
|
|
2023
|
+
const db2 = db();
|
|
2024
|
+
const schema = db2.getSchema();
|
|
2025
|
+
if (this.fresh) {
|
|
2026
|
+
await db2.dropDatabase(import_neko_config2.config.get("databases.default.database"));
|
|
2027
|
+
await db2.createDatabase(import_neko_config2.config.get("databases.default.database"));
|
|
2028
|
+
logger().info("database dropped and created fresh!");
|
|
2029
|
+
}
|
|
2030
|
+
if (this.refresh && await schema.tableExists("migrations")) {
|
|
2031
|
+
logger().info("reverting all migrations!!");
|
|
2032
|
+
const existing_migrations = await db2.runQuery({
|
|
2033
|
+
sql: "select * from migrations order by created_at DESC",
|
|
2034
|
+
parts: [],
|
|
2035
|
+
bindings: []
|
|
2036
|
+
});
|
|
2037
|
+
const migrationsDir2 = import_neko_config2.config.get("migration.path");
|
|
2038
|
+
for (const migration_record of existing_migrations) {
|
|
2039
|
+
logger().info(`rolling back ${migration_record.filename}`);
|
|
2040
|
+
try {
|
|
2041
|
+
const MigrationClass = (await import(import_path2.default.join(migrationsDir2, migration_record.filename))).default;
|
|
2042
|
+
const migrationInstance = new MigrationClass();
|
|
2043
|
+
await migrationInstance.down(db2.getSchema());
|
|
2293
2044
|
await db2.runQuery({
|
|
2294
|
-
sql: "delete from migrations where
|
|
2045
|
+
sql: "delete from migrations where filename = $1",
|
|
2295
2046
|
parts: [],
|
|
2296
|
-
bindings: [
|
|
2047
|
+
bindings: [migration_record.filename]
|
|
2297
2048
|
});
|
|
2049
|
+
} catch (error) {
|
|
2050
|
+
logger().error(
|
|
2051
|
+
`Failed to rollback migration ${migration_record.filename}: ${error}`
|
|
2052
|
+
);
|
|
2053
|
+
throw error;
|
|
2298
2054
|
}
|
|
2055
|
+
}
|
|
2056
|
+
logger().info(
|
|
2057
|
+
`rolled back ${existing_migrations.length} migrations successfully!`
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2060
|
+
if (!await schema.tableExists("migrations")) {
|
|
2061
|
+
await schema.createTable("migrations", (blueprint) => {
|
|
2062
|
+
blueprint.id();
|
|
2063
|
+
blueprint.timestamps();
|
|
2064
|
+
blueprint.string("filename");
|
|
2065
|
+
blueprint.integer("batch");
|
|
2299
2066
|
});
|
|
2300
2067
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2068
|
+
const migrationsDir = import_neko_config2.config.get("migration.path");
|
|
2069
|
+
let files = [];
|
|
2070
|
+
const dirEntries = await import_promises.default.readdir(migrationsDir);
|
|
2071
|
+
files = dirEntries.filter((entry) => entry.endsWith(".ts") || entry.endsWith(".js")).sort();
|
|
2072
|
+
let batch_number = await db2.runQuery({
|
|
2073
|
+
sql: "select max(batch) as next_batch from migrations",
|
|
2074
|
+
parts: [],
|
|
2075
|
+
bindings: []
|
|
2076
|
+
});
|
|
2077
|
+
batch_number = batch_number[0].next_batch || 0;
|
|
2078
|
+
batch_number++;
|
|
2079
|
+
const migrations = await db2.runQuery({
|
|
2080
|
+
sql: "select * from migrations order by created_at ASC",
|
|
2081
|
+
parts: [],
|
|
2082
|
+
bindings: []
|
|
2083
|
+
});
|
|
2084
|
+
const completed_migrations = migrations.map((r) => r.filename);
|
|
2085
|
+
const pending_migrations = files.filter(
|
|
2086
|
+
(file) => !completed_migrations.includes(file)
|
|
2087
|
+
);
|
|
2088
|
+
let migrated_count = 0;
|
|
2089
|
+
for (const class_to_migrate of pending_migrations) {
|
|
2090
|
+
logger().info(`migrating up ${class_to_migrate}`);
|
|
2091
|
+
const ClassToMigrate = (await import(import_path2.default.join(migrationsDir, class_to_migrate))).default;
|
|
2092
|
+
const c = new ClassToMigrate();
|
|
2093
|
+
await c.up(db2.getSchema());
|
|
2094
|
+
await db2.runQuery({
|
|
2095
|
+
sql: "insert into migrations (filename, batch) values ($1,$2)",
|
|
2096
|
+
parts: [],
|
|
2097
|
+
bindings: [class_to_migrate, batch_number]
|
|
2098
|
+
});
|
|
2099
|
+
migrated_count++;
|
|
2100
|
+
}
|
|
2101
|
+
if (migrated_count === 0) {
|
|
2102
|
+
logger().warn("no migrations to run!");
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
logger().info(`migrated ${migrated_count} migrations successfully!`);
|
|
2106
|
+
return;
|
|
2107
|
+
});
|
|
2303
2108
|
}
|
|
2304
|
-
}
|
|
2109
|
+
};
|
|
2110
|
+
cli().register(MigrateCommand);
|
|
2305
2111
|
|
|
2306
|
-
// src/app/console/migrate/
|
|
2307
|
-
var
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2112
|
+
// src/app/console/migrate/GenerateMigrateCommand.mts
|
|
2113
|
+
var import_clipanion3 = require("clipanion");
|
|
2114
|
+
var import_change_case_all = require("change-case-all");
|
|
2115
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
2116
|
+
var fs2 = __toESM(require("fs/promises"), 1);
|
|
2117
|
+
var import_neko_config3 = require("@devbro/neko-config");
|
|
2118
|
+
var import_handlebars = __toESM(require("handlebars"), 1);
|
|
2119
|
+
var import_url = require("url");
|
|
2120
|
+
var import_meta = {};
|
|
2121
|
+
var GenerateMigrateCommand = class extends import_clipanion3.Command {
|
|
2122
|
+
static {
|
|
2123
|
+
__name(this, "GenerateMigrateCommand");
|
|
2313
2124
|
}
|
|
2314
|
-
|
|
2125
|
+
static paths = [
|
|
2126
|
+
[`generate`, `migrate`],
|
|
2127
|
+
["generate", "migration"]
|
|
2128
|
+
];
|
|
2129
|
+
name = import_clipanion3.Option.String({ required: true });
|
|
2130
|
+
async execute() {
|
|
2131
|
+
const date = /* @__PURE__ */ new Date();
|
|
2132
|
+
const year = date.getFullYear();
|
|
2133
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
2134
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
2135
|
+
const secondsOfDay = String(
|
|
2136
|
+
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
2137
|
+
).padStart(5, "0");
|
|
2138
|
+
const fixed_name = import_change_case_all.Case.snake(this.name);
|
|
2139
|
+
const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;
|
|
2140
|
+
this.context.stdout.write(`creating migration file ${filename}
|
|
2141
|
+
`);
|
|
2142
|
+
await fs2.mkdir(import_neko_config3.config.get("migration.path"), { recursive: true });
|
|
2143
|
+
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
2144
|
+
if (!dirname) {
|
|
2145
|
+
dirname = import_path3.default.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
2146
|
+
}
|
|
2147
|
+
const compiledTemplate = import_handlebars.default.compile(
|
|
2148
|
+
(await fs2.readFile(import_path3.default.join(dirname, "./make_migration.tpl"))).toString()
|
|
2149
|
+
);
|
|
2150
|
+
const template = await compiledTemplate({
|
|
2151
|
+
className: import_change_case_all.Case.pascal(this.name) + "Migration",
|
|
2152
|
+
tableName: import_change_case_all.Case.snake(this.name)
|
|
2153
|
+
});
|
|
2154
|
+
await fs2.writeFile(
|
|
2155
|
+
import_path3.default.join(import_neko_config3.config.get("migration.path"), filename),
|
|
2156
|
+
template
|
|
2157
|
+
);
|
|
2158
|
+
}
|
|
2159
|
+
};
|
|
2160
|
+
cli().register(GenerateMigrateCommand);
|
|
2315
2161
|
|
|
2316
|
-
// src/app/console/
|
|
2317
|
-
var
|
|
2318
|
-
var
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2162
|
+
// src/app/console/migrate/MigrateRollbackCommand.mts
|
|
2163
|
+
var import_clipanion4 = require("clipanion");
|
|
2164
|
+
var import_neko_context5 = require("@devbro/neko-context");
|
|
2165
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
2166
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
2167
|
+
var import_neko_config4 = require("@devbro/neko-config");
|
|
2168
|
+
var t = __toESM(require_lib(), 1);
|
|
2169
|
+
var MigrateRollbackCommand = class extends import_clipanion4.Command {
|
|
2170
|
+
static {
|
|
2171
|
+
__name(this, "MigrateRollbackCommand");
|
|
2172
|
+
}
|
|
2173
|
+
static paths = [[`migrate`, "rollback"]];
|
|
2174
|
+
steps = import_clipanion4.Option.String(`--steps`, "1", {
|
|
2175
|
+
description: `how many migrations to rollback`,
|
|
2176
|
+
validator: t.isNumber()
|
|
2177
|
+
});
|
|
2178
|
+
async execute() {
|
|
2179
|
+
await import_neko_context5.context_provider.run(async () => {
|
|
2180
|
+
const db2 = db();
|
|
2181
|
+
const schema = db2.getSchema();
|
|
2182
|
+
const migrationsDir = import_neko_config4.config.get("migration.path");
|
|
2183
|
+
let files = [];
|
|
2184
|
+
const dirEntries = await import_promises2.default.readdir(migrationsDir);
|
|
2185
|
+
files = dirEntries.filter((entry) => entry.endsWith(".ts")).sort();
|
|
2186
|
+
const migrations = await db2.runQuery({
|
|
2187
|
+
sql: "select * from migrations order by created_at DESC limit $1",
|
|
2188
|
+
parts: [],
|
|
2189
|
+
bindings: [this.steps]
|
|
2190
|
+
});
|
|
2191
|
+
for (const migration of migrations) {
|
|
2192
|
+
const class_to_migrate = migration.filename;
|
|
2193
|
+
logger().info(`rolling back ${class_to_migrate}`);
|
|
2194
|
+
const ClassToMigrate = (await import(import_path4.default.join(migrationsDir, class_to_migrate))).default;
|
|
2195
|
+
const c = new ClassToMigrate();
|
|
2196
|
+
await c.down(db2.getSchema());
|
|
2197
|
+
await db2.runQuery({
|
|
2198
|
+
sql: "delete from migrations where id = $1",
|
|
2199
|
+
parts: [],
|
|
2200
|
+
bindings: [migration.id]
|
|
2201
|
+
});
|
|
2328
2202
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
};
|
|
2206
|
+
cli().register(MigrateRollbackCommand);
|
|
2207
|
+
|
|
2208
|
+
// src/app/console/StartCommand.mts
|
|
2209
|
+
var import_clipanion5 = require("clipanion");
|
|
2210
|
+
var import_neko_config5 = require("@devbro/neko-config");
|
|
2211
|
+
var import_neko_sql = require("@devbro/neko-sql");
|
|
2212
|
+
var StartCommand = class extends import_clipanion5.Command {
|
|
2213
|
+
static {
|
|
2214
|
+
__name(this, "StartCommand");
|
|
2215
|
+
}
|
|
2216
|
+
scheduler = import_clipanion5.Option.Boolean(`--scheduler`, false);
|
|
2217
|
+
cron = import_clipanion5.Option.Boolean(`--cron`, false);
|
|
2218
|
+
http = import_clipanion5.Option.Boolean(`--http`, false);
|
|
2219
|
+
queue = import_clipanion5.Option.Boolean(`--queue`, false);
|
|
2220
|
+
all = import_clipanion5.Option.Boolean("--all", false);
|
|
2221
|
+
static paths = [[`start`]];
|
|
2222
|
+
async execute() {
|
|
2223
|
+
if ([this.all, this.http, this.scheduler || this.cron, this.queue].filter(
|
|
2224
|
+
(x) => x
|
|
2225
|
+
).length == 0) {
|
|
2226
|
+
this.context.stdout.write(
|
|
2227
|
+
`No service was selected. please check -h for details
|
|
2341
2228
|
`
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2229
|
+
);
|
|
2230
|
+
return;
|
|
2231
|
+
}
|
|
2232
|
+
logger().info(`Starting Server
|
|
2346
2233
|
`);
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2234
|
+
import_neko_sql.PostgresqlConnection.defaults.idleTimeoutMillis = 1e4;
|
|
2235
|
+
if (this.scheduler || this.cron || this.all) {
|
|
2236
|
+
logger().info(`starting scheduler
|
|
2350
2237
|
`);
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
}
|
|
2358
|
-
}
|
|
2359
|
-
if (this.http || this.all) {
|
|
2360
|
-
const server = httpServer();
|
|
2361
|
-
await server.listen(import_neko_config5.config.get("port"), () => {
|
|
2362
|
-
logger().info(
|
|
2363
|
-
"Server is running on http://localhost:" + import_neko_config5.config.get("port")
|
|
2364
|
-
);
|
|
2365
|
-
});
|
|
2366
|
-
}
|
|
2238
|
+
scheduler().start();
|
|
2239
|
+
}
|
|
2240
|
+
if (this.queue || this.all) {
|
|
2241
|
+
const config_queues = import_neko_config5.config.get("queues");
|
|
2242
|
+
for (const [name, conf] of Object.entries(config_queues)) {
|
|
2243
|
+
queue(name).start();
|
|
2367
2244
|
}
|
|
2368
|
-
}
|
|
2369
|
-
|
|
2245
|
+
}
|
|
2246
|
+
if (this.http || this.all) {
|
|
2247
|
+
const server = httpServer();
|
|
2248
|
+
await server.listen(import_neko_config5.config.get("port"), () => {
|
|
2249
|
+
logger().info(
|
|
2250
|
+
"Server is running on http://localhost:" + import_neko_config5.config.get("port")
|
|
2251
|
+
);
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2370
2254
|
}
|
|
2371
|
-
}
|
|
2255
|
+
};
|
|
2256
|
+
cli().register(StartCommand);
|
|
2372
2257
|
|
|
2373
2258
|
// src/app/console/DefaultCommand.mts
|
|
2374
|
-
var import_clipanion6
|
|
2375
|
-
var
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
}
|
|
2384
|
-
static usage = import_clipanion6.Command.Usage({
|
|
2385
|
-
category: `Main`,
|
|
2386
|
-
description: `server management command line.`,
|
|
2387
|
-
details: `
|
|
2259
|
+
var import_clipanion6 = require("clipanion");
|
|
2260
|
+
var DefaultCommand = class extends import_clipanion6.Command {
|
|
2261
|
+
static {
|
|
2262
|
+
__name(this, "DefaultCommand");
|
|
2263
|
+
}
|
|
2264
|
+
static usage = import_clipanion6.Command.Usage({
|
|
2265
|
+
category: `Main`,
|
|
2266
|
+
description: `server management command line.`,
|
|
2267
|
+
details: `
|
|
2388
2268
|
The base command for running and managing your server.
|
|
2389
2269
|
|
|
2390
2270
|
Make sure you understand how things work.
|
|
2391
2271
|
`,
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2272
|
+
examples: []
|
|
2273
|
+
});
|
|
2274
|
+
async execute() {
|
|
2275
|
+
const commandList = cli().registrations;
|
|
2276
|
+
const paths = [];
|
|
2277
|
+
commandList.forEach(
|
|
2278
|
+
(index, val) => paths.push(index.builder.paths[0]?.join(" ") || "")
|
|
2279
|
+
);
|
|
2280
|
+
console.log("Available commands:");
|
|
2281
|
+
for (const cmd of paths) {
|
|
2282
|
+
if (cmd) {
|
|
2283
|
+
console.log(cmd);
|
|
2406
2284
|
}
|
|
2407
|
-
}
|
|
2408
|
-
cli().register(DefaultCommand);
|
|
2285
|
+
}
|
|
2409
2286
|
}
|
|
2410
|
-
}
|
|
2287
|
+
};
|
|
2288
|
+
cli().register(DefaultCommand);
|
|
2411
2289
|
|
|
2412
|
-
// src/app/console/KeyGenerateCommand.mts
|
|
2413
|
-
var import_clipanion7
|
|
2414
|
-
var
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
static paths = [[`generate`, "key"]];
|
|
2427
|
-
static usage = import_clipanion7.Command.Usage({
|
|
2428
|
-
category: `Main`,
|
|
2429
|
-
description: `generate keys`,
|
|
2430
|
-
details: `
|
|
2290
|
+
// src/app/console/KeyGenerateCommand.mts
|
|
2291
|
+
var import_clipanion7 = require("clipanion");
|
|
2292
|
+
var import_crypto = require("crypto");
|
|
2293
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
2294
|
+
var import_path5 = __toESM(require("path"), 1);
|
|
2295
|
+
var KeyGenerateCommand = class extends import_clipanion7.Command {
|
|
2296
|
+
static {
|
|
2297
|
+
__name(this, "KeyGenerateCommand");
|
|
2298
|
+
}
|
|
2299
|
+
static paths = [[`generate`, "key"]];
|
|
2300
|
+
static usage = import_clipanion7.Command.Usage({
|
|
2301
|
+
category: `Main`,
|
|
2302
|
+
description: `generate keys`,
|
|
2303
|
+
details: `
|
|
2431
2304
|
This command generates RSA key pair for JWT signing.
|
|
2432
2305
|
Use --rotate flag to preserve old public key.
|
|
2433
2306
|
`,
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
}
|
|
2455
|
-
});
|
|
2456
|
-
let envfile = "";
|
|
2457
|
-
try {
|
|
2458
|
-
envfile = await import_promises3.default.readFile(import_path5.default.join(process.cwd(), ".env"), "utf-8");
|
|
2459
|
-
} catch {
|
|
2460
|
-
}
|
|
2461
|
-
let old_public_key = envfile.match(/^jwt_secret_public=(.*)/m);
|
|
2462
|
-
envfile = this.addEnvParam(
|
|
2463
|
-
envfile,
|
|
2464
|
-
"jwt_secret_public",
|
|
2465
|
-
this.stripPemHeaders(publicKey)
|
|
2466
|
-
);
|
|
2467
|
-
envfile = this.addEnvParam(
|
|
2468
|
-
envfile,
|
|
2469
|
-
"jwt_secret_private",
|
|
2470
|
-
this.stripPemHeaders(privateKey)
|
|
2471
|
-
);
|
|
2472
|
-
if (this.rotate && old_public_key && old_public_key[1]) {
|
|
2473
|
-
envfile = this.addEnvParam(
|
|
2474
|
-
envfile,
|
|
2475
|
-
"jwt_secret_public_retired",
|
|
2476
|
-
old_public_key[1]
|
|
2477
|
-
);
|
|
2478
|
-
}
|
|
2479
|
-
await import_promises3.default.writeFile(import_path5.default.join(process.cwd(), ".env"), envfile, "utf-8");
|
|
2307
|
+
examples: [
|
|
2308
|
+
[`Generate new keys`, `generate key`],
|
|
2309
|
+
[`Rotate existing keys`, `generate key --rotate`]
|
|
2310
|
+
]
|
|
2311
|
+
});
|
|
2312
|
+
rotate = import_clipanion7.Option.Boolean(`--rotate`, false, {
|
|
2313
|
+
description: `Rotate existing keys (backup old keys before replacement)`
|
|
2314
|
+
});
|
|
2315
|
+
async execute() {
|
|
2316
|
+
logger().info("generating keys for jwt token and adding to .env file");
|
|
2317
|
+
const { publicKey, privateKey } = (0, import_crypto.generateKeyPairSync)("rsa", {
|
|
2318
|
+
modulusLength: 2048,
|
|
2319
|
+
// 2048-bit key is standard for RS256
|
|
2320
|
+
publicKeyEncoding: {
|
|
2321
|
+
type: "spki",
|
|
2322
|
+
format: "pem"
|
|
2323
|
+
},
|
|
2324
|
+
privateKeyEncoding: {
|
|
2325
|
+
type: "pkcs8",
|
|
2326
|
+
format: "pem"
|
|
2480
2327
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2328
|
+
});
|
|
2329
|
+
let envfile = "";
|
|
2330
|
+
try {
|
|
2331
|
+
envfile = await import_promises3.default.readFile(import_path5.default.join(process.cwd(), ".env"), "utf-8");
|
|
2332
|
+
} catch {
|
|
2333
|
+
}
|
|
2334
|
+
let old_public_key = envfile.match(/^jwt_secret_public=(.*)/m);
|
|
2335
|
+
envfile = this.addEnvParam(
|
|
2336
|
+
envfile,
|
|
2337
|
+
"jwt_secret_public",
|
|
2338
|
+
this.stripPemHeaders(publicKey)
|
|
2339
|
+
);
|
|
2340
|
+
envfile = this.addEnvParam(
|
|
2341
|
+
envfile,
|
|
2342
|
+
"jwt_secret_private",
|
|
2343
|
+
this.stripPemHeaders(privateKey)
|
|
2344
|
+
);
|
|
2345
|
+
if (this.rotate && old_public_key && old_public_key[1]) {
|
|
2346
|
+
envfile = this.addEnvParam(
|
|
2347
|
+
envfile,
|
|
2348
|
+
"jwt_secret_public_retired",
|
|
2349
|
+
old_public_key[1]
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
await import_promises3.default.writeFile(import_path5.default.join(process.cwd(), ".env"), envfile, "utf-8");
|
|
2353
|
+
}
|
|
2354
|
+
addEnvParam(file, key, value) {
|
|
2355
|
+
let regex = new RegExp(`^${key}=.*`, "gm");
|
|
2356
|
+
file = file.replace(regex, `${key}=${value}`);
|
|
2357
|
+
const match = file.match(regex);
|
|
2358
|
+
if (!match) {
|
|
2359
|
+
file = file + `
|
|
2487
2360
|
${key}=${value}`;
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
}
|
|
2491
|
-
stripPemHeaders(pem) {
|
|
2492
|
-
return pem.replace(/-----BEGIN [\w\s]+-----/g, "").replace(/-----END [\w\s]+-----/g, "").replace(/\r?\n|\r/g, "");
|
|
2493
|
-
}
|
|
2494
|
-
};
|
|
2495
|
-
cli().register(KeyGenerateCommand);
|
|
2361
|
+
}
|
|
2362
|
+
return file;
|
|
2496
2363
|
}
|
|
2497
|
-
|
|
2364
|
+
stripPemHeaders(pem) {
|
|
2365
|
+
return pem.replace(/-----BEGIN [\w\s]+-----/g, "").replace(/-----END [\w\s]+-----/g, "").replace(/\r?\n|\r/g, "");
|
|
2366
|
+
}
|
|
2367
|
+
};
|
|
2368
|
+
cli().register(KeyGenerateCommand);
|
|
2498
2369
|
|
|
2499
2370
|
// src/app/console/generate/GenerateControllerCommand.mts
|
|
2500
|
-
var import_clipanion8
|
|
2501
|
-
var
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
2531
|
-
).padStart(5, "0");
|
|
2532
|
-
const fixed_name = import_change_case_all2.Case.snake(this.name);
|
|
2533
|
-
const filename = `${import_change_case_all2.Case.capital(this.name)}Controller.ts`;
|
|
2534
|
-
this.context.stdout.write(`creating migration file ${filename}
|
|
2371
|
+
var import_clipanion8 = require("clipanion");
|
|
2372
|
+
var import_change_case_all2 = require("change-case-all");
|
|
2373
|
+
var import_path6 = __toESM(require("path"), 1);
|
|
2374
|
+
var fs5 = __toESM(require("fs/promises"), 1);
|
|
2375
|
+
var import_neko_config6 = require("@devbro/neko-config");
|
|
2376
|
+
var import_handlebars2 = __toESM(require("handlebars"), 1);
|
|
2377
|
+
var import_url2 = require("url");
|
|
2378
|
+
var import_pluralize = __toESM(require("pluralize"), 1);
|
|
2379
|
+
var import_meta2 = {};
|
|
2380
|
+
var GenerateControllerCommand = class extends import_clipanion8.Command {
|
|
2381
|
+
static {
|
|
2382
|
+
__name(this, "GenerateControllerCommand");
|
|
2383
|
+
}
|
|
2384
|
+
static paths = [
|
|
2385
|
+
[`make`, `controller`],
|
|
2386
|
+
[`generate`, `controller`]
|
|
2387
|
+
];
|
|
2388
|
+
name = import_clipanion8.Option.String({ required: true });
|
|
2389
|
+
async execute() {
|
|
2390
|
+
const rootDir = process.cwd();
|
|
2391
|
+
const date = /* @__PURE__ */ new Date();
|
|
2392
|
+
const year = date.getFullYear();
|
|
2393
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
2394
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
2395
|
+
const secondsOfDay = String(
|
|
2396
|
+
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
2397
|
+
).padStart(5, "0");
|
|
2398
|
+
const fixed_name = import_change_case_all2.Case.snake(this.name);
|
|
2399
|
+
const filename = `${import_change_case_all2.Case.capital(this.name)}Controller.ts`;
|
|
2400
|
+
this.context.stdout.write(`creating migration file ${filename}
|
|
2535
2401
|
`);
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
}
|
|
2554
|
-
};
|
|
2555
|
-
cli().register(GenerateControllerCommand);
|
|
2402
|
+
await fs5.mkdir(import_neko_config6.config.get("migration.path"), { recursive: true });
|
|
2403
|
+
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
2404
|
+
if (!dirname) {
|
|
2405
|
+
dirname = import_path6.default.dirname((0, import_url2.fileURLToPath)(import_meta2.url));
|
|
2406
|
+
}
|
|
2407
|
+
const compiledTemplate = import_handlebars2.default.compile(
|
|
2408
|
+
(await fs5.readFile(import_path6.default.join(dirname, "./controller.tpl"))).toString()
|
|
2409
|
+
);
|
|
2410
|
+
const template = await compiledTemplate({
|
|
2411
|
+
className: import_change_case_all2.Case.pascal(this.name),
|
|
2412
|
+
classNameLower: import_change_case_all2.Case.snake(this.name),
|
|
2413
|
+
routeName: import_change_case_all2.Case.kebab((0, import_pluralize.default)(this.name))
|
|
2414
|
+
});
|
|
2415
|
+
await fs5.writeFile(
|
|
2416
|
+
import_path6.default.join(rootDir, "src/app/controllers", filename),
|
|
2417
|
+
template
|
|
2418
|
+
);
|
|
2556
2419
|
}
|
|
2557
|
-
}
|
|
2420
|
+
};
|
|
2421
|
+
cli().register(GenerateControllerCommand);
|
|
2422
|
+
|
|
2423
|
+
// src/app/console/generate/GenerateApiDocsCommand.mts
|
|
2424
|
+
var import_clipanion9 = require("clipanion");
|
|
2425
|
+
var import_path7 = __toESM(require("path"), 1);
|
|
2426
|
+
var fs6 = __toESM(require("fs/promises"), 1);
|
|
2558
2427
|
|
|
2559
2428
|
// src/config.mts
|
|
2560
2429
|
var config_exports = {};
|
|
2561
|
-
|
|
2562
|
-
"src/config.mts"() {
|
|
2563
|
-
"use strict";
|
|
2564
|
-
__reExport(config_exports, require("@devbro/neko-config"));
|
|
2565
|
-
}
|
|
2566
|
-
});
|
|
2430
|
+
__reExport(config_exports, require("@devbro/neko-config"));
|
|
2567
2431
|
|
|
2568
2432
|
// src/app/console/generate/GenerateApiDocsCommand.mts
|
|
2569
|
-
var
|
|
2570
|
-
var
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
GenerateApiDocsCommand = class extends import_clipanion9.Command {
|
|
2580
|
-
static {
|
|
2581
|
-
__name(this, "GenerateApiDocsCommand");
|
|
2582
|
-
}
|
|
2583
|
-
static paths = [[`generate`, `apidocs`]];
|
|
2584
|
-
static usage = import_clipanion9.Command.Usage({
|
|
2585
|
-
category: `Generate`,
|
|
2586
|
-
description: `Generate OpenAPI documentation from routes`,
|
|
2587
|
-
details: `
|
|
2433
|
+
var import_neko_helper4 = require("@devbro/neko-helper");
|
|
2434
|
+
var GenerateApiDocsCommand = class extends import_clipanion9.Command {
|
|
2435
|
+
static {
|
|
2436
|
+
__name(this, "GenerateApiDocsCommand");
|
|
2437
|
+
}
|
|
2438
|
+
static paths = [[`generate`, `apidocs`]];
|
|
2439
|
+
static usage = import_clipanion9.Command.Usage({
|
|
2440
|
+
category: `Generate`,
|
|
2441
|
+
description: `Generate OpenAPI documentation from routes`,
|
|
2442
|
+
details: `
|
|
2588
2443
|
This command utility generates OpenAPI 3.0 specification documentation by analyzing
|
|
2589
2444
|
your application's routes and merging with example files.
|
|
2590
2445
|
|
|
@@ -2617,597 +2472,586 @@ api_docs: {
|
|
|
2617
2472
|
|
|
2618
2473
|
\`\`\`
|
|
2619
2474
|
`,
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2475
|
+
examples: [
|
|
2476
|
+
[
|
|
2477
|
+
`Generate from routes`,
|
|
2478
|
+
`$0 generate apidocs generate-from-routes --output path/to/output.json`
|
|
2479
|
+
],
|
|
2480
|
+
[
|
|
2481
|
+
`Generate base spec`,
|
|
2482
|
+
`$0 generate apidocs generate-base --output path/to/output.json`
|
|
2483
|
+
],
|
|
2484
|
+
[`Merge files`, `$0 generate apidocs merge-files`],
|
|
2485
|
+
[`Show help`, `$0 generate apidocs --help`]
|
|
2486
|
+
]
|
|
2487
|
+
});
|
|
2488
|
+
subcommand = import_clipanion9.Option.String({ required: false });
|
|
2489
|
+
output = import_clipanion9.Option.String(`--output,-o`, {
|
|
2490
|
+
description: `Output file path for generated documentation`
|
|
2491
|
+
});
|
|
2492
|
+
config = import_clipanion9.Option.String(`--config,-c`, {
|
|
2493
|
+
description: `Path in config to get details from (default: api_docs)`,
|
|
2494
|
+
required: false
|
|
2495
|
+
});
|
|
2496
|
+
async execute() {
|
|
2497
|
+
if (!this.subcommand) {
|
|
2498
|
+
this.context.stdout.write(
|
|
2499
|
+
this.constructor.usage?.toString() || "No help available\n"
|
|
2500
|
+
);
|
|
2501
|
+
return 0;
|
|
2502
|
+
}
|
|
2503
|
+
switch (this.subcommand) {
|
|
2504
|
+
case "generate-from-routes":
|
|
2505
|
+
return await this.executeGenerateFromRoutes();
|
|
2506
|
+
case "generate-base":
|
|
2507
|
+
return await this.executeGenerateBase();
|
|
2508
|
+
case "merge-files":
|
|
2509
|
+
return await this.executeMergeFiles();
|
|
2510
|
+
default:
|
|
2511
|
+
this.context.stderr.write(`Unknown subcommand: ${this.subcommand}
|
|
2657
2512
|
`);
|
|
2658
|
-
this.context.stdout.write(
|
|
2659
|
-
this.constructor.usage?.toString() || "No help available\n"
|
|
2660
|
-
);
|
|
2661
|
-
return 1;
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
async executeGenerateFromRoutes() {
|
|
2665
2513
|
this.context.stdout.write(
|
|
2666
|
-
|
|
2667
|
-
`
|
|
2668
|
-
);
|
|
2669
|
-
const openApiSpec = this.generateFromRoutes();
|
|
2670
|
-
const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_from_routes.json");
|
|
2671
|
-
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2672
|
-
await fs6.writeFile(
|
|
2673
|
-
outputPath,
|
|
2674
|
-
JSON.stringify(openApiSpec, null, 2),
|
|
2675
|
-
"utf-8"
|
|
2514
|
+
this.constructor.usage?.toString() || "No help available\n"
|
|
2676
2515
|
);
|
|
2677
|
-
|
|
2678
|
-
|
|
2516
|
+
return 1;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
async executeGenerateFromRoutes() {
|
|
2520
|
+
this.context.stdout.write(
|
|
2521
|
+
`Generating OpenAPI documentation from routes...
|
|
2679
2522
|
`
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2523
|
+
);
|
|
2524
|
+
const openApiSpec = this.generateFromRoutes();
|
|
2525
|
+
const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_from_routes.json");
|
|
2526
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2527
|
+
await fs6.writeFile(
|
|
2528
|
+
outputPath,
|
|
2529
|
+
JSON.stringify(openApiSpec, null, 2),
|
|
2530
|
+
"utf-8"
|
|
2531
|
+
);
|
|
2532
|
+
this.context.stdout.write(
|
|
2533
|
+
`OpenAPI routes documentation generated at: ${outputPath}
|
|
2683
2534
|
`
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
}
|
|
2687
|
-
|
|
2688
|
-
|
|
2535
|
+
);
|
|
2536
|
+
this.context.stdout.write(
|
|
2537
|
+
`Total routes documented: ${Object.keys(openApiSpec.paths).length}
|
|
2538
|
+
`
|
|
2539
|
+
);
|
|
2540
|
+
return 0;
|
|
2541
|
+
}
|
|
2542
|
+
async executeGenerateBase() {
|
|
2543
|
+
this.context.stdout.write(`Generating base OpenAPI specification...
|
|
2689
2544
|
`);
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2545
|
+
const baseSpec = this.getBaseOpenApiSpec();
|
|
2546
|
+
const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_base.json");
|
|
2547
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2548
|
+
await fs6.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), "utf-8");
|
|
2549
|
+
this.context.stdout.write(
|
|
2550
|
+
`Base OpenAPI specification generated at: ${outputPath}
|
|
2696
2551
|
`
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2552
|
+
);
|
|
2553
|
+
return 0;
|
|
2554
|
+
}
|
|
2555
|
+
async executeMergeFiles() {
|
|
2556
|
+
this.context.stdout.write(`Merging OpenAPI files...
|
|
2702
2557
|
`);
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2558
|
+
let configPath = this.config || "api_docs";
|
|
2559
|
+
const files_to_merge = config_exports.config.get(`${configPath}.merge_files`);
|
|
2560
|
+
let final_api_docs = {};
|
|
2561
|
+
for (const file_path of files_to_merge) {
|
|
2562
|
+
try {
|
|
2563
|
+
const file_json = JSON.parse(await fs6.readFile(file_path, "utf8"));
|
|
2564
|
+
final_api_docs = import_neko_helper4.Arr.deepMerge(final_api_docs, file_json);
|
|
2565
|
+
this.context.stdout.write(` Merged: ${file_path}
|
|
2711
2566
|
`);
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
`
|
|
2716
|
-
);
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
const outputPath = this.output || config_exports.config.get(`${configPath}.output`);
|
|
2720
|
-
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2721
|
-
await fs6.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));
|
|
2722
|
-
this.context.stdout.write(
|
|
2723
|
-
`Final OpenAPI document written to: ${outputPath}
|
|
2567
|
+
} catch (error) {
|
|
2568
|
+
this.context.stderr.write(
|
|
2569
|
+
` Warning: Could not read ${file_path}: ${error.message}
|
|
2724
2570
|
`
|
|
2725
2571
|
);
|
|
2726
|
-
return 0;
|
|
2727
2572
|
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2573
|
+
}
|
|
2574
|
+
const outputPath = this.output || config_exports.config.get(`${configPath}.output`);
|
|
2575
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2576
|
+
await fs6.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));
|
|
2577
|
+
this.context.stdout.write(
|
|
2578
|
+
`Final OpenAPI document written to: ${outputPath}
|
|
2579
|
+
`
|
|
2580
|
+
);
|
|
2581
|
+
return 0;
|
|
2582
|
+
}
|
|
2583
|
+
extractParameters(routePath) {
|
|
2584
|
+
const paramRegex = /:([a-zA-Z0-9_]+)/g;
|
|
2585
|
+
const parameters = [];
|
|
2586
|
+
let match;
|
|
2587
|
+
while ((match = paramRegex.exec(routePath)) !== null) {
|
|
2588
|
+
parameters.push({
|
|
2589
|
+
name: match[1],
|
|
2590
|
+
in: "path",
|
|
2591
|
+
required: true,
|
|
2592
|
+
schema: {
|
|
2593
|
+
type: "string"
|
|
2594
|
+
},
|
|
2595
|
+
description: `Path parameter ${match[1]}`
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2598
|
+
return parameters;
|
|
2599
|
+
}
|
|
2600
|
+
generateFromRoutes() {
|
|
2601
|
+
const openApiSpec = {
|
|
2602
|
+
paths: {}
|
|
2603
|
+
};
|
|
2604
|
+
const routes = router().routes;
|
|
2605
|
+
for (const route of routes) {
|
|
2606
|
+
const routePath = route.path;
|
|
2607
|
+
const openApiPath = routePath.replace(/\/$/g, "");
|
|
2608
|
+
if (!openApiSpec.paths[openApiPath]) {
|
|
2609
|
+
openApiSpec.paths[openApiPath] = {};
|
|
2610
|
+
}
|
|
2611
|
+
for (const method of route.methods) {
|
|
2612
|
+
const lowerMethod = method.toLowerCase();
|
|
2613
|
+
if (lowerMethod === "head") {
|
|
2614
|
+
continue;
|
|
2742
2615
|
}
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2616
|
+
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
2617
|
+
summary: `${routePath}`,
|
|
2618
|
+
description: `Endpoint for ${method} ${routePath}`,
|
|
2619
|
+
security: [],
|
|
2620
|
+
parameters: this.extractParameters(routePath),
|
|
2621
|
+
responses: {}
|
|
2748
2622
|
};
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
for (const method of route.methods) {
|
|
2757
|
-
const lowerMethod = method.toLowerCase();
|
|
2758
|
-
if (lowerMethod === "head") {
|
|
2759
|
-
continue;
|
|
2760
|
-
}
|
|
2761
|
-
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
2762
|
-
summary: `${routePath}`,
|
|
2763
|
-
description: `Endpoint for ${method} ${routePath}`,
|
|
2764
|
-
security: [],
|
|
2765
|
-
parameters: this.extractParameters(routePath),
|
|
2766
|
-
responses: {}
|
|
2767
|
-
};
|
|
2768
|
-
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
2769
|
-
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
2770
|
-
required: true,
|
|
2771
|
-
content: {
|
|
2772
|
-
"application/json": {
|
|
2773
|
-
schema: {
|
|
2774
|
-
type: "object"
|
|
2775
|
-
}
|
|
2776
|
-
}
|
|
2623
|
+
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
2624
|
+
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
2625
|
+
required: true,
|
|
2626
|
+
content: {
|
|
2627
|
+
"application/json": {
|
|
2628
|
+
schema: {
|
|
2629
|
+
type: "object"
|
|
2777
2630
|
}
|
|
2778
|
-
};
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
return openApiSpec;
|
|
2783
|
-
}
|
|
2784
|
-
getBaseOpenApiSpec() {
|
|
2785
|
-
const openApiSpec = {
|
|
2786
|
-
openapi: "3.0.0",
|
|
2787
|
-
info: {
|
|
2788
|
-
title: "API Documentation",
|
|
2789
|
-
version: "1.0.0",
|
|
2790
|
-
description: "Auto-generated API documentation"
|
|
2791
|
-
},
|
|
2792
|
-
servers: [
|
|
2793
|
-
{
|
|
2794
|
-
url: "/",
|
|
2795
|
-
description: "Local server"
|
|
2796
|
-
}
|
|
2797
|
-
],
|
|
2798
|
-
components: {
|
|
2799
|
-
securitySchemes: {
|
|
2800
|
-
bearerAuth: {
|
|
2801
|
-
type: "http",
|
|
2802
|
-
scheme: "bearer",
|
|
2803
|
-
bearerFormat: "JWT",
|
|
2804
|
-
description: "JWT token authentication"
|
|
2805
2631
|
}
|
|
2806
2632
|
}
|
|
2807
|
-
}
|
|
2808
|
-
security: [
|
|
2809
|
-
{
|
|
2810
|
-
bearerAuth: []
|
|
2811
|
-
}
|
|
2812
|
-
],
|
|
2813
|
-
paths: {}
|
|
2814
|
-
};
|
|
2815
|
-
return openApiSpec;
|
|
2816
|
-
}
|
|
2817
|
-
};
|
|
2818
|
-
cli().register(GenerateApiDocsCommand);
|
|
2819
|
-
}
|
|
2820
|
-
});
|
|
2821
|
-
|
|
2822
|
-
// src/app/console/generate/index.mts
|
|
2823
|
-
var init_generate = __esm({
|
|
2824
|
-
"src/app/console/generate/index.mts"() {
|
|
2825
|
-
"use strict";
|
|
2826
|
-
init_GenerateControllerCommand();
|
|
2827
|
-
init_GenerateApiDocsCommand();
|
|
2828
|
-
}
|
|
2829
|
-
});
|
|
2830
|
-
|
|
2831
|
-
// src/app/console/project/CreateProjectCommand.mts
|
|
2832
|
-
var import_clipanion10, import_change_case_all3, import_path8, fs7, import_url3, import_handlebars3, import_child_process, import_prompts, import_meta3, CreateProjectCommand;
|
|
2833
|
-
var init_CreateProjectCommand = __esm({
|
|
2834
|
-
"src/app/console/project/CreateProjectCommand.mts"() {
|
|
2835
|
-
"use strict";
|
|
2836
|
-
import_clipanion10 = require("clipanion");
|
|
2837
|
-
import_change_case_all3 = require("change-case-all");
|
|
2838
|
-
import_path8 = __toESM(require("path"), 1);
|
|
2839
|
-
fs7 = __toESM(require("fs/promises"), 1);
|
|
2840
|
-
import_url3 = require("url");
|
|
2841
|
-
import_handlebars3 = __toESM(require("handlebars"), 1);
|
|
2842
|
-
import_child_process = require("child_process");
|
|
2843
|
-
import_prompts = require("@inquirer/prompts");
|
|
2844
|
-
import_meta3 = {};
|
|
2845
|
-
CreateProjectCommand = class extends import_clipanion10.Command {
|
|
2846
|
-
static {
|
|
2847
|
-
__name(this, "CreateProjectCommand");
|
|
2848
|
-
}
|
|
2849
|
-
static paths = [[`create`, `project`]];
|
|
2850
|
-
static usage = import_clipanion10.Command.Usage({
|
|
2851
|
-
category: `Project`,
|
|
2852
|
-
description: `Create a new project`,
|
|
2853
|
-
details: `
|
|
2854
|
-
This command creates a new project with the specified name at the given path.
|
|
2855
|
-
If no path is provided, the project will be created in the current directory.
|
|
2856
|
-
`,
|
|
2857
|
-
examples: [
|
|
2858
|
-
[
|
|
2859
|
-
`Create a new project in specified directory`,
|
|
2860
|
-
`create project --path /path/to/my-project --git`
|
|
2861
|
-
],
|
|
2862
|
-
[
|
|
2863
|
-
`Create a new project at a specific path with git initialized`,
|
|
2864
|
-
`create project --path /path/to/my-project --git`
|
|
2865
|
-
]
|
|
2866
|
-
]
|
|
2867
|
-
});
|
|
2868
|
-
projectPath = import_clipanion10.Option.String("--path", { required: true });
|
|
2869
|
-
git = import_clipanion10.Option.Boolean(`--git`, false, {
|
|
2870
|
-
description: `Initialize a git repository in the new project`
|
|
2871
|
-
});
|
|
2872
|
-
async folderExists(folderPath) {
|
|
2873
|
-
try {
|
|
2874
|
-
const stats = await fs7.stat(folderPath);
|
|
2875
|
-
return stats.isDirectory();
|
|
2876
|
-
} catch (error) {
|
|
2877
|
-
if (error.code === "ENOENT") {
|
|
2878
|
-
return false;
|
|
2879
|
-
}
|
|
2880
|
-
throw error;
|
|
2633
|
+
};
|
|
2881
2634
|
}
|
|
2882
2635
|
}
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
},
|
|
2899
|
-
{
|
|
2900
|
-
name: "Zod",
|
|
2901
|
-
value: "zod",
|
|
2902
|
-
description: "https://zod.dev/"
|
|
2903
|
-
},
|
|
2904
|
-
new import_prompts.Separator(),
|
|
2905
|
-
{
|
|
2906
|
-
name: "None",
|
|
2907
|
-
value: "none",
|
|
2908
|
-
disabled: false
|
|
2909
|
-
}
|
|
2910
|
-
]
|
|
2911
|
-
});
|
|
2912
|
-
await fs7.mkdir(projectPath, { recursive: true });
|
|
2913
|
-
console.log(`Created project directory at: ${projectPath}`);
|
|
2914
|
-
const dirname = typeof __dirname === "undefined" ? import_path8.default.dirname((0, import_url3.fileURLToPath)(import_meta3.url)) : __dirname;
|
|
2915
|
-
let basePath = import_path8.default.join(dirname, `./base_project`);
|
|
2916
|
-
if (await this.folderExists(basePath) === false) {
|
|
2917
|
-
basePath = import_path8.default.join(dirname, `../app/console/project/base_project`);
|
|
2636
|
+
}
|
|
2637
|
+
return openApiSpec;
|
|
2638
|
+
}
|
|
2639
|
+
getBaseOpenApiSpec() {
|
|
2640
|
+
const openApiSpec = {
|
|
2641
|
+
openapi: "3.0.0",
|
|
2642
|
+
info: {
|
|
2643
|
+
title: "API Documentation",
|
|
2644
|
+
version: "1.0.0",
|
|
2645
|
+
description: "Auto-generated API documentation"
|
|
2646
|
+
},
|
|
2647
|
+
servers: [
|
|
2648
|
+
{
|
|
2649
|
+
url: "/",
|
|
2650
|
+
description: "Local server"
|
|
2918
2651
|
}
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
packageJson.name = import_change_case_all3.Case.snake(import_path8.default.basename(projectPath));
|
|
2928
|
-
await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2929
|
-
console.log(`Updated package.json with project name: ${packageJson.name}`);
|
|
2930
|
-
if (this.git) {
|
|
2931
|
-
try {
|
|
2932
|
-
(0, import_child_process.execSync)(
|
|
2933
|
-
'git init; git add --all; git commit --allow-empty -m "chore: first commit for pashmak"',
|
|
2934
|
-
{
|
|
2935
|
-
cwd: projectPath
|
|
2936
|
-
}
|
|
2937
|
-
);
|
|
2938
|
-
} catch (error) {
|
|
2939
|
-
console.error(`Failed to create project.`, error);
|
|
2940
|
-
return 1;
|
|
2652
|
+
],
|
|
2653
|
+
components: {
|
|
2654
|
+
securitySchemes: {
|
|
2655
|
+
bearerAuth: {
|
|
2656
|
+
type: "http",
|
|
2657
|
+
scheme: "bearer",
|
|
2658
|
+
bearerFormat: "JWT",
|
|
2659
|
+
description: "JWT token authentication"
|
|
2941
2660
|
}
|
|
2942
2661
|
}
|
|
2943
|
-
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
const srcPath = import_path8.default.join(src, file.name);
|
|
2948
|
-
const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path8.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path8.default.join(dest, file.name);
|
|
2949
|
-
if (file.isDirectory()) {
|
|
2950
|
-
await fs7.mkdir(destPath, { recursive: true });
|
|
2951
|
-
await this.processTplFolder(srcPath, destPath, data);
|
|
2952
|
-
} else if (file.name.endsWith(".tpl")) {
|
|
2953
|
-
await this.processTplFile(srcPath, destPath, data);
|
|
2954
|
-
} else {
|
|
2955
|
-
throw new Error(
|
|
2956
|
-
"unexpected non tpl file: " + srcPath + " " + file.name
|
|
2957
|
-
);
|
|
2958
|
-
}
|
|
2662
|
+
},
|
|
2663
|
+
security: [
|
|
2664
|
+
{
|
|
2665
|
+
bearerAuth: []
|
|
2959
2666
|
}
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
import_handlebars3.default.registerHelper("eq", (a, b) => a === b);
|
|
2963
|
-
const compiledTemplate = import_handlebars3.default.compile(
|
|
2964
|
-
(await fs7.readFile(src)).toString()
|
|
2965
|
-
);
|
|
2966
|
-
const template = await compiledTemplate(data);
|
|
2967
|
-
await fs7.writeFile(dest, template);
|
|
2968
|
-
}
|
|
2667
|
+
],
|
|
2668
|
+
paths: {}
|
|
2969
2669
|
};
|
|
2670
|
+
return openApiSpec;
|
|
2970
2671
|
}
|
|
2971
|
-
}
|
|
2672
|
+
};
|
|
2673
|
+
cli().register(GenerateApiDocsCommand);
|
|
2972
2674
|
|
|
2973
|
-
// src/app/console/
|
|
2974
|
-
var
|
|
2975
|
-
var
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2675
|
+
// src/app/console/project/CreateProjectCommand.mts
|
|
2676
|
+
var import_clipanion10 = require("clipanion");
|
|
2677
|
+
var import_change_case_all3 = require("change-case-all");
|
|
2678
|
+
var import_path8 = __toESM(require("path"), 1);
|
|
2679
|
+
var fs7 = __toESM(require("fs/promises"), 1);
|
|
2680
|
+
var import_url3 = require("url");
|
|
2681
|
+
var import_handlebars3 = __toESM(require("handlebars"), 1);
|
|
2682
|
+
var import_child_process = require("child_process");
|
|
2683
|
+
var import_prompts = require("@inquirer/prompts");
|
|
2684
|
+
var import_meta3 = {};
|
|
2685
|
+
var CreateProjectCommand = class extends import_clipanion10.Command {
|
|
2686
|
+
static {
|
|
2687
|
+
__name(this, "CreateProjectCommand");
|
|
2688
|
+
}
|
|
2689
|
+
static paths = [[`create`, `project`]];
|
|
2690
|
+
static usage = import_clipanion10.Command.Usage({
|
|
2691
|
+
category: `Project`,
|
|
2692
|
+
description: `Create a new project`,
|
|
2693
|
+
details: `
|
|
2694
|
+
This command creates a new project interactively.
|
|
2695
|
+
You will be prompted for the project path and other configuration options.
|
|
2696
|
+
`,
|
|
2697
|
+
examples: [[`Create a new project`, `create project`]]
|
|
2698
|
+
});
|
|
2699
|
+
projectPath = "";
|
|
2700
|
+
executor = "";
|
|
2701
|
+
packageManager = "";
|
|
2702
|
+
linter = "";
|
|
2703
|
+
validation_library = "";
|
|
2704
|
+
database_type = "";
|
|
2705
|
+
async folderExists(folderPath) {
|
|
2706
|
+
try {
|
|
2707
|
+
const stats = await fs7.stat(folderPath);
|
|
2708
|
+
return stats.isDirectory();
|
|
2709
|
+
} catch (error) {
|
|
2710
|
+
if (error.code === "ENOENT") {
|
|
2711
|
+
return false;
|
|
2990
2712
|
}
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
}
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
);
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
});
|
|
3017
|
-
await fs8.writeFile(
|
|
3018
|
-
import_path9.default.join(import_neko_config7.config.get("migration.path"), filename),
|
|
3019
|
-
template
|
|
2713
|
+
throw error;
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
async execute() {
|
|
2717
|
+
await this.setupProjectPath();
|
|
2718
|
+
await this.setupGit();
|
|
2719
|
+
await this.setupExecutorAndPackageManager();
|
|
2720
|
+
await this.setupLinter();
|
|
2721
|
+
await this.setupGeneralPackages();
|
|
2722
|
+
await this.setupBaseProject();
|
|
2723
|
+
await this.installPackages();
|
|
2724
|
+
}
|
|
2725
|
+
async processTplFolder(src, dest, data = {}) {
|
|
2726
|
+
const files = await fs7.readdir(src, { withFileTypes: true });
|
|
2727
|
+
for (const file of files) {
|
|
2728
|
+
const srcPath = import_path8.default.join(src, file.name);
|
|
2729
|
+
const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path8.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path8.default.join(dest, file.name);
|
|
2730
|
+
if (file.isDirectory()) {
|
|
2731
|
+
await fs7.mkdir(destPath, { recursive: true });
|
|
2732
|
+
await this.processTplFolder(srcPath, destPath, data);
|
|
2733
|
+
} else if (file.name.endsWith(".tpl")) {
|
|
2734
|
+
await this.processTplFile(srcPath, destPath, data);
|
|
2735
|
+
} else {
|
|
2736
|
+
throw new Error(
|
|
2737
|
+
"unexpected non tpl file: " + srcPath + " " + file.name
|
|
3020
2738
|
);
|
|
3021
2739
|
}
|
|
3022
|
-
}
|
|
3023
|
-
cli().register(GenerateQueueMigrateCommand);
|
|
2740
|
+
}
|
|
3024
2741
|
}
|
|
3025
|
-
})
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
GenerateApiDocsCommand: () => GenerateApiDocsCommand,
|
|
3033
|
-
GenerateControllerCommand: () => GenerateControllerCommand,
|
|
3034
|
-
GenerateMigrateCommand: () => GenerateMigrateCommand,
|
|
3035
|
-
GenerateQueueMigrateCommand: () => GenerateQueueMigrateCommand,
|
|
3036
|
-
KeyGenerateCommand: () => KeyGenerateCommand,
|
|
3037
|
-
MigrateCommand: () => MigrateCommand,
|
|
3038
|
-
MigrateRollbackCommand: () => MigrateRollbackCommand,
|
|
3039
|
-
StartCommand: () => StartCommand
|
|
3040
|
-
});
|
|
3041
|
-
var init_console = __esm({
|
|
3042
|
-
"src/app/console/index.mts"() {
|
|
3043
|
-
"use strict";
|
|
3044
|
-
init_migrate();
|
|
3045
|
-
init_StartCommand();
|
|
3046
|
-
init_DefaultCommand();
|
|
3047
|
-
init_KeyGenerateCommand();
|
|
3048
|
-
init_generate();
|
|
3049
|
-
init_CreateProjectCommand();
|
|
3050
|
-
init_GenerateQueueMigrateCommand();
|
|
3051
|
-
init_facades();
|
|
3052
|
-
init_CreateProjectCommand();
|
|
3053
|
-
cli().register(CreateProjectCommand);
|
|
2742
|
+
async processTplFile(src, dest, data = {}) {
|
|
2743
|
+
import_handlebars3.default.registerHelper("eq", (a, b) => a === b);
|
|
2744
|
+
const compiledTemplate = import_handlebars3.default.compile(
|
|
2745
|
+
(await fs7.readFile(src)).toString()
|
|
2746
|
+
);
|
|
2747
|
+
const template = await compiledTemplate(data);
|
|
2748
|
+
await fs7.writeFile(dest, template);
|
|
3054
2749
|
}
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
2750
|
+
async setupProjectPath() {
|
|
2751
|
+
const pathInput = await (0, import_prompts.input)({
|
|
2752
|
+
message: "Enter project path (leave empty to use current directory):",
|
|
2753
|
+
default: ""
|
|
2754
|
+
});
|
|
2755
|
+
this.projectPath = pathInput.trim() ? import_path8.default.resolve(pathInput.trim()) : process.cwd();
|
|
2756
|
+
await fs7.mkdir(this.projectPath, { recursive: true });
|
|
2757
|
+
const files = await fs7.readdir(this.projectPath);
|
|
2758
|
+
if (files.length > 0) {
|
|
2759
|
+
throw new Error(
|
|
2760
|
+
`Directory ${this.projectPath} is not empty. Please use an empty directory.`
|
|
2761
|
+
);
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
async setupExecutorAndPackageManager() {
|
|
2765
|
+
this.executor = await (0, import_prompts.select)({
|
|
2766
|
+
message: "Select a TypeScript executor",
|
|
2767
|
+
choices: [
|
|
2768
|
+
{
|
|
2769
|
+
name: "Bun",
|
|
2770
|
+
value: "bun",
|
|
2771
|
+
description: "Fast all-in-one JavaScript runtime"
|
|
2772
|
+
},
|
|
2773
|
+
{
|
|
2774
|
+
name: "TSX",
|
|
2775
|
+
value: "tsx",
|
|
2776
|
+
description: "TypeScript execute (tsx) - Node.js enhanced with esbuild"
|
|
3079
2777
|
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
2778
|
+
]
|
|
2779
|
+
});
|
|
2780
|
+
this.packageManager = this.executor === "bun" ? "bun" : await (0, import_prompts.select)({
|
|
2781
|
+
message: "Select a package manager",
|
|
2782
|
+
choices: [
|
|
2783
|
+
{
|
|
2784
|
+
name: "Yarn",
|
|
2785
|
+
value: "yarn",
|
|
2786
|
+
description: "Fast, reliable, and secure dependency management"
|
|
2787
|
+
},
|
|
2788
|
+
{
|
|
2789
|
+
name: "npm",
|
|
2790
|
+
value: "npm",
|
|
2791
|
+
description: "Node package manager (default)"
|
|
2792
|
+
},
|
|
2793
|
+
{
|
|
2794
|
+
name: "Bun",
|
|
2795
|
+
value: "bun",
|
|
2796
|
+
description: "Ultra-fast package manager built into Bun"
|
|
3088
2797
|
}
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
2798
|
+
],
|
|
2799
|
+
default: "yarn"
|
|
2800
|
+
});
|
|
2801
|
+
(0, import_child_process.execSync)(`${this.packageManager} init -y`, {
|
|
2802
|
+
stdio: "inherit",
|
|
2803
|
+
cwd: this.projectPath
|
|
2804
|
+
});
|
|
2805
|
+
const packageJsonPath = import_path8.default.join(this.projectPath, `package.json`);
|
|
2806
|
+
let packageJson = JSON.parse(await fs7.readFile(packageJsonPath, `utf-8`));
|
|
2807
|
+
packageJson.type = "module";
|
|
2808
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
2809
|
+
packageJson.scripts.prepare = "husky init";
|
|
2810
|
+
packageJson.scripts.clean = "rm -rf dist";
|
|
2811
|
+
if (this.executor === "bun") {
|
|
2812
|
+
packageJson.scripts.dev = "bun run dev";
|
|
2813
|
+
packageJson.scripts.start = "bun run pdev";
|
|
2814
|
+
packageJson.scripts.build = "bun run build";
|
|
2815
|
+
packageJson.scripts.test = "vitest";
|
|
2816
|
+
packageJson.scripts["test:watch"] = "vitest --watch";
|
|
2817
|
+
packageJson.scripts["test:coverage"] = "vitest run --coverage";
|
|
2818
|
+
} else if (this.executor === "tsx") {
|
|
2819
|
+
packageJson.scripts.dev = "tsx --watch -r tsconfig-paths/register src/index.ts start --all | npx pino-pretty";
|
|
2820
|
+
packageJson.scripts.start = "tsx dist/index.js";
|
|
2821
|
+
packageJson.scripts.build = "tsc";
|
|
2822
|
+
packageJson.scripts.test = "vitest";
|
|
2823
|
+
packageJson.scripts["test:watch"] = "vitest --watch";
|
|
2824
|
+
packageJson.scripts["test:coverage"] = "vitest run --coverage";
|
|
2825
|
+
}
|
|
2826
|
+
await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
3101
2827
|
}
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
import_neko_orm = require("@devbro/neko-orm");
|
|
3116
|
-
import_neko_context6 = require("@devbro/neko-context");
|
|
3117
|
-
import_neko_config8 = require("@devbro/neko-config");
|
|
3118
|
-
init_global();
|
|
3119
|
-
DatabaseServiceProvider = class _DatabaseServiceProvider extends Middleware {
|
|
3120
|
-
static {
|
|
3121
|
-
__name(this, "DatabaseServiceProvider");
|
|
3122
|
-
}
|
|
3123
|
-
async call(req, res, next) {
|
|
3124
|
-
const db_configs = import_neko_config8.config.get("databases");
|
|
3125
|
-
const conns = [];
|
|
3126
|
-
try {
|
|
3127
|
-
for (const [name, db_config] of Object.entries(db_configs)) {
|
|
3128
|
-
const conn = await this.getConnection(db_config);
|
|
3129
|
-
(0, import_neko_context6.ctx)().set(["database", name], conn);
|
|
3130
|
-
conns.push(conn);
|
|
3131
|
-
}
|
|
3132
|
-
import_neko_orm.BaseModel.setConnection(() => {
|
|
3133
|
-
const key = ["database", "default"];
|
|
3134
|
-
let rc;
|
|
3135
|
-
if (import_neko_context6.ctx.isActive()) {
|
|
3136
|
-
rc = (0, import_neko_context6.ctx)().get(key);
|
|
3137
|
-
} else if (Global.has(key)) {
|
|
3138
|
-
rc = Global.get(key);
|
|
3139
|
-
} else {
|
|
3140
|
-
rc = this.getConnection(db_configs["default"]);
|
|
3141
|
-
Global.set(key, rc);
|
|
3142
|
-
}
|
|
3143
|
-
return rc;
|
|
3144
|
-
});
|
|
3145
|
-
await next();
|
|
3146
|
-
} finally {
|
|
3147
|
-
for (const conn of conns) {
|
|
3148
|
-
await conn.disconnect();
|
|
3149
|
-
}
|
|
2828
|
+
async setupLinter() {
|
|
2829
|
+
this.linter = await (0, import_prompts.select)({
|
|
2830
|
+
message: "Select a linter",
|
|
2831
|
+
choices: [
|
|
2832
|
+
{
|
|
2833
|
+
name: "Biome",
|
|
2834
|
+
value: "biome",
|
|
2835
|
+
description: "Fast formatter and linter for JavaScript, TypeScript, and more"
|
|
2836
|
+
},
|
|
2837
|
+
{
|
|
2838
|
+
name: "ESLint",
|
|
2839
|
+
value: "eslint",
|
|
2840
|
+
description: "Find and fix problems in your JavaScript code"
|
|
3150
2841
|
}
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
2842
|
+
]
|
|
2843
|
+
});
|
|
2844
|
+
const packageJsonPath = import_path8.default.join(this.projectPath, `package.json`);
|
|
2845
|
+
let packageJson = JSON.parse(await fs7.readFile(packageJsonPath, `utf-8`));
|
|
2846
|
+
if (this.linter === "biome") {
|
|
2847
|
+
packageJson.scripts.lint = "biome check . --ext .ts,.tsx";
|
|
2848
|
+
packageJson.scripts.format = "biome format . --ext .ts,.tsx --write";
|
|
2849
|
+
this.addPackage("@biomejs/biome", true);
|
|
2850
|
+
} else if (this.linter === "eslint") {
|
|
2851
|
+
packageJson.scripts.lint = "eslint . --ext .ts,.tsx";
|
|
2852
|
+
packageJson.scripts.format = "eslint . --ext .ts,.tsx --fix";
|
|
2853
|
+
this.addPackage("eslint", true);
|
|
2854
|
+
}
|
|
2855
|
+
await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2856
|
+
}
|
|
2857
|
+
async setupGeneralPackages() {
|
|
2858
|
+
this.validation_library = await (0, import_prompts.select)({
|
|
2859
|
+
message: "Select a package you want for validation",
|
|
2860
|
+
choices: [
|
|
2861
|
+
{
|
|
2862
|
+
name: "Yup",
|
|
2863
|
+
value: "yup",
|
|
2864
|
+
description: "https://github.com/jquense/yup"
|
|
2865
|
+
},
|
|
2866
|
+
{
|
|
2867
|
+
name: "Zod",
|
|
2868
|
+
value: "zod",
|
|
2869
|
+
description: "https://zod.dev/"
|
|
2870
|
+
},
|
|
2871
|
+
new import_prompts.Separator(),
|
|
2872
|
+
{
|
|
2873
|
+
name: "None",
|
|
2874
|
+
value: "none",
|
|
2875
|
+
disabled: false
|
|
3158
2876
|
}
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
2877
|
+
]
|
|
2878
|
+
});
|
|
2879
|
+
this.validation_library === "none" || await this.addPackage(this.validation_library);
|
|
2880
|
+
this.database_type = await (0, import_prompts.select)({
|
|
2881
|
+
message: "Select a database type (you can add more databases later)",
|
|
2882
|
+
choices: [
|
|
2883
|
+
{
|
|
2884
|
+
name: "PostgreSQL",
|
|
2885
|
+
value: "postgresql",
|
|
2886
|
+
description: "A powerful, open source object-relational database system"
|
|
2887
|
+
},
|
|
2888
|
+
{
|
|
2889
|
+
name: "MySQL",
|
|
2890
|
+
value: "mysql",
|
|
2891
|
+
description: "The world's most popular open source database"
|
|
2892
|
+
},
|
|
2893
|
+
{
|
|
2894
|
+
name: "SQLite",
|
|
2895
|
+
value: "sqlite",
|
|
2896
|
+
description: "A C library that provides a lightweight disk-based database"
|
|
2897
|
+
}
|
|
2898
|
+
]
|
|
2899
|
+
});
|
|
2900
|
+
if (this.database_type === "postgresql") {
|
|
2901
|
+
await this.addPackage("pg pg-cursor");
|
|
2902
|
+
} else if (this.database_type === "mysql") {
|
|
2903
|
+
await this.addPackage("mysql2");
|
|
2904
|
+
} else if (this.database_type === "sqlite") {
|
|
2905
|
+
await this.addPackage("sqlite3");
|
|
2906
|
+
}
|
|
2907
|
+
await this.addPackage("@devbro/pashmak tsconfig-paths dotenv ");
|
|
2908
|
+
await this.addPackage(
|
|
2909
|
+
"husky vitest supertest @types/supertest pino-pretty typescript tsx",
|
|
2910
|
+
true
|
|
2911
|
+
);
|
|
2912
|
+
}
|
|
2913
|
+
async setupBaseProject() {
|
|
2914
|
+
console.log(`Using project directory: ${this.projectPath}`);
|
|
2915
|
+
const dirname = typeof __dirname === "undefined" ? import_path8.default.dirname((0, import_url3.fileURLToPath)(import_meta3.url)) : __dirname;
|
|
2916
|
+
let basePath = import_path8.default.join(dirname, `./base_project`);
|
|
2917
|
+
if (await this.folderExists(basePath) === false) {
|
|
2918
|
+
basePath = import_path8.default.join(dirname, `../app/console/project/base_project`);
|
|
2919
|
+
}
|
|
2920
|
+
console.log(`Using base project path: ${basePath}`);
|
|
2921
|
+
const baseProjectPath = basePath;
|
|
2922
|
+
await this.processTplFolder(baseProjectPath, this.projectPath, {
|
|
2923
|
+
validation_library: this.validation_library,
|
|
2924
|
+
executor: this.executor,
|
|
2925
|
+
package_manager: this.packageManager,
|
|
2926
|
+
linter: this.linter,
|
|
2927
|
+
database_type: this.database_type
|
|
2928
|
+
});
|
|
2929
|
+
console.log(`Copied base project files to: ${this.projectPath}`);
|
|
2930
|
+
const packageJsonPath = import_path8.default.join(this.projectPath, "package.json");
|
|
2931
|
+
let packageJson = JSON.parse(await fs7.readFile(packageJsonPath, `utf-8`));
|
|
2932
|
+
packageJson.name = import_change_case_all3.Case.snake(import_path8.default.basename(this.projectPath));
|
|
2933
|
+
await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2934
|
+
console.log(`Updated package.json with project name: ${packageJson.name}`);
|
|
2935
|
+
}
|
|
2936
|
+
async addPackage(packageName, dev = false) {
|
|
2937
|
+
let install_command = "";
|
|
2938
|
+
switch (this.packageManager) {
|
|
2939
|
+
case "bun":
|
|
2940
|
+
install_command = `bun add ${packageName}${dev ? " -d" : ""}`;
|
|
2941
|
+
break;
|
|
2942
|
+
case "yarn":
|
|
2943
|
+
install_command = `yarn add ${packageName}${dev ? " -D" : ""} --no-install`;
|
|
2944
|
+
break;
|
|
2945
|
+
case "npm":
|
|
2946
|
+
install_command = `npm install ${packageName}${dev ? " --save-dev" : ""} --package-lock-only`;
|
|
2947
|
+
break;
|
|
2948
|
+
}
|
|
2949
|
+
(0, import_child_process.execSync)(install_command, {
|
|
2950
|
+
stdio: "inherit",
|
|
2951
|
+
cwd: this.projectPath
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2954
|
+
async installPackages() {
|
|
2955
|
+
const install_command = this.packageManager === "bun" ? `bun install` : this.packageManager === "yarn" ? `yarn` : `npm install`;
|
|
2956
|
+
(0, import_child_process.execSync)(install_command, {
|
|
2957
|
+
stdio: "inherit",
|
|
2958
|
+
cwd: this.projectPath
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2961
|
+
async setupGit() {
|
|
2962
|
+
const initGit = await (0, import_prompts.select)({
|
|
2963
|
+
message: "Initialize a git repository?",
|
|
2964
|
+
choices: [
|
|
2965
|
+
{
|
|
2966
|
+
name: "Yes",
|
|
2967
|
+
value: true,
|
|
2968
|
+
description: "Initialize git and create first commit"
|
|
2969
|
+
},
|
|
2970
|
+
{
|
|
2971
|
+
name: "No",
|
|
2972
|
+
value: false,
|
|
2973
|
+
description: "Skip git initialization"
|
|
3165
2974
|
}
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
2975
|
+
]
|
|
2976
|
+
});
|
|
2977
|
+
if (initGit) {
|
|
2978
|
+
const gitignoreContent = [
|
|
2979
|
+
"node_modules/",
|
|
2980
|
+
"dist/",
|
|
2981
|
+
".env",
|
|
2982
|
+
".env.*",
|
|
2983
|
+
"!.env.example",
|
|
2984
|
+
"*.log",
|
|
2985
|
+
"coverage/",
|
|
2986
|
+
".DS_Store"
|
|
2987
|
+
].join("\n") + "\n";
|
|
2988
|
+
await fs7.writeFile(
|
|
2989
|
+
import_path8.default.join(this.projectPath, ".gitignore"),
|
|
2990
|
+
gitignoreContent
|
|
2991
|
+
);
|
|
2992
|
+
(0, import_child_process.execSync)(
|
|
2993
|
+
`git init; git add --all; git commit --allow-empty -m "chore: first commit"`,
|
|
2994
|
+
{
|
|
2995
|
+
cwd: this.projectPath
|
|
3169
2996
|
}
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
};
|
|
2997
|
+
);
|
|
2998
|
+
}
|
|
3173
2999
|
}
|
|
3174
|
-
|
|
3000
|
+
async catch(error) {
|
|
3001
|
+
if (Error.isError(error)) {
|
|
3002
|
+
console.error(error.message);
|
|
3003
|
+
} else {
|
|
3004
|
+
console.error(error);
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
};
|
|
3175
3008
|
|
|
3176
|
-
// src/
|
|
3177
|
-
var
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
var
|
|
3184
|
-
|
|
3185
|
-
var
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
const
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3009
|
+
// src/app/console/queue/GenerateQueueMigrateCommand.mts
|
|
3010
|
+
var import_clipanion11 = require("clipanion");
|
|
3011
|
+
var import_change_case_all4 = require("change-case-all");
|
|
3012
|
+
var import_path9 = __toESM(require("path"), 1);
|
|
3013
|
+
var fs8 = __toESM(require("fs/promises"), 1);
|
|
3014
|
+
var import_neko_config7 = require("@devbro/neko-config");
|
|
3015
|
+
var import_handlebars4 = __toESM(require("handlebars"), 1);
|
|
3016
|
+
var import_url4 = require("url");
|
|
3017
|
+
var import_meta4 = {};
|
|
3018
|
+
var GenerateQueueMigrateCommand = class extends import_clipanion11.Command {
|
|
3019
|
+
static {
|
|
3020
|
+
__name(this, "GenerateQueueMigrateCommand");
|
|
3021
|
+
}
|
|
3022
|
+
static paths = [[`generate`, `queue`, "migration"]];
|
|
3023
|
+
name = "queue_messages";
|
|
3024
|
+
async execute() {
|
|
3025
|
+
const date = /* @__PURE__ */ new Date();
|
|
3026
|
+
const year = date.getFullYear();
|
|
3027
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
3028
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
3029
|
+
const secondsOfDay = String(
|
|
3030
|
+
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
3031
|
+
).padStart(5, "0");
|
|
3032
|
+
const fixed_name = "queue_messages";
|
|
3033
|
+
const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;
|
|
3034
|
+
this.context.stdout.write(`creating migration file ${filename}
|
|
3035
|
+
`);
|
|
3036
|
+
await fs8.mkdir(import_neko_config7.config.get("migration.path"), { recursive: true });
|
|
3037
|
+
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
3038
|
+
if (!dirname) {
|
|
3039
|
+
dirname = import_path9.default.dirname((0, import_url4.fileURLToPath)(import_meta4.url));
|
|
3040
|
+
}
|
|
3041
|
+
const compiledTemplate = import_handlebars4.default.compile(
|
|
3042
|
+
(await fs8.readFile(import_path9.default.join(dirname, "./queue_migration.tpl"))).toString()
|
|
3204
3043
|
);
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
}
|
|
3044
|
+
const template = await compiledTemplate({
|
|
3045
|
+
className: import_change_case_all4.Case.pascal(this.name) + "Migration",
|
|
3046
|
+
tableName: import_change_case_all4.Case.snake(this.name)
|
|
3047
|
+
});
|
|
3048
|
+
await fs8.writeFile(
|
|
3049
|
+
import_path9.default.join(import_neko_config7.config.get("migration.path"), filename),
|
|
3050
|
+
template
|
|
3051
|
+
);
|
|
3052
|
+
}
|
|
3053
|
+
};
|
|
3054
|
+
cli().register(GenerateQueueMigrateCommand);
|
|
3055
|
+
|
|
3056
|
+
// src/app/console/index.mts
|
|
3057
|
+
cli().register(CreateProjectCommand);
|