semola 0.5.0 → 0.5.2
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/README.md +75 -20
- package/dist/api/core/index.cjs +206 -0
- package/dist/api/core/index.d.cts +21 -0
- package/dist/api/core/index.d.cts.map +1 -0
- package/dist/api/core/index.d.mts +21 -0
- package/dist/api/core/index.d.mts.map +1 -0
- package/dist/api/core/index.mjs +208 -0
- package/dist/api/core/index.mjs.map +1 -0
- package/dist/api/core/types.d.cts +107 -0
- package/dist/api/core/types.d.cts.map +1 -0
- package/dist/api/core/types.d.mts +107 -0
- package/dist/api/core/types.d.mts.map +1 -0
- package/dist/api/middleware/index.cjs +8 -0
- package/dist/api/middleware/index.d.cts +11 -0
- package/dist/api/middleware/index.d.cts.map +1 -0
- package/dist/api/middleware/index.d.mts +11 -0
- package/dist/api/middleware/index.d.mts.map +1 -0
- package/dist/api/middleware/index.mjs +10 -0
- package/dist/api/middleware/index.mjs.map +1 -0
- package/dist/api/middleware/types.d.cts +16 -0
- package/dist/api/middleware/types.d.cts.map +1 -0
- package/dist/api/middleware/types.d.mts +16 -0
- package/dist/api/middleware/types.d.mts.map +1 -0
- package/dist/api/openapi/index.cjs +254 -0
- package/dist/api/openapi/index.mjs +256 -0
- package/dist/api/openapi/index.mjs.map +1 -0
- package/dist/api/openapi/types.d.cts +60 -0
- package/dist/api/openapi/types.d.cts.map +1 -0
- package/dist/api/openapi/types.d.mts +60 -0
- package/dist/api/openapi/types.d.mts.map +1 -0
- package/dist/api/validation/index.cjs +64 -0
- package/dist/api/validation/index.mjs +61 -0
- package/dist/api/validation/index.mjs.map +1 -0
- package/dist/cache/types.d.cts +17 -0
- package/dist/cache/types.d.cts.map +1 -0
- package/dist/cache/types.d.mts +17 -0
- package/dist/cache/types.d.mts.map +1 -0
- package/dist/cron/scanner.cjs +237 -0
- package/dist/cron/scanner.mjs +238 -0
- package/dist/cron/scanner.mjs.map +1 -0
- package/dist/cron/types.d.cts +11 -0
- package/dist/cron/types.d.cts.map +1 -0
- package/dist/cron/types.d.mts +11 -0
- package/dist/cron/types.d.mts.map +1 -0
- package/dist/errors/types.d.cts +5 -0
- package/dist/errors/types.d.cts.map +1 -0
- package/dist/errors/types.d.mts +5 -0
- package/dist/errors/types.d.mts.map +1 -0
- package/dist/i18n/types.d.cts +13 -0
- package/dist/i18n/types.d.cts.map +1 -0
- package/dist/i18n/types.d.mts +13 -0
- package/dist/i18n/types.d.mts.map +1 -0
- package/dist/lib/api/index.cjs +5 -0
- package/dist/lib/api/index.d.cts +5 -0
- package/dist/lib/api/index.d.mts +5 -0
- package/dist/lib/api/index.mjs +3 -0
- package/dist/lib/cache/index.cjs +74 -0
- package/dist/lib/cache/index.d.cts +36 -0
- package/dist/lib/cache/index.d.cts.map +1 -0
- package/dist/lib/cache/index.d.mts +36 -0
- package/dist/lib/cache/index.d.mts.map +1 -0
- package/dist/lib/cache/index.mjs +75 -0
- package/dist/lib/cache/index.mjs.map +1 -0
- package/dist/lib/cron/index.cjs +276 -0
- package/dist/lib/cron/index.d.cts +39 -0
- package/dist/lib/cron/index.d.cts.map +1 -0
- package/dist/lib/cron/index.d.mts +39 -0
- package/dist/lib/cron/index.d.mts.map +1 -0
- package/dist/lib/cron/index.mjs +277 -0
- package/dist/lib/cron/index.mjs.map +1 -0
- package/dist/lib/errors/index.cjs +30 -0
- package/dist/lib/errors/index.d.cts +13 -0
- package/dist/lib/errors/index.d.cts.map +1 -0
- package/dist/lib/errors/index.d.mts +13 -0
- package/dist/lib/errors/index.d.mts.map +1 -0
- package/dist/lib/errors/index.mjs +28 -0
- package/dist/lib/errors/index.mjs.map +1 -0
- package/dist/lib/i18n/index.cjs +37 -0
- package/dist/lib/i18n/index.d.cts +20 -0
- package/dist/lib/i18n/index.d.cts.map +1 -0
- package/dist/lib/i18n/index.d.mts +20 -0
- package/dist/lib/i18n/index.d.mts.map +1 -0
- package/dist/lib/i18n/index.mjs +38 -0
- package/dist/lib/i18n/index.mjs.map +1 -0
- package/dist/lib/policy/index.cjs +99 -0
- package/dist/lib/policy/index.d.cts +21 -0
- package/dist/lib/policy/index.d.cts.map +1 -0
- package/dist/lib/policy/index.d.mts +21 -0
- package/dist/lib/policy/index.d.mts.map +1 -0
- package/dist/lib/policy/index.mjs +81 -0
- package/dist/lib/policy/index.mjs.map +1 -0
- package/dist/lib/prompts/index.cjs +409 -0
- package/dist/lib/prompts/index.d.cts +31 -0
- package/dist/lib/prompts/index.d.cts.map +1 -0
- package/dist/lib/prompts/index.d.mts +31 -0
- package/dist/lib/prompts/index.d.mts.map +1 -0
- package/dist/lib/prompts/index.mjs +405 -0
- package/dist/lib/prompts/index.mjs.map +1 -0
- package/dist/lib/pubsub/index.cjs +48 -0
- package/dist/lib/pubsub/index.d.cts +27 -0
- package/dist/lib/pubsub/index.d.cts.map +1 -0
- package/dist/lib/pubsub/index.d.mts +27 -0
- package/dist/lib/pubsub/index.d.mts.map +1 -0
- package/dist/lib/pubsub/index.mjs +49 -0
- package/dist/lib/pubsub/index.mjs.map +1 -0
- package/dist/lib/queue/index.cjs +182 -0
- package/dist/lib/queue/index.d.cts +32 -0
- package/dist/lib/queue/index.d.cts.map +1 -0
- package/dist/lib/queue/index.d.mts +32 -0
- package/dist/lib/queue/index.d.mts.map +1 -0
- package/dist/lib/queue/index.mjs +183 -0
- package/dist/lib/queue/index.mjs.map +1 -0
- package/dist/node_modules/@standard-schema/spec/dist/index.d.cts +80 -0
- package/dist/node_modules/@standard-schema/spec/dist/index.d.cts.map +1 -0
- package/dist/node_modules/@standard-schema/spec/dist/index.d.mts +80 -0
- package/dist/node_modules/@standard-schema/spec/dist/index.d.mts.map +1 -0
- package/dist/policy/helpers.cjs +206 -0
- package/dist/policy/helpers.d.cts +50 -0
- package/dist/policy/helpers.d.cts.map +1 -0
- package/dist/policy/helpers.d.mts +50 -0
- package/dist/policy/helpers.d.mts.map +1 -0
- package/dist/policy/helpers.mjs +190 -0
- package/dist/policy/helpers.mjs.map +1 -0
- package/dist/policy/types.d.cts +16 -0
- package/dist/policy/types.d.cts.map +1 -0
- package/dist/policy/types.d.mts +16 -0
- package/dist/policy/types.d.mts.map +1 -0
- package/dist/prompts/core/keys.cjs +165 -0
- package/dist/prompts/core/keys.mjs +167 -0
- package/dist/prompts/core/keys.mjs.map +1 -0
- package/dist/prompts/core/runtime.cjs +104 -0
- package/dist/prompts/core/runtime.mjs +106 -0
- package/dist/prompts/core/runtime.mjs.map +1 -0
- package/dist/prompts/core/session.cjs +98 -0
- package/dist/prompts/core/session.mjs +100 -0
- package/dist/prompts/core/session.mjs.map +1 -0
- package/dist/prompts/core/types.d.cts +21 -0
- package/dist/prompts/core/types.d.cts.map +1 -0
- package/dist/prompts/core/types.d.mts +21 -0
- package/dist/prompts/core/types.d.mts.map +1 -0
- package/dist/prompts/types.d.cts +52 -0
- package/dist/prompts/types.d.cts.map +1 -0
- package/dist/prompts/types.d.mts +52 -0
- package/dist/prompts/types.d.mts.map +1 -0
- package/dist/pubsub/types.d.cts +10 -0
- package/dist/pubsub/types.d.cts.map +1 -0
- package/dist/pubsub/types.d.mts +10 -0
- package/dist/pubsub/types.d.mts.map +1 -0
- package/dist/queue/types.d.cts +47 -0
- package/dist/queue/types.d.cts.map +1 -0
- package/dist/queue/types.d.mts +47 -0
- package/dist/queue/types.d.mts.map +1 -0
- package/package.json +86 -16
- package/dist/lib/api/core/index.d.ts +0 -15
- package/dist/lib/api/core/index.d.ts.map +0 -1
- package/dist/lib/api/core/index.js +0 -166
- package/dist/lib/api/core/index.js.map +0 -1
- package/dist/lib/api/core/index.test.d.ts +0 -2
- package/dist/lib/api/core/index.test.d.ts.map +0 -1
- package/dist/lib/api/core/index.test.js +0 -219
- package/dist/lib/api/core/index.test.js.map +0 -1
- package/dist/lib/api/core/types.d.ts +0 -102
- package/dist/lib/api/core/types.d.ts.map +0 -1
- package/dist/lib/api/core/types.js +0 -2
- package/dist/lib/api/core/types.js.map +0 -1
- package/dist/lib/api/index.d.ts +0 -5
- package/dist/lib/api/index.d.ts.map +0 -1
- package/dist/lib/api/index.js +0 -3
- package/dist/lib/api/index.js.map +0 -1
- package/dist/lib/api/middleware/index.d.ts +0 -7
- package/dist/lib/api/middleware/index.d.ts.map +0 -1
- package/dist/lib/api/middleware/index.js +0 -7
- package/dist/lib/api/middleware/index.js.map +0 -1
- package/dist/lib/api/middleware/index.test.d.ts +0 -2
- package/dist/lib/api/middleware/index.test.d.ts.map +0 -1
- package/dist/lib/api/middleware/index.test.js +0 -67
- package/dist/lib/api/middleware/index.test.js.map +0 -1
- package/dist/lib/api/middleware/types.d.ts +0 -12
- package/dist/lib/api/middleware/types.d.ts.map +0 -1
- package/dist/lib/api/middleware/types.js +0 -2
- package/dist/lib/api/middleware/types.js.map +0 -1
- package/dist/lib/api/openapi/index.d.ts +0 -31
- package/dist/lib/api/openapi/index.d.ts.map +0 -1
- package/dist/lib/api/openapi/index.js +0 -328
- package/dist/lib/api/openapi/index.js.map +0 -1
- package/dist/lib/api/openapi/index.test.d.ts +0 -2
- package/dist/lib/api/openapi/index.test.d.ts.map +0 -1
- package/dist/lib/api/openapi/index.test.js +0 -359
- package/dist/lib/api/openapi/index.test.js.map +0 -1
- package/dist/lib/api/openapi/types.d.ts +0 -57
- package/dist/lib/api/openapi/types.d.ts.map +0 -1
- package/dist/lib/api/openapi/types.js +0 -5
- package/dist/lib/api/openapi/types.js.map +0 -1
- package/dist/lib/api/validation/index.d.ts +0 -33
- package/dist/lib/api/validation/index.d.ts.map +0 -1
- package/dist/lib/api/validation/index.js +0 -81
- package/dist/lib/api/validation/index.js.map +0 -1
- package/dist/lib/api/validation/index.test.d.ts +0 -2
- package/dist/lib/api/validation/index.test.d.ts.map +0 -1
- package/dist/lib/api/validation/index.test.js +0 -135
- package/dist/lib/api/validation/index.test.js.map +0 -1
- package/dist/lib/cache/index.d.ts +0 -25
- package/dist/lib/cache/index.d.ts.map +0 -1
- package/dist/lib/cache/index.js +0 -62
- package/dist/lib/cache/index.js.map +0 -1
- package/dist/lib/cache/index.test.d.ts +0 -2
- package/dist/lib/cache/index.test.d.ts.map +0 -1
- package/dist/lib/cache/index.test.js +0 -314
- package/dist/lib/cache/index.test.js.map +0 -1
- package/dist/lib/cache/types.d.ts +0 -5
- package/dist/lib/cache/types.d.ts.map +0 -1
- package/dist/lib/cache/types.js +0 -2
- package/dist/lib/cache/types.js.map +0 -1
- package/dist/lib/errors/index.d.ts +0 -9
- package/dist/lib/errors/index.d.ts.map +0 -1
- package/dist/lib/errors/index.js +0 -25
- package/dist/lib/errors/index.js.map +0 -1
- package/dist/lib/errors/index.test.d.ts +0 -2
- package/dist/lib/errors/index.test.d.ts.map +0 -1
- package/dist/lib/errors/index.test.js +0 -197
- package/dist/lib/errors/index.test.js.map +0 -1
- package/dist/lib/errors/types.d.ts +0 -2
- package/dist/lib/errors/types.d.ts.map +0 -1
- package/dist/lib/errors/types.js +0 -2
- package/dist/lib/errors/types.js.map +0 -1
- package/dist/lib/i18n/index.d.ts +0 -18
- package/dist/lib/i18n/index.d.ts.map +0 -1
- package/dist/lib/i18n/index.js +0 -38
- package/dist/lib/i18n/index.js.map +0 -1
- package/dist/lib/i18n/index.test.d.ts +0 -2
- package/dist/lib/i18n/index.test.d.ts.map +0 -1
- package/dist/lib/i18n/index.test.js +0 -402
- package/dist/lib/i18n/index.test.js.map +0 -1
- package/dist/lib/i18n/types.d.ts +0 -15
- package/dist/lib/i18n/types.d.ts.map +0 -1
- package/dist/lib/i18n/types.js +0 -2
- package/dist/lib/i18n/types.js.map +0 -1
- package/dist/lib/policy/index.d.ts +0 -9
- package/dist/lib/policy/index.d.ts.map +0 -1
- package/dist/lib/policy/index.js +0 -51
- package/dist/lib/policy/index.js.map +0 -1
- package/dist/lib/policy/index.test.d.ts +0 -2
- package/dist/lib/policy/index.test.d.ts.map +0 -1
- package/dist/lib/policy/index.test.js +0 -328
- package/dist/lib/policy/index.test.js.map +0 -1
- package/dist/lib/policy/types.d.ts +0 -27
- package/dist/lib/policy/types.d.ts.map +0 -1
- package/dist/lib/policy/types.js +0 -2
- package/dist/lib/policy/types.js.map +0 -1
- package/dist/lib/pubsub/index.d.ts +0 -23
- package/dist/lib/pubsub/index.d.ts.map +0 -1
- package/dist/lib/pubsub/index.js +0 -55
- package/dist/lib/pubsub/index.js.map +0 -1
- package/dist/lib/pubsub/index.test.d.ts +0 -2
- package/dist/lib/pubsub/index.test.d.ts.map +0 -1
- package/dist/lib/pubsub/index.test.js +0 -550
- package/dist/lib/pubsub/index.test.js.map +0 -1
- package/dist/lib/pubsub/types.d.ts +0 -7
- package/dist/lib/pubsub/types.d.ts.map +0 -1
- package/dist/lib/pubsub/types.js +0 -2
- package/dist/lib/pubsub/types.js.map +0 -1
- package/dist/lib/queue/index.d.ts +0 -28
- package/dist/lib/queue/index.d.ts.map +0 -1
- package/dist/lib/queue/index.js +0 -211
- package/dist/lib/queue/index.js.map +0 -1
- package/dist/lib/queue/index.test.d.ts +0 -2
- package/dist/lib/queue/index.test.d.ts.map +0 -1
- package/dist/lib/queue/index.test.js +0 -740
- package/dist/lib/queue/index.test.js.map +0 -1
- package/dist/lib/queue/types.d.ts +0 -52
- package/dist/lib/queue/types.d.ts.map +0 -1
- package/dist/lib/queue/types.js +0 -2
- package/dist/lib/queue/types.js.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { MessageHandler, PubSubOptions } from "../../pubsub/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/pubsub/index.d.ts
|
|
4
|
+
declare class PubSub<T extends Record<string, unknown>> {
|
|
5
|
+
private options;
|
|
6
|
+
private isSubscribed;
|
|
7
|
+
constructor(options: PubSubOptions);
|
|
8
|
+
publish(message: T): Promise<readonly [null, number | null] | readonly [{
|
|
9
|
+
readonly type: "SerializationError";
|
|
10
|
+
readonly message: string;
|
|
11
|
+
}, null] | readonly [{
|
|
12
|
+
readonly type: "PublishError";
|
|
13
|
+
readonly message: string;
|
|
14
|
+
}, null]>;
|
|
15
|
+
subscribe(handler: MessageHandler<T>): Promise<readonly [null, number | null] | readonly [{
|
|
16
|
+
readonly type: "SubscribeError";
|
|
17
|
+
readonly message: string;
|
|
18
|
+
}, null]>;
|
|
19
|
+
unsubscribe(): Promise<readonly [null, boolean] | readonly [{
|
|
20
|
+
readonly type: "UnsubscribeError";
|
|
21
|
+
readonly message: string;
|
|
22
|
+
}, null]>;
|
|
23
|
+
isActive(): boolean;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { PubSub };
|
|
27
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/lib/pubsub/index.ts"],"mappings":";;;cAGa,MAAA,WAAiB,MAAA;EAAA,QACpB,OAAA;EAAA,QACA,YAAA;cAEW,OAAA,EAAS,aAAA;EAIf,OAAA,CAAQ,OAAA,EAAS,CAAA,GAAC,OAAA;IAAA;;;;;;EAuBlB,SAAA,CAAU,OAAA,EAAS,cAAA,CAAe,CAAA,IAAE,OAAA;IAAA;;;EAgCpC,WAAA,CAAA,GAAW,OAAA;IAAA;;;EAuBjB,QAAA,CAAA;AAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { err, mightThrow, mightThrowSync, ok } from "../errors/index.mjs";
|
|
2
|
+
//#region src/lib/pubsub/index.ts
|
|
3
|
+
var PubSub = class {
|
|
4
|
+
options;
|
|
5
|
+
isSubscribed = false;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
async publish(message) {
|
|
10
|
+
const [stringifyError, stringified] = mightThrowSync(() => JSON.stringify(message));
|
|
11
|
+
if (stringifyError || !stringified) return err("SerializationError", "Unable to serialize message");
|
|
12
|
+
const [publishError, count] = await mightThrow(this.options.publisher.publish(this.options.channel, stringified));
|
|
13
|
+
if (publishError) return err("PublishError", `Unable to publish to ${this.options.channel}`);
|
|
14
|
+
return ok(count);
|
|
15
|
+
}
|
|
16
|
+
async subscribe(handler) {
|
|
17
|
+
if (this.isActive()) return err("SubscribeError", "Already subscribed");
|
|
18
|
+
this.isSubscribed = true;
|
|
19
|
+
const wrappedHandler = async (message, channel) => {
|
|
20
|
+
const [parseError, parsed] = mightThrowSync(() => JSON.parse(message));
|
|
21
|
+
if (parseError) return;
|
|
22
|
+
if (!parsed) return;
|
|
23
|
+
await mightThrow(Promise.resolve(handler(parsed, channel)));
|
|
24
|
+
};
|
|
25
|
+
const [subscribeError, count] = await mightThrow(this.options.subscriber.subscribe(this.options.channel, wrappedHandler));
|
|
26
|
+
if (subscribeError) {
|
|
27
|
+
this.isSubscribed = false;
|
|
28
|
+
return err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
|
|
29
|
+
}
|
|
30
|
+
return ok(count);
|
|
31
|
+
}
|
|
32
|
+
async unsubscribe() {
|
|
33
|
+
if (!this.isActive()) return err("UnsubscribeError", "Not subscribed");
|
|
34
|
+
this.isSubscribed = false;
|
|
35
|
+
const [unsubscribeError] = await mightThrow(this.options.subscriber.unsubscribe(this.options.channel));
|
|
36
|
+
if (unsubscribeError) {
|
|
37
|
+
this.isSubscribed = true;
|
|
38
|
+
return err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
|
|
39
|
+
}
|
|
40
|
+
return ok(true);
|
|
41
|
+
}
|
|
42
|
+
isActive() {
|
|
43
|
+
return this.isSubscribed;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { PubSub };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/lib/pubsub/index.ts"],"sourcesContent":["import { err, mightThrow, mightThrowSync, ok } from \"../errors/index.js\";\nimport type { MessageHandler, PubSubOptions } from \"./types.js\";\n\nexport class PubSub<T extends Record<string, unknown>> {\n private options: PubSubOptions;\n private isSubscribed = false;\n\n public constructor(options: PubSubOptions) {\n this.options = options;\n }\n\n public async publish(message: T) {\n const [stringifyError, stringified] = mightThrowSync(() =>\n JSON.stringify(message),\n );\n\n if (stringifyError || !stringified) {\n return err(\"SerializationError\", \"Unable to serialize message\");\n }\n\n const [publishError, count] = await mightThrow(\n this.options.publisher.publish(this.options.channel, stringified),\n );\n\n if (publishError) {\n return err(\n \"PublishError\",\n `Unable to publish to ${this.options.channel}`,\n );\n }\n\n return ok(count);\n }\n\n public async subscribe(handler: MessageHandler<T>) {\n if (this.isActive()) {\n return err(\"SubscribeError\", \"Already subscribed\");\n }\n\n this.isSubscribed = true;\n\n const wrappedHandler = async (message: string, channel: string) => {\n const [parseError, parsed] = mightThrowSync<T>(() => JSON.parse(message));\n\n if (parseError) return;\n if (!parsed) return;\n\n await mightThrow(Promise.resolve(handler(parsed, channel)));\n };\n\n const [subscribeError, count] = await mightThrow(\n this.options.subscriber.subscribe(this.options.channel, wrappedHandler),\n );\n\n if (subscribeError) {\n this.isSubscribed = false;\n\n return err(\n \"SubscribeError\",\n `Unable to subscribe to ${this.options.channel}`,\n );\n }\n\n return ok(count);\n }\n\n public async unsubscribe() {\n if (!this.isActive()) {\n return err(\"UnsubscribeError\", \"Not subscribed\");\n }\n\n this.isSubscribed = false;\n\n const [unsubscribeError] = await mightThrow(\n this.options.subscriber.unsubscribe(this.options.channel),\n );\n\n if (unsubscribeError) {\n this.isSubscribed = true;\n\n return err(\n \"UnsubscribeError\",\n `Unable to unsubscribe from ${this.options.channel}`,\n );\n }\n\n return ok(true);\n }\n\n public isActive() {\n return this.isSubscribed;\n }\n}\n"],"mappings":";;AAGA,IAAa,SAAb,MAAuD;CACrD;CACA,eAAuB;CAEvB,YAAmB,SAAwB;AACzC,OAAK,UAAU;;CAGjB,MAAa,QAAQ,SAAY;EAC/B,MAAM,CAAC,gBAAgB,eAAe,qBACpC,KAAK,UAAU,QAAQ,CACxB;AAED,MAAI,kBAAkB,CAAC,YACrB,QAAO,IAAI,sBAAsB,8BAA8B;EAGjE,MAAM,CAAC,cAAc,SAAS,MAAM,WAClC,KAAK,QAAQ,UAAU,QAAQ,KAAK,QAAQ,SAAS,YAAY,CAClE;AAED,MAAI,aACF,QAAO,IACL,gBACA,wBAAwB,KAAK,QAAQ,UACtC;AAGH,SAAO,GAAG,MAAM;;CAGlB,MAAa,UAAU,SAA4B;AACjD,MAAI,KAAK,UAAU,CACjB,QAAO,IAAI,kBAAkB,qBAAqB;AAGpD,OAAK,eAAe;EAEpB,MAAM,iBAAiB,OAAO,SAAiB,YAAoB;GACjE,MAAM,CAAC,YAAY,UAAU,qBAAwB,KAAK,MAAM,QAAQ,CAAC;AAEzE,OAAI,WAAY;AAChB,OAAI,CAAC,OAAQ;AAEb,SAAM,WAAW,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,CAAC,CAAC;;EAG7D,MAAM,CAAC,gBAAgB,SAAS,MAAM,WACpC,KAAK,QAAQ,WAAW,UAAU,KAAK,QAAQ,SAAS,eAAe,CACxE;AAED,MAAI,gBAAgB;AAClB,QAAK,eAAe;AAEpB,UAAO,IACL,kBACA,0BAA0B,KAAK,QAAQ,UACxC;;AAGH,SAAO,GAAG,MAAM;;CAGlB,MAAa,cAAc;AACzB,MAAI,CAAC,KAAK,UAAU,CAClB,QAAO,IAAI,oBAAoB,iBAAiB;AAGlD,OAAK,eAAe;EAEpB,MAAM,CAAC,oBAAoB,MAAM,WAC/B,KAAK,QAAQ,WAAW,YAAY,KAAK,QAAQ,QAAQ,CAC1D;AAED,MAAI,kBAAkB;AACpB,QAAK,eAAe;AAEpB,UAAO,IACL,oBACA,8BAA8B,KAAK,QAAQ,UAC5C;;AAGH,SAAO,GAAG,KAAK;;CAGjB,WAAkB;AAChB,SAAO,KAAK"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_lib_errors_index = require("../errors/index.cjs");
|
|
3
|
+
//#region src/lib/queue/index.ts
|
|
4
|
+
const toMinimalJob = (jobState) => ({
|
|
5
|
+
id: jobState.id,
|
|
6
|
+
data: jobState.data,
|
|
7
|
+
attempts: jobState.attempts,
|
|
8
|
+
maxRetries: jobState.maxRetries,
|
|
9
|
+
createdAt: jobState.createdAt
|
|
10
|
+
});
|
|
11
|
+
const DEFAULT_RETRIES = 3;
|
|
12
|
+
const DEFAULT_TIMEOUT = 3e4;
|
|
13
|
+
const DEFAULT_CONCURRENCY = 1;
|
|
14
|
+
const DEFAULT_POLL_INTERVAL = 100;
|
|
15
|
+
const MAX_BACKOFF_DELAY = 6e4;
|
|
16
|
+
const BASE_BACKOFF_DELAY = 1e3;
|
|
17
|
+
const BACKOFF_MULTIPLIER = 2;
|
|
18
|
+
const SHUTDOWN_POLL_INTERVAL = 10;
|
|
19
|
+
var Queue = class {
|
|
20
|
+
options;
|
|
21
|
+
running = true;
|
|
22
|
+
activeWorkers = 0;
|
|
23
|
+
retries;
|
|
24
|
+
timeout;
|
|
25
|
+
concurrency;
|
|
26
|
+
pollInterval;
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.options = options;
|
|
29
|
+
this.retries = options.retries ?? DEFAULT_RETRIES;
|
|
30
|
+
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
31
|
+
this.concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
32
|
+
this.pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;
|
|
33
|
+
this.startWorkers();
|
|
34
|
+
}
|
|
35
|
+
async enqueue(data) {
|
|
36
|
+
const job = {
|
|
37
|
+
id: crypto.randomUUID(),
|
|
38
|
+
data,
|
|
39
|
+
attempts: 0,
|
|
40
|
+
maxRetries: this.retries,
|
|
41
|
+
createdAt: Date.now()
|
|
42
|
+
};
|
|
43
|
+
const [serializeError, serialized] = this.serializeJob(job);
|
|
44
|
+
if (serializeError || !serialized) return require_lib_errors_index.err("QueueError", "Unable to serialize job data");
|
|
45
|
+
const [enqueueError] = await this.enqueueJobData(serialized);
|
|
46
|
+
if (enqueueError) return require_lib_errors_index.err("QueueError", "Unable to enqueue job");
|
|
47
|
+
return require_lib_errors_index.ok(job.id);
|
|
48
|
+
}
|
|
49
|
+
async stop() {
|
|
50
|
+
this.running = false;
|
|
51
|
+
while (this.activeWorkers > 0) await new Promise((resolve) => setTimeout(resolve, SHUTDOWN_POLL_INTERVAL));
|
|
52
|
+
}
|
|
53
|
+
waitForPollInterval() {
|
|
54
|
+
return new Promise((resolve) => setTimeout(resolve, this.pollInterval));
|
|
55
|
+
}
|
|
56
|
+
serializeJob(job) {
|
|
57
|
+
return require_lib_errors_index.mightThrowSync(() => JSON.stringify(job));
|
|
58
|
+
}
|
|
59
|
+
async enqueueJobData(serialized) {
|
|
60
|
+
const queueKey = `queue:${this.options.name}:jobs`;
|
|
61
|
+
return require_lib_errors_index.mightThrow(this.options.redis.lpush(queueKey, serialized));
|
|
62
|
+
}
|
|
63
|
+
async moveToDeadLetterQueue(jobData, parseError) {
|
|
64
|
+
const deadLetterKey = `queue:${this.options.name}:dead-letter`;
|
|
65
|
+
const deadLetterEntry = JSON.stringify({
|
|
66
|
+
jobData,
|
|
67
|
+
parseError: this.formatErrorMessage(parseError),
|
|
68
|
+
timestamp: Date.now()
|
|
69
|
+
});
|
|
70
|
+
return require_lib_errors_index.mightThrow(this.options.redis.lpush(deadLetterKey, deadLetterEntry));
|
|
71
|
+
}
|
|
72
|
+
formatErrorMessage(error) {
|
|
73
|
+
return error instanceof Error ? error.message : String(error);
|
|
74
|
+
}
|
|
75
|
+
startWorkers() {
|
|
76
|
+
for (let i = 0; i < this.concurrency; i++) this.processJobs();
|
|
77
|
+
}
|
|
78
|
+
async processJobs() {
|
|
79
|
+
while (this.running) {
|
|
80
|
+
const queueKey = `queue:${this.options.name}:jobs`;
|
|
81
|
+
const [popError, jobData] = await require_lib_errors_index.mightThrow(this.options.redis.rpop(queueKey));
|
|
82
|
+
if (popError) {
|
|
83
|
+
await this.waitForPollInterval();
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (!jobData) {
|
|
87
|
+
await this.waitForPollInterval();
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const [parseError, job] = require_lib_errors_index.mightThrowSync(() => JSON.parse(jobData));
|
|
91
|
+
if (parseError || !job) {
|
|
92
|
+
await this.callOnErrorForParseFailure(jobData, parseError);
|
|
93
|
+
await this.moveToDeadLetterQueue(jobData, parseError);
|
|
94
|
+
await this.waitForPollInterval();
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (!this.running) {
|
|
98
|
+
const [stringifyError, serialized] = this.serializeJob(job);
|
|
99
|
+
if (!stringifyError && serialized) await require_lib_errors_index.mightThrow(this.options.redis.lpush(queueKey, serialized));
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
this.activeWorkers++;
|
|
103
|
+
await require_lib_errors_index.mightThrow(this.handleJob(job));
|
|
104
|
+
this.activeWorkers--;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async handleJob(job) {
|
|
108
|
+
const controller = new AbortController();
|
|
109
|
+
const handlerPromise = Promise.resolve().then(() => this.options.handler(job.data, controller.signal));
|
|
110
|
+
let timerId;
|
|
111
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
112
|
+
timerId = setTimeout(() => {
|
|
113
|
+
reject(/* @__PURE__ */ new Error(`Job timeout after ${this.timeout}ms`));
|
|
114
|
+
}, this.timeout);
|
|
115
|
+
});
|
|
116
|
+
const [handlerError] = await require_lib_errors_index.mightThrow(Promise.race([handlerPromise.then(() => void 0), timeoutPromise]));
|
|
117
|
+
if (timerId) clearTimeout(timerId);
|
|
118
|
+
if (handlerError && !controller.signal.aborted) controller.abort();
|
|
119
|
+
if (!handlerError) {
|
|
120
|
+
if (this.options.onSuccess) await require_lib_errors_index.mightThrow(Promise.resolve(this.options.onSuccess(toMinimalJob(job))));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
job.attempts++;
|
|
124
|
+
const errorMsg = this.formatErrorMessage(handlerError);
|
|
125
|
+
job.error = errorMsg;
|
|
126
|
+
if (!job.errorHistory) job.errorHistory = [];
|
|
127
|
+
job.errorHistory.push({
|
|
128
|
+
attempt: job.attempts,
|
|
129
|
+
error: errorMsg,
|
|
130
|
+
timestamp: Date.now()
|
|
131
|
+
});
|
|
132
|
+
if (job.attempts <= job.maxRetries) {
|
|
133
|
+
if (this.options.onRetry) {
|
|
134
|
+
const delay = Math.min(BASE_BACKOFF_DELAY * BACKOFF_MULTIPLIER ** (job.attempts - 1), MAX_BACKOFF_DELAY);
|
|
135
|
+
await require_lib_errors_index.mightThrow(Promise.resolve(this.options.onRetry({
|
|
136
|
+
job: toMinimalJob(job),
|
|
137
|
+
error: errorMsg,
|
|
138
|
+
nextRetryDelayMs: delay,
|
|
139
|
+
retriesRemaining: job.maxRetries - job.attempts,
|
|
140
|
+
backoffMultiplier: BACKOFF_MULTIPLIER
|
|
141
|
+
})));
|
|
142
|
+
}
|
|
143
|
+
await this.retryJob(job);
|
|
144
|
+
} else await this.callOnError(job);
|
|
145
|
+
}
|
|
146
|
+
async callOnError(job) {
|
|
147
|
+
if (!this.options.onError) return;
|
|
148
|
+
await require_lib_errors_index.mightThrow(Promise.resolve(this.options.onError({
|
|
149
|
+
job: toMinimalJob(job),
|
|
150
|
+
lastError: job.error ?? "",
|
|
151
|
+
totalDurationMs: Date.now() - job.createdAt,
|
|
152
|
+
totalAttempts: job.attempts,
|
|
153
|
+
errorHistory: job.errorHistory ?? []
|
|
154
|
+
})));
|
|
155
|
+
}
|
|
156
|
+
async callOnErrorForParseFailure(jobData, parseError) {
|
|
157
|
+
if (!this.options.onParseError) return;
|
|
158
|
+
await require_lib_errors_index.mightThrow(Promise.resolve(this.options.onParseError({
|
|
159
|
+
rawJobData: jobData,
|
|
160
|
+
parseError: this.formatErrorMessage(parseError),
|
|
161
|
+
timestamp: Date.now()
|
|
162
|
+
})));
|
|
163
|
+
}
|
|
164
|
+
async retryJob(job) {
|
|
165
|
+
const delay = Math.min(BASE_BACKOFF_DELAY * BACKOFF_MULTIPLIER ** (job.attempts - 1), MAX_BACKOFF_DELAY);
|
|
166
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
167
|
+
const [stringifyError, serialized] = this.serializeJob(job);
|
|
168
|
+
if (stringifyError || !serialized) {
|
|
169
|
+
job.error = `Failed to serialize job for retry: ${this.formatErrorMessage(stringifyError)}`;
|
|
170
|
+
await this.callOnError(job);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const queueKey = `queue:${this.options.name}:jobs`;
|
|
174
|
+
const [pushError] = await require_lib_errors_index.mightThrow(this.options.redis.lpush(queueKey, serialized));
|
|
175
|
+
if (pushError) {
|
|
176
|
+
job.error = `Failed to re-enqueue job for retry: ${this.formatErrorMessage(pushError)}`;
|
|
177
|
+
await this.callOnError(job);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
//#endregion
|
|
182
|
+
exports.Queue = Queue;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { QueueOptions } from "../../queue/types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/queue/index.d.ts
|
|
4
|
+
declare class Queue<T> {
|
|
5
|
+
private options;
|
|
6
|
+
private running;
|
|
7
|
+
private activeWorkers;
|
|
8
|
+
private retries;
|
|
9
|
+
private timeout;
|
|
10
|
+
private concurrency;
|
|
11
|
+
private pollInterval;
|
|
12
|
+
constructor(options: QueueOptions<T>);
|
|
13
|
+
enqueue(data: T): Promise<readonly [null, string] | readonly [{
|
|
14
|
+
readonly type: "QueueError";
|
|
15
|
+
readonly message: string;
|
|
16
|
+
}, null]>;
|
|
17
|
+
stop(): Promise<void>;
|
|
18
|
+
private waitForPollInterval;
|
|
19
|
+
private serializeJob;
|
|
20
|
+
private enqueueJobData;
|
|
21
|
+
private moveToDeadLetterQueue;
|
|
22
|
+
private formatErrorMessage;
|
|
23
|
+
private startWorkers;
|
|
24
|
+
private processJobs;
|
|
25
|
+
private handleJob;
|
|
26
|
+
private callOnError;
|
|
27
|
+
private callOnErrorForParseFailure;
|
|
28
|
+
private retryJob;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { Queue };
|
|
32
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/lib/queue/index.ts"],"mappings":";;;cAoBa,KAAA;EAAA,QACH,OAAA;EAAA,QACA,OAAA;EAAA,QACA,aAAA;EAAA,QACA,OAAA;EAAA,QACA,OAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;cAEW,OAAA,EAAS,YAAA,CAAa,CAAA;EAS5B,OAAA,CAAQ,IAAA,EAAM,CAAA,GAAC,OAAA;IAAA;;;EAsBf,IAAA,CAAA,GAAI,OAAA;EAAA,QAWT,mBAAA;EAAA,QAIA,YAAA;EAAA,QAIM,cAAA;EAAA,QAKA,qBAAA;EAAA,QAWN,kBAAA;EAAA,QAIA,YAAA;EAAA,QAMM,WAAA;EAAA,QAkDA,SAAA;EAAA,QA6EA,WAAA;EAAA,QAkBA,0BAAA;EAAA,QAmBA,QAAA;AAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { QueueOptions } from "../../queue/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/queue/index.d.ts
|
|
4
|
+
declare class Queue<T> {
|
|
5
|
+
private options;
|
|
6
|
+
private running;
|
|
7
|
+
private activeWorkers;
|
|
8
|
+
private retries;
|
|
9
|
+
private timeout;
|
|
10
|
+
private concurrency;
|
|
11
|
+
private pollInterval;
|
|
12
|
+
constructor(options: QueueOptions<T>);
|
|
13
|
+
enqueue(data: T): Promise<readonly [null, string] | readonly [{
|
|
14
|
+
readonly type: "QueueError";
|
|
15
|
+
readonly message: string;
|
|
16
|
+
}, null]>;
|
|
17
|
+
stop(): Promise<void>;
|
|
18
|
+
private waitForPollInterval;
|
|
19
|
+
private serializeJob;
|
|
20
|
+
private enqueueJobData;
|
|
21
|
+
private moveToDeadLetterQueue;
|
|
22
|
+
private formatErrorMessage;
|
|
23
|
+
private startWorkers;
|
|
24
|
+
private processJobs;
|
|
25
|
+
private handleJob;
|
|
26
|
+
private callOnError;
|
|
27
|
+
private callOnErrorForParseFailure;
|
|
28
|
+
private retryJob;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { Queue };
|
|
32
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/lib/queue/index.ts"],"mappings":";;;cAoBa,KAAA;EAAA,QACH,OAAA;EAAA,QACA,OAAA;EAAA,QACA,aAAA;EAAA,QACA,OAAA;EAAA,QACA,OAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;cAEW,OAAA,EAAS,YAAA,CAAa,CAAA;EAS5B,OAAA,CAAQ,IAAA,EAAM,CAAA,GAAC,OAAA;IAAA;;;EAsBf,IAAA,CAAA,GAAI,OAAA;EAAA,QAWT,mBAAA;EAAA,QAIA,YAAA;EAAA,QAIM,cAAA;EAAA,QAKA,qBAAA;EAAA,QAWN,kBAAA;EAAA,QAIA,YAAA;EAAA,QAMM,WAAA;EAAA,QAkDA,SAAA;EAAA,QA6EA,WAAA;EAAA,QAkBA,0BAAA;EAAA,QAmBA,QAAA;AAAA"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { err, mightThrow, mightThrowSync, ok } from "../errors/index.mjs";
|
|
2
|
+
//#region src/lib/queue/index.ts
|
|
3
|
+
const toMinimalJob = (jobState) => ({
|
|
4
|
+
id: jobState.id,
|
|
5
|
+
data: jobState.data,
|
|
6
|
+
attempts: jobState.attempts,
|
|
7
|
+
maxRetries: jobState.maxRetries,
|
|
8
|
+
createdAt: jobState.createdAt
|
|
9
|
+
});
|
|
10
|
+
const DEFAULT_RETRIES = 3;
|
|
11
|
+
const DEFAULT_TIMEOUT = 3e4;
|
|
12
|
+
const DEFAULT_CONCURRENCY = 1;
|
|
13
|
+
const DEFAULT_POLL_INTERVAL = 100;
|
|
14
|
+
const MAX_BACKOFF_DELAY = 6e4;
|
|
15
|
+
const BASE_BACKOFF_DELAY = 1e3;
|
|
16
|
+
const BACKOFF_MULTIPLIER = 2;
|
|
17
|
+
const SHUTDOWN_POLL_INTERVAL = 10;
|
|
18
|
+
var Queue = class {
|
|
19
|
+
options;
|
|
20
|
+
running = true;
|
|
21
|
+
activeWorkers = 0;
|
|
22
|
+
retries;
|
|
23
|
+
timeout;
|
|
24
|
+
concurrency;
|
|
25
|
+
pollInterval;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.retries = options.retries ?? DEFAULT_RETRIES;
|
|
29
|
+
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
30
|
+
this.concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
31
|
+
this.pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;
|
|
32
|
+
this.startWorkers();
|
|
33
|
+
}
|
|
34
|
+
async enqueue(data) {
|
|
35
|
+
const job = {
|
|
36
|
+
id: crypto.randomUUID(),
|
|
37
|
+
data,
|
|
38
|
+
attempts: 0,
|
|
39
|
+
maxRetries: this.retries,
|
|
40
|
+
createdAt: Date.now()
|
|
41
|
+
};
|
|
42
|
+
const [serializeError, serialized] = this.serializeJob(job);
|
|
43
|
+
if (serializeError || !serialized) return err("QueueError", "Unable to serialize job data");
|
|
44
|
+
const [enqueueError] = await this.enqueueJobData(serialized);
|
|
45
|
+
if (enqueueError) return err("QueueError", "Unable to enqueue job");
|
|
46
|
+
return ok(job.id);
|
|
47
|
+
}
|
|
48
|
+
async stop() {
|
|
49
|
+
this.running = false;
|
|
50
|
+
while (this.activeWorkers > 0) await new Promise((resolve) => setTimeout(resolve, SHUTDOWN_POLL_INTERVAL));
|
|
51
|
+
}
|
|
52
|
+
waitForPollInterval() {
|
|
53
|
+
return new Promise((resolve) => setTimeout(resolve, this.pollInterval));
|
|
54
|
+
}
|
|
55
|
+
serializeJob(job) {
|
|
56
|
+
return mightThrowSync(() => JSON.stringify(job));
|
|
57
|
+
}
|
|
58
|
+
async enqueueJobData(serialized) {
|
|
59
|
+
const queueKey = `queue:${this.options.name}:jobs`;
|
|
60
|
+
return mightThrow(this.options.redis.lpush(queueKey, serialized));
|
|
61
|
+
}
|
|
62
|
+
async moveToDeadLetterQueue(jobData, parseError) {
|
|
63
|
+
const deadLetterKey = `queue:${this.options.name}:dead-letter`;
|
|
64
|
+
const deadLetterEntry = JSON.stringify({
|
|
65
|
+
jobData,
|
|
66
|
+
parseError: this.formatErrorMessage(parseError),
|
|
67
|
+
timestamp: Date.now()
|
|
68
|
+
});
|
|
69
|
+
return mightThrow(this.options.redis.lpush(deadLetterKey, deadLetterEntry));
|
|
70
|
+
}
|
|
71
|
+
formatErrorMessage(error) {
|
|
72
|
+
return error instanceof Error ? error.message : String(error);
|
|
73
|
+
}
|
|
74
|
+
startWorkers() {
|
|
75
|
+
for (let i = 0; i < this.concurrency; i++) this.processJobs();
|
|
76
|
+
}
|
|
77
|
+
async processJobs() {
|
|
78
|
+
while (this.running) {
|
|
79
|
+
const queueKey = `queue:${this.options.name}:jobs`;
|
|
80
|
+
const [popError, jobData] = await mightThrow(this.options.redis.rpop(queueKey));
|
|
81
|
+
if (popError) {
|
|
82
|
+
await this.waitForPollInterval();
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (!jobData) {
|
|
86
|
+
await this.waitForPollInterval();
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const [parseError, job] = mightThrowSync(() => JSON.parse(jobData));
|
|
90
|
+
if (parseError || !job) {
|
|
91
|
+
await this.callOnErrorForParseFailure(jobData, parseError);
|
|
92
|
+
await this.moveToDeadLetterQueue(jobData, parseError);
|
|
93
|
+
await this.waitForPollInterval();
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (!this.running) {
|
|
97
|
+
const [stringifyError, serialized] = this.serializeJob(job);
|
|
98
|
+
if (!stringifyError && serialized) await mightThrow(this.options.redis.lpush(queueKey, serialized));
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
this.activeWorkers++;
|
|
102
|
+
await mightThrow(this.handleJob(job));
|
|
103
|
+
this.activeWorkers--;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async handleJob(job) {
|
|
107
|
+
const controller = new AbortController();
|
|
108
|
+
const handlerPromise = Promise.resolve().then(() => this.options.handler(job.data, controller.signal));
|
|
109
|
+
let timerId;
|
|
110
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
111
|
+
timerId = setTimeout(() => {
|
|
112
|
+
reject(/* @__PURE__ */ new Error(`Job timeout after ${this.timeout}ms`));
|
|
113
|
+
}, this.timeout);
|
|
114
|
+
});
|
|
115
|
+
const [handlerError] = await mightThrow(Promise.race([handlerPromise.then(() => void 0), timeoutPromise]));
|
|
116
|
+
if (timerId) clearTimeout(timerId);
|
|
117
|
+
if (handlerError && !controller.signal.aborted) controller.abort();
|
|
118
|
+
if (!handlerError) {
|
|
119
|
+
if (this.options.onSuccess) await mightThrow(Promise.resolve(this.options.onSuccess(toMinimalJob(job))));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
job.attempts++;
|
|
123
|
+
const errorMsg = this.formatErrorMessage(handlerError);
|
|
124
|
+
job.error = errorMsg;
|
|
125
|
+
if (!job.errorHistory) job.errorHistory = [];
|
|
126
|
+
job.errorHistory.push({
|
|
127
|
+
attempt: job.attempts,
|
|
128
|
+
error: errorMsg,
|
|
129
|
+
timestamp: Date.now()
|
|
130
|
+
});
|
|
131
|
+
if (job.attempts <= job.maxRetries) {
|
|
132
|
+
if (this.options.onRetry) {
|
|
133
|
+
const delay = Math.min(BASE_BACKOFF_DELAY * BACKOFF_MULTIPLIER ** (job.attempts - 1), MAX_BACKOFF_DELAY);
|
|
134
|
+
await mightThrow(Promise.resolve(this.options.onRetry({
|
|
135
|
+
job: toMinimalJob(job),
|
|
136
|
+
error: errorMsg,
|
|
137
|
+
nextRetryDelayMs: delay,
|
|
138
|
+
retriesRemaining: job.maxRetries - job.attempts,
|
|
139
|
+
backoffMultiplier: BACKOFF_MULTIPLIER
|
|
140
|
+
})));
|
|
141
|
+
}
|
|
142
|
+
await this.retryJob(job);
|
|
143
|
+
} else await this.callOnError(job);
|
|
144
|
+
}
|
|
145
|
+
async callOnError(job) {
|
|
146
|
+
if (!this.options.onError) return;
|
|
147
|
+
await mightThrow(Promise.resolve(this.options.onError({
|
|
148
|
+
job: toMinimalJob(job),
|
|
149
|
+
lastError: job.error ?? "",
|
|
150
|
+
totalDurationMs: Date.now() - job.createdAt,
|
|
151
|
+
totalAttempts: job.attempts,
|
|
152
|
+
errorHistory: job.errorHistory ?? []
|
|
153
|
+
})));
|
|
154
|
+
}
|
|
155
|
+
async callOnErrorForParseFailure(jobData, parseError) {
|
|
156
|
+
if (!this.options.onParseError) return;
|
|
157
|
+
await mightThrow(Promise.resolve(this.options.onParseError({
|
|
158
|
+
rawJobData: jobData,
|
|
159
|
+
parseError: this.formatErrorMessage(parseError),
|
|
160
|
+
timestamp: Date.now()
|
|
161
|
+
})));
|
|
162
|
+
}
|
|
163
|
+
async retryJob(job) {
|
|
164
|
+
const delay = Math.min(BASE_BACKOFF_DELAY * BACKOFF_MULTIPLIER ** (job.attempts - 1), MAX_BACKOFF_DELAY);
|
|
165
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
166
|
+
const [stringifyError, serialized] = this.serializeJob(job);
|
|
167
|
+
if (stringifyError || !serialized) {
|
|
168
|
+
job.error = `Failed to serialize job for retry: ${this.formatErrorMessage(stringifyError)}`;
|
|
169
|
+
await this.callOnError(job);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const queueKey = `queue:${this.options.name}:jobs`;
|
|
173
|
+
const [pushError] = await mightThrow(this.options.redis.lpush(queueKey, serialized));
|
|
174
|
+
if (pushError) {
|
|
175
|
+
job.error = `Failed to re-enqueue job for retry: ${this.formatErrorMessage(pushError)}`;
|
|
176
|
+
await this.callOnError(job);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
//#endregion
|
|
181
|
+
export { Queue };
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/lib/queue/index.ts"],"sourcesContent":["import { err, mightThrow, mightThrowSync, ok } from \"../errors/index.js\";\nimport type { Job, JobState, QueueOptions } from \"./types.js\";\n\nconst toMinimalJob = <T>(jobState: JobState<T>): Job<T> => ({\n id: jobState.id,\n data: jobState.data,\n attempts: jobState.attempts,\n maxRetries: jobState.maxRetries,\n createdAt: jobState.createdAt,\n});\n\nconst DEFAULT_RETRIES = 3;\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_CONCURRENCY = 1;\nconst DEFAULT_POLL_INTERVAL = 100;\nconst MAX_BACKOFF_DELAY = 60000;\nconst BASE_BACKOFF_DELAY = 1000;\nconst BACKOFF_MULTIPLIER = 2;\nconst SHUTDOWN_POLL_INTERVAL = 10;\n\nexport class Queue<T> {\n private options: QueueOptions<T>;\n private running = true;\n private activeWorkers = 0;\n private retries: number;\n private timeout: number;\n private concurrency: number;\n private pollInterval: number;\n\n public constructor(options: QueueOptions<T>) {\n this.options = options;\n this.retries = options.retries ?? DEFAULT_RETRIES;\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n this.concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n this.pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.startWorkers();\n }\n\n public async enqueue(data: T) {\n const job: JobState<T> = {\n id: crypto.randomUUID(),\n data,\n attempts: 0,\n maxRetries: this.retries,\n createdAt: Date.now(),\n };\n\n const [serializeError, serialized] = this.serializeJob(job);\n if (serializeError || !serialized) {\n return err(\"QueueError\", \"Unable to serialize job data\");\n }\n\n const [enqueueError] = await this.enqueueJobData(serialized);\n if (enqueueError) {\n return err(\"QueueError\", \"Unable to enqueue job\");\n }\n\n return ok(job.id);\n }\n\n public async stop() {\n this.running = false;\n\n // Wait for all active workers to finish processing\n while (this.activeWorkers > 0) {\n await new Promise((resolve) =>\n setTimeout(resolve, SHUTDOWN_POLL_INTERVAL),\n );\n }\n }\n\n private waitForPollInterval() {\n return new Promise((resolve) => setTimeout(resolve, this.pollInterval));\n }\n\n private serializeJob(job: JobState<T>) {\n return mightThrowSync(() => JSON.stringify(job));\n }\n\n private async enqueueJobData(serialized: string) {\n const queueKey = `queue:${this.options.name}:jobs`;\n return mightThrow(this.options.redis.lpush(queueKey, serialized));\n }\n\n private async moveToDeadLetterQueue(jobData: string, parseError: unknown) {\n const deadLetterKey = `queue:${this.options.name}:dead-letter`;\n const deadLetterEntry = JSON.stringify({\n jobData,\n parseError: this.formatErrorMessage(parseError),\n timestamp: Date.now(),\n });\n\n return mightThrow(this.options.redis.lpush(deadLetterKey, deadLetterEntry));\n }\n\n private formatErrorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n }\n\n private startWorkers() {\n for (let i = 0; i < this.concurrency; i++) {\n this.processJobs();\n }\n }\n\n private async processJobs() {\n while (this.running) {\n const queueKey = `queue:${this.options.name}:jobs`;\n\n const [popError, jobData] = await mightThrow(\n this.options.redis.rpop(queueKey),\n );\n\n if (popError) {\n await this.waitForPollInterval();\n continue;\n }\n\n if (!jobData) {\n await this.waitForPollInterval();\n continue;\n }\n\n const [parseError, job] = mightThrowSync<JobState<T>>(() =>\n JSON.parse(jobData),\n );\n\n if (parseError || !job) {\n // Handle malformed payload: preserve to dead-letter queue and notify\n await this.callOnErrorForParseFailure(jobData, parseError);\n await this.moveToDeadLetterQueue(jobData, parseError);\n\n await this.waitForPollInterval();\n continue;\n }\n\n // Skip processing if we've been stopped\n if (!this.running) {\n // Re-enqueue the job so it's not lost\n const [stringifyError, serialized] = this.serializeJob(job);\n\n if (!stringifyError && serialized) {\n await mightThrow(this.options.redis.lpush(queueKey, serialized));\n }\n\n break;\n }\n\n this.activeWorkers++;\n\n await mightThrow(this.handleJob(job));\n this.activeWorkers--;\n }\n }\n\n private async handleJob(job: JobState<T>) {\n const controller = new AbortController();\n\n const handlerPromise = Promise.resolve().then(() =>\n this.options.handler(job.data, controller.signal),\n );\n\n let timerId: NodeJS.Timeout | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timerId = setTimeout(() => {\n reject(new Error(`Job timeout after ${this.timeout}ms`));\n }, this.timeout);\n });\n\n const [handlerError] = await mightThrow(\n Promise.race([handlerPromise.then(() => undefined), timeoutPromise]),\n );\n\n if (timerId) {\n clearTimeout(timerId);\n }\n\n // Abort handler if timeout occurred\n if (handlerError && !controller.signal.aborted) {\n controller.abort();\n }\n\n if (!handlerError) {\n if (this.options.onSuccess) {\n await mightThrow(\n Promise.resolve(this.options.onSuccess(toMinimalJob(job))),\n );\n }\n\n return;\n }\n\n job.attempts++;\n\n const errorMsg = this.formatErrorMessage(handlerError);\n job.error = errorMsg;\n\n if (!job.errorHistory) {\n job.errorHistory = [];\n }\n job.errorHistory.push({\n attempt: job.attempts,\n error: errorMsg,\n timestamp: Date.now(),\n });\n\n // Check if we should retry. Attempt starts at 1, so we retry while attempts <= maxRetries\n if (job.attempts <= job.maxRetries) {\n if (this.options.onRetry) {\n const delay = Math.min(\n BASE_BACKOFF_DELAY * BACKOFF_MULTIPLIER ** (job.attempts - 1),\n MAX_BACKOFF_DELAY,\n );\n await mightThrow(\n Promise.resolve(\n this.options.onRetry({\n job: toMinimalJob(job),\n error: errorMsg,\n nextRetryDelayMs: delay,\n retriesRemaining: job.maxRetries - job.attempts,\n backoffMultiplier: BACKOFF_MULTIPLIER,\n }),\n ),\n );\n }\n await this.retryJob(job);\n } else {\n await this.callOnError(job);\n }\n }\n\n private async callOnError(job: JobState<T>) {\n if (!this.options.onError) {\n return;\n }\n\n await mightThrow(\n Promise.resolve(\n this.options.onError({\n job: toMinimalJob(job),\n lastError: job.error ?? \"\",\n totalDurationMs: Date.now() - job.createdAt,\n totalAttempts: job.attempts,\n errorHistory: job.errorHistory ?? [],\n }),\n ),\n );\n }\n\n private async callOnErrorForParseFailure(\n jobData: string,\n parseError: unknown,\n ) {\n if (!this.options.onParseError) {\n return;\n }\n\n await mightThrow(\n Promise.resolve(\n this.options.onParseError({\n rawJobData: jobData,\n parseError: this.formatErrorMessage(parseError),\n timestamp: Date.now(),\n }),\n ),\n );\n }\n\n private async retryJob(job: JobState<T>) {\n // Exponential backoff: 1st retry (attempts=1) -> 1000ms, 2nd (attempts=2) -> 2000ms, etc.\n const delay = Math.min(\n BASE_BACKOFF_DELAY * BACKOFF_MULTIPLIER ** (job.attempts - 1),\n MAX_BACKOFF_DELAY,\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n const [stringifyError, serialized] = this.serializeJob(job);\n\n if (stringifyError || !serialized) {\n job.error = `Failed to serialize job for retry: ${this.formatErrorMessage(stringifyError)}`;\n await this.callOnError(job);\n return;\n }\n\n const queueKey = `queue:${this.options.name}:jobs`;\n const [pushError] = await mightThrow(\n this.options.redis.lpush(queueKey, serialized),\n );\n\n if (pushError) {\n job.error = `Failed to re-enqueue job for retry: ${this.formatErrorMessage(pushError)}`;\n await this.callOnError(job);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//#region node_modules/@standard-schema/spec/dist/index.d.ts
|
|
2
|
+
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
3
|
+
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
4
|
+
/** The Standard properties. */
|
|
5
|
+
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
6
|
+
}
|
|
7
|
+
declare namespace StandardTypedV1 {
|
|
8
|
+
/** The Standard Typed properties interface. */
|
|
9
|
+
interface Props<Input = unknown, Output = Input> {
|
|
10
|
+
/** The version number of the standard. */
|
|
11
|
+
readonly version: 1;
|
|
12
|
+
/** The vendor name of the schema library. */
|
|
13
|
+
readonly vendor: string;
|
|
14
|
+
/** Inferred types associated with the schema. */
|
|
15
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** The Standard Typed types interface. */
|
|
18
|
+
interface Types<Input = unknown, Output = Input> {
|
|
19
|
+
/** The input type of the schema. */
|
|
20
|
+
readonly input: Input;
|
|
21
|
+
/** The output type of the schema. */
|
|
22
|
+
readonly output: Output;
|
|
23
|
+
}
|
|
24
|
+
/** Infers the input type of a Standard Typed. */
|
|
25
|
+
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
26
|
+
/** Infers the output type of a Standard Typed. */
|
|
27
|
+
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
28
|
+
}
|
|
29
|
+
/** The Standard Schema interface. */
|
|
30
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
31
|
+
/** The Standard Schema properties. */
|
|
32
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
33
|
+
}
|
|
34
|
+
declare namespace StandardSchemaV1 {
|
|
35
|
+
/** The Standard Schema properties interface. */
|
|
36
|
+
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
37
|
+
/** Validates unknown input values. */
|
|
38
|
+
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
|
|
39
|
+
}
|
|
40
|
+
/** The result interface of the validate function. */
|
|
41
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
42
|
+
/** The result interface if validation succeeds. */
|
|
43
|
+
interface SuccessResult<Output> {
|
|
44
|
+
/** The typed output value. */
|
|
45
|
+
readonly value: Output;
|
|
46
|
+
/** A falsy value for `issues` indicates success. */
|
|
47
|
+
readonly issues?: undefined;
|
|
48
|
+
}
|
|
49
|
+
interface Options {
|
|
50
|
+
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
51
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
52
|
+
}
|
|
53
|
+
/** The result interface if validation fails. */
|
|
54
|
+
interface FailureResult {
|
|
55
|
+
/** The issues of failed validation. */
|
|
56
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
57
|
+
}
|
|
58
|
+
/** The issue interface of the failure output. */
|
|
59
|
+
interface Issue {
|
|
60
|
+
/** The error message of the issue. */
|
|
61
|
+
readonly message: string;
|
|
62
|
+
/** The path of the issue, if any. */
|
|
63
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
64
|
+
}
|
|
65
|
+
/** The path segment interface of the issue. */
|
|
66
|
+
interface PathSegment {
|
|
67
|
+
/** The key representing a path segment. */
|
|
68
|
+
readonly key: PropertyKey;
|
|
69
|
+
}
|
|
70
|
+
/** The Standard types interface. */
|
|
71
|
+
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
|
|
72
|
+
/** Infers the input type of a Standard. */
|
|
73
|
+
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
74
|
+
/** Infers the output type of a Standard. */
|
|
75
|
+
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
76
|
+
}
|
|
77
|
+
/** The Standard JSON Schema interface. */
|
|
78
|
+
//#endregion
|
|
79
|
+
export { StandardSchemaV1 };
|
|
80
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":["StandardTypedV1","Input","Output","Props","Schema","Types","NonNullable","version","vendor","types","input","output","InferInput","InferOutput","StandardSchemaV1","Options","Result","Promise","SuccessResult","FailureResult","Record","Issue","ReadonlyArray","PropertyKey","PathSegment","validate","value","options","issues","libraryOptions","message","path","key","StandardJSONSchemaV1","Converter","Target","jsonSchema","target"],"sources":["../../../../../node_modules/@standard-schema/spec/dist/index.d.ts"],"x_google_ignoreList":[0],"mappings":";;UACUA,eAAAA,2BAA0CC,KAAAA;EAA3B;EAAA,SAEZ,WAAA,EAAaD,eAAAA,CAAgBG,KAAAA,CAAMF,KAAAA,EAAOC,MAAAA;AAAAA;AAAAA,kBAErCF,eAAAA;EAFqCE;EAAAA,UAIzCC,KAAAA,2BAAgCF,KAAAA;IAJC;IAAA,SAM9BM,OAAAA;IARSN;IAAAA,SAUTO,MAAAA;IAVmCP;IAAAA,SAYnCQ,KAAAA,GAAQJ,KAAAA,CAAMJ,KAAAA,EAAOC,MAAAA;EAAAA;EAVIC;EAAAA,UAa5BE,KAAAA,2BAAgCJ,KAAAA;IAbSC;IAAAA,SAetCQ,KAAAA,EAAOT,KAAAA;IAfqC;IAAA,SAiB5CU,MAAAA,EAAQT,MAAAA;EAAAA;EAfQD;EAAAA,KAkBxBW,UAAAA,gBAA0BZ,eAAAA,IAAmBM,WAAAA,CAAYF,MAAAA;EAVnCH;EAAAA,KAYtBY,WAAAA,gBAA2Bb,eAAAA,IAAmBM,WAAAA,CAAYF,MAAAA;AAAAA;;UAGzDU,gBAAAA,2BAA2Cb,KAAAA;EAR5BC;EAAAA,SAUZ,WAAA,EAAaY,gBAAAA,CAAiBX,KAAAA,CAAMF,KAAAA,EAAOC,MAAAA;AAAAA;AAAAA,kBAEtCY,gBAAAA;EAPkBd;EAAAA,UAStBG,KAAAA,2BAAgCF,KAAAA,UAAeD,eAAAA,CAAgBG,KAAAA,CAAMF,KAAAA,EAAOC,MAAAA;IATnCI;IAAAA,SAWtCmB,QAAAA,GAAWC,KAAAA,WAAgBC,OAAAA,GAAUb,gBAAAA,CAAiBC,OAAAA,iBAAwBC,MAAAA,CAAOd,MAAAA,IAAUe,OAAAA,CAAQD,MAAAA,CAAOd,MAAAA;EAAAA;EA7BjHC;EAAAA,KAgCLa,MAAAA,WAAiBE,aAAAA,CAAchB,MAAAA,IAAUiB,aAAAA;EAhCbjB;EAAAA,UAkCvBgB,aAAAA;IAhCGX;IAAAA,SAkCAmB,KAAAA,EAAOxB,MAAAA;IA9BPO;IAAAA,SAgCAmB,MAAAA;EAAAA;EAAAA,UAEHb,OAAAA;IA/BAV;IAAAA,SAiCGwB,cAAAA,GAAiBT,MAAAA;EAAAA;EAjCYnB;EAAAA,UAoChCkB,aAAAA;IAlCUlB;IAAAA,SAoCP2B,MAAAA,EAAQN,aAAAA,CAAcD,KAAAA;EAAAA;EA/B9BT;EAAAA,UAkCKS,KAAAA;IAlCqBrB;IAAAA,SAoClB8B,OAAAA;IApCiD1B;IAAAA,SAsCjD2B,IAAAA,GAAOT,aAAAA,CAAcC,WAAAA,GAAcC,WAAAA;EAAAA;EApChBxB;EAAAA,UAuCtBwB,WAAAA;IAvCqDpB;IAAAA,SAyClD4B,GAAAA,EAAKT,WAAAA;EAAAA;EAtCZT;EAAAA,UAyCIT,KAAAA,2BAAgCJ,KAAAA,UAAeD,eAAAA,CAAgBK,KAAAA,CAAMJ,KAAAA,EAAOC,MAAAA;EAzCrCD;EAAAA,KA4C5CW,UAAAA,gBAA0BZ,eAAAA,IAAmBA,eAAAA,CAAgBY,UAAAA,CAAWR,MAAAA;EA1CzBF;EAAAA,KA4C/CW,WAAAA,gBAA2Bb,eAAAA,IAAmBA,eAAAA,CAAgBa,WAAAA,CAAYT,MAAAA;AAAAA"}
|