@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
@@ -1195,6 +1195,9 @@ module.exports = __toCommonJS(MigrateRollbackCommand_exports);
1195
1195
  var import_neko_context = require("@devbro/neko-context");
1196
1196
  var import_errors = require("@devbro/neko-http/errors");
1197
1197
 
1198
+ // ../neko-router/dist/CompiledRoute.mjs
1199
+ var import_stream = require("stream");
1200
+
1198
1201
  // ../neko-router/dist/Middleware.mjs
1199
1202
  var Middleware = class {
1200
1203
  static {
@@ -1272,6 +1275,9 @@ var CompiledRoute = class {
1272
1275
  if (typeof value.toJson === "function") {
1273
1276
  return traverse(value.toJson());
1274
1277
  }
1278
+ if (typeof value.toJSON === "function") {
1279
+ return traverse(value.toJSON());
1280
+ }
1275
1281
  if (Array.isArray(value)) {
1276
1282
  return value.map(traverse);
1277
1283
  }
@@ -1296,7 +1302,7 @@ var CompiledRoute = class {
1296
1302
  }
1297
1303
  return String(obj);
1298
1304
  }
1299
- processResponseBody(res, controller_rc) {
1305
+ async processResponseBody(res, controller_rc) {
1300
1306
  if (controller_rc && res.writableEnded) {
1301
1307
  throw new Error("cannot write to response, response has already ended");
1302
1308
  }
@@ -1305,18 +1311,36 @@ var CompiledRoute = class {
1305
1311
  }
1306
1312
  if (controller_rc) {
1307
1313
  const header_content_type = res.getHeader("Content-Type");
1308
- if (!header_content_type && typeof controller_rc === "object") {
1314
+ if (controller_rc instanceof import_stream.Stream || Buffer.isBuffer(controller_rc)) {
1315
+ await this.writeAsync(res, controller_rc);
1316
+ res.end();
1317
+ } else if (!header_content_type && typeof controller_rc === "object") {
1309
1318
  res.setHeader("Content-Type", "application/json");
1319
+ res.end(this.convertToString(controller_rc));
1310
1320
  } else if (!header_content_type) {
1311
1321
  res.setHeader("Content-Type", "text/plain");
1322
+ res.end(this.convertToString(controller_rc));
1323
+ } else {
1324
+ res.end(this.convertToString(controller_rc));
1312
1325
  }
1313
- res.end(this.convertToString(controller_rc));
1314
1326
  return;
1315
1327
  } else {
1316
1328
  res.statusCode = [200].includes(res.statusCode) ? 204 : res.statusCode;
1317
1329
  res.end();
1318
1330
  }
1319
1331
  }
1332
+ async writeAsync(res, chunk) {
1333
+ return new Promise((resolve, reject) => {
1334
+ const ok = res.write(chunk, (err) => {
1335
+ if (err) reject(err);
1336
+ });
1337
+ if (ok) {
1338
+ resolve(0);
1339
+ } else {
1340
+ res.once("drain", resolve);
1341
+ }
1342
+ });
1343
+ }
1320
1344
  async runMiddlewares(middlewares, req, res) {
1321
1345
  let index = 0;
1322
1346
  const me = this;
@@ -1374,7 +1398,7 @@ var Route = class {
1374
1398
  i = start;
1375
1399
  } else if (char === "*") {
1376
1400
  let start = i + 1;
1377
- while (start < path3.length && /[a-zA-Z0-9_]/.test(path3[start])) {
1401
+ while (start < path3.length && /[a-zA-Z0-9_\.]/.test(path3[start])) {
1378
1402
  start++;
1379
1403
  }
1380
1404
  tokens.push({ type: "WILDCARD", value: path3.slice(i + 1, start) });
@@ -1444,6 +1468,10 @@ var Route = class {
1444
1468
  params: r.groups || {}
1445
1469
  };
1446
1470
  }
1471
+ prependMiddleware(middlewares) {
1472
+ this.middlewares = [].concat(middlewares, this.middlewares);
1473
+ return this;
1474
+ }
1447
1475
  addMiddleware(middlewares) {
1448
1476
  this.middlewares = this.middlewares.concat(middlewares);
1449
1477
  return this;
@@ -1458,6 +1486,62 @@ var Route = class {
1458
1486
 
1459
1487
  // ../neko-router/dist/Router.mjs
1460
1488
  var import_path = __toESM(require("path"), 1);
1489
+
1490
+ // ../node_modules/url-join/lib/url-join.js
1491
+ function normalize(strArray) {
1492
+ var resultArray = [];
1493
+ if (strArray.length === 0) {
1494
+ return "";
1495
+ }
1496
+ if (typeof strArray[0] !== "string") {
1497
+ throw new TypeError("Url must be a string. Received " + strArray[0]);
1498
+ }
1499
+ if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
1500
+ var first = strArray.shift();
1501
+ strArray[0] = first + strArray[0];
1502
+ }
1503
+ if (strArray[0].match(/^file:\/\/\//)) {
1504
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///");
1505
+ } else {
1506
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://");
1507
+ }
1508
+ for (var i = 0; i < strArray.length; i++) {
1509
+ var component = strArray[i];
1510
+ if (typeof component !== "string") {
1511
+ throw new TypeError("Url must be a string. Received " + component);
1512
+ }
1513
+ if (component === "") {
1514
+ continue;
1515
+ }
1516
+ if (i > 0) {
1517
+ component = component.replace(/^[\/]+/, "");
1518
+ }
1519
+ if (i < strArray.length - 1) {
1520
+ component = component.replace(/[\/]+$/, "");
1521
+ } else {
1522
+ component = component.replace(/[\/]+$/, "/");
1523
+ }
1524
+ resultArray.push(component);
1525
+ }
1526
+ var str = resultArray.join("/");
1527
+ str = str.replace(/\/(\?|&|#[^!])/g, "$1");
1528
+ var parts = str.split("?");
1529
+ str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&");
1530
+ return str;
1531
+ }
1532
+ __name(normalize, "normalize");
1533
+ function urlJoin() {
1534
+ var input;
1535
+ if (typeof arguments[0] === "object") {
1536
+ input = arguments[0];
1537
+ } else {
1538
+ input = [].slice.call(arguments);
1539
+ }
1540
+ return normalize(input);
1541
+ }
1542
+ __name(urlJoin, "urlJoin");
1543
+
1544
+ // ../neko-router/dist/Router.mjs
1461
1545
  var Router = class {
1462
1546
  static {
1463
1547
  __name(this, "Router");
@@ -1482,6 +1566,12 @@ var Router = class {
1482
1566
  }).addMiddleware([...controller.baseMiddlewares, ...route.middlewares]);
1483
1567
  }
1484
1568
  }
1569
+ addRouter(path22, router2) {
1570
+ for (const route of router2.routes) {
1571
+ let path222 = urlJoin("/", path22, route.path);
1572
+ this.addRoute(route.methods, path222, route.handler).addMiddleware(router2.getMiddlewares()).addMiddleware(route.getMiddlewares());
1573
+ }
1574
+ }
1485
1575
  addGlobalMiddleware(middlewares) {
1486
1576
  this.middlewares = this.middlewares.concat(middlewares);
1487
1577
  }
@@ -1522,7 +1612,7 @@ var import_neko_scheduler = require("@devbro/neko-scheduler");
1522
1612
  var import_neko_helper = require("@devbro/neko-helper");
1523
1613
  var import_neko_context2 = require("@devbro/neko-context");
1524
1614
  var import_neko_storage = require("@devbro/neko-storage");
1525
- var import_neko_mailer = require("@devbro/neko-mailer");
1615
+ var import_neko_mailer2 = require("@devbro/neko-mailer");
1526
1616
  var import_neko_config = require("@devbro/neko-config");
1527
1617
  var import_clipanion = require("clipanion");
1528
1618
 
@@ -1533,6 +1623,153 @@ __reExport(http_exports, require("@devbro/neko-http"));
1533
1623
  // src/facades.mts
1534
1624
  var yup = __toESM(require("yup"), 1);
1535
1625
  var import_neko_logger = require("@devbro/neko-logger");
1626
+
1627
+ // src/factories.mts
1628
+ var import_neko_mailer = require("@devbro/neko-mailer");
1629
+ var import_neko_queue = require("@devbro/neko-queue");
1630
+ var import_neko_queue2 = require("@devbro/neko-queue");
1631
+
1632
+ // src/queue.mts
1633
+ var queue_exports = {};
1634
+ __export(queue_exports, {
1635
+ DatabaseTransport: () => DatabaseTransport
1636
+ });
1637
+ __reExport(queue_exports, require("@devbro/neko-queue"));
1638
+ var import_neko_sql = require("@devbro/neko-sql");
1639
+ var DatabaseTransport = class {
1640
+ // default to 100 messages per fetch
1641
+ constructor(db_config) {
1642
+ this.db_config = db_config;
1643
+ }
1644
+ static {
1645
+ __name(this, "DatabaseTransport");
1646
+ }
1647
+ listenInterval = 6e4;
1648
+ // default to 1 minute
1649
+ messageLimit = 100;
1650
+ setListenInterval(interval) {
1651
+ this.listenInterval = interval;
1652
+ }
1653
+ setMessageLimit(limit) {
1654
+ this.messageLimit = limit;
1655
+ }
1656
+ async dispatch(channel, message) {
1657
+ const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
1658
+ try {
1659
+ await conn.connect();
1660
+ let q = conn.getQuery();
1661
+ await q.table("queue_messages").insert({
1662
+ channel,
1663
+ message,
1664
+ processed: false,
1665
+ created_at: /* @__PURE__ */ new Date(),
1666
+ updated_at: /* @__PURE__ */ new Date(),
1667
+ last_tried_at: null,
1668
+ process_message: ""
1669
+ });
1670
+ } finally {
1671
+ await conn.disconnect();
1672
+ }
1673
+ }
1674
+ async listen(channel, callback) {
1675
+ return new Promise(async (resolve, reject) => {
1676
+ setInterval(async () => {
1677
+ const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
1678
+ try {
1679
+ await conn.connect();
1680
+ let q = conn.getQuery();
1681
+ let messages = await q.table("queue_messages").whereOp("channel", "=", channel).whereOp("processed", "=", false).limit(this.messageLimit).orderBy("last_tried_at", "asc").get();
1682
+ for (let msg of messages) {
1683
+ try {
1684
+ await callback(msg.message);
1685
+ await q.table("queue_messages").whereOp("id", "=", msg.id).update({
1686
+ processed: true,
1687
+ updated_at: /* @__PURE__ */ new Date()
1688
+ });
1689
+ } catch (error) {
1690
+ await q.table("queue_messages").whereOp("id", "=", msg.id).update({
1691
+ processed: false,
1692
+ last_tried_at: /* @__PURE__ */ new Date(),
1693
+ process_message: error.message || "Error processing message"
1694
+ });
1695
+ }
1696
+ }
1697
+ } finally {
1698
+ await conn.disconnect();
1699
+ }
1700
+ }, this.listenInterval);
1701
+ });
1702
+ }
1703
+ };
1704
+
1705
+ // src/factories.mts
1706
+ var FlexibleFactory = class {
1707
+ static {
1708
+ __name(this, "FlexibleFactory");
1709
+ }
1710
+ registry = /* @__PURE__ */ new Map();
1711
+ register(key, ctor) {
1712
+ this.registry.set(key, ctor);
1713
+ }
1714
+ create(key, ...args) {
1715
+ const ctor = this.registry.get(key);
1716
+ if (!ctor) {
1717
+ throw new Error(`No factory registered for key: ${key}`);
1718
+ }
1719
+ return new ctor(...args);
1720
+ }
1721
+ };
1722
+ var MailerFactory = class _MailerFactory {
1723
+ static {
1724
+ __name(this, "MailerFactory");
1725
+ }
1726
+ static instance = new FlexibleFactory();
1727
+ static register(key, factory) {
1728
+ _MailerFactory.instance.register(key, factory);
1729
+ }
1730
+ static create(key, ...args) {
1731
+ return _MailerFactory.instance.create(key, ...args);
1732
+ }
1733
+ };
1734
+ MailerFactory.register("logger", (opt) => {
1735
+ return new import_neko_mailer.FunctionProvider((mail) => {
1736
+ logger().info({
1737
+ msg: "Sending email",
1738
+ mail
1739
+ });
1740
+ });
1741
+ });
1742
+ MailerFactory.register("SES", (opt) => {
1743
+ return new import_neko_mailer.SESProvider(opt);
1744
+ });
1745
+ MailerFactory.register("SMTP", (opt) => {
1746
+ return new import_neko_mailer.SMTPProvider(opt);
1747
+ });
1748
+ MailerFactory.register("MEMORY", (opt) => {
1749
+ return new import_neko_mailer.MemoryProvider();
1750
+ });
1751
+ var QueueFactory = class _QueueFactory {
1752
+ static {
1753
+ __name(this, "QueueFactory");
1754
+ }
1755
+ static instance = new FlexibleFactory();
1756
+ static register(key, factory) {
1757
+ _QueueFactory.instance.register(key, factory);
1758
+ }
1759
+ static create(key, ...args) {
1760
+ return _QueueFactory.instance.create(key, ...args);
1761
+ }
1762
+ };
1763
+ QueueFactory.register("database", (opt) => {
1764
+ let transport = new DatabaseTransport(opt);
1765
+ return new import_neko_queue.QueueConnection(transport);
1766
+ });
1767
+ QueueFactory.register("memory", (opt) => {
1768
+ let transport = new import_neko_queue2.MemoryTransport(opt);
1769
+ return new import_neko_queue.QueueConnection(transport);
1770
+ });
1771
+
1772
+ // src/facades.mts
1536
1773
  var router = (0, import_neko_helper.createSingleton)(() => new Router());
1537
1774
  var scheduler = (0, import_neko_helper.createSingleton)(() => {
1538
1775
  const rc = new import_neko_scheduler.Scheduler();
@@ -1603,27 +1840,19 @@ var logger = (0, import_neko_helper.createSingleton)((label) => {
1603
1840
  });
1604
1841
  var mailer = (0, import_neko_helper.createSingleton)((label) => {
1605
1842
  const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
1606
- let provider;
1607
- if (mailer_config.provider === "logger") {
1608
- provider = new import_neko_mailer.FunctionProvider((mail) => {
1609
- logger().info({
1610
- msg: "Sending email",
1611
- mail
1612
- });
1613
- });
1614
- } else if (mailer_config.provider === "SES") {
1615
- provider = new import_neko_mailer.SESProvider(mailer_config.config);
1616
- } else if (mailer_config.provider === "SMTP") {
1617
- provider = new import_neko_mailer.SMTPProvider(mailer_config.config);
1618
- } else if (mailer_config.provider === "MEMORY") {
1619
- provider = new import_neko_mailer.MemoryProvider();
1620
- }
1621
- if (!provider) {
1622
- throw new Error(
1623
- `cannot initiate mailer provider: ${mailer_config?.provider}`
1624
- );
1843
+ let provider = MailerFactory.create(
1844
+ mailer_config.provider,
1845
+ mailer_config.config
1846
+ );
1847
+ const rc = new import_neko_mailer2.Mailer(provider);
1848
+ return rc;
1849
+ });
1850
+ var queue = (0, import_neko_helper.createSingleton)(async (label) => {
1851
+ const queue_config = import_neko_config.config.get(["queues", label].join("."));
1852
+ if (!queue_config) {
1853
+ throw new Error(`Queue configuration for '${label}' not found`);
1625
1854
  }
1626
- const rc = new import_neko_mailer.Mailer(provider);
1855
+ const rc = await QueueFactory.create(queue_config.type, queue_config);
1627
1856
  return rc;
1628
1857
  });
1629
1858
 
@@ -1639,7 +1868,7 @@ var MigrateRollbackCommand = class extends import_clipanion2.Command {
1639
1868
  __name(this, "MigrateRollbackCommand");
1640
1869
  }
1641
1870
  static paths = [[`migrate`, "rollback"]];
1642
- steps = import_clipanion2.Option.String(`--steps`, {
1871
+ steps = import_clipanion2.Option.String(`--steps`, "1", {
1643
1872
  description: `how many migrations to rollback`,
1644
1873
  validator: t.isNumber()
1645
1874
  });
@@ -1652,13 +1881,12 @@ var MigrateRollbackCommand = class extends import_clipanion2.Command {
1652
1881
  const dirEntries = await import_promises.default.readdir(migrationsDir);
1653
1882
  files = dirEntries.filter((entry) => entry.endsWith(".ts")).sort();
1654
1883
  const migrations = await db2.runQuery({
1655
- sql: "select * from migrations order by created_at DESC",
1656
- bindings: []
1884
+ sql: "select * from migrations order by created_at DESC limit $1",
1885
+ bindings: [this.steps]
1657
1886
  });
1658
- const count = 0;
1659
1887
  for (const migration of migrations) {
1660
1888
  const class_to_migrate = migration.filename;
1661
- this.context.stdout.write(`rolling back ${class_to_migrate}`);
1889
+ logger().info(`rolling back ${class_to_migrate}`);
1662
1890
  const ClassToMigrate = (await import(import_path2.default.join(migrationsDir, class_to_migrate))).default;
1663
1891
  const c = new ClassToMigrate();
1664
1892
  await c.down(db2.getSchema());