@devbro/pashmak 0.1.55 → 0.1.56
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/index.js +268 -70
- 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/bin/pashmak_cli.js +265 -66
- package/dist/cjs/index.js +1785 -1993
- package/dist/cjs/middlewares.js +60 -2
- 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/config.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/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/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
|
};
|
|
@@ -26,1077 +23,13 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
26
23
|
};
|
|
27
24
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
28
25
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
-
mod
|
|
35
|
-
));
|
|
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
|
-
|
|
239
|
-
// ../neko-router/dist/esm/Route.mjs
|
|
240
|
-
var Route;
|
|
241
|
-
var init_Route = __esm({
|
|
242
|
-
"../neko-router/dist/esm/Route.mjs"() {
|
|
243
|
-
"use strict";
|
|
244
|
-
Route = class {
|
|
245
|
-
static {
|
|
246
|
-
__name(this, "Route");
|
|
247
|
-
}
|
|
248
|
-
constructor(methods, path10, handler) {
|
|
249
|
-
this.methods = methods;
|
|
250
|
-
this.path = path10;
|
|
251
|
-
this.handler = handler;
|
|
252
|
-
this.urlRegex = this.pathToRegex(path10);
|
|
253
|
-
}
|
|
254
|
-
middlewares = [];
|
|
255
|
-
urlRegex;
|
|
256
|
-
pathToRegex(path10) {
|
|
257
|
-
const lex = this.lexUrlPath(path10);
|
|
258
|
-
return this.tokensToRegex(lex);
|
|
259
|
-
}
|
|
260
|
-
lexUrlPath(path10) {
|
|
261
|
-
const tokens = [];
|
|
262
|
-
let i = 0;
|
|
263
|
-
while (i < path10.length) {
|
|
264
|
-
const char = path10[i];
|
|
265
|
-
if (char === "/") {
|
|
266
|
-
tokens.push({ type: "SLASH", value: "/" });
|
|
267
|
-
i++;
|
|
268
|
-
} else if (char === ":") {
|
|
269
|
-
let start = i + 1;
|
|
270
|
-
while (start < path10.length && /[a-zA-Z0-9_]/.test(path10[start])) {
|
|
271
|
-
start++;
|
|
272
|
-
}
|
|
273
|
-
tokens.push({ type: "PARAM", value: path10.slice(i + 1, start) });
|
|
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);
|
|
360
|
-
}
|
|
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
|
-
}
|
|
388
|
-
if (component === "") {
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
if (i > 0) {
|
|
392
|
-
component = component.replace(/^[\/]+/, "");
|
|
393
|
-
}
|
|
394
|
-
if (i < strArray.length - 1) {
|
|
395
|
-
component = component.replace(/[\/]+$/, "");
|
|
396
|
-
} else {
|
|
397
|
-
component = component.replace(/[\/]+$/, "/");
|
|
398
|
-
}
|
|
399
|
-
resultArray.push(component);
|
|
400
|
-
}
|
|
401
|
-
var str = resultArray.join("/");
|
|
402
|
-
str = str.replace(/\/(\?|&|#[^!])/g, "$1");
|
|
403
|
-
var parts = str.split("?");
|
|
404
|
-
str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&");
|
|
405
|
-
return str;
|
|
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
|
-
});
|
|
26
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
+
mod
|
|
32
|
+
));
|
|
1100
33
|
|
|
1101
34
|
// ../node_modules/typanion/lib/index.js
|
|
1102
35
|
var require_lib = __commonJS({
|
|
@@ -2173,418 +1106,1288 @@ var require_lib = __commonJS({
|
|
|
2173
1106
|
expect: true,
|
|
2174
1107
|
message: `requires using`
|
|
2175
1108
|
}
|
|
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
|
-
});
|
|
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
|
+
var FlexibleFactory = class {
|
|
1743
|
+
static {
|
|
1744
|
+
__name(this, "FlexibleFactory");
|
|
1745
|
+
}
|
|
1746
|
+
registry = /* @__PURE__ */ new Map();
|
|
1747
|
+
register(key, ctor) {
|
|
1748
|
+
this.registry.set(key, ctor);
|
|
1749
|
+
}
|
|
1750
|
+
create(key, ...args) {
|
|
1751
|
+
const ctor = this.registry.get(key);
|
|
1752
|
+
if (!ctor) {
|
|
1753
|
+
throw new Error(`No factory registered for key: ${key}`);
|
|
2194
1754
|
}
|
|
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
|
-
exports2.isString = isString;
|
|
2242
|
-
exports2.isTuple = isTuple;
|
|
2243
|
-
exports2.isUUID4 = isUUID4;
|
|
2244
|
-
exports2.isUnknown = isUnknown;
|
|
2245
|
-
exports2.isUpperCase = isUpperCase;
|
|
2246
|
-
exports2.makeTrait = makeTrait;
|
|
2247
|
-
exports2.makeValidator = makeValidator;
|
|
2248
|
-
exports2.matchesRegExp = matchesRegExp;
|
|
2249
|
-
exports2.softAssert = softAssert;
|
|
1755
|
+
return ctor(...args);
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
import_neko_mailer.MailerProviderFactory.register("ses", (opt) => {
|
|
1759
|
+
return new import_neko_mailer.SESProvider(opt);
|
|
1760
|
+
});
|
|
1761
|
+
import_neko_mailer.MailerProviderFactory.register("smtp", (opt) => {
|
|
1762
|
+
return new import_neko_mailer.SMTPProvider(opt);
|
|
1763
|
+
});
|
|
1764
|
+
import_neko_mailer.MailerProviderFactory.register("memory", (opt) => {
|
|
1765
|
+
return new import_neko_mailer.MemoryProvider();
|
|
1766
|
+
});
|
|
1767
|
+
import_neko_queue.QueueTransportFactory.register("database", (opt) => {
|
|
1768
|
+
return new DatabaseTransport(opt);
|
|
1769
|
+
});
|
|
1770
|
+
import_neko_queue.QueueTransportFactory.register("memory", (opt) => {
|
|
1771
|
+
return new import_neko_queue.MemoryTransport(opt);
|
|
1772
|
+
});
|
|
1773
|
+
import_neko_queue.QueueTransportFactory.register("sqs", (opt) => {
|
|
1774
|
+
return new import_neko_queue.AwsSqsTransport(opt);
|
|
1775
|
+
});
|
|
1776
|
+
import_neko_queue.QueueTransportFactory.register("amqp", (opt) => {
|
|
1777
|
+
return new import_neko_queue.AmqpTransport(opt);
|
|
1778
|
+
});
|
|
1779
|
+
import_neko_queue.QueueTransportFactory.register("redis", (opt) => {
|
|
1780
|
+
return new import_neko_queue.RedisTransport(opt);
|
|
1781
|
+
});
|
|
1782
|
+
import_neko_queue.QueueTransportFactory.register("async", (opt) => {
|
|
1783
|
+
return new import_neko_queue.AsyncTransport();
|
|
1784
|
+
});
|
|
1785
|
+
import_neko_queue.QueueTransportFactory.register("azure_service_bus", (opt) => {
|
|
1786
|
+
return new import_neko_queue.AzureServiceBusTransport(opt);
|
|
1787
|
+
});
|
|
1788
|
+
import_neko_queue.QueueTransportFactory.register("google_pubsub", (opt) => {
|
|
1789
|
+
return new import_neko_queue.GooglePubSubTransport(opt);
|
|
1790
|
+
});
|
|
1791
|
+
var CacheProviderFactory = class _CacheProviderFactory {
|
|
1792
|
+
static {
|
|
1793
|
+
__name(this, "CacheProviderFactory");
|
|
1794
|
+
}
|
|
1795
|
+
static instance = new FlexibleFactory();
|
|
1796
|
+
static register(key, factory) {
|
|
1797
|
+
_CacheProviderFactory.instance.register(key, factory);
|
|
1798
|
+
}
|
|
1799
|
+
static create(key, ...args) {
|
|
1800
|
+
return _CacheProviderFactory.instance.create(key, ...args);
|
|
2250
1801
|
}
|
|
1802
|
+
};
|
|
1803
|
+
CacheProviderFactory.register("memory", (opt) => {
|
|
1804
|
+
return new import_neko_cache.MemoryCacheProvider(opt);
|
|
1805
|
+
});
|
|
1806
|
+
CacheProviderFactory.register("redis", (opt) => {
|
|
1807
|
+
return new import_neko_cache.RedisCacheProvider(opt);
|
|
1808
|
+
});
|
|
1809
|
+
CacheProviderFactory.register("file", (opt) => {
|
|
1810
|
+
return new import_neko_cache.FileCacheProvider(opt);
|
|
1811
|
+
});
|
|
1812
|
+
CacheProviderFactory.register("disabled", (opt) => {
|
|
1813
|
+
return new import_neko_cache.DisabledCacheProvider();
|
|
1814
|
+
});
|
|
1815
|
+
import_neko_storage.StorageProviderFactory.register("local", (opt) => {
|
|
1816
|
+
return new import_neko_storage.LocalStorageProvider(opt);
|
|
1817
|
+
});
|
|
1818
|
+
import_neko_storage.StorageProviderFactory.register("s3", (opt) => {
|
|
1819
|
+
return new import_neko_storage.AWSS3StorageProvider(opt);
|
|
1820
|
+
});
|
|
1821
|
+
import_neko_storage.StorageProviderFactory.register("gcp", (opt) => {
|
|
1822
|
+
return new import_neko_storage.GCPStorageProvider(opt);
|
|
1823
|
+
});
|
|
1824
|
+
import_neko_storage.StorageProviderFactory.register("azure", (opt) => {
|
|
1825
|
+
return new import_neko_storage.AzureBlobStorageProvider(opt);
|
|
1826
|
+
});
|
|
1827
|
+
import_neko_storage.StorageProviderFactory.register("ftp", (opt) => {
|
|
1828
|
+
return new import_neko_storage.FTPStorageProvider(opt);
|
|
1829
|
+
});
|
|
1830
|
+
import_neko_storage.StorageProviderFactory.register("sftp", (opt) => {
|
|
1831
|
+
return new import_neko_storage.SFTPStorageProvider(opt);
|
|
2251
1832
|
});
|
|
2252
1833
|
|
|
2253
|
-
// src/
|
|
2254
|
-
var
|
|
2255
|
-
var
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
1834
|
+
// src/facades.mts
|
|
1835
|
+
var import_neko_cache2 = require("@devbro/neko-cache");
|
|
1836
|
+
var import_neko_queue2 = require("@devbro/neko-queue");
|
|
1837
|
+
function wrapSingletonWithAccessors(singletonFn) {
|
|
1838
|
+
let methodsInitialized = false;
|
|
1839
|
+
const initializeMethods = /* @__PURE__ */ __name(() => {
|
|
1840
|
+
if (methodsInitialized) return;
|
|
1841
|
+
const defaultInstance = singletonFn();
|
|
1842
|
+
const prototype = Object.getPrototypeOf(defaultInstance);
|
|
1843
|
+
const methodNames = Object.getOwnPropertyNames(prototype).filter(
|
|
1844
|
+
(name) => name !== "constructor" && typeof prototype[name] === "function"
|
|
1845
|
+
);
|
|
1846
|
+
for (const methodName of methodNames) {
|
|
1847
|
+
singletonFn[methodName] = (...args) => {
|
|
1848
|
+
const instance = singletonFn();
|
|
1849
|
+
return instance[methodName](...args);
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
methodsInitialized = true;
|
|
1853
|
+
}, "initializeMethods");
|
|
1854
|
+
return new Proxy(singletonFn, {
|
|
1855
|
+
get(target, prop, receiver) {
|
|
1856
|
+
if (typeof prop === "string" && !Reflect.has(target, prop)) {
|
|
1857
|
+
initializeMethods();
|
|
2268
1858
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
1859
|
+
return Reflect.get(target, prop, receiver);
|
|
1860
|
+
}
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
__name(wrapSingletonWithAccessors, "wrapSingletonWithAccessors");
|
|
1864
|
+
var router = (0, import_neko_helper3.createSingleton)(() => new Router());
|
|
1865
|
+
var scheduler = wrapSingletonWithAccessors(
|
|
1866
|
+
(0, import_neko_helper3.createSingleton)(() => {
|
|
1867
|
+
const rc = new import_neko_scheduler.Scheduler();
|
|
1868
|
+
rc.setErrorHandler((err, job) => {
|
|
1869
|
+
logger().error({
|
|
1870
|
+
msg: "Scheduled job error",
|
|
1871
|
+
err,
|
|
1872
|
+
job_name: job.getName()
|
|
2273
1873
|
});
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
1874
|
+
});
|
|
1875
|
+
return rc;
|
|
1876
|
+
})
|
|
1877
|
+
);
|
|
1878
|
+
var db = /* @__PURE__ */ __name((label = "default") => (0, import_neko_context3.ctx)().getOrThrow(["database", label]), "db");
|
|
1879
|
+
var storage = wrapSingletonWithAccessors(
|
|
1880
|
+
(0, import_neko_helper3.createSingleton)((label = "default") => {
|
|
1881
|
+
let storage_config = import_neko_config.config.get(["storages", label].join("."));
|
|
1882
|
+
const provider = import_neko_storage2.StorageProviderFactory.create(
|
|
1883
|
+
storage_config.provider,
|
|
1884
|
+
storage_config.config
|
|
1885
|
+
);
|
|
1886
|
+
return new import_neko_storage2.Storage(provider);
|
|
1887
|
+
})
|
|
1888
|
+
);
|
|
1889
|
+
var cli = (0, import_neko_helper3.createSingleton)(() => {
|
|
1890
|
+
const [node, app, ...args] = process.argv;
|
|
1891
|
+
return new import_clipanion.Cli({
|
|
1892
|
+
binaryLabel: `My Application`,
|
|
1893
|
+
binaryName: `${node} ${app}`,
|
|
1894
|
+
binaryVersion: `1.0.0`
|
|
1895
|
+
});
|
|
1896
|
+
});
|
|
1897
|
+
var httpServer = (0, import_neko_helper3.createSingleton)(() => {
|
|
1898
|
+
const server = new http_exports.HttpServer();
|
|
1899
|
+
server.setErrorHandler(handleHttpErrors);
|
|
1900
|
+
server.setRouter(router());
|
|
1901
|
+
return server;
|
|
1902
|
+
});
|
|
1903
|
+
var logger = wrapSingletonWithAccessors(
|
|
1904
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1905
|
+
const logger_config = import_neko_config.config.get(["loggers", label].join("."));
|
|
1906
|
+
const rc = new import_neko_logger.Logger(logger_config);
|
|
1907
|
+
rc.setExtrasFunction((message) => {
|
|
1908
|
+
message.requestId = (0, import_neko_context3.ctxSafe)()?.get("requestId") || "N/A";
|
|
1909
|
+
return message;
|
|
1910
|
+
});
|
|
1911
|
+
return rc;
|
|
1912
|
+
})
|
|
1913
|
+
);
|
|
1914
|
+
var mailer = wrapSingletonWithAccessors(
|
|
1915
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1916
|
+
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
1917
|
+
const provider = import_neko_mailer2.MailerProviderFactory.create(
|
|
1918
|
+
mailer_config.provider,
|
|
1919
|
+
mailer_config.config
|
|
1920
|
+
);
|
|
1921
|
+
const rc = new import_neko_mailer2.Mailer(provider);
|
|
1922
|
+
return rc;
|
|
1923
|
+
})
|
|
1924
|
+
);
|
|
1925
|
+
var queue = wrapSingletonWithAccessors(
|
|
1926
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1927
|
+
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
1928
|
+
if (!queue_config) {
|
|
1929
|
+
throw new Error(`Queue configuration for '${label}' not found`);
|
|
1930
|
+
}
|
|
1931
|
+
const provider = import_neko_queue2.QueueTransportFactory.create(
|
|
1932
|
+
queue_config.provider,
|
|
1933
|
+
queue_config.config
|
|
1934
|
+
);
|
|
1935
|
+
return new import_neko_queue2.QueueConnection(provider);
|
|
1936
|
+
})
|
|
1937
|
+
);
|
|
1938
|
+
var cache = wrapSingletonWithAccessors(
|
|
1939
|
+
(0, import_neko_helper3.createSingleton)((label) => {
|
|
1940
|
+
const cache_config = import_neko_config.config.get(["caches", label].join("."));
|
|
1941
|
+
if (!cache_config) {
|
|
1942
|
+
throw new Error(`Cache configuration for '${label}' not found`);
|
|
1943
|
+
}
|
|
1944
|
+
const provider = CacheProviderFactory.create(
|
|
1945
|
+
cache_config.provider,
|
|
1946
|
+
cache_config.config
|
|
1947
|
+
);
|
|
1948
|
+
return new import_neko_cache2.Cache(provider);
|
|
1949
|
+
})
|
|
1950
|
+
);
|
|
1951
|
+
|
|
1952
|
+
// src/app/console/migrate/MigrateCommand.mts
|
|
1953
|
+
var import_clipanion2 = require("clipanion");
|
|
1954
|
+
var import_neko_context4 = require("@devbro/neko-context");
|
|
1955
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
1956
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
1957
|
+
var import_neko_config2 = require("@devbro/neko-config");
|
|
1958
|
+
var MigrateCommand = class extends import_clipanion2.Command {
|
|
1959
|
+
static {
|
|
1960
|
+
__name(this, "MigrateCommand");
|
|
1961
|
+
}
|
|
1962
|
+
static paths = [[`migrate`]];
|
|
1963
|
+
fresh = import_clipanion2.Option.Boolean(`--fresh`, false, {
|
|
1964
|
+
description: `whether to delete and recreate database`
|
|
1965
|
+
});
|
|
1966
|
+
refresh = import_clipanion2.Option.Boolean(`--refresh`, false, {
|
|
1967
|
+
description: `whether to drop all tables before running migrations by using rollback function`
|
|
1968
|
+
});
|
|
1969
|
+
async execute() {
|
|
1970
|
+
await import_neko_context4.context_provider.run(async () => {
|
|
1971
|
+
const db2 = db();
|
|
1972
|
+
const schema = db2.getSchema();
|
|
1973
|
+
if (this.fresh) {
|
|
1974
|
+
await db2.dropDatabase(import_neko_config2.config.get("databases.default.database"));
|
|
1975
|
+
await db2.createDatabase(import_neko_config2.config.get("databases.default.database"));
|
|
1976
|
+
logger().info("database dropped and created fresh!");
|
|
1977
|
+
}
|
|
1978
|
+
if (this.refresh && await schema.tableExists("migrations")) {
|
|
1979
|
+
logger().info("reverting all migrations!!");
|
|
1980
|
+
const existing_migrations = await db2.runQuery({
|
|
1981
|
+
sql: "select * from migrations order by created_at DESC",
|
|
1982
|
+
parts: [],
|
|
1983
|
+
bindings: []
|
|
1984
|
+
});
|
|
1985
|
+
const migrationsDir2 = import_neko_config2.config.get("migration.path");
|
|
1986
|
+
for (const migration_record of existing_migrations) {
|
|
1987
|
+
logger().info(`rolling back ${migration_record.filename}`);
|
|
1988
|
+
try {
|
|
1989
|
+
const MigrationClass = (await import(import_path2.default.join(migrationsDir2, migration_record.filename))).default;
|
|
1990
|
+
const migrationInstance = new MigrationClass();
|
|
1991
|
+
await migrationInstance.down(db2.getSchema());
|
|
2293
1992
|
await db2.runQuery({
|
|
2294
|
-
sql: "delete from migrations where
|
|
1993
|
+
sql: "delete from migrations where filename = $1",
|
|
2295
1994
|
parts: [],
|
|
2296
|
-
bindings: [
|
|
1995
|
+
bindings: [migration_record.filename]
|
|
2297
1996
|
});
|
|
1997
|
+
} catch (error) {
|
|
1998
|
+
logger().error(
|
|
1999
|
+
`Failed to rollback migration ${migration_record.filename}: ${error}`
|
|
2000
|
+
);
|
|
2001
|
+
throw error;
|
|
2298
2002
|
}
|
|
2003
|
+
}
|
|
2004
|
+
logger().info(
|
|
2005
|
+
`rolled back ${existing_migrations.length} migrations successfully!`
|
|
2006
|
+
);
|
|
2007
|
+
}
|
|
2008
|
+
if (!await schema.tableExists("migrations")) {
|
|
2009
|
+
await schema.createTable("migrations", (blueprint) => {
|
|
2010
|
+
blueprint.id();
|
|
2011
|
+
blueprint.timestamps();
|
|
2012
|
+
blueprint.string("filename");
|
|
2013
|
+
blueprint.integer("batch");
|
|
2299
2014
|
});
|
|
2300
2015
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2016
|
+
const migrationsDir = import_neko_config2.config.get("migration.path");
|
|
2017
|
+
let files = [];
|
|
2018
|
+
const dirEntries = await import_promises.default.readdir(migrationsDir);
|
|
2019
|
+
files = dirEntries.filter((entry) => entry.endsWith(".ts") || entry.endsWith(".js")).sort();
|
|
2020
|
+
let batch_number = await db2.runQuery({
|
|
2021
|
+
sql: "select max(batch) as next_batch from migrations",
|
|
2022
|
+
parts: [],
|
|
2023
|
+
bindings: []
|
|
2024
|
+
});
|
|
2025
|
+
batch_number = batch_number[0].next_batch || 0;
|
|
2026
|
+
batch_number++;
|
|
2027
|
+
const migrations = await db2.runQuery({
|
|
2028
|
+
sql: "select * from migrations order by created_at ASC",
|
|
2029
|
+
parts: [],
|
|
2030
|
+
bindings: []
|
|
2031
|
+
});
|
|
2032
|
+
const completed_migrations = migrations.map((r) => r.filename);
|
|
2033
|
+
const pending_migrations = files.filter(
|
|
2034
|
+
(file) => !completed_migrations.includes(file)
|
|
2035
|
+
);
|
|
2036
|
+
let migrated_count = 0;
|
|
2037
|
+
for (const class_to_migrate of pending_migrations) {
|
|
2038
|
+
logger().info(`migrating up ${class_to_migrate}`);
|
|
2039
|
+
const ClassToMigrate = (await import(import_path2.default.join(migrationsDir, class_to_migrate))).default;
|
|
2040
|
+
const c = new ClassToMigrate();
|
|
2041
|
+
await c.up(db2.getSchema());
|
|
2042
|
+
await db2.runQuery({
|
|
2043
|
+
sql: "insert into migrations (filename, batch) values ($1,$2)",
|
|
2044
|
+
parts: [],
|
|
2045
|
+
bindings: [class_to_migrate, batch_number]
|
|
2046
|
+
});
|
|
2047
|
+
migrated_count++;
|
|
2048
|
+
}
|
|
2049
|
+
if (migrated_count === 0) {
|
|
2050
|
+
logger().warn("no migrations to run!");
|
|
2051
|
+
return;
|
|
2052
|
+
}
|
|
2053
|
+
logger().info(`migrated ${migrated_count} migrations successfully!`);
|
|
2054
|
+
return;
|
|
2055
|
+
});
|
|
2303
2056
|
}
|
|
2304
|
-
}
|
|
2057
|
+
};
|
|
2058
|
+
cli().register(MigrateCommand);
|
|
2305
2059
|
|
|
2306
|
-
// src/app/console/migrate/
|
|
2307
|
-
var
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2060
|
+
// src/app/console/migrate/GenerateMigrateCommand.mts
|
|
2061
|
+
var import_clipanion3 = require("clipanion");
|
|
2062
|
+
var import_change_case_all = require("change-case-all");
|
|
2063
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
2064
|
+
var fs2 = __toESM(require("fs/promises"), 1);
|
|
2065
|
+
var import_neko_config3 = require("@devbro/neko-config");
|
|
2066
|
+
var import_handlebars = __toESM(require("handlebars"), 1);
|
|
2067
|
+
var import_url = require("url");
|
|
2068
|
+
var import_meta = {};
|
|
2069
|
+
var GenerateMigrateCommand = class extends import_clipanion3.Command {
|
|
2070
|
+
static {
|
|
2071
|
+
__name(this, "GenerateMigrateCommand");
|
|
2313
2072
|
}
|
|
2314
|
-
|
|
2073
|
+
static paths = [
|
|
2074
|
+
[`generate`, `migrate`],
|
|
2075
|
+
["generate", "migration"]
|
|
2076
|
+
];
|
|
2077
|
+
name = import_clipanion3.Option.String({ required: true });
|
|
2078
|
+
async execute() {
|
|
2079
|
+
const date = /* @__PURE__ */ new Date();
|
|
2080
|
+
const year = date.getFullYear();
|
|
2081
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
2082
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
2083
|
+
const secondsOfDay = String(
|
|
2084
|
+
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
2085
|
+
).padStart(5, "0");
|
|
2086
|
+
const fixed_name = import_change_case_all.Case.snake(this.name);
|
|
2087
|
+
const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;
|
|
2088
|
+
this.context.stdout.write(`creating migration file ${filename}
|
|
2089
|
+
`);
|
|
2090
|
+
await fs2.mkdir(import_neko_config3.config.get("migration.path"), { recursive: true });
|
|
2091
|
+
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
2092
|
+
if (!dirname) {
|
|
2093
|
+
dirname = import_path3.default.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
2094
|
+
}
|
|
2095
|
+
const compiledTemplate = import_handlebars.default.compile(
|
|
2096
|
+
(await fs2.readFile(import_path3.default.join(dirname, "./make_migration.tpl"))).toString()
|
|
2097
|
+
);
|
|
2098
|
+
const template = await compiledTemplate({
|
|
2099
|
+
className: import_change_case_all.Case.pascal(this.name) + "Migration",
|
|
2100
|
+
tableName: import_change_case_all.Case.snake(this.name)
|
|
2101
|
+
});
|
|
2102
|
+
await fs2.writeFile(
|
|
2103
|
+
import_path3.default.join(import_neko_config3.config.get("migration.path"), filename),
|
|
2104
|
+
template
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
cli().register(GenerateMigrateCommand);
|
|
2315
2109
|
|
|
2316
|
-
// src/app/console/
|
|
2317
|
-
var
|
|
2318
|
-
var
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2110
|
+
// src/app/console/migrate/MigrateRollbackCommand.mts
|
|
2111
|
+
var import_clipanion4 = require("clipanion");
|
|
2112
|
+
var import_neko_context5 = require("@devbro/neko-context");
|
|
2113
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
2114
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
2115
|
+
var import_neko_config4 = require("@devbro/neko-config");
|
|
2116
|
+
var t = __toESM(require_lib(), 1);
|
|
2117
|
+
var MigrateRollbackCommand = class extends import_clipanion4.Command {
|
|
2118
|
+
static {
|
|
2119
|
+
__name(this, "MigrateRollbackCommand");
|
|
2120
|
+
}
|
|
2121
|
+
static paths = [[`migrate`, "rollback"]];
|
|
2122
|
+
steps = import_clipanion4.Option.String(`--steps`, "1", {
|
|
2123
|
+
description: `how many migrations to rollback`,
|
|
2124
|
+
validator: t.isNumber()
|
|
2125
|
+
});
|
|
2126
|
+
async execute() {
|
|
2127
|
+
await import_neko_context5.context_provider.run(async () => {
|
|
2128
|
+
const db2 = db();
|
|
2129
|
+
const schema = db2.getSchema();
|
|
2130
|
+
const migrationsDir = import_neko_config4.config.get("migration.path");
|
|
2131
|
+
let files = [];
|
|
2132
|
+
const dirEntries = await import_promises2.default.readdir(migrationsDir);
|
|
2133
|
+
files = dirEntries.filter((entry) => entry.endsWith(".ts")).sort();
|
|
2134
|
+
const migrations = await db2.runQuery({
|
|
2135
|
+
sql: "select * from migrations order by created_at DESC limit $1",
|
|
2136
|
+
parts: [],
|
|
2137
|
+
bindings: [this.steps]
|
|
2138
|
+
});
|
|
2139
|
+
for (const migration of migrations) {
|
|
2140
|
+
const class_to_migrate = migration.filename;
|
|
2141
|
+
logger().info(`rolling back ${class_to_migrate}`);
|
|
2142
|
+
const ClassToMigrate = (await import(import_path4.default.join(migrationsDir, class_to_migrate))).default;
|
|
2143
|
+
const c = new ClassToMigrate();
|
|
2144
|
+
await c.down(db2.getSchema());
|
|
2145
|
+
await db2.runQuery({
|
|
2146
|
+
sql: "delete from migrations where id = $1",
|
|
2147
|
+
parts: [],
|
|
2148
|
+
bindings: [migration.id]
|
|
2149
|
+
});
|
|
2328
2150
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
cli().register(MigrateRollbackCommand);
|
|
2155
|
+
|
|
2156
|
+
// src/app/console/StartCommand.mts
|
|
2157
|
+
var import_clipanion5 = require("clipanion");
|
|
2158
|
+
var import_neko_config5 = require("@devbro/neko-config");
|
|
2159
|
+
var import_neko_sql = require("@devbro/neko-sql");
|
|
2160
|
+
var StartCommand = class extends import_clipanion5.Command {
|
|
2161
|
+
static {
|
|
2162
|
+
__name(this, "StartCommand");
|
|
2163
|
+
}
|
|
2164
|
+
scheduler = import_clipanion5.Option.Boolean(`--scheduler`, false);
|
|
2165
|
+
cron = import_clipanion5.Option.Boolean(`--cron`, false);
|
|
2166
|
+
http = import_clipanion5.Option.Boolean(`--http`, false);
|
|
2167
|
+
queue = import_clipanion5.Option.Boolean(`--queue`, false);
|
|
2168
|
+
all = import_clipanion5.Option.Boolean("--all", false);
|
|
2169
|
+
static paths = [[`start`]];
|
|
2170
|
+
async execute() {
|
|
2171
|
+
if ([this.all, this.http, this.scheduler || this.cron, this.queue].filter(
|
|
2172
|
+
(x) => x
|
|
2173
|
+
).length == 0) {
|
|
2174
|
+
this.context.stdout.write(
|
|
2175
|
+
`No service was selected. please check -h for details
|
|
2341
2176
|
`
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2177
|
+
);
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
logger().info(`Starting Server
|
|
2346
2181
|
`);
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2182
|
+
import_neko_sql.PostgresqlConnection.defaults.idleTimeoutMillis = 1e4;
|
|
2183
|
+
if (this.scheduler || this.cron || this.all) {
|
|
2184
|
+
logger().info(`starting scheduler
|
|
2350
2185
|
`);
|
|
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
|
-
}
|
|
2186
|
+
scheduler().start();
|
|
2187
|
+
}
|
|
2188
|
+
if (this.queue || this.all) {
|
|
2189
|
+
const config_queues = import_neko_config5.config.get("queues");
|
|
2190
|
+
for (const [name, conf] of Object.entries(config_queues)) {
|
|
2191
|
+
queue(name).start();
|
|
2367
2192
|
}
|
|
2368
|
-
}
|
|
2369
|
-
|
|
2193
|
+
}
|
|
2194
|
+
if (this.http || this.all) {
|
|
2195
|
+
const server = httpServer();
|
|
2196
|
+
await server.listen(import_neko_config5.config.get("port"), () => {
|
|
2197
|
+
logger().info(
|
|
2198
|
+
"Server is running on http://localhost:" + import_neko_config5.config.get("port")
|
|
2199
|
+
);
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2370
2202
|
}
|
|
2371
|
-
}
|
|
2203
|
+
};
|
|
2204
|
+
cli().register(StartCommand);
|
|
2372
2205
|
|
|
2373
2206
|
// 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: `
|
|
2207
|
+
var import_clipanion6 = require("clipanion");
|
|
2208
|
+
var DefaultCommand = class extends import_clipanion6.Command {
|
|
2209
|
+
static {
|
|
2210
|
+
__name(this, "DefaultCommand");
|
|
2211
|
+
}
|
|
2212
|
+
static usage = import_clipanion6.Command.Usage({
|
|
2213
|
+
category: `Main`,
|
|
2214
|
+
description: `server management command line.`,
|
|
2215
|
+
details: `
|
|
2388
2216
|
The base command for running and managing your server.
|
|
2389
2217
|
|
|
2390
2218
|
Make sure you understand how things work.
|
|
2391
2219
|
`,
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2220
|
+
examples: []
|
|
2221
|
+
});
|
|
2222
|
+
async execute() {
|
|
2223
|
+
const commandList = cli().registrations;
|
|
2224
|
+
const paths = [];
|
|
2225
|
+
commandList.forEach(
|
|
2226
|
+
(index, val) => paths.push(index.builder.paths[0]?.join(" ") || "")
|
|
2227
|
+
);
|
|
2228
|
+
console.log("Available commands:");
|
|
2229
|
+
for (const cmd of paths) {
|
|
2230
|
+
if (cmd) {
|
|
2231
|
+
console.log(cmd);
|
|
2406
2232
|
}
|
|
2407
|
-
}
|
|
2408
|
-
cli().register(DefaultCommand);
|
|
2233
|
+
}
|
|
2409
2234
|
}
|
|
2410
|
-
}
|
|
2235
|
+
};
|
|
2236
|
+
cli().register(DefaultCommand);
|
|
2411
2237
|
|
|
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: `
|
|
2238
|
+
// src/app/console/KeyGenerateCommand.mts
|
|
2239
|
+
var import_clipanion7 = require("clipanion");
|
|
2240
|
+
var import_crypto = require("crypto");
|
|
2241
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
2242
|
+
var import_path5 = __toESM(require("path"), 1);
|
|
2243
|
+
var KeyGenerateCommand = class extends import_clipanion7.Command {
|
|
2244
|
+
static {
|
|
2245
|
+
__name(this, "KeyGenerateCommand");
|
|
2246
|
+
}
|
|
2247
|
+
static paths = [[`generate`, "key"]];
|
|
2248
|
+
static usage = import_clipanion7.Command.Usage({
|
|
2249
|
+
category: `Main`,
|
|
2250
|
+
description: `generate keys`,
|
|
2251
|
+
details: `
|
|
2431
2252
|
This command generates RSA key pair for JWT signing.
|
|
2432
2253
|
Use --rotate flag to preserve old public key.
|
|
2433
2254
|
`,
|
|
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");
|
|
2255
|
+
examples: [
|
|
2256
|
+
[`Generate new keys`, `generate key`],
|
|
2257
|
+
[`Rotate existing keys`, `generate key --rotate`]
|
|
2258
|
+
]
|
|
2259
|
+
});
|
|
2260
|
+
rotate = import_clipanion7.Option.Boolean(`--rotate`, false, {
|
|
2261
|
+
description: `Rotate existing keys (backup old keys before replacement)`
|
|
2262
|
+
});
|
|
2263
|
+
async execute() {
|
|
2264
|
+
logger().info("generating keys for jwt token and adding to .env file");
|
|
2265
|
+
const { publicKey, privateKey } = (0, import_crypto.generateKeyPairSync)("rsa", {
|
|
2266
|
+
modulusLength: 2048,
|
|
2267
|
+
// 2048-bit key is standard for RS256
|
|
2268
|
+
publicKeyEncoding: {
|
|
2269
|
+
type: "spki",
|
|
2270
|
+
format: "pem"
|
|
2271
|
+
},
|
|
2272
|
+
privateKeyEncoding: {
|
|
2273
|
+
type: "pkcs8",
|
|
2274
|
+
format: "pem"
|
|
2480
2275
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2276
|
+
});
|
|
2277
|
+
let envfile = "";
|
|
2278
|
+
try {
|
|
2279
|
+
envfile = await import_promises3.default.readFile(import_path5.default.join(process.cwd(), ".env"), "utf-8");
|
|
2280
|
+
} catch {
|
|
2281
|
+
}
|
|
2282
|
+
let old_public_key = envfile.match(/^jwt_secret_public=(.*)/m);
|
|
2283
|
+
envfile = this.addEnvParam(
|
|
2284
|
+
envfile,
|
|
2285
|
+
"jwt_secret_public",
|
|
2286
|
+
this.stripPemHeaders(publicKey)
|
|
2287
|
+
);
|
|
2288
|
+
envfile = this.addEnvParam(
|
|
2289
|
+
envfile,
|
|
2290
|
+
"jwt_secret_private",
|
|
2291
|
+
this.stripPemHeaders(privateKey)
|
|
2292
|
+
);
|
|
2293
|
+
if (this.rotate && old_public_key && old_public_key[1]) {
|
|
2294
|
+
envfile = this.addEnvParam(
|
|
2295
|
+
envfile,
|
|
2296
|
+
"jwt_secret_public_retired",
|
|
2297
|
+
old_public_key[1]
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2300
|
+
await import_promises3.default.writeFile(import_path5.default.join(process.cwd(), ".env"), envfile, "utf-8");
|
|
2301
|
+
}
|
|
2302
|
+
addEnvParam(file, key, value) {
|
|
2303
|
+
let regex = new RegExp(`^${key}=.*`, "gm");
|
|
2304
|
+
file = file.replace(regex, `${key}=${value}`);
|
|
2305
|
+
const match = file.match(regex);
|
|
2306
|
+
if (!match) {
|
|
2307
|
+
file = file + `
|
|
2487
2308
|
${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);
|
|
2309
|
+
}
|
|
2310
|
+
return file;
|
|
2496
2311
|
}
|
|
2497
|
-
|
|
2312
|
+
stripPemHeaders(pem) {
|
|
2313
|
+
return pem.replace(/-----BEGIN [\w\s]+-----/g, "").replace(/-----END [\w\s]+-----/g, "").replace(/\r?\n|\r/g, "");
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
cli().register(KeyGenerateCommand);
|
|
2498
2317
|
|
|
2499
2318
|
// 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}
|
|
2319
|
+
var import_clipanion8 = require("clipanion");
|
|
2320
|
+
var import_change_case_all2 = require("change-case-all");
|
|
2321
|
+
var import_path6 = __toESM(require("path"), 1);
|
|
2322
|
+
var fs5 = __toESM(require("fs/promises"), 1);
|
|
2323
|
+
var import_neko_config6 = require("@devbro/neko-config");
|
|
2324
|
+
var import_handlebars2 = __toESM(require("handlebars"), 1);
|
|
2325
|
+
var import_url2 = require("url");
|
|
2326
|
+
var import_pluralize = __toESM(require("pluralize"), 1);
|
|
2327
|
+
var import_meta2 = {};
|
|
2328
|
+
var GenerateControllerCommand = class extends import_clipanion8.Command {
|
|
2329
|
+
static {
|
|
2330
|
+
__name(this, "GenerateControllerCommand");
|
|
2331
|
+
}
|
|
2332
|
+
static paths = [
|
|
2333
|
+
[`make`, `controller`],
|
|
2334
|
+
[`generate`, `controller`]
|
|
2335
|
+
];
|
|
2336
|
+
name = import_clipanion8.Option.String({ required: true });
|
|
2337
|
+
async execute() {
|
|
2338
|
+
const rootDir = process.cwd();
|
|
2339
|
+
const date = /* @__PURE__ */ new Date();
|
|
2340
|
+
const year = date.getFullYear();
|
|
2341
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
2342
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
2343
|
+
const secondsOfDay = String(
|
|
2344
|
+
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
2345
|
+
).padStart(5, "0");
|
|
2346
|
+
const fixed_name = import_change_case_all2.Case.snake(this.name);
|
|
2347
|
+
const filename = `${import_change_case_all2.Case.capital(this.name)}Controller.ts`;
|
|
2348
|
+
this.context.stdout.write(`creating migration file ${filename}
|
|
2535
2349
|
`);
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
}
|
|
2554
|
-
};
|
|
2555
|
-
cli().register(GenerateControllerCommand);
|
|
2350
|
+
await fs5.mkdir(import_neko_config6.config.get("migration.path"), { recursive: true });
|
|
2351
|
+
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
2352
|
+
if (!dirname) {
|
|
2353
|
+
dirname = import_path6.default.dirname((0, import_url2.fileURLToPath)(import_meta2.url));
|
|
2354
|
+
}
|
|
2355
|
+
const compiledTemplate = import_handlebars2.default.compile(
|
|
2356
|
+
(await fs5.readFile(import_path6.default.join(dirname, "./controller.tpl"))).toString()
|
|
2357
|
+
);
|
|
2358
|
+
const template = await compiledTemplate({
|
|
2359
|
+
className: import_change_case_all2.Case.pascal(this.name),
|
|
2360
|
+
classNameLower: import_change_case_all2.Case.snake(this.name),
|
|
2361
|
+
routeName: import_change_case_all2.Case.kebab((0, import_pluralize.default)(this.name))
|
|
2362
|
+
});
|
|
2363
|
+
await fs5.writeFile(
|
|
2364
|
+
import_path6.default.join(rootDir, "src/app/controllers", filename),
|
|
2365
|
+
template
|
|
2366
|
+
);
|
|
2556
2367
|
}
|
|
2557
|
-
}
|
|
2368
|
+
};
|
|
2369
|
+
cli().register(GenerateControllerCommand);
|
|
2370
|
+
|
|
2371
|
+
// src/app/console/generate/GenerateApiDocsCommand.mts
|
|
2372
|
+
var import_clipanion9 = require("clipanion");
|
|
2373
|
+
var import_path7 = __toESM(require("path"), 1);
|
|
2374
|
+
var fs6 = __toESM(require("fs/promises"), 1);
|
|
2558
2375
|
|
|
2559
2376
|
// src/config.mts
|
|
2560
2377
|
var config_exports = {};
|
|
2561
|
-
|
|
2562
|
-
"src/config.mts"() {
|
|
2563
|
-
"use strict";
|
|
2564
|
-
__reExport(config_exports, require("@devbro/neko-config"));
|
|
2565
|
-
}
|
|
2566
|
-
});
|
|
2378
|
+
__reExport(config_exports, require("@devbro/neko-config"));
|
|
2567
2379
|
|
|
2568
2380
|
// 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: `
|
|
2381
|
+
var import_neko_helper4 = require("@devbro/neko-helper");
|
|
2382
|
+
var GenerateApiDocsCommand = class extends import_clipanion9.Command {
|
|
2383
|
+
static {
|
|
2384
|
+
__name(this, "GenerateApiDocsCommand");
|
|
2385
|
+
}
|
|
2386
|
+
static paths = [[`generate`, `apidocs`]];
|
|
2387
|
+
static usage = import_clipanion9.Command.Usage({
|
|
2388
|
+
category: `Generate`,
|
|
2389
|
+
description: `Generate OpenAPI documentation from routes`,
|
|
2390
|
+
details: `
|
|
2588
2391
|
This command utility generates OpenAPI 3.0 specification documentation by analyzing
|
|
2589
2392
|
your application's routes and merging with example files.
|
|
2590
2393
|
|
|
@@ -2617,597 +2420,586 @@ api_docs: {
|
|
|
2617
2420
|
|
|
2618
2421
|
\`\`\`
|
|
2619
2422
|
`,
|
|
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
|
-
|
|
2423
|
+
examples: [
|
|
2424
|
+
[
|
|
2425
|
+
`Generate from routes`,
|
|
2426
|
+
`$0 generate apidocs generate-from-routes --output path/to/output.json`
|
|
2427
|
+
],
|
|
2428
|
+
[
|
|
2429
|
+
`Generate base spec`,
|
|
2430
|
+
`$0 generate apidocs generate-base --output path/to/output.json`
|
|
2431
|
+
],
|
|
2432
|
+
[`Merge files`, `$0 generate apidocs merge-files`],
|
|
2433
|
+
[`Show help`, `$0 generate apidocs --help`]
|
|
2434
|
+
]
|
|
2435
|
+
});
|
|
2436
|
+
subcommand = import_clipanion9.Option.String({ required: false });
|
|
2437
|
+
output = import_clipanion9.Option.String(`--output,-o`, {
|
|
2438
|
+
description: `Output file path for generated documentation`
|
|
2439
|
+
});
|
|
2440
|
+
config = import_clipanion9.Option.String(`--config,-c`, {
|
|
2441
|
+
description: `Path in config to get details from (default: api_docs)`,
|
|
2442
|
+
required: false
|
|
2443
|
+
});
|
|
2444
|
+
async execute() {
|
|
2445
|
+
if (!this.subcommand) {
|
|
2446
|
+
this.context.stdout.write(
|
|
2447
|
+
this.constructor.usage?.toString() || "No help available\n"
|
|
2448
|
+
);
|
|
2449
|
+
return 0;
|
|
2450
|
+
}
|
|
2451
|
+
switch (this.subcommand) {
|
|
2452
|
+
case "generate-from-routes":
|
|
2453
|
+
return await this.executeGenerateFromRoutes();
|
|
2454
|
+
case "generate-base":
|
|
2455
|
+
return await this.executeGenerateBase();
|
|
2456
|
+
case "merge-files":
|
|
2457
|
+
return await this.executeMergeFiles();
|
|
2458
|
+
default:
|
|
2459
|
+
this.context.stderr.write(`Unknown subcommand: ${this.subcommand}
|
|
2657
2460
|
`);
|
|
2658
|
-
this.context.stdout.write(
|
|
2659
|
-
this.constructor.usage?.toString() || "No help available\n"
|
|
2660
|
-
);
|
|
2661
|
-
return 1;
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
async executeGenerateFromRoutes() {
|
|
2665
2461
|
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"
|
|
2462
|
+
this.constructor.usage?.toString() || "No help available\n"
|
|
2676
2463
|
);
|
|
2677
|
-
|
|
2678
|
-
|
|
2464
|
+
return 1;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
async executeGenerateFromRoutes() {
|
|
2468
|
+
this.context.stdout.write(
|
|
2469
|
+
`Generating OpenAPI documentation from routes...
|
|
2679
2470
|
`
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2471
|
+
);
|
|
2472
|
+
const openApiSpec = this.generateFromRoutes();
|
|
2473
|
+
const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_from_routes.json");
|
|
2474
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2475
|
+
await fs6.writeFile(
|
|
2476
|
+
outputPath,
|
|
2477
|
+
JSON.stringify(openApiSpec, null, 2),
|
|
2478
|
+
"utf-8"
|
|
2479
|
+
);
|
|
2480
|
+
this.context.stdout.write(
|
|
2481
|
+
`OpenAPI routes documentation generated at: ${outputPath}
|
|
2683
2482
|
`
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
}
|
|
2687
|
-
|
|
2688
|
-
|
|
2483
|
+
);
|
|
2484
|
+
this.context.stdout.write(
|
|
2485
|
+
`Total routes documented: ${Object.keys(openApiSpec.paths).length}
|
|
2486
|
+
`
|
|
2487
|
+
);
|
|
2488
|
+
return 0;
|
|
2489
|
+
}
|
|
2490
|
+
async executeGenerateBase() {
|
|
2491
|
+
this.context.stdout.write(`Generating base OpenAPI specification...
|
|
2689
2492
|
`);
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2493
|
+
const baseSpec = this.getBaseOpenApiSpec();
|
|
2494
|
+
const outputPath = this.output || import_path7.default.join(config_exports.config.get("private_path"), "openapi_base.json");
|
|
2495
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2496
|
+
await fs6.writeFile(outputPath, JSON.stringify(baseSpec, null, 2), "utf-8");
|
|
2497
|
+
this.context.stdout.write(
|
|
2498
|
+
`Base OpenAPI specification generated at: ${outputPath}
|
|
2696
2499
|
`
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2500
|
+
);
|
|
2501
|
+
return 0;
|
|
2502
|
+
}
|
|
2503
|
+
async executeMergeFiles() {
|
|
2504
|
+
this.context.stdout.write(`Merging OpenAPI files...
|
|
2702
2505
|
`);
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2506
|
+
let configPath = this.config || "api_docs";
|
|
2507
|
+
const files_to_merge = config_exports.config.get(`${configPath}.merge_files`);
|
|
2508
|
+
let final_api_docs = {};
|
|
2509
|
+
for (const file_path of files_to_merge) {
|
|
2510
|
+
try {
|
|
2511
|
+
const file_json = JSON.parse(await fs6.readFile(file_path, "utf8"));
|
|
2512
|
+
final_api_docs = import_neko_helper4.Arr.deepMerge(final_api_docs, file_json);
|
|
2513
|
+
this.context.stdout.write(` Merged: ${file_path}
|
|
2711
2514
|
`);
|
|
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}
|
|
2515
|
+
} catch (error) {
|
|
2516
|
+
this.context.stderr.write(
|
|
2517
|
+
` Warning: Could not read ${file_path}: ${error.message}
|
|
2724
2518
|
`
|
|
2725
2519
|
);
|
|
2726
|
-
return 0;
|
|
2727
2520
|
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2521
|
+
}
|
|
2522
|
+
const outputPath = this.output || config_exports.config.get(`${configPath}.output`);
|
|
2523
|
+
await fs6.mkdir(import_path7.default.dirname(outputPath), { recursive: true });
|
|
2524
|
+
await fs6.writeFile(outputPath, JSON.stringify(final_api_docs, null, 2));
|
|
2525
|
+
this.context.stdout.write(
|
|
2526
|
+
`Final OpenAPI document written to: ${outputPath}
|
|
2527
|
+
`
|
|
2528
|
+
);
|
|
2529
|
+
return 0;
|
|
2530
|
+
}
|
|
2531
|
+
extractParameters(routePath) {
|
|
2532
|
+
const paramRegex = /:([a-zA-Z0-9_]+)/g;
|
|
2533
|
+
const parameters = [];
|
|
2534
|
+
let match;
|
|
2535
|
+
while ((match = paramRegex.exec(routePath)) !== null) {
|
|
2536
|
+
parameters.push({
|
|
2537
|
+
name: match[1],
|
|
2538
|
+
in: "path",
|
|
2539
|
+
required: true,
|
|
2540
|
+
schema: {
|
|
2541
|
+
type: "string"
|
|
2542
|
+
},
|
|
2543
|
+
description: `Path parameter ${match[1]}`
|
|
2544
|
+
});
|
|
2545
|
+
}
|
|
2546
|
+
return parameters;
|
|
2547
|
+
}
|
|
2548
|
+
generateFromRoutes() {
|
|
2549
|
+
const openApiSpec = {
|
|
2550
|
+
paths: {}
|
|
2551
|
+
};
|
|
2552
|
+
const routes = router().routes;
|
|
2553
|
+
for (const route of routes) {
|
|
2554
|
+
const routePath = route.path;
|
|
2555
|
+
const openApiPath = routePath.replace(/\/$/g, "");
|
|
2556
|
+
if (!openApiSpec.paths[openApiPath]) {
|
|
2557
|
+
openApiSpec.paths[openApiPath] = {};
|
|
2558
|
+
}
|
|
2559
|
+
for (const method of route.methods) {
|
|
2560
|
+
const lowerMethod = method.toLowerCase();
|
|
2561
|
+
if (lowerMethod === "head") {
|
|
2562
|
+
continue;
|
|
2742
2563
|
}
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2564
|
+
openApiSpec.paths[openApiPath][lowerMethod] = {
|
|
2565
|
+
summary: `${routePath}`,
|
|
2566
|
+
description: `Endpoint for ${method} ${routePath}`,
|
|
2567
|
+
security: [],
|
|
2568
|
+
parameters: this.extractParameters(routePath),
|
|
2569
|
+
responses: {}
|
|
2748
2570
|
};
|
|
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
|
-
}
|
|
2571
|
+
if (["post", "put", "patch"].includes(lowerMethod)) {
|
|
2572
|
+
openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
|
|
2573
|
+
required: true,
|
|
2574
|
+
content: {
|
|
2575
|
+
"application/json": {
|
|
2576
|
+
schema: {
|
|
2577
|
+
type: "object"
|
|
2777
2578
|
}
|
|
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
2579
|
}
|
|
2806
2580
|
}
|
|
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;
|
|
2581
|
+
};
|
|
2881
2582
|
}
|
|
2882
2583
|
}
|
|
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`);
|
|
2584
|
+
}
|
|
2585
|
+
return openApiSpec;
|
|
2586
|
+
}
|
|
2587
|
+
getBaseOpenApiSpec() {
|
|
2588
|
+
const openApiSpec = {
|
|
2589
|
+
openapi: "3.0.0",
|
|
2590
|
+
info: {
|
|
2591
|
+
title: "API Documentation",
|
|
2592
|
+
version: "1.0.0",
|
|
2593
|
+
description: "Auto-generated API documentation"
|
|
2594
|
+
},
|
|
2595
|
+
servers: [
|
|
2596
|
+
{
|
|
2597
|
+
url: "/",
|
|
2598
|
+
description: "Local server"
|
|
2918
2599
|
}
|
|
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;
|
|
2600
|
+
],
|
|
2601
|
+
components: {
|
|
2602
|
+
securitySchemes: {
|
|
2603
|
+
bearerAuth: {
|
|
2604
|
+
type: "http",
|
|
2605
|
+
scheme: "bearer",
|
|
2606
|
+
bearerFormat: "JWT",
|
|
2607
|
+
description: "JWT token authentication"
|
|
2941
2608
|
}
|
|
2942
2609
|
}
|
|
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
|
-
}
|
|
2610
|
+
},
|
|
2611
|
+
security: [
|
|
2612
|
+
{
|
|
2613
|
+
bearerAuth: []
|
|
2959
2614
|
}
|
|
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
|
-
}
|
|
2615
|
+
],
|
|
2616
|
+
paths: {}
|
|
2969
2617
|
};
|
|
2618
|
+
return openApiSpec;
|
|
2970
2619
|
}
|
|
2971
|
-
}
|
|
2620
|
+
};
|
|
2621
|
+
cli().register(GenerateApiDocsCommand);
|
|
2972
2622
|
|
|
2973
|
-
// src/app/console/
|
|
2974
|
-
var
|
|
2975
|
-
var
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2623
|
+
// src/app/console/project/CreateProjectCommand.mts
|
|
2624
|
+
var import_clipanion10 = require("clipanion");
|
|
2625
|
+
var import_change_case_all3 = require("change-case-all");
|
|
2626
|
+
var import_path8 = __toESM(require("path"), 1);
|
|
2627
|
+
var fs7 = __toESM(require("fs/promises"), 1);
|
|
2628
|
+
var import_url3 = require("url");
|
|
2629
|
+
var import_handlebars3 = __toESM(require("handlebars"), 1);
|
|
2630
|
+
var import_child_process = require("child_process");
|
|
2631
|
+
var import_prompts = require("@inquirer/prompts");
|
|
2632
|
+
var import_meta3 = {};
|
|
2633
|
+
var CreateProjectCommand = class extends import_clipanion10.Command {
|
|
2634
|
+
static {
|
|
2635
|
+
__name(this, "CreateProjectCommand");
|
|
2636
|
+
}
|
|
2637
|
+
static paths = [[`create`, `project`]];
|
|
2638
|
+
static usage = import_clipanion10.Command.Usage({
|
|
2639
|
+
category: `Project`,
|
|
2640
|
+
description: `Create a new project`,
|
|
2641
|
+
details: `
|
|
2642
|
+
This command creates a new project interactively.
|
|
2643
|
+
You will be prompted for the project path and other configuration options.
|
|
2644
|
+
`,
|
|
2645
|
+
examples: [[`Create a new project`, `create project`]]
|
|
2646
|
+
});
|
|
2647
|
+
projectPath = "";
|
|
2648
|
+
executor = "";
|
|
2649
|
+
packageManager = "";
|
|
2650
|
+
linter = "";
|
|
2651
|
+
validation_library = "";
|
|
2652
|
+
database_type = "";
|
|
2653
|
+
async folderExists(folderPath) {
|
|
2654
|
+
try {
|
|
2655
|
+
const stats = await fs7.stat(folderPath);
|
|
2656
|
+
return stats.isDirectory();
|
|
2657
|
+
} catch (error) {
|
|
2658
|
+
if (error.code === "ENOENT") {
|
|
2659
|
+
return false;
|
|
2990
2660
|
}
|
|
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
|
|
2661
|
+
throw error;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
async execute() {
|
|
2665
|
+
await this.setupProjectPath();
|
|
2666
|
+
await this.setupGit();
|
|
2667
|
+
await this.setupExecutorAndPackageManager();
|
|
2668
|
+
await this.setupLinter();
|
|
2669
|
+
await this.setupGeneralPackages();
|
|
2670
|
+
await this.setupBaseProject();
|
|
2671
|
+
await this.installPackages();
|
|
2672
|
+
}
|
|
2673
|
+
async processTplFolder(src, dest, data = {}) {
|
|
2674
|
+
const files = await fs7.readdir(src, { withFileTypes: true });
|
|
2675
|
+
for (const file of files) {
|
|
2676
|
+
const srcPath = import_path8.default.join(src, file.name);
|
|
2677
|
+
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);
|
|
2678
|
+
if (file.isDirectory()) {
|
|
2679
|
+
await fs7.mkdir(destPath, { recursive: true });
|
|
2680
|
+
await this.processTplFolder(srcPath, destPath, data);
|
|
2681
|
+
} else if (file.name.endsWith(".tpl")) {
|
|
2682
|
+
await this.processTplFile(srcPath, destPath, data);
|
|
2683
|
+
} else {
|
|
2684
|
+
throw new Error(
|
|
2685
|
+
"unexpected non tpl file: " + srcPath + " " + file.name
|
|
3020
2686
|
);
|
|
3021
2687
|
}
|
|
3022
|
-
}
|
|
3023
|
-
cli().register(GenerateQueueMigrateCommand);
|
|
2688
|
+
}
|
|
3024
2689
|
}
|
|
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);
|
|
2690
|
+
async processTplFile(src, dest, data = {}) {
|
|
2691
|
+
import_handlebars3.default.registerHelper("eq", (a, b) => a === b);
|
|
2692
|
+
const compiledTemplate = import_handlebars3.default.compile(
|
|
2693
|
+
(await fs7.readFile(src)).toString()
|
|
2694
|
+
);
|
|
2695
|
+
const template = await compiledTemplate(data);
|
|
2696
|
+
await fs7.writeFile(dest, template);
|
|
3054
2697
|
}
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
2698
|
+
async setupProjectPath() {
|
|
2699
|
+
const pathInput = await (0, import_prompts.input)({
|
|
2700
|
+
message: "Enter project path (leave empty to use current directory):",
|
|
2701
|
+
default: ""
|
|
2702
|
+
});
|
|
2703
|
+
this.projectPath = pathInput.trim() ? import_path8.default.resolve(pathInput.trim()) : process.cwd();
|
|
2704
|
+
await fs7.mkdir(this.projectPath, { recursive: true });
|
|
2705
|
+
const files = await fs7.readdir(this.projectPath);
|
|
2706
|
+
if (files.length > 0) {
|
|
2707
|
+
throw new Error(
|
|
2708
|
+
`Directory ${this.projectPath} is not empty. Please use an empty directory.`
|
|
2709
|
+
);
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
async setupExecutorAndPackageManager() {
|
|
2713
|
+
this.executor = await (0, import_prompts.select)({
|
|
2714
|
+
message: "Select a TypeScript executor",
|
|
2715
|
+
choices: [
|
|
2716
|
+
{
|
|
2717
|
+
name: "Bun",
|
|
2718
|
+
value: "bun",
|
|
2719
|
+
description: "Fast all-in-one JavaScript runtime"
|
|
2720
|
+
},
|
|
2721
|
+
{
|
|
2722
|
+
name: "TSX",
|
|
2723
|
+
value: "tsx",
|
|
2724
|
+
description: "TypeScript execute (tsx) - Node.js enhanced with esbuild"
|
|
3079
2725
|
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
2726
|
+
]
|
|
2727
|
+
});
|
|
2728
|
+
this.packageManager = this.executor === "bun" ? "bun" : await (0, import_prompts.select)({
|
|
2729
|
+
message: "Select a package manager",
|
|
2730
|
+
choices: [
|
|
2731
|
+
{
|
|
2732
|
+
name: "Yarn",
|
|
2733
|
+
value: "yarn",
|
|
2734
|
+
description: "Fast, reliable, and secure dependency management"
|
|
2735
|
+
},
|
|
2736
|
+
{
|
|
2737
|
+
name: "npm",
|
|
2738
|
+
value: "npm",
|
|
2739
|
+
description: "Node package manager (default)"
|
|
2740
|
+
},
|
|
2741
|
+
{
|
|
2742
|
+
name: "Bun",
|
|
2743
|
+
value: "bun",
|
|
2744
|
+
description: "Ultra-fast package manager built into Bun"
|
|
3088
2745
|
}
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
2746
|
+
],
|
|
2747
|
+
default: "yarn"
|
|
2748
|
+
});
|
|
2749
|
+
(0, import_child_process.execSync)(`${this.packageManager} init -y`, {
|
|
2750
|
+
stdio: "inherit",
|
|
2751
|
+
cwd: this.projectPath
|
|
2752
|
+
});
|
|
2753
|
+
const packageJsonPath = import_path8.default.join(this.projectPath, `package.json`);
|
|
2754
|
+
let packageJson = JSON.parse(await fs7.readFile(packageJsonPath, `utf-8`));
|
|
2755
|
+
packageJson.type = "module";
|
|
2756
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
2757
|
+
packageJson.scripts.prepare = "husky init";
|
|
2758
|
+
packageJson.scripts.clean = "rm -rf dist";
|
|
2759
|
+
if (this.executor === "bun") {
|
|
2760
|
+
packageJson.scripts.dev = "bun run dev";
|
|
2761
|
+
packageJson.scripts.start = "bun run pdev";
|
|
2762
|
+
packageJson.scripts.build = "bun run build";
|
|
2763
|
+
packageJson.scripts.test = "vitest";
|
|
2764
|
+
packageJson.scripts["test:watch"] = "vitest --watch";
|
|
2765
|
+
packageJson.scripts["test:coverage"] = "vitest run --coverage";
|
|
2766
|
+
} else if (this.executor === "tsx") {
|
|
2767
|
+
packageJson.scripts.dev = "tsx --watch -r tsconfig-paths/register src/index.ts start --all | npx pino-pretty";
|
|
2768
|
+
packageJson.scripts.start = "tsx dist/index.js";
|
|
2769
|
+
packageJson.scripts.build = "tsc";
|
|
2770
|
+
packageJson.scripts.test = "vitest";
|
|
2771
|
+
packageJson.scripts["test:watch"] = "vitest --watch";
|
|
2772
|
+
packageJson.scripts["test:coverage"] = "vitest run --coverage";
|
|
2773
|
+
}
|
|
2774
|
+
await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
3101
2775
|
}
|
|
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
|
-
}
|
|
2776
|
+
async setupLinter() {
|
|
2777
|
+
this.linter = await (0, import_prompts.select)({
|
|
2778
|
+
message: "Select a linter",
|
|
2779
|
+
choices: [
|
|
2780
|
+
{
|
|
2781
|
+
name: "Biome",
|
|
2782
|
+
value: "biome",
|
|
2783
|
+
description: "Fast formatter and linter for JavaScript, TypeScript, and more"
|
|
2784
|
+
},
|
|
2785
|
+
{
|
|
2786
|
+
name: "ESLint",
|
|
2787
|
+
value: "eslint",
|
|
2788
|
+
description: "Find and fix problems in your JavaScript code"
|
|
3150
2789
|
}
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
2790
|
+
]
|
|
2791
|
+
});
|
|
2792
|
+
const packageJsonPath = import_path8.default.join(this.projectPath, `package.json`);
|
|
2793
|
+
let packageJson = JSON.parse(await fs7.readFile(packageJsonPath, `utf-8`));
|
|
2794
|
+
if (this.linter === "biome") {
|
|
2795
|
+
packageJson.scripts.lint = "biome check . --ext .ts,.tsx";
|
|
2796
|
+
packageJson.scripts.format = "biome format . --ext .ts,.tsx --write";
|
|
2797
|
+
this.addPackage("@biomejs/biome", true);
|
|
2798
|
+
} else if (this.linter === "eslint") {
|
|
2799
|
+
packageJson.scripts.lint = "eslint . --ext .ts,.tsx";
|
|
2800
|
+
packageJson.scripts.format = "eslint . --ext .ts,.tsx --fix";
|
|
2801
|
+
this.addPackage("eslint", true);
|
|
2802
|
+
}
|
|
2803
|
+
await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2804
|
+
}
|
|
2805
|
+
async setupGeneralPackages() {
|
|
2806
|
+
this.validation_library = await (0, import_prompts.select)({
|
|
2807
|
+
message: "Select a package you want for validation",
|
|
2808
|
+
choices: [
|
|
2809
|
+
{
|
|
2810
|
+
name: "Yup",
|
|
2811
|
+
value: "yup",
|
|
2812
|
+
description: "https://github.com/jquense/yup"
|
|
2813
|
+
},
|
|
2814
|
+
{
|
|
2815
|
+
name: "Zod",
|
|
2816
|
+
value: "zod",
|
|
2817
|
+
description: "https://zod.dev/"
|
|
2818
|
+
},
|
|
2819
|
+
new import_prompts.Separator(),
|
|
2820
|
+
{
|
|
2821
|
+
name: "None",
|
|
2822
|
+
value: "none",
|
|
2823
|
+
disabled: false
|
|
3158
2824
|
}
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
2825
|
+
]
|
|
2826
|
+
});
|
|
2827
|
+
this.validation_library === "none" || await this.addPackage(this.validation_library);
|
|
2828
|
+
this.database_type = await (0, import_prompts.select)({
|
|
2829
|
+
message: "Select a database type (you can add more databases later)",
|
|
2830
|
+
choices: [
|
|
2831
|
+
{
|
|
2832
|
+
name: "PostgreSQL",
|
|
2833
|
+
value: "postgresql",
|
|
2834
|
+
description: "A powerful, open source object-relational database system"
|
|
2835
|
+
},
|
|
2836
|
+
{
|
|
2837
|
+
name: "MySQL",
|
|
2838
|
+
value: "mysql",
|
|
2839
|
+
description: "The world's most popular open source database"
|
|
2840
|
+
},
|
|
2841
|
+
{
|
|
2842
|
+
name: "SQLite",
|
|
2843
|
+
value: "sqlite",
|
|
2844
|
+
description: "A C library that provides a lightweight disk-based database"
|
|
2845
|
+
}
|
|
2846
|
+
]
|
|
2847
|
+
});
|
|
2848
|
+
if (this.database_type === "postgresql") {
|
|
2849
|
+
await this.addPackage("pg pg-cursor");
|
|
2850
|
+
} else if (this.database_type === "mysql") {
|
|
2851
|
+
await this.addPackage("mysql2");
|
|
2852
|
+
} else if (this.database_type === "sqlite") {
|
|
2853
|
+
await this.addPackage("sqlite3");
|
|
2854
|
+
}
|
|
2855
|
+
await this.addPackage("@devbro/pashmak tsconfig-paths dotenv ");
|
|
2856
|
+
await this.addPackage(
|
|
2857
|
+
"husky vitest supertest @types/supertest pino-pretty typescript tsx",
|
|
2858
|
+
true
|
|
2859
|
+
);
|
|
2860
|
+
}
|
|
2861
|
+
async setupBaseProject() {
|
|
2862
|
+
console.log(`Using project directory: ${this.projectPath}`);
|
|
2863
|
+
const dirname = typeof __dirname === "undefined" ? import_path8.default.dirname((0, import_url3.fileURLToPath)(import_meta3.url)) : __dirname;
|
|
2864
|
+
let basePath = import_path8.default.join(dirname, `./base_project`);
|
|
2865
|
+
if (await this.folderExists(basePath) === false) {
|
|
2866
|
+
basePath = import_path8.default.join(dirname, `../app/console/project/base_project`);
|
|
2867
|
+
}
|
|
2868
|
+
console.log(`Using base project path: ${basePath}`);
|
|
2869
|
+
const baseProjectPath = basePath;
|
|
2870
|
+
await this.processTplFolder(baseProjectPath, this.projectPath, {
|
|
2871
|
+
validation_library: this.validation_library,
|
|
2872
|
+
executor: this.executor,
|
|
2873
|
+
package_manager: this.packageManager,
|
|
2874
|
+
linter: this.linter,
|
|
2875
|
+
database_type: this.database_type
|
|
2876
|
+
});
|
|
2877
|
+
console.log(`Copied base project files to: ${this.projectPath}`);
|
|
2878
|
+
const packageJsonPath = import_path8.default.join(this.projectPath, "package.json");
|
|
2879
|
+
let packageJson = JSON.parse(await fs7.readFile(packageJsonPath, `utf-8`));
|
|
2880
|
+
packageJson.name = import_change_case_all3.Case.snake(import_path8.default.basename(this.projectPath));
|
|
2881
|
+
await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2882
|
+
console.log(`Updated package.json with project name: ${packageJson.name}`);
|
|
2883
|
+
}
|
|
2884
|
+
async addPackage(packageName, dev = false) {
|
|
2885
|
+
let install_command = "";
|
|
2886
|
+
switch (this.packageManager) {
|
|
2887
|
+
case "bun":
|
|
2888
|
+
install_command = `bun add ${packageName}${dev ? " -d" : ""}`;
|
|
2889
|
+
break;
|
|
2890
|
+
case "yarn":
|
|
2891
|
+
install_command = `yarn add ${packageName}${dev ? " -D" : ""} --no-install`;
|
|
2892
|
+
break;
|
|
2893
|
+
case "npm":
|
|
2894
|
+
install_command = `npm install ${packageName}${dev ? " --save-dev" : ""} --package-lock-only`;
|
|
2895
|
+
break;
|
|
2896
|
+
}
|
|
2897
|
+
(0, import_child_process.execSync)(install_command, {
|
|
2898
|
+
stdio: "inherit",
|
|
2899
|
+
cwd: this.projectPath
|
|
2900
|
+
});
|
|
2901
|
+
}
|
|
2902
|
+
async installPackages() {
|
|
2903
|
+
const install_command = this.packageManager === "bun" ? `bun install` : this.packageManager === "yarn" ? `yarn` : `npm install`;
|
|
2904
|
+
(0, import_child_process.execSync)(install_command, {
|
|
2905
|
+
stdio: "inherit",
|
|
2906
|
+
cwd: this.projectPath
|
|
2907
|
+
});
|
|
2908
|
+
}
|
|
2909
|
+
async setupGit() {
|
|
2910
|
+
const initGit = await (0, import_prompts.select)({
|
|
2911
|
+
message: "Initialize a git repository?",
|
|
2912
|
+
choices: [
|
|
2913
|
+
{
|
|
2914
|
+
name: "Yes",
|
|
2915
|
+
value: true,
|
|
2916
|
+
description: "Initialize git and create first commit"
|
|
2917
|
+
},
|
|
2918
|
+
{
|
|
2919
|
+
name: "No",
|
|
2920
|
+
value: false,
|
|
2921
|
+
description: "Skip git initialization"
|
|
3165
2922
|
}
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
2923
|
+
]
|
|
2924
|
+
});
|
|
2925
|
+
if (initGit) {
|
|
2926
|
+
const gitignoreContent = [
|
|
2927
|
+
"node_modules/",
|
|
2928
|
+
"dist/",
|
|
2929
|
+
".env",
|
|
2930
|
+
".env.*",
|
|
2931
|
+
"!.env.example",
|
|
2932
|
+
"*.log",
|
|
2933
|
+
"coverage/",
|
|
2934
|
+
".DS_Store"
|
|
2935
|
+
].join("\n") + "\n";
|
|
2936
|
+
await fs7.writeFile(
|
|
2937
|
+
import_path8.default.join(this.projectPath, ".gitignore"),
|
|
2938
|
+
gitignoreContent
|
|
2939
|
+
);
|
|
2940
|
+
(0, import_child_process.execSync)(
|
|
2941
|
+
`git init; git add --all; git commit --allow-empty -m "chore: first commit"`,
|
|
2942
|
+
{
|
|
2943
|
+
cwd: this.projectPath
|
|
3169
2944
|
}
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
};
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
3173
2947
|
}
|
|
3174
|
-
|
|
2948
|
+
async catch(error) {
|
|
2949
|
+
if (Error.isError(error)) {
|
|
2950
|
+
console.error(error.message);
|
|
2951
|
+
} else {
|
|
2952
|
+
console.error(error);
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
};
|
|
3175
2956
|
|
|
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
|
-
|
|
2957
|
+
// src/app/console/queue/GenerateQueueMigrateCommand.mts
|
|
2958
|
+
var import_clipanion11 = require("clipanion");
|
|
2959
|
+
var import_change_case_all4 = require("change-case-all");
|
|
2960
|
+
var import_path9 = __toESM(require("path"), 1);
|
|
2961
|
+
var fs8 = __toESM(require("fs/promises"), 1);
|
|
2962
|
+
var import_neko_config7 = require("@devbro/neko-config");
|
|
2963
|
+
var import_handlebars4 = __toESM(require("handlebars"), 1);
|
|
2964
|
+
var import_url4 = require("url");
|
|
2965
|
+
var import_meta4 = {};
|
|
2966
|
+
var GenerateQueueMigrateCommand = class extends import_clipanion11.Command {
|
|
2967
|
+
static {
|
|
2968
|
+
__name(this, "GenerateQueueMigrateCommand");
|
|
2969
|
+
}
|
|
2970
|
+
static paths = [[`generate`, `queue`, "migration"]];
|
|
2971
|
+
name = "queue_messages";
|
|
2972
|
+
async execute() {
|
|
2973
|
+
const date = /* @__PURE__ */ new Date();
|
|
2974
|
+
const year = date.getFullYear();
|
|
2975
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
2976
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
2977
|
+
const secondsOfDay = String(
|
|
2978
|
+
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
2979
|
+
).padStart(5, "0");
|
|
2980
|
+
const fixed_name = "queue_messages";
|
|
2981
|
+
const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;
|
|
2982
|
+
this.context.stdout.write(`creating migration file ${filename}
|
|
2983
|
+
`);
|
|
2984
|
+
await fs8.mkdir(import_neko_config7.config.get("migration.path"), { recursive: true });
|
|
2985
|
+
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
2986
|
+
if (!dirname) {
|
|
2987
|
+
dirname = import_path9.default.dirname((0, import_url4.fileURLToPath)(import_meta4.url));
|
|
2988
|
+
}
|
|
2989
|
+
const compiledTemplate = import_handlebars4.default.compile(
|
|
2990
|
+
(await fs8.readFile(import_path9.default.join(dirname, "./queue_migration.tpl"))).toString()
|
|
3204
2991
|
);
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
}
|
|
2992
|
+
const template = await compiledTemplate({
|
|
2993
|
+
className: import_change_case_all4.Case.pascal(this.name) + "Migration",
|
|
2994
|
+
tableName: import_change_case_all4.Case.snake(this.name)
|
|
2995
|
+
});
|
|
2996
|
+
await fs8.writeFile(
|
|
2997
|
+
import_path9.default.join(import_neko_config7.config.get("migration.path"), filename),
|
|
2998
|
+
template
|
|
2999
|
+
);
|
|
3000
|
+
}
|
|
3001
|
+
};
|
|
3002
|
+
cli().register(GenerateQueueMigrateCommand);
|
|
3003
|
+
|
|
3004
|
+
// src/app/console/index.mts
|
|
3005
|
+
cli().register(CreateProjectCommand);
|