@devbro/pashmak 0.1.11 → 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.
- package/dist/app/console/migrate/make_migration.tpl +5 -5
- package/dist/app/console/queue/GenerateMigrateCommand.d.mts +9 -0
- package/dist/app/console/queue/GenerateMigrateCommand.mjs +51 -0
- package/dist/app/console/queue/GenerateMigrateCommand.mjs.map +1 -0
- package/dist/app/console/queue/queue_migration.tpl +19 -0
- package/dist/bin/app/console/DefaultCommand.cjs +160 -21
- package/dist/bin/app/console/KeyGenerateCommand.cjs +160 -21
- package/dist/bin/app/console/StartCommand.cjs +163 -24
- package/dist/bin/app/console/generate/GenerateControllerCommand.cjs +160 -21
- package/dist/bin/app/console/generate/index.cjs +160 -21
- package/dist/bin/app/console/index.cjs +162 -23
- package/dist/bin/app/console/migrate/GenerateMigrateCommand.cjs +160 -21
- package/dist/bin/app/console/migrate/MigrateCommand.cjs +161 -22
- package/dist/bin/app/console/migrate/MigrateRollbackCommand.cjs +160 -21
- package/dist/bin/app/console/migrate/index.cjs +160 -21
- package/dist/bin/app/console/queue/GenerateMigrateCommand.cjs +752 -0
- package/dist/bin/facades.cjs +163 -22
- package/dist/bin/factories.cjs +707 -0
- package/dist/bin/index.cjs +178 -28
- package/dist/bin/middlewares.cjs +161 -22
- package/dist/bin/queue.cjs +99 -0
- package/dist/facades.d.mts +3 -1
- package/dist/facades.mjs +15 -27
- package/dist/facades.mjs.map +1 -1
- package/dist/factories.d.mts +20 -0
- package/dist/factories.mjs +83 -0
- package/dist/factories.mjs.map +1 -0
- package/dist/queue.d.mts +15 -0
- package/dist/queue.mjs +73 -0
- package/dist/queue.mjs.map +1 -0
- package/package.json +7 -1
|
@@ -3,13 +3,13 @@ import { Schema, Blueprint } from "@devbro/pashmak/sql";
|
|
|
3
3
|
|
|
4
4
|
export default class {{className}} extends Migration {
|
|
5
5
|
async up(schema: Schema) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
await schema.createTable("{{tableName}}", (table: Blueprint) => {
|
|
7
|
+
table.id();
|
|
8
|
+
table.timestamps();
|
|
9
|
+
});
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
async down(schema: Schema) {
|
|
13
|
-
|
|
13
|
+
await schema.dropTableIfExists("{{tableName}}");
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
import { cli } from "../../../facades.mjs";
|
|
4
|
+
import { Command, Option } from "clipanion";
|
|
5
|
+
import { Case } from "change-case-all";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import * as fs from "fs/promises";
|
|
8
|
+
import { config } from "@devbro/neko-config";
|
|
9
|
+
import handlebars from "handlebars";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
class GenerateMigrateCommand extends Command {
|
|
12
|
+
static {
|
|
13
|
+
__name(this, "GenerateMigrateCommand");
|
|
14
|
+
}
|
|
15
|
+
static paths = [[`generate`, `queue`, "migration"]];
|
|
16
|
+
name = Option.String({ required: true });
|
|
17
|
+
async execute() {
|
|
18
|
+
const date = /* @__PURE__ */ new Date();
|
|
19
|
+
const year = date.getFullYear();
|
|
20
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
21
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
22
|
+
const secondsOfDay = String(
|
|
23
|
+
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()
|
|
24
|
+
).padStart(5, "0");
|
|
25
|
+
const fixed_name = "queue_messages";
|
|
26
|
+
const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;
|
|
27
|
+
this.context.stdout.write(`creating migration file ${filename}
|
|
28
|
+
`);
|
|
29
|
+
await fs.mkdir(config.get("migration.path"), { recursive: true });
|
|
30
|
+
let dirname = typeof __dirname === "string" ? __dirname : void 0;
|
|
31
|
+
if (!dirname) {
|
|
32
|
+
dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
33
|
+
}
|
|
34
|
+
const compiledTemplate = handlebars.compile(
|
|
35
|
+
(await fs.readFile(path.join(dirname, "./queue_migration.tpl"))).toString()
|
|
36
|
+
);
|
|
37
|
+
const template = await compiledTemplate({
|
|
38
|
+
className: Case.pascal(this.name) + "Migration",
|
|
39
|
+
tableName: Case.snake(this.name)
|
|
40
|
+
});
|
|
41
|
+
await fs.writeFile(
|
|
42
|
+
path.join(config.get("migration.path"), filename),
|
|
43
|
+
template
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
cli().register(GenerateMigrateCommand);
|
|
48
|
+
export {
|
|
49
|
+
GenerateMigrateCommand
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=GenerateMigrateCommand.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/app/console/queue/GenerateMigrateCommand.mts"],"sourcesContent":["import { cli } from \"../../../facades.mjs\";\nimport { Command, Option } from \"clipanion\";\nimport { Case } from \"change-case-all\";\nimport path from \"path\";\nimport * as fs from \"fs/promises\";\nimport { config } from \"@devbro/neko-config\";\nimport handlebars from \"handlebars\";\nimport { fileURLToPath } from \"url\";\nimport { table } from \"console\";\n\nexport class GenerateMigrateCommand extends Command {\n static paths = [[`generate`, `queue`, \"migration\"]];\n\n name = Option.String({ required: true });\n\n async execute() {\n const date = new Date();\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const secondsOfDay = String(\n date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds(),\n ).padStart(5, \"0\");\n\n const fixed_name = \"queue_messages\";\n const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;\n this.context.stdout.write(`creating migration file ${filename}\\n`);\n\n await fs.mkdir(config.get(\"migration.path\"), { recursive: true });\n\n let dirname = typeof __dirname === \"string\" ? __dirname : undefined;\n if (!dirname) {\n dirname = path.dirname(fileURLToPath(import.meta.url));\n }\n\n const compiledTemplate = handlebars.compile(\n (\n await fs.readFile(path.join(dirname, \"./queue_migration.tpl\"))\n ).toString(),\n );\n const template = await compiledTemplate({\n className: Case.pascal(this.name) + \"Migration\",\n tableName: Case.snake(this.name),\n });\n\n await fs.writeFile(\n path.join(config.get(\"migration.path\"), filename),\n template,\n );\n }\n}\n\ncli().register(GenerateMigrateCommand);\n"],"mappings":";;AAAA,SAAS,WAAW;AACpB,SAAS,SAAS,cAAc;AAChC,SAAS,YAAY;AACrB,OAAO,UAAU;AACjB,YAAY,QAAQ;AACpB,SAAS,cAAc;AACvB,OAAO,gBAAgB;AACvB,SAAS,qBAAqB;AAGvB,MAAM,+BAA+B,QAAQ;AAAA,EAVpD,OAUoD;AAAA;AAAA;AAAA,EAClD,OAAO,QAAQ,CAAC,CAAC,YAAY,SAAS,WAAW,CAAC;AAAA,EAElD,OAAO,OAAO,OAAO,EAAE,UAAU,KAAK,CAAC;AAAA,EAEvC,MAAM,UAAU;AACd,UAAM,OAAO,oBAAI,KAAK;AACtB,UAAM,OAAO,KAAK,YAAY;AAC9B,UAAM,QAAQ,OAAO,KAAK,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACzD,UAAM,MAAM,OAAO,KAAK,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,UAAM,eAAe;AAAA,MACnB,KAAK,SAAS,IAAI,OAAO,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW;AAAA,IACpE,EAAE,SAAS,GAAG,GAAG;AAEjB,UAAM,aAAa;AACnB,UAAM,WAAW,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,YAAY,IAAI,UAAU;AACtE,SAAK,QAAQ,OAAO,MAAM,2BAA2B,QAAQ;AAAA,CAAI;AAEjE,UAAM,GAAG,MAAM,OAAO,IAAI,gBAAgB,GAAG,EAAE,WAAW,KAAK,CAAC;AAEhE,QAAI,UAAU,OAAO,cAAc,WAAW,YAAY;AAC1D,QAAI,CAAC,SAAS;AACZ,gBAAU,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAAA,IACvD;AAEA,UAAM,mBAAmB,WAAW;AAAA,OAEhC,MAAM,GAAG,SAAS,KAAK,KAAK,SAAS,uBAAuB,CAAC,GAC7D,SAAS;AAAA,IACb;AACA,UAAM,WAAW,MAAM,iBAAiB;AAAA,MACtC,WAAW,KAAK,OAAO,KAAK,IAAI,IAAI;AAAA,MACpC,WAAW,KAAK,MAAM,KAAK,IAAI;AAAA,IACjC,CAAC;AAED,UAAM,GAAG;AAAA,MACP,KAAK,KAAK,OAAO,IAAI,gBAAgB,GAAG,QAAQ;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAI,EAAE,SAAS,sBAAsB;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Migration } from '@devbro/pashmak/sql';
|
|
2
|
+
import { Schema, Blueprint } from "@devbro/pashmak/sql";
|
|
3
|
+
|
|
4
|
+
export default class {{className}} extends Migration {
|
|
5
|
+
async up(schema: Schema) {
|
|
6
|
+
await schema.createTable("{{tableName}}", (table: Blueprint) => {
|
|
7
|
+
table.id();
|
|
8
|
+
table.timestamps();
|
|
9
|
+
table.string('channel');
|
|
10
|
+
table.text('message');
|
|
11
|
+
table.datetimeTz('last_tried_at').nullable(true);
|
|
12
|
+
table.text('process_message').default('');
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async down(schema: Schema) {
|
|
17
|
+
await schema.dropTableIfExists("{{tableName}}");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -458,7 +458,7 @@ var import_neko_scheduler = require("@devbro/neko-scheduler");
|
|
|
458
458
|
var import_neko_helper = require("@devbro/neko-helper");
|
|
459
459
|
var import_neko_context2 = require("@devbro/neko-context");
|
|
460
460
|
var import_neko_storage = require("@devbro/neko-storage");
|
|
461
|
-
var
|
|
461
|
+
var import_neko_mailer2 = require("@devbro/neko-mailer");
|
|
462
462
|
var import_neko_config = require("@devbro/neko-config");
|
|
463
463
|
var import_clipanion = require("clipanion");
|
|
464
464
|
|
|
@@ -469,6 +469,153 @@ __reExport(http_exports, require("@devbro/neko-http"));
|
|
|
469
469
|
// src/facades.mts
|
|
470
470
|
var yup = __toESM(require("yup"), 1);
|
|
471
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
|
|
472
619
|
var router = (0, import_neko_helper.createSingleton)(() => new Router());
|
|
473
620
|
var scheduler = (0, import_neko_helper.createSingleton)(() => {
|
|
474
621
|
const rc = new import_neko_scheduler.Scheduler();
|
|
@@ -538,27 +685,19 @@ var logger = (0, import_neko_helper.createSingleton)((label) => {
|
|
|
538
685
|
});
|
|
539
686
|
var mailer = (0, import_neko_helper.createSingleton)((label) => {
|
|
540
687
|
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
541
|
-
let provider
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
provider = new import_neko_mailer.SMTPProvider(mailer_config.config);
|
|
553
|
-
} else if (mailer_config.provider === "MEMORY") {
|
|
554
|
-
provider = new import_neko_mailer.MemoryProvider();
|
|
555
|
-
}
|
|
556
|
-
if (!provider) {
|
|
557
|
-
throw new Error(
|
|
558
|
-
`cannot initiate mailer provider: ${mailer_config?.provider}`
|
|
559
|
-
);
|
|
688
|
+
let provider = MailerFactory.create(
|
|
689
|
+
mailer_config.provider,
|
|
690
|
+
mailer_config.config
|
|
691
|
+
);
|
|
692
|
+
const rc = new import_neko_mailer2.Mailer(provider);
|
|
693
|
+
return rc;
|
|
694
|
+
});
|
|
695
|
+
var queue = (0, import_neko_helper.createSingleton)(async (label) => {
|
|
696
|
+
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
697
|
+
if (!queue_config) {
|
|
698
|
+
throw new Error(`Queue configuration for '${label}' not found`);
|
|
560
699
|
}
|
|
561
|
-
const rc =
|
|
700
|
+
const rc = await QueueFactory.create(queue_config.type, queue_config);
|
|
562
701
|
return rc;
|
|
563
702
|
});
|
|
564
703
|
|
|
@@ -461,7 +461,7 @@ var import_neko_scheduler = require("@devbro/neko-scheduler");
|
|
|
461
461
|
var import_neko_helper = require("@devbro/neko-helper");
|
|
462
462
|
var import_neko_context2 = require("@devbro/neko-context");
|
|
463
463
|
var import_neko_storage = require("@devbro/neko-storage");
|
|
464
|
-
var
|
|
464
|
+
var import_neko_mailer2 = require("@devbro/neko-mailer");
|
|
465
465
|
var import_neko_config = require("@devbro/neko-config");
|
|
466
466
|
var import_clipanion = require("clipanion");
|
|
467
467
|
|
|
@@ -472,6 +472,153 @@ __reExport(http_exports, require("@devbro/neko-http"));
|
|
|
472
472
|
// src/facades.mts
|
|
473
473
|
var yup = __toESM(require("yup"), 1);
|
|
474
474
|
var import_neko_logger = require("@devbro/neko-logger");
|
|
475
|
+
|
|
476
|
+
// src/factories.mts
|
|
477
|
+
var import_neko_mailer = require("@devbro/neko-mailer");
|
|
478
|
+
var import_neko_queue = require("@devbro/neko-queue");
|
|
479
|
+
var import_neko_queue2 = require("@devbro/neko-queue");
|
|
480
|
+
|
|
481
|
+
// src/queue.mts
|
|
482
|
+
var queue_exports = {};
|
|
483
|
+
__export(queue_exports, {
|
|
484
|
+
DatabaseTransport: () => DatabaseTransport
|
|
485
|
+
});
|
|
486
|
+
__reExport(queue_exports, require("@devbro/neko-queue"));
|
|
487
|
+
var import_neko_sql = require("@devbro/neko-sql");
|
|
488
|
+
var DatabaseTransport = class {
|
|
489
|
+
// default to 100 messages per fetch
|
|
490
|
+
constructor(db_config) {
|
|
491
|
+
this.db_config = db_config;
|
|
492
|
+
}
|
|
493
|
+
static {
|
|
494
|
+
__name(this, "DatabaseTransport");
|
|
495
|
+
}
|
|
496
|
+
listenInterval = 6e4;
|
|
497
|
+
// default to 1 minute
|
|
498
|
+
messageLimit = 100;
|
|
499
|
+
setListenInterval(interval) {
|
|
500
|
+
this.listenInterval = interval;
|
|
501
|
+
}
|
|
502
|
+
setMessageLimit(limit) {
|
|
503
|
+
this.messageLimit = limit;
|
|
504
|
+
}
|
|
505
|
+
async dispatch(channel, message) {
|
|
506
|
+
const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
|
|
507
|
+
try {
|
|
508
|
+
await conn.connect();
|
|
509
|
+
let q = conn.getQuery();
|
|
510
|
+
await q.table("queue_messages").insert({
|
|
511
|
+
channel,
|
|
512
|
+
message,
|
|
513
|
+
processed: false,
|
|
514
|
+
created_at: /* @__PURE__ */ new Date(),
|
|
515
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
516
|
+
last_tried_at: null,
|
|
517
|
+
process_message: ""
|
|
518
|
+
});
|
|
519
|
+
} finally {
|
|
520
|
+
await conn.disconnect();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
async listen(channel, callback) {
|
|
524
|
+
return new Promise(async (resolve, reject) => {
|
|
525
|
+
setInterval(async () => {
|
|
526
|
+
const conn = new import_neko_sql.PostgresqlConnection(this.db_config);
|
|
527
|
+
try {
|
|
528
|
+
await conn.connect();
|
|
529
|
+
let q = conn.getQuery();
|
|
530
|
+
let messages = await q.table("queue_messages").whereOp("channel", "=", channel).whereOp("processed", "=", false).limit(this.messageLimit).orderBy("last_tried_at", "asc").get();
|
|
531
|
+
for (let msg of messages) {
|
|
532
|
+
try {
|
|
533
|
+
await callback(msg.message);
|
|
534
|
+
await q.table("queue_messages").whereOp("id", "=", msg.id).update({
|
|
535
|
+
processed: true,
|
|
536
|
+
updated_at: /* @__PURE__ */ new Date()
|
|
537
|
+
});
|
|
538
|
+
} catch (error) {
|
|
539
|
+
await q.table("queue_messages").whereOp("id", "=", msg.id).update({
|
|
540
|
+
processed: false,
|
|
541
|
+
last_tried_at: /* @__PURE__ */ new Date(),
|
|
542
|
+
process_message: error.message || "Error processing message"
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
} finally {
|
|
547
|
+
await conn.disconnect();
|
|
548
|
+
}
|
|
549
|
+
}, this.listenInterval);
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
// src/factories.mts
|
|
555
|
+
var FlexibleFactory = class {
|
|
556
|
+
static {
|
|
557
|
+
__name(this, "FlexibleFactory");
|
|
558
|
+
}
|
|
559
|
+
registry = /* @__PURE__ */ new Map();
|
|
560
|
+
register(key, ctor) {
|
|
561
|
+
this.registry.set(key, ctor);
|
|
562
|
+
}
|
|
563
|
+
create(key, ...args) {
|
|
564
|
+
const ctor = this.registry.get(key);
|
|
565
|
+
if (!ctor) {
|
|
566
|
+
throw new Error(`No factory registered for key: ${key}`);
|
|
567
|
+
}
|
|
568
|
+
return new ctor(...args);
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
var MailerFactory = class _MailerFactory {
|
|
572
|
+
static {
|
|
573
|
+
__name(this, "MailerFactory");
|
|
574
|
+
}
|
|
575
|
+
static instance = new FlexibleFactory();
|
|
576
|
+
static register(key, factory) {
|
|
577
|
+
_MailerFactory.instance.register(key, factory);
|
|
578
|
+
}
|
|
579
|
+
static create(key, ...args) {
|
|
580
|
+
return _MailerFactory.instance.create(key, ...args);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
MailerFactory.register("logger", (opt) => {
|
|
584
|
+
return new import_neko_mailer.FunctionProvider((mail) => {
|
|
585
|
+
logger().info({
|
|
586
|
+
msg: "Sending email",
|
|
587
|
+
mail
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
});
|
|
591
|
+
MailerFactory.register("SES", (opt) => {
|
|
592
|
+
return new import_neko_mailer.SESProvider(opt);
|
|
593
|
+
});
|
|
594
|
+
MailerFactory.register("SMTP", (opt) => {
|
|
595
|
+
return new import_neko_mailer.SMTPProvider(opt);
|
|
596
|
+
});
|
|
597
|
+
MailerFactory.register("MEMORY", (opt) => {
|
|
598
|
+
return new import_neko_mailer.MemoryProvider();
|
|
599
|
+
});
|
|
600
|
+
var QueueFactory = class _QueueFactory {
|
|
601
|
+
static {
|
|
602
|
+
__name(this, "QueueFactory");
|
|
603
|
+
}
|
|
604
|
+
static instance = new FlexibleFactory();
|
|
605
|
+
static register(key, factory) {
|
|
606
|
+
_QueueFactory.instance.register(key, factory);
|
|
607
|
+
}
|
|
608
|
+
static create(key, ...args) {
|
|
609
|
+
return _QueueFactory.instance.create(key, ...args);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
QueueFactory.register("database", (opt) => {
|
|
613
|
+
let transport = new DatabaseTransport(opt);
|
|
614
|
+
return new import_neko_queue.QueueConnection(transport);
|
|
615
|
+
});
|
|
616
|
+
QueueFactory.register("memory", (opt) => {
|
|
617
|
+
let transport = new import_neko_queue2.MemoryTransport(opt);
|
|
618
|
+
return new import_neko_queue.QueueConnection(transport);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// src/facades.mts
|
|
475
622
|
var router = (0, import_neko_helper.createSingleton)(() => new Router());
|
|
476
623
|
var scheduler = (0, import_neko_helper.createSingleton)(() => {
|
|
477
624
|
const rc = new import_neko_scheduler.Scheduler();
|
|
@@ -541,27 +688,19 @@ var logger = (0, import_neko_helper.createSingleton)((label) => {
|
|
|
541
688
|
});
|
|
542
689
|
var mailer = (0, import_neko_helper.createSingleton)((label) => {
|
|
543
690
|
const mailer_config = import_neko_config.config.get(["mailer", label].join("."));
|
|
544
|
-
let provider
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
provider = new import_neko_mailer.SMTPProvider(mailer_config.config);
|
|
556
|
-
} else if (mailer_config.provider === "MEMORY") {
|
|
557
|
-
provider = new import_neko_mailer.MemoryProvider();
|
|
558
|
-
}
|
|
559
|
-
if (!provider) {
|
|
560
|
-
throw new Error(
|
|
561
|
-
`cannot initiate mailer provider: ${mailer_config?.provider}`
|
|
562
|
-
);
|
|
691
|
+
let provider = MailerFactory.create(
|
|
692
|
+
mailer_config.provider,
|
|
693
|
+
mailer_config.config
|
|
694
|
+
);
|
|
695
|
+
const rc = new import_neko_mailer2.Mailer(provider);
|
|
696
|
+
return rc;
|
|
697
|
+
});
|
|
698
|
+
var queue = (0, import_neko_helper.createSingleton)(async (label) => {
|
|
699
|
+
const queue_config = import_neko_config.config.get(["queues", label].join("."));
|
|
700
|
+
if (!queue_config) {
|
|
701
|
+
throw new Error(`Queue configuration for '${label}' not found`);
|
|
563
702
|
}
|
|
564
|
-
const rc =
|
|
703
|
+
const rc = await QueueFactory.create(queue_config.type, queue_config);
|
|
565
704
|
return rc;
|
|
566
705
|
});
|
|
567
706
|
|