semola 0.5.2 → 0.5.4

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 (160) hide show
  1. package/README.md +88 -13
  2. package/dist/index-BhGNDjPq.d.mts +13 -0
  3. package/dist/index-DxSbeGP-.d.cts +13 -0
  4. package/dist/lib/api/index.cjs +522 -4
  5. package/dist/lib/api/index.d.cts +270 -4
  6. package/dist/lib/api/index.d.mts +270 -4
  7. package/dist/lib/api/index.mjs +520 -2
  8. package/dist/lib/cache/index.d.cts +19 -7
  9. package/dist/lib/cache/index.d.mts +19 -7
  10. package/dist/lib/cache/index.mjs +0 -2
  11. package/dist/lib/cron/index.cjs +470 -11
  12. package/dist/lib/cron/index.d.cts +112 -5
  13. package/dist/lib/cron/index.d.mts +112 -5
  14. package/dist/lib/cron/index.mjs +461 -12
  15. package/dist/lib/errors/index.d.cts +2 -13
  16. package/dist/lib/errors/index.d.mts +2 -13
  17. package/dist/lib/errors/index.mjs +0 -2
  18. package/dist/lib/i18n/index.cjs +6 -1
  19. package/dist/lib/i18n/index.d.cts +12 -4
  20. package/dist/lib/i18n/index.d.mts +12 -4
  21. package/dist/lib/i18n/index.mjs +6 -3
  22. package/dist/lib/logging/index.cjs +387 -0
  23. package/dist/lib/logging/index.d.cts +108 -0
  24. package/dist/lib/logging/index.d.mts +108 -0
  25. package/dist/lib/logging/index.mjs +374 -0
  26. package/dist/lib/policy/index.cjs +206 -20
  27. package/dist/lib/policy/index.d.cts +61 -5
  28. package/dist/lib/policy/index.d.mts +61 -5
  29. package/dist/lib/policy/index.mjs +187 -3
  30. package/dist/lib/prompts/index.cjs +374 -14
  31. package/dist/lib/prompts/index.d.cts +77 -12
  32. package/dist/lib/prompts/index.d.mts +77 -12
  33. package/dist/lib/prompts/index.mjs +362 -4
  34. package/dist/lib/pubsub/index.cjs +82 -13
  35. package/dist/lib/pubsub/index.d.cts +23 -9
  36. package/dist/lib/pubsub/index.d.mts +23 -9
  37. package/dist/lib/pubsub/index.mjs +82 -15
  38. package/dist/lib/queue/index.d.cts +46 -4
  39. package/dist/lib/queue/index.d.mts +46 -4
  40. package/dist/lib/queue/index.mjs +0 -2
  41. package/dist/lib/workflow/index.cjs +534 -0
  42. package/dist/lib/workflow/index.d.cts +85 -0
  43. package/dist/lib/workflow/index.d.mts +85 -0
  44. package/dist/lib/workflow/index.mjs +533 -0
  45. package/package.json +29 -3
  46. package/dist/api/core/index.cjs +0 -206
  47. package/dist/api/core/index.d.cts +0 -21
  48. package/dist/api/core/index.d.cts.map +0 -1
  49. package/dist/api/core/index.d.mts +0 -21
  50. package/dist/api/core/index.d.mts.map +0 -1
  51. package/dist/api/core/index.mjs +0 -208
  52. package/dist/api/core/index.mjs.map +0 -1
  53. package/dist/api/core/types.d.cts +0 -107
  54. package/dist/api/core/types.d.cts.map +0 -1
  55. package/dist/api/core/types.d.mts +0 -107
  56. package/dist/api/core/types.d.mts.map +0 -1
  57. package/dist/api/middleware/index.cjs +0 -8
  58. package/dist/api/middleware/index.d.cts +0 -11
  59. package/dist/api/middleware/index.d.cts.map +0 -1
  60. package/dist/api/middleware/index.d.mts +0 -11
  61. package/dist/api/middleware/index.d.mts.map +0 -1
  62. package/dist/api/middleware/index.mjs +0 -10
  63. package/dist/api/middleware/index.mjs.map +0 -1
  64. package/dist/api/middleware/types.d.cts +0 -16
  65. package/dist/api/middleware/types.d.cts.map +0 -1
  66. package/dist/api/middleware/types.d.mts +0 -16
  67. package/dist/api/middleware/types.d.mts.map +0 -1
  68. package/dist/api/openapi/index.cjs +0 -254
  69. package/dist/api/openapi/index.mjs +0 -256
  70. package/dist/api/openapi/index.mjs.map +0 -1
  71. package/dist/api/openapi/types.d.cts +0 -60
  72. package/dist/api/openapi/types.d.cts.map +0 -1
  73. package/dist/api/openapi/types.d.mts +0 -60
  74. package/dist/api/openapi/types.d.mts.map +0 -1
  75. package/dist/api/validation/index.cjs +0 -64
  76. package/dist/api/validation/index.mjs +0 -61
  77. package/dist/api/validation/index.mjs.map +0 -1
  78. package/dist/cache/types.d.cts +0 -17
  79. package/dist/cache/types.d.cts.map +0 -1
  80. package/dist/cache/types.d.mts +0 -17
  81. package/dist/cache/types.d.mts.map +0 -1
  82. package/dist/cron/scanner.cjs +0 -237
  83. package/dist/cron/scanner.mjs +0 -238
  84. package/dist/cron/scanner.mjs.map +0 -1
  85. package/dist/cron/types.d.cts +0 -11
  86. package/dist/cron/types.d.cts.map +0 -1
  87. package/dist/cron/types.d.mts +0 -11
  88. package/dist/cron/types.d.mts.map +0 -1
  89. package/dist/errors/types.d.cts +0 -5
  90. package/dist/errors/types.d.cts.map +0 -1
  91. package/dist/errors/types.d.mts +0 -5
  92. package/dist/errors/types.d.mts.map +0 -1
  93. package/dist/i18n/types.d.cts +0 -13
  94. package/dist/i18n/types.d.cts.map +0 -1
  95. package/dist/i18n/types.d.mts +0 -13
  96. package/dist/i18n/types.d.mts.map +0 -1
  97. package/dist/lib/cache/index.d.cts.map +0 -1
  98. package/dist/lib/cache/index.d.mts.map +0 -1
  99. package/dist/lib/cache/index.mjs.map +0 -1
  100. package/dist/lib/cron/index.d.cts.map +0 -1
  101. package/dist/lib/cron/index.d.mts.map +0 -1
  102. package/dist/lib/cron/index.mjs.map +0 -1
  103. package/dist/lib/errors/index.d.cts.map +0 -1
  104. package/dist/lib/errors/index.d.mts.map +0 -1
  105. package/dist/lib/errors/index.mjs.map +0 -1
  106. package/dist/lib/i18n/index.d.cts.map +0 -1
  107. package/dist/lib/i18n/index.d.mts.map +0 -1
  108. package/dist/lib/i18n/index.mjs.map +0 -1
  109. package/dist/lib/policy/index.d.cts.map +0 -1
  110. package/dist/lib/policy/index.d.mts.map +0 -1
  111. package/dist/lib/policy/index.mjs.map +0 -1
  112. package/dist/lib/prompts/index.d.cts.map +0 -1
  113. package/dist/lib/prompts/index.d.mts.map +0 -1
  114. package/dist/lib/prompts/index.mjs.map +0 -1
  115. package/dist/lib/pubsub/index.d.cts.map +0 -1
  116. package/dist/lib/pubsub/index.d.mts.map +0 -1
  117. package/dist/lib/pubsub/index.mjs.map +0 -1
  118. package/dist/lib/queue/index.d.cts.map +0 -1
  119. package/dist/lib/queue/index.d.mts.map +0 -1
  120. package/dist/lib/queue/index.mjs.map +0 -1
  121. package/dist/node_modules/@standard-schema/spec/dist/index.d.cts +0 -80
  122. package/dist/node_modules/@standard-schema/spec/dist/index.d.cts.map +0 -1
  123. package/dist/node_modules/@standard-schema/spec/dist/index.d.mts +0 -80
  124. package/dist/node_modules/@standard-schema/spec/dist/index.d.mts.map +0 -1
  125. package/dist/policy/helpers.cjs +0 -206
  126. package/dist/policy/helpers.d.cts +0 -50
  127. package/dist/policy/helpers.d.cts.map +0 -1
  128. package/dist/policy/helpers.d.mts +0 -50
  129. package/dist/policy/helpers.d.mts.map +0 -1
  130. package/dist/policy/helpers.mjs +0 -190
  131. package/dist/policy/helpers.mjs.map +0 -1
  132. package/dist/policy/types.d.cts +0 -16
  133. package/dist/policy/types.d.cts.map +0 -1
  134. package/dist/policy/types.d.mts +0 -16
  135. package/dist/policy/types.d.mts.map +0 -1
  136. package/dist/prompts/core/keys.cjs +0 -165
  137. package/dist/prompts/core/keys.mjs +0 -167
  138. package/dist/prompts/core/keys.mjs.map +0 -1
  139. package/dist/prompts/core/runtime.cjs +0 -104
  140. package/dist/prompts/core/runtime.mjs +0 -106
  141. package/dist/prompts/core/runtime.mjs.map +0 -1
  142. package/dist/prompts/core/session.cjs +0 -98
  143. package/dist/prompts/core/session.mjs +0 -100
  144. package/dist/prompts/core/session.mjs.map +0 -1
  145. package/dist/prompts/core/types.d.cts +0 -21
  146. package/dist/prompts/core/types.d.cts.map +0 -1
  147. package/dist/prompts/core/types.d.mts +0 -21
  148. package/dist/prompts/core/types.d.mts.map +0 -1
  149. package/dist/prompts/types.d.cts +0 -52
  150. package/dist/prompts/types.d.cts.map +0 -1
  151. package/dist/prompts/types.d.mts +0 -52
  152. package/dist/prompts/types.d.mts.map +0 -1
  153. package/dist/pubsub/types.d.cts +0 -10
  154. package/dist/pubsub/types.d.cts.map +0 -1
  155. package/dist/pubsub/types.d.mts +0 -10
  156. package/dist/pubsub/types.d.mts.map +0 -1
  157. package/dist/queue/types.d.cts +0 -47
  158. package/dist/queue/types.d.cts.map +0 -1
  159. package/dist/queue/types.d.mts +0 -47
  160. package/dist/queue/types.d.mts.map +0 -1
@@ -4,9 +4,45 @@ const require_lib_errors_index = require("../errors/index.cjs");
4
4
  var PubSub = class {
5
5
  options;
6
6
  isSubscribed = false;
7
+ nextHandlerId = 0;
8
+ handlers = /* @__PURE__ */ new Map();
9
+ unsubscribeInFlight = null;
10
+ subscribeInFlight = null;
7
11
  constructor(options) {
8
12
  this.options = options;
9
13
  }
14
+ async onMessage(message, channel) {
15
+ const [parseError, parsed] = require_lib_errors_index.mightThrowSync(() => JSON.parse(message));
16
+ if (parseError) return;
17
+ if (!parsed) return;
18
+ const handlers = Array.from(this.handlers.values());
19
+ for (const handler of handlers) await require_lib_errors_index.mightThrow(Promise.resolve().then(() => handler(parsed, channel)));
20
+ }
21
+ async unsubscribeHandler(handlerId) {
22
+ const inFlightUnsubscribe = this.unsubscribeInFlight;
23
+ if (inFlightUnsubscribe) await inFlightUnsubscribe;
24
+ const handler = this.handlers.get(handlerId);
25
+ if (!handler) return require_lib_errors_index.err("UnsubscribeError", "Not subscribed");
26
+ this.handlers.delete(handlerId);
27
+ if (this.handlers.size > 0) return require_lib_errors_index.ok(true);
28
+ this.isSubscribed = false;
29
+ this.unsubscribeInFlight = require_lib_errors_index.mightThrow(this.options.subscriber.unsubscribe(this.options.channel));
30
+ const unsubscribeInFlight = this.unsubscribeInFlight;
31
+ if (!unsubscribeInFlight) {
32
+ this.handlers.set(handlerId, handler);
33
+ this.isSubscribed = true;
34
+ return require_lib_errors_index.err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
35
+ }
36
+ const [unsubscribeError] = await unsubscribeInFlight;
37
+ if (unsubscribeError) {
38
+ this.handlers.set(handlerId, handler);
39
+ this.isSubscribed = true;
40
+ this.unsubscribeInFlight = null;
41
+ return require_lib_errors_index.err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
42
+ }
43
+ this.unsubscribeInFlight = null;
44
+ return require_lib_errors_index.ok(true);
45
+ }
10
46
  async publish(message) {
11
47
  const [stringifyError, stringified] = require_lib_errors_index.mightThrowSync(() => JSON.stringify(message));
12
48
  if (stringifyError || !stringified) return require_lib_errors_index.err("SerializationError", "Unable to serialize message");
@@ -15,33 +51,66 @@ var PubSub = class {
15
51
  return require_lib_errors_index.ok(count);
16
52
  }
17
53
  async subscribe(handler) {
18
- if (this.isActive()) return require_lib_errors_index.err("SubscribeError", "Already subscribed");
19
- this.isSubscribed = true;
20
- const wrappedHandler = async (message, channel) => {
21
- const [parseError, parsed] = require_lib_errors_index.mightThrowSync(() => JSON.parse(message));
22
- if (parseError) return;
23
- if (!parsed) return;
24
- await require_lib_errors_index.mightThrow(Promise.resolve(handler(parsed, channel)));
25
- };
26
- const [subscribeError, count] = await require_lib_errors_index.mightThrow(this.options.subscriber.subscribe(this.options.channel, wrappedHandler));
54
+ const inFlightUnsubscribe = this.unsubscribeInFlight;
55
+ if (inFlightUnsubscribe) await inFlightUnsubscribe;
56
+ const handlerId = this.nextHandlerId;
57
+ this.nextHandlerId += 1;
58
+ this.handlers.set(handlerId, handler);
59
+ if (this.isActive()) return require_lib_errors_index.ok(() => this.unsubscribeHandler(handlerId));
60
+ const inFlightSubscribe = this.subscribeInFlight;
61
+ if (inFlightSubscribe) {
62
+ const [inFlightError] = await inFlightSubscribe;
63
+ if (inFlightError || !this.isSubscribed) {
64
+ this.handlers.delete(handlerId);
65
+ return require_lib_errors_index.err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
66
+ }
67
+ return require_lib_errors_index.ok(() => this.unsubscribeHandler(handlerId));
68
+ }
69
+ this.subscribeInFlight = require_lib_errors_index.mightThrow(this.options.subscriber.subscribe(this.options.channel, async (message, channel) => this.onMessage(message, channel)));
70
+ const subscribeInFlight = this.subscribeInFlight;
71
+ if (!subscribeInFlight) {
72
+ this.handlers.delete(handlerId);
73
+ return require_lib_errors_index.err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
74
+ }
75
+ const [subscribeError, count] = await subscribeInFlight;
76
+ this.subscribeInFlight = null;
27
77
  if (subscribeError) {
28
- this.isSubscribed = false;
78
+ this.handlers.delete(handlerId);
29
79
  return require_lib_errors_index.err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
30
80
  }
31
- return require_lib_errors_index.ok(count);
81
+ if (!count) {
82
+ this.handlers.delete(handlerId);
83
+ return require_lib_errors_index.err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
84
+ }
85
+ this.isSubscribed = true;
86
+ return require_lib_errors_index.ok(() => this.unsubscribeHandler(handlerId));
32
87
  }
33
88
  async unsubscribe() {
89
+ const inFlightUnsubscribe = this.unsubscribeInFlight;
90
+ if (inFlightUnsubscribe) await inFlightUnsubscribe;
34
91
  if (!this.isActive()) return require_lib_errors_index.err("UnsubscribeError", "Not subscribed");
92
+ const handlers = new Map(this.handlers);
93
+ this.handlers.clear();
35
94
  this.isSubscribed = false;
36
- const [unsubscribeError] = await require_lib_errors_index.mightThrow(this.options.subscriber.unsubscribe(this.options.channel));
95
+ this.unsubscribeInFlight = require_lib_errors_index.mightThrow(this.options.subscriber.unsubscribe(this.options.channel));
96
+ const unsubscribeInFlight = this.unsubscribeInFlight;
97
+ if (!unsubscribeInFlight) {
98
+ this.handlers = handlers;
99
+ this.isSubscribed = true;
100
+ return require_lib_errors_index.err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
101
+ }
102
+ const [unsubscribeError] = await unsubscribeInFlight;
37
103
  if (unsubscribeError) {
104
+ this.handlers = handlers;
38
105
  this.isSubscribed = true;
106
+ this.unsubscribeInFlight = null;
39
107
  return require_lib_errors_index.err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
40
108
  }
109
+ this.unsubscribeInFlight = null;
41
110
  return require_lib_errors_index.ok(true);
42
111
  }
43
112
  isActive() {
44
- return this.isSubscribed;
113
+ return this.handlers.size > 0 && this.isSubscribed;
45
114
  }
46
115
  };
47
116
  //#endregion
@@ -1,27 +1,41 @@
1
- import { MessageHandler, PubSubOptions } from "../../pubsub/types.cjs";
2
-
1
+ //#region src/lib/pubsub/types.d.ts
2
+ type PubSubOptions = {
3
+ subscriber: Bun.RedisClient;
4
+ publisher: Bun.RedisClient;
5
+ channel: string;
6
+ };
7
+ type MessageHandler<T> = (message: T, channel: string) => void | Promise<void>;
8
+ //#endregion
3
9
  //#region src/lib/pubsub/index.d.ts
4
10
  declare class PubSub<T extends Record<string, unknown>> {
5
11
  private options;
6
12
  private isSubscribed;
13
+ private nextHandlerId;
14
+ private handlers;
15
+ private unsubscribeInFlight;
16
+ private subscribeInFlight;
7
17
  constructor(options: PubSubOptions);
8
- publish(message: T): Promise<readonly [null, number | null] | readonly [{
18
+ private onMessage;
19
+ private unsubscribeHandler;
20
+ publish(message: T): Promise<readonly [{
9
21
  readonly type: "SerializationError";
10
22
  readonly message: string;
11
23
  }, null] | readonly [{
12
24
  readonly type: "PublishError";
13
25
  readonly message: string;
14
- }, null]>;
15
- subscribe(handler: MessageHandler<T>): Promise<readonly [null, number | null] | readonly [{
26
+ }, null] | readonly [null, number]>;
27
+ subscribe(handler: MessageHandler<T>): Promise<readonly [null, () => Promise<readonly [{
28
+ readonly type: "UnsubscribeError";
29
+ readonly message: string;
30
+ }, null] | readonly [null, boolean]>] | readonly [{
16
31
  readonly type: "SubscribeError";
17
32
  readonly message: string;
18
33
  }, null]>;
19
- unsubscribe(): Promise<readonly [null, boolean] | readonly [{
34
+ unsubscribe(): Promise<readonly [{
20
35
  readonly type: "UnsubscribeError";
21
36
  readonly message: string;
22
- }, null]>;
37
+ }, null] | readonly [null, boolean]>;
23
38
  isActive(): boolean;
24
39
  }
25
40
  //#endregion
26
- export { PubSub };
27
- //# sourceMappingURL=index.d.cts.map
41
+ export { PubSub };
@@ -1,27 +1,41 @@
1
- import { MessageHandler, PubSubOptions } from "../../pubsub/types.mjs";
2
-
1
+ //#region src/lib/pubsub/types.d.ts
2
+ type PubSubOptions = {
3
+ subscriber: Bun.RedisClient;
4
+ publisher: Bun.RedisClient;
5
+ channel: string;
6
+ };
7
+ type MessageHandler<T> = (message: T, channel: string) => void | Promise<void>;
8
+ //#endregion
3
9
  //#region src/lib/pubsub/index.d.ts
4
10
  declare class PubSub<T extends Record<string, unknown>> {
5
11
  private options;
6
12
  private isSubscribed;
13
+ private nextHandlerId;
14
+ private handlers;
15
+ private unsubscribeInFlight;
16
+ private subscribeInFlight;
7
17
  constructor(options: PubSubOptions);
8
- publish(message: T): Promise<readonly [null, number | null] | readonly [{
18
+ private onMessage;
19
+ private unsubscribeHandler;
20
+ publish(message: T): Promise<readonly [{
9
21
  readonly type: "SerializationError";
10
22
  readonly message: string;
11
23
  }, null] | readonly [{
12
24
  readonly type: "PublishError";
13
25
  readonly message: string;
14
- }, null]>;
15
- subscribe(handler: MessageHandler<T>): Promise<readonly [null, number | null] | readonly [{
26
+ }, null] | readonly [null, number]>;
27
+ subscribe(handler: MessageHandler<T>): Promise<readonly [null, () => Promise<readonly [{
28
+ readonly type: "UnsubscribeError";
29
+ readonly message: string;
30
+ }, null] | readonly [null, boolean]>] | readonly [{
16
31
  readonly type: "SubscribeError";
17
32
  readonly message: string;
18
33
  }, null]>;
19
- unsubscribe(): Promise<readonly [null, boolean] | readonly [{
34
+ unsubscribe(): Promise<readonly [{
20
35
  readonly type: "UnsubscribeError";
21
36
  readonly message: string;
22
- }, null]>;
37
+ }, null] | readonly [null, boolean]>;
23
38
  isActive(): boolean;
24
39
  }
25
40
  //#endregion
26
- export { PubSub };
27
- //# sourceMappingURL=index.d.mts.map
41
+ export { PubSub };
@@ -3,9 +3,45 @@ import { err, mightThrow, mightThrowSync, ok } from "../errors/index.mjs";
3
3
  var PubSub = class {
4
4
  options;
5
5
  isSubscribed = false;
6
+ nextHandlerId = 0;
7
+ handlers = /* @__PURE__ */ new Map();
8
+ unsubscribeInFlight = null;
9
+ subscribeInFlight = null;
6
10
  constructor(options) {
7
11
  this.options = options;
8
12
  }
13
+ async onMessage(message, channel) {
14
+ const [parseError, parsed] = mightThrowSync(() => JSON.parse(message));
15
+ if (parseError) return;
16
+ if (!parsed) return;
17
+ const handlers = Array.from(this.handlers.values());
18
+ for (const handler of handlers) await mightThrow(Promise.resolve().then(() => handler(parsed, channel)));
19
+ }
20
+ async unsubscribeHandler(handlerId) {
21
+ const inFlightUnsubscribe = this.unsubscribeInFlight;
22
+ if (inFlightUnsubscribe) await inFlightUnsubscribe;
23
+ const handler = this.handlers.get(handlerId);
24
+ if (!handler) return err("UnsubscribeError", "Not subscribed");
25
+ this.handlers.delete(handlerId);
26
+ if (this.handlers.size > 0) return ok(true);
27
+ this.isSubscribed = false;
28
+ this.unsubscribeInFlight = mightThrow(this.options.subscriber.unsubscribe(this.options.channel));
29
+ const unsubscribeInFlight = this.unsubscribeInFlight;
30
+ if (!unsubscribeInFlight) {
31
+ this.handlers.set(handlerId, handler);
32
+ this.isSubscribed = true;
33
+ return err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
34
+ }
35
+ const [unsubscribeError] = await unsubscribeInFlight;
36
+ if (unsubscribeError) {
37
+ this.handlers.set(handlerId, handler);
38
+ this.isSubscribed = true;
39
+ this.unsubscribeInFlight = null;
40
+ return err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
41
+ }
42
+ this.unsubscribeInFlight = null;
43
+ return ok(true);
44
+ }
9
45
  async publish(message) {
10
46
  const [stringifyError, stringified] = mightThrowSync(() => JSON.stringify(message));
11
47
  if (stringifyError || !stringified) return err("SerializationError", "Unable to serialize message");
@@ -14,36 +50,67 @@ var PubSub = class {
14
50
  return ok(count);
15
51
  }
16
52
  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));
53
+ const inFlightUnsubscribe = this.unsubscribeInFlight;
54
+ if (inFlightUnsubscribe) await inFlightUnsubscribe;
55
+ const handlerId = this.nextHandlerId;
56
+ this.nextHandlerId += 1;
57
+ this.handlers.set(handlerId, handler);
58
+ if (this.isActive()) return ok(() => this.unsubscribeHandler(handlerId));
59
+ const inFlightSubscribe = this.subscribeInFlight;
60
+ if (inFlightSubscribe) {
61
+ const [inFlightError] = await inFlightSubscribe;
62
+ if (inFlightError || !this.isSubscribed) {
63
+ this.handlers.delete(handlerId);
64
+ return err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
65
+ }
66
+ return ok(() => this.unsubscribeHandler(handlerId));
67
+ }
68
+ this.subscribeInFlight = mightThrow(this.options.subscriber.subscribe(this.options.channel, async (message, channel) => this.onMessage(message, channel)));
69
+ const subscribeInFlight = this.subscribeInFlight;
70
+ if (!subscribeInFlight) {
71
+ this.handlers.delete(handlerId);
72
+ return err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
73
+ }
74
+ const [subscribeError, count] = await subscribeInFlight;
75
+ this.subscribeInFlight = null;
26
76
  if (subscribeError) {
27
- this.isSubscribed = false;
77
+ this.handlers.delete(handlerId);
28
78
  return err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
29
79
  }
30
- return ok(count);
80
+ if (!count) {
81
+ this.handlers.delete(handlerId);
82
+ return err("SubscribeError", `Unable to subscribe to ${this.options.channel}`);
83
+ }
84
+ this.isSubscribed = true;
85
+ return ok(() => this.unsubscribeHandler(handlerId));
31
86
  }
32
87
  async unsubscribe() {
88
+ const inFlightUnsubscribe = this.unsubscribeInFlight;
89
+ if (inFlightUnsubscribe) await inFlightUnsubscribe;
33
90
  if (!this.isActive()) return err("UnsubscribeError", "Not subscribed");
91
+ const handlers = new Map(this.handlers);
92
+ this.handlers.clear();
34
93
  this.isSubscribed = false;
35
- const [unsubscribeError] = await mightThrow(this.options.subscriber.unsubscribe(this.options.channel));
94
+ this.unsubscribeInFlight = mightThrow(this.options.subscriber.unsubscribe(this.options.channel));
95
+ const unsubscribeInFlight = this.unsubscribeInFlight;
96
+ if (!unsubscribeInFlight) {
97
+ this.handlers = handlers;
98
+ this.isSubscribed = true;
99
+ return err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
100
+ }
101
+ const [unsubscribeError] = await unsubscribeInFlight;
36
102
  if (unsubscribeError) {
103
+ this.handlers = handlers;
37
104
  this.isSubscribed = true;
105
+ this.unsubscribeInFlight = null;
38
106
  return err("UnsubscribeError", `Unable to unsubscribe from ${this.options.channel}`);
39
107
  }
108
+ this.unsubscribeInFlight = null;
40
109
  return ok(true);
41
110
  }
42
111
  isActive() {
43
- return this.isSubscribed;
112
+ return this.handlers.size > 0 && this.isSubscribed;
44
113
  }
45
114
  };
46
115
  //#endregion
47
116
  export { PubSub };
48
-
49
- //# sourceMappingURL=index.mjs.map
@@ -1,5 +1,48 @@
1
- import { QueueOptions } from "../../queue/types.cjs";
2
-
1
+ //#region src/lib/queue/types.d.ts
2
+ type Job<T> = {
3
+ id: string;
4
+ data: T;
5
+ attempts: number;
6
+ maxRetries: number;
7
+ createdAt: number;
8
+ };
9
+ type RetryContext<T> = {
10
+ job: Job<T>;
11
+ error: string;
12
+ nextRetryDelayMs: number;
13
+ retriesRemaining: number;
14
+ backoffMultiplier: number;
15
+ };
16
+ type ErrorContext<T> = {
17
+ job: Job<T>;
18
+ lastError: string;
19
+ totalDurationMs: number;
20
+ totalAttempts: number;
21
+ errorHistory: Array<{
22
+ attempt: number;
23
+ error: string;
24
+ timestamp: number;
25
+ }>;
26
+ };
27
+ type ParseErrorContext = {
28
+ rawJobData: string;
29
+ parseError: string;
30
+ timestamp: number;
31
+ };
32
+ type QueueOptions<T> = {
33
+ name: string;
34
+ redis: Bun.RedisClient;
35
+ handler: (data: T, signal?: AbortSignal) => void | Promise<void>;
36
+ onSuccess?: (job: Job<T>) => void | Promise<void>;
37
+ onRetry?: (context: RetryContext<T>) => void | Promise<void>;
38
+ onError?: (context: ErrorContext<T>) => void | Promise<void>;
39
+ onParseError?: (context: ParseErrorContext) => void | Promise<void>;
40
+ retries?: number;
41
+ timeout?: number;
42
+ concurrency?: number;
43
+ pollInterval?: number;
44
+ };
45
+ //#endregion
3
46
  //#region src/lib/queue/index.d.ts
4
47
  declare class Queue<T> {
5
48
  private options;
@@ -28,5 +71,4 @@ declare class Queue<T> {
28
71
  private retryJob;
29
72
  }
30
73
  //#endregion
31
- export { Queue };
32
- //# sourceMappingURL=index.d.cts.map
74
+ export { Queue };
@@ -1,5 +1,48 @@
1
- import { QueueOptions } from "../../queue/types.mjs";
2
-
1
+ //#region src/lib/queue/types.d.ts
2
+ type Job<T> = {
3
+ id: string;
4
+ data: T;
5
+ attempts: number;
6
+ maxRetries: number;
7
+ createdAt: number;
8
+ };
9
+ type RetryContext<T> = {
10
+ job: Job<T>;
11
+ error: string;
12
+ nextRetryDelayMs: number;
13
+ retriesRemaining: number;
14
+ backoffMultiplier: number;
15
+ };
16
+ type ErrorContext<T> = {
17
+ job: Job<T>;
18
+ lastError: string;
19
+ totalDurationMs: number;
20
+ totalAttempts: number;
21
+ errorHistory: Array<{
22
+ attempt: number;
23
+ error: string;
24
+ timestamp: number;
25
+ }>;
26
+ };
27
+ type ParseErrorContext = {
28
+ rawJobData: string;
29
+ parseError: string;
30
+ timestamp: number;
31
+ };
32
+ type QueueOptions<T> = {
33
+ name: string;
34
+ redis: Bun.RedisClient;
35
+ handler: (data: T, signal?: AbortSignal) => void | Promise<void>;
36
+ onSuccess?: (job: Job<T>) => void | Promise<void>;
37
+ onRetry?: (context: RetryContext<T>) => void | Promise<void>;
38
+ onError?: (context: ErrorContext<T>) => void | Promise<void>;
39
+ onParseError?: (context: ParseErrorContext) => void | Promise<void>;
40
+ retries?: number;
41
+ timeout?: number;
42
+ concurrency?: number;
43
+ pollInterval?: number;
44
+ };
45
+ //#endregion
3
46
  //#region src/lib/queue/index.d.ts
4
47
  declare class Queue<T> {
5
48
  private options;
@@ -28,5 +71,4 @@ declare class Queue<T> {
28
71
  private retryJob;
29
72
  }
30
73
  //#endregion
31
- export { Queue };
32
- //# sourceMappingURL=index.d.mts.map
74
+ export { Queue };
@@ -179,5 +179,3 @@ var Queue = class {
179
179
  };
180
180
  //#endregion
181
181
  export { Queue };
182
-
183
- //# sourceMappingURL=index.mjs.map