@devbro/pashmak 0.1.10 → 0.1.12

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.
Files changed (40) hide show
  1. package/dist/app/console/migrate/MigrateCommand.d.mts +1 -0
  2. package/dist/app/console/migrate/MigrateCommand.mjs +33 -16
  3. package/dist/app/console/migrate/MigrateCommand.mjs.map +1 -1
  4. package/dist/app/console/migrate/MigrateRollbackCommand.d.mts +1 -1
  5. package/dist/app/console/migrate/MigrateRollbackCommand.mjs +5 -6
  6. package/dist/app/console/migrate/MigrateRollbackCommand.mjs.map +1 -1
  7. package/dist/app/console/migrate/make_migration.tpl +5 -5
  8. package/dist/app/console/queue/GenerateMigrateCommand.d.mts +9 -0
  9. package/dist/app/console/queue/GenerateMigrateCommand.mjs +51 -0
  10. package/dist/app/console/queue/GenerateMigrateCommand.mjs.map +1 -0
  11. package/dist/app/console/queue/queue_migration.tpl +19 -0
  12. package/dist/bin/app/console/DefaultCommand.cjs +254 -25
  13. package/dist/bin/app/console/KeyGenerateCommand.cjs +254 -25
  14. package/dist/bin/app/console/StartCommand.cjs +257 -28
  15. package/dist/bin/app/console/generate/GenerateControllerCommand.cjs +254 -25
  16. package/dist/bin/app/console/generate/index.cjs +254 -25
  17. package/dist/bin/app/console/index.cjs +293 -48
  18. package/dist/bin/app/console/migrate/GenerateMigrateCommand.cjs +254 -25
  19. package/dist/bin/app/console/migrate/MigrateCommand.cjs +288 -42
  20. package/dist/bin/app/console/migrate/MigrateRollbackCommand.cjs +258 -30
  21. package/dist/bin/app/console/migrate/index.cjs +291 -46
  22. package/dist/bin/app/console/queue/GenerateMigrateCommand.cjs +752 -0
  23. package/dist/bin/facades.cjs +257 -26
  24. package/dist/bin/factories.cjs +707 -0
  25. package/dist/bin/index.cjs +312 -54
  26. package/dist/bin/middlewares.cjs +255 -26
  27. package/dist/bin/queue.cjs +99 -0
  28. package/dist/bin/router.cjs +95 -5
  29. package/dist/facades.d.mts +3 -1
  30. package/dist/facades.mjs +15 -27
  31. package/dist/facades.mjs.map +1 -1
  32. package/dist/factories.d.mts +20 -0
  33. package/dist/factories.mjs +83 -0
  34. package/dist/factories.mjs.map +1 -0
  35. package/dist/queue.d.mts +15 -0
  36. package/dist/queue.mjs +73 -0
  37. package/dist/queue.mjs.map +1 -0
  38. package/dist/router.mjs +1 -1
  39. package/dist/router.mjs.map +1 -1
  40. package/package.json +10 -3
@@ -41,6 +41,9 @@ module.exports = __toCommonJS(middlewares_exports);
41
41
  var import_neko_context = require("@devbro/neko-context");
42
42
  var import_errors = require("@devbro/neko-http/errors");
43
43
 
44
+ // ../neko-router/dist/CompiledRoute.mjs
45
+ var import_stream = require("stream");
46
+
44
47
  // ../neko-router/dist/Middleware.mjs
45
48
  var Middleware = class {
46
49
  static {
@@ -118,6 +121,9 @@ var CompiledRoute = class {
118
121
  if (typeof value.toJson === "function") {
119
122
  return traverse(value.toJson());
120
123
  }
124
+ if (typeof value.toJSON === "function") {
125
+ return traverse(value.toJSON());
126
+ }
121
127
  if (Array.isArray(value)) {
122
128
  return value.map(traverse);
123
129
  }
@@ -142,7 +148,7 @@ var CompiledRoute = class {
142
148
  }
143
149
  return String(obj);
144
150
  }
145
- processResponseBody(res, controller_rc) {
151
+ async processResponseBody(res, controller_rc) {
146
152
  if (controller_rc && res.writableEnded) {
147
153
  throw new Error("cannot write to response, response has already ended");
148
154
  }
@@ -151,18 +157,36 @@ var CompiledRoute = class {
151
157
  }
152
158
  if (controller_rc) {
153
159
  const header_content_type = res.getHeader("Content-Type");
154
- if (!header_content_type && typeof controller_rc === "object") {
160
+ if (controller_rc instanceof import_stream.Stream || Buffer.isBuffer(controller_rc)) {
161
+ await this.writeAsync(res, controller_rc);
162
+ res.end();
163
+ } else if (!header_content_type && typeof controller_rc === "object") {
155
164
  res.setHeader("Content-Type", "application/json");
165
+ res.end(this.convertToString(controller_rc));
156
166
  } else if (!header_content_type) {
157
167
  res.setHeader("Content-Type", "text/plain");
168
+ res.end(this.convertToString(controller_rc));
169
+ } else {
170
+ res.end(this.convertToString(controller_rc));
158
171
  }
159
- res.end(this.convertToString(controller_rc));
160
172
  return;
161
173
  } else {
162
174
  res.statusCode = [200].includes(res.statusCode) ? 204 : res.statusCode;
163
175
  res.end();
164
176
  }
165
177
  }
178
+ async writeAsync(res, chunk) {
179
+ return new Promise((resolve, reject) => {
180
+ const ok = res.write(chunk, (err) => {
181
+ if (err) reject(err);
182
+ });
183
+ if (ok) {
184
+ resolve(0);
185
+ } else {
186
+ res.once("drain", resolve);
187
+ }
188
+ });
189
+ }
166
190
  async runMiddlewares(middlewares, req, res) {
167
191
  let index = 0;
168
192
  const me = this;
@@ -220,7 +244,7 @@ var Route = class {
220
244
  i = start;
221
245
  } else if (char === "*") {
222
246
  let start = i + 1;
223
- while (start < path2.length && /[a-zA-Z0-9_]/.test(path2[start])) {
247
+ while (start < path2.length && /[a-zA-Z0-9_\.]/.test(path2[start])) {
224
248
  start++;
225
249
  }
226
250
  tokens.push({ type: "WILDCARD", value: path2.slice(i + 1, start) });
@@ -290,6 +314,10 @@ var Route = class {
290
314
  params: r.groups || {}
291
315
  };
292
316
  }
317
+ prependMiddleware(middlewares) {
318
+ this.middlewares = [].concat(middlewares, this.middlewares);
319
+ return this;
320
+ }
293
321
  addMiddleware(middlewares) {
294
322
  this.middlewares = this.middlewares.concat(middlewares);
295
323
  return this;
@@ -304,6 +332,62 @@ var Route = class {
304
332
 
305
333
  // ../neko-router/dist/Router.mjs
306
334
  var import_path = __toESM(require("path"), 1);
335
+
336
+ // ../node_modules/url-join/lib/url-join.js
337
+ function normalize(strArray) {
338
+ var resultArray = [];
339
+ if (strArray.length === 0) {
340
+ return "";
341
+ }
342
+ if (typeof strArray[0] !== "string") {
343
+ throw new TypeError("Url must be a string. Received " + strArray[0]);
344
+ }
345
+ if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
346
+ var first = strArray.shift();
347
+ strArray[0] = first + strArray[0];
348
+ }
349
+ if (strArray[0].match(/^file:\/\/\//)) {
350
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///");
351
+ } else {
352
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://");
353
+ }
354
+ for (var i = 0; i < strArray.length; i++) {
355
+ var component = strArray[i];
356
+ if (typeof component !== "string") {
357
+ throw new TypeError("Url must be a string. Received " + component);
358
+ }
359
+ if (component === "") {
360
+ continue;
361
+ }
362
+ if (i > 0) {
363
+ component = component.replace(/^[\/]+/, "");
364
+ }
365
+ if (i < strArray.length - 1) {
366
+ component = component.replace(/[\/]+$/, "");
367
+ } else {
368
+ component = component.replace(/[\/]+$/, "/");
369
+ }
370
+ resultArray.push(component);
371
+ }
372
+ var str = resultArray.join("/");
373
+ str = str.replace(/\/(\?|&|#[^!])/g, "$1");
374
+ var parts = str.split("?");
375
+ str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&");
376
+ return str;
377
+ }
378
+ __name(normalize, "normalize");
379
+ function urlJoin() {
380
+ var input;
381
+ if (typeof arguments[0] === "object") {
382
+ input = arguments[0];
383
+ } else {
384
+ input = [].slice.call(arguments);
385
+ }
386
+ return normalize(input);
387
+ }
388
+ __name(urlJoin, "urlJoin");
389
+
390
+ // ../neko-router/dist/Router.mjs
307
391
  var Router = class {
308
392
  static {
309
393
  __name(this, "Router");
@@ -328,6 +412,12 @@ var Router = class {
328
412
  }).addMiddleware([...controller.baseMiddlewares, ...route.middlewares]);
329
413
  }
330
414
  }
415
+ addRouter(path2, router2) {
416
+ for (const route of router2.routes) {
417
+ let path22 = urlJoin("/", path2, route.path);
418
+ this.addRoute(route.methods, path22, route.handler).addMiddleware(router2.getMiddlewares()).addMiddleware(route.getMiddlewares());
419
+ }
420
+ }
331
421
  addGlobalMiddleware(middlewares) {
332
422
  this.middlewares = this.middlewares.concat(middlewares);
333
423
  }
@@ -368,7 +458,7 @@ var import_neko_scheduler = require("@devbro/neko-scheduler");
368
458
  var import_neko_helper = require("@devbro/neko-helper");
369
459
  var import_neko_context2 = require("@devbro/neko-context");
370
460
  var import_neko_storage = require("@devbro/neko-storage");
371
- var import_neko_mailer = require("@devbro/neko-mailer");
461
+ var import_neko_mailer2 = require("@devbro/neko-mailer");
372
462
  var import_neko_config = require("@devbro/neko-config");
373
463
  var import_clipanion = require("clipanion");
374
464
 
@@ -379,6 +469,153 @@ __reExport(http_exports, require("@devbro/neko-http"));
379
469
  // src/facades.mts
380
470
  var yup = __toESM(require("yup"), 1);
381
471
  var import_neko_logger = require("@devbro/neko-logger");
472
+
473
+ // src/factories.mts
474
+ var import_neko_mailer = require("@devbro/neko-mailer");
475
+ var import_neko_queue = require("@devbro/neko-queue");
476
+ var import_neko_queue2 = require("@devbro/neko-queue");
477
+
478
+ // src/queue.mts
479
+ var queue_exports = {};
480
+ __export(queue_exports, {
481
+ DatabaseTransport: () => DatabaseTransport
482
+ });
483
+ __reExport(queue_exports, require("@devbro/neko-queue"));
484
+ var import_neko_sql = require("@devbro/neko-sql");
485
+ var DatabaseTransport = class {
486
+ // default to 100 messages per fetch
487
+ constructor(db_config) {
488
+ this.db_config = db_config;
489
+ }
490
+ static {
491
+ __name(this, "DatabaseTransport");
492
+ }
493
+ listenInterval = 6e4;
494
+ // default to 1 minute
495
+ messageLimit = 100;
496
+ setListenInterval(interval) {
497
+ this.listenInterval = interval;
498
+ }
499
+ setMessageLimit(limit) {
500
+ this.messageLimit = limit;
501
+ }
502
+ async dispatch(channel, message) {
503
+ const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
504
+ try {
505
+ await conn.connect();
506
+ let q = conn.getQuery();
507
+ await q.table("queue_messages").insert({
508
+ channel,
509
+ message,
510
+ processed: false,
511
+ created_at: /* @__PURE__ */ new Date(),
512
+ updated_at: /* @__PURE__ */ new Date(),
513
+ last_tried_at: null,
514
+ process_message: ""
515
+ });
516
+ } finally {
517
+ await conn.disconnect();
518
+ }
519
+ }
520
+ async listen(channel, callback) {
521
+ return new Promise(async (resolve, reject) => {
522
+ setInterval(async () => {
523
+ const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
524
+ try {
525
+ await conn.connect();
526
+ let q = conn.getQuery();
527
+ let messages = await q.table("queue_messages").whereOp("channel", "=", channel).whereOp("processed", "=", false).limit(this.messageLimit).orderBy("last_tried_at", "asc").get();
528
+ for (let msg of messages) {
529
+ try {
530
+ await callback(msg.message);
531
+ await q.table("queue_messages").whereOp("id", "=", msg.id).update({
532
+ processed: true,
533
+ updated_at: /* @__PURE__ */ new Date()
534
+ });
535
+ } catch (error) {
536
+ await q.table("queue_messages").whereOp("id", "=", msg.id).update({
537
+ processed: false,
538
+ last_tried_at: /* @__PURE__ */ new Date(),
539
+ process_message: error.message || "Error processing message"
540
+ });
541
+ }
542
+ }
543
+ } finally {
544
+ await conn.disconnect();
545
+ }
546
+ }, this.listenInterval);
547
+ });
548
+ }
549
+ };
550
+
551
+ // src/factories.mts
552
+ var FlexibleFactory = class {
553
+ static {
554
+ __name(this, "FlexibleFactory");
555
+ }
556
+ registry = /* @__PURE__ */ new Map();
557
+ register(key, ctor) {
558
+ this.registry.set(key, ctor);
559
+ }
560
+ create(key, ...args) {
561
+ const ctor = this.registry.get(key);
562
+ if (!ctor) {
563
+ throw new Error(`No factory registered for key: ${key}`);
564
+ }
565
+ return new ctor(...args);
566
+ }
567
+ };
568
+ var MailerFactory = class _MailerFactory {
569
+ static {
570
+ __name(this, "MailerFactory");
571
+ }
572
+ static instance = new FlexibleFactory();
573
+ static register(key, factory) {
574
+ _MailerFactory.instance.register(key, factory);
575
+ }
576
+ static create(key, ...args) {
577
+ return _MailerFactory.instance.create(key, ...args);
578
+ }
579
+ };
580
+ MailerFactory.register("logger", (opt) => {
581
+ return new import_neko_mailer.FunctionProvider((mail) => {
582
+ logger().info({
583
+ msg: "Sending email",
584
+ mail
585
+ });
586
+ });
587
+ });
588
+ MailerFactory.register("SES", (opt) => {
589
+ return new import_neko_mailer.SESProvider(opt);
590
+ });
591
+ MailerFactory.register("SMTP", (opt) => {
592
+ return new import_neko_mailer.SMTPProvider(opt);
593
+ });
594
+ MailerFactory.register("MEMORY", (opt) => {
595
+ return new import_neko_mailer.MemoryProvider();
596
+ });
597
+ var QueueFactory = class _QueueFactory {
598
+ static {
599
+ __name(this, "QueueFactory");
600
+ }
601
+ static instance = new FlexibleFactory();
602
+ static register(key, factory) {
603
+ _QueueFactory.instance.register(key, factory);
604
+ }
605
+ static create(key, ...args) {
606
+ return _QueueFactory.instance.create(key, ...args);
607
+ }
608
+ };
609
+ QueueFactory.register("database", (opt) => {
610
+ let transport = new DatabaseTransport(opt);
611
+ return new import_neko_queue.QueueConnection(transport);
612
+ });
613
+ QueueFactory.register("memory", (opt) => {
614
+ let transport = new import_neko_queue2.MemoryTransport(opt);
615
+ return new import_neko_queue.QueueConnection(transport);
616
+ });
617
+
618
+ // src/facades.mts
382
619
  var router = (0, import_neko_helper.createSingleton)(() => new Router());
383
620
  var scheduler = (0, import_neko_helper.createSingleton)(() => {
384
621
  const rc = new import_neko_scheduler.Scheduler();
@@ -449,27 +686,19 @@ var logger = (0, import_neko_helper.createSingleton)((label) => {
449
686
  });
450
687
  var mailer = (0, import_neko_helper.createSingleton)((label) => {
451
688
  const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
452
- let provider;
453
- if (mailer_config.provider === "logger") {
454
- provider = new import_neko_mailer.FunctionProvider((mail) => {
455
- logger().info({
456
- msg: "Sending email",
457
- mail
458
- });
459
- });
460
- } else if (mailer_config.provider === "SES") {
461
- provider = new import_neko_mailer.SESProvider(mailer_config.config);
462
- } else if (mailer_config.provider === "SMTP") {
463
- provider = new import_neko_mailer.SMTPProvider(mailer_config.config);
464
- } else if (mailer_config.provider === "MEMORY") {
465
- provider = new import_neko_mailer.MemoryProvider();
466
- }
467
- if (!provider) {
468
- throw new Error(
469
- `cannot initiate mailer provider: ${mailer_config?.provider}`
470
- );
471
- }
472
- const rc = new import_neko_mailer.Mailer(provider);
689
+ let provider = MailerFactory.create(
690
+ mailer_config.provider,
691
+ mailer_config.config
692
+ );
693
+ const rc = new import_neko_mailer2.Mailer(provider);
694
+ return rc;
695
+ });
696
+ var queue = (0, import_neko_helper.createSingleton)(async (label) => {
697
+ const queue_config = import_neko_config.config.get(["queues", label].join("."));
698
+ if (!queue_config) {
699
+ throw new Error(`Queue configuration for '${label}' not found`);
700
+ }
701
+ const rc = await QueueFactory.create(queue_config.type, queue_config);
473
702
  return rc;
474
703
  });
475
704
 
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/queue.mts
23
+ var queue_exports = {};
24
+ __export(queue_exports, {
25
+ DatabaseTransport: () => DatabaseTransport
26
+ });
27
+ module.exports = __toCommonJS(queue_exports);
28
+ __reExport(queue_exports, require("@devbro/neko-queue"), module.exports);
29
+ var import_neko_sql = require("@devbro/neko-sql");
30
+ var DatabaseTransport = class {
31
+ // default to 100 messages per fetch
32
+ constructor(db_config) {
33
+ this.db_config = db_config;
34
+ }
35
+ static {
36
+ __name(this, "DatabaseTransport");
37
+ }
38
+ listenInterval = 6e4;
39
+ // default to 1 minute
40
+ messageLimit = 100;
41
+ setListenInterval(interval) {
42
+ this.listenInterval = interval;
43
+ }
44
+ setMessageLimit(limit) {
45
+ this.messageLimit = limit;
46
+ }
47
+ async dispatch(channel, message) {
48
+ const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
49
+ try {
50
+ await conn.connect();
51
+ let q = conn.getQuery();
52
+ await q.table("queue_messages").insert({
53
+ channel,
54
+ message,
55
+ processed: false,
56
+ created_at: /* @__PURE__ */ new Date(),
57
+ updated_at: /* @__PURE__ */ new Date(),
58
+ last_tried_at: null,
59
+ process_message: ""
60
+ });
61
+ } finally {
62
+ await conn.disconnect();
63
+ }
64
+ }
65
+ async listen(channel, callback) {
66
+ return new Promise(async (resolve, reject) => {
67
+ setInterval(async () => {
68
+ const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
69
+ try {
70
+ await conn.connect();
71
+ let q = conn.getQuery();
72
+ let messages = await q.table("queue_messages").whereOp("channel", "=", channel).whereOp("processed", "=", false).limit(this.messageLimit).orderBy("last_tried_at", "asc").get();
73
+ for (let msg of messages) {
74
+ try {
75
+ await callback(msg.message);
76
+ await q.table("queue_messages").whereOp("id", "=", msg.id).update({
77
+ processed: true,
78
+ updated_at: /* @__PURE__ */ new Date()
79
+ });
80
+ } catch (error) {
81
+ await q.table("queue_messages").whereOp("id", "=", msg.id).update({
82
+ processed: false,
83
+ last_tried_at: /* @__PURE__ */ new Date(),
84
+ process_message: error.message || "Error processing message"
85
+ });
86
+ }
87
+ }
88
+ } finally {
89
+ await conn.disconnect();
90
+ }
91
+ }, this.listenInterval);
92
+ });
93
+ }
94
+ };
95
+ // Annotate the CommonJS export names for ESM import in node:
96
+ 0 && (module.exports = {
97
+ DatabaseTransport,
98
+ ...require("@devbro/neko-queue")
99
+ });
@@ -54,6 +54,9 @@ module.exports = __toCommonJS(router_exports);
54
54
  var import_neko_context = require("@devbro/neko-context");
55
55
  var import_errors = require("@devbro/neko-http/errors");
56
56
 
57
+ // ../neko-router/dist/CompiledRoute.mjs
58
+ var import_stream = require("stream");
59
+
57
60
  // ../neko-router/dist/Middleware.mjs
58
61
  var Middleware = class {
59
62
  static {
@@ -131,6 +134,9 @@ var CompiledRoute = class {
131
134
  if (typeof value.toJson === "function") {
132
135
  return traverse(value.toJson());
133
136
  }
137
+ if (typeof value.toJSON === "function") {
138
+ return traverse(value.toJSON());
139
+ }
134
140
  if (Array.isArray(value)) {
135
141
  return value.map(traverse);
136
142
  }
@@ -155,7 +161,7 @@ var CompiledRoute = class {
155
161
  }
156
162
  return String(obj);
157
163
  }
158
- processResponseBody(res, controller_rc) {
164
+ async processResponseBody(res, controller_rc) {
159
165
  if (controller_rc && res.writableEnded) {
160
166
  throw new Error("cannot write to response, response has already ended");
161
167
  }
@@ -164,18 +170,36 @@ var CompiledRoute = class {
164
170
  }
165
171
  if (controller_rc) {
166
172
  const header_content_type = res.getHeader("Content-Type");
167
- if (!header_content_type && typeof controller_rc === "object") {
173
+ if (controller_rc instanceof import_stream.Stream || Buffer.isBuffer(controller_rc)) {
174
+ await this.writeAsync(res, controller_rc);
175
+ res.end();
176
+ } else if (!header_content_type && typeof controller_rc === "object") {
168
177
  res.setHeader("Content-Type", "application/json");
178
+ res.end(this.convertToString(controller_rc));
169
179
  } else if (!header_content_type) {
170
180
  res.setHeader("Content-Type", "text/plain");
181
+ res.end(this.convertToString(controller_rc));
182
+ } else {
183
+ res.end(this.convertToString(controller_rc));
171
184
  }
172
- res.end(this.convertToString(controller_rc));
173
185
  return;
174
186
  } else {
175
187
  res.statusCode = [200].includes(res.statusCode) ? 204 : res.statusCode;
176
188
  res.end();
177
189
  }
178
190
  }
191
+ async writeAsync(res, chunk) {
192
+ return new Promise((resolve, reject) => {
193
+ const ok = res.write(chunk, (err) => {
194
+ if (err) reject(err);
195
+ });
196
+ if (ok) {
197
+ resolve(0);
198
+ } else {
199
+ res.once("drain", resolve);
200
+ }
201
+ });
202
+ }
179
203
  async runMiddlewares(middlewares, req, res) {
180
204
  let index = 0;
181
205
  const me = this;
@@ -336,7 +360,7 @@ var Route = class {
336
360
  i = start;
337
361
  } else if (char === "*") {
338
362
  let start = i + 1;
339
- while (start < path2.length && /[a-zA-Z0-9_]/.test(path2[start])) {
363
+ while (start < path2.length && /[a-zA-Z0-9_\.]/.test(path2[start])) {
340
364
  start++;
341
365
  }
342
366
  tokens.push({ type: "WILDCARD", value: path2.slice(i + 1, start) });
@@ -406,6 +430,10 @@ var Route = class {
406
430
  params: r.groups || {}
407
431
  };
408
432
  }
433
+ prependMiddleware(middlewares) {
434
+ this.middlewares = [].concat(middlewares, this.middlewares);
435
+ return this;
436
+ }
409
437
  addMiddleware(middlewares) {
410
438
  this.middlewares = this.middlewares.concat(middlewares);
411
439
  return this;
@@ -420,6 +448,62 @@ var Route = class {
420
448
 
421
449
  // ../neko-router/dist/Router.mjs
422
450
  var import_path = __toESM(require("path"), 1);
451
+
452
+ // ../node_modules/url-join/lib/url-join.js
453
+ function normalize(strArray) {
454
+ var resultArray = [];
455
+ if (strArray.length === 0) {
456
+ return "";
457
+ }
458
+ if (typeof strArray[0] !== "string") {
459
+ throw new TypeError("Url must be a string. Received " + strArray[0]);
460
+ }
461
+ if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
462
+ var first = strArray.shift();
463
+ strArray[0] = first + strArray[0];
464
+ }
465
+ if (strArray[0].match(/^file:\/\/\//)) {
466
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///");
467
+ } else {
468
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://");
469
+ }
470
+ for (var i = 0; i < strArray.length; i++) {
471
+ var component = strArray[i];
472
+ if (typeof component !== "string") {
473
+ throw new TypeError("Url must be a string. Received " + component);
474
+ }
475
+ if (component === "") {
476
+ continue;
477
+ }
478
+ if (i > 0) {
479
+ component = component.replace(/^[\/]+/, "");
480
+ }
481
+ if (i < strArray.length - 1) {
482
+ component = component.replace(/[\/]+$/, "");
483
+ } else {
484
+ component = component.replace(/[\/]+$/, "/");
485
+ }
486
+ resultArray.push(component);
487
+ }
488
+ var str = resultArray.join("/");
489
+ str = str.replace(/\/(\?|&|#[^!])/g, "$1");
490
+ var parts = str.split("?");
491
+ str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&");
492
+ return str;
493
+ }
494
+ __name(normalize, "normalize");
495
+ function urlJoin() {
496
+ var input;
497
+ if (typeof arguments[0] === "object") {
498
+ input = arguments[0];
499
+ } else {
500
+ input = [].slice.call(arguments);
501
+ }
502
+ return normalize(input);
503
+ }
504
+ __name(urlJoin, "urlJoin");
505
+
506
+ // ../neko-router/dist/Router.mjs
423
507
  var Router = class {
424
508
  static {
425
509
  __name(this, "Router");
@@ -444,6 +528,12 @@ var Router = class {
444
528
  }).addMiddleware([...controller.baseMiddlewares, ...route.middlewares]);
445
529
  }
446
530
  }
531
+ addRouter(path2, router) {
532
+ for (const route of router.routes) {
533
+ let path22 = urlJoin("/", path2, route.path);
534
+ this.addRoute(route.methods, path22, route.handler).addMiddleware(router.getMiddlewares()).addMiddleware(route.getMiddlewares());
535
+ }
536
+ }
447
537
  addGlobalMiddleware(middlewares) {
448
538
  this.middlewares = this.middlewares.concat(middlewares);
449
539
  }
@@ -505,7 +595,7 @@ function Model(model, paramName) {
505
595
  return createParamDecorator(async () => {
506
596
  let rc = await model.find((0, import_neko_context.ctx)().get("request").params[paramName]);
507
597
  if (!rc) {
508
- throw new import_errors.HttpNotFoundError("Object not found");
598
+ throw new import_errors.HttpNotFoundError("Object not found", "OBJECT_NOT_FOUND");
509
599
  }
510
600
  return rc;
511
601
  });
@@ -7,6 +7,7 @@ import { Storage } from '@devbro/neko-storage';
7
7
  import { Mailer } from '@devbro/neko-mailer';
8
8
  import { HttpServer } from '@devbro/neko-http';
9
9
  import { Logger } from '@devbro/neko-logger';
10
+ import { QueueConnection } from '@devbro/neko-queue';
10
11
 
11
12
  declare const router: (label?: string, ...args: any[]) => Router;
12
13
  declare const scheduler: (label?: string, ...args: any[]) => Scheduler;
@@ -16,5 +17,6 @@ declare const cli: (label?: string, ...args: any[]) => Cli<clipanion.BaseContext
16
17
  declare const httpServer: (label?: string, ...args: any[]) => HttpServer;
17
18
  declare const logger: (label?: string, ...args: any[]) => Logger;
18
19
  declare const mailer: (label?: string, ...args: any[]) => Mailer;
20
+ declare const queue: (label?: string, ...args: any[]) => Promise<QueueConnection<any>>;
19
21
 
20
- export { cli, db, httpServer, logger, mailer, router, scheduler, storage };
22
+ export { cli, db, httpServer, logger, mailer, queue, router, scheduler, storage };