@grupodiariodaregiao/bunstone 0.3.12 → 0.4.1

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/index.js CHANGED
@@ -116733,6 +116733,20 @@ class RabbitMQConnection {
116733
116733
  RabbitMQConnection.consumerChannels.set(queue2, channel);
116734
116734
  return channel;
116735
116735
  }
116736
+ static async createRoutingKeyConsumerChannel(exchange, routingKey) {
116737
+ const connection2 = await RabbitMQConnection.getConnection();
116738
+ const channel = await connection2.createChannel();
116739
+ const prefetch = RabbitMQConnection.options?.prefetch ?? 10;
116740
+ await channel.prefetch(prefetch);
116741
+ const { queue: queueName } = await channel.assertQueue("", {
116742
+ exclusive: true,
116743
+ autoDelete: true,
116744
+ durable: false
116745
+ });
116746
+ await channel.bindQueue(queueName, exchange, routingKey);
116747
+ logger2.log(`Routing-key consumer queue "${queueName}" bound to exchange "${exchange}" with key "${routingKey}"`);
116748
+ return { channel, queueName };
116749
+ }
116736
116750
  static async initialise() {
116737
116751
  await RabbitMQConnection.getConnection();
116738
116752
  }
@@ -117576,42 +117590,114 @@ if (document.readyState === 'loading') {
117576
117590
  AppStartup.logger.error(`RabbitMQ initialisation failed: ${err.message}`);
117577
117591
  return;
117578
117592
  }
117593
+ const queueMap = new Map;
117579
117594
  for (const [providerClass, descriptors] of providersRabbitMQ.entries()) {
117580
117595
  const instance = injectables?.get(providerClass) ?? new providerClass;
117581
117596
  for (const descriptor of descriptors) {
117582
- const { queue: queue2, noAck = false } = descriptor.options;
117583
- AppStartup.logger.log(`Registering RabbitMQ consumer for queue: "${queue2}" \u2192 ${providerClass.name}.${descriptor.methodName}()`);
117584
- try {
117585
- const channel = await RabbitMQConnection.getConsumerChannel(queue2);
117586
- await channel.consume(queue2, async (raw) => {
117587
- if (!raw)
117588
- return;
117589
- const data = (() => {
117597
+ const {
117598
+ queue: queue2,
117599
+ exchange,
117600
+ routingKey,
117601
+ noAck = false
117602
+ } = descriptor.options;
117603
+ if (exchange && routingKey) {
117604
+ AppStartup.logger.log(`Registering RabbitMQ consumer for exchange: "${exchange}" routingKey: "${routingKey}" \u2192 ${providerClass.name}.${descriptor.methodName}()`);
117605
+ try {
117606
+ const { channel, queueName } = await RabbitMQConnection.createRoutingKeyConsumerChannel(exchange, routingKey);
117607
+ await channel.consume(queueName, async (raw) => {
117608
+ if (!raw)
117609
+ return;
117610
+ const data = (() => {
117611
+ try {
117612
+ return JSON.parse(raw.content.toString());
117613
+ } catch {
117614
+ return raw.content.toString();
117615
+ }
117616
+ })();
117617
+ const msg = {
117618
+ data,
117619
+ raw,
117620
+ ack: () => channel.ack(raw),
117621
+ nack: (requeue = true) => channel.nack(raw, false, requeue),
117622
+ reject: () => channel.reject(raw, false)
117623
+ };
117590
117624
  try {
117591
- return JSON.parse(raw.content.toString());
117592
- } catch {
117593
- return raw.content.toString();
117625
+ await instance[descriptor.methodName](msg);
117626
+ } catch (err) {
117627
+ AppStartup.logger.error(`Unhandled error in RabbitMQ handler ${providerClass.name}.${descriptor.methodName}() on exchange "${exchange}" routingKey "${routingKey}": ${err.message}`);
117628
+ if (!noAck) {
117629
+ channel.nack(raw, false, true);
117630
+ }
117594
117631
  }
117595
- })();
117596
- const msg = {
117597
- data,
117598
- raw,
117599
- ack: () => channel.ack(raw),
117600
- nack: (requeue = true) => channel.nack(raw, false, requeue),
117601
- reject: () => channel.reject(raw, false)
117602
- };
117632
+ }, { noAck });
117633
+ } catch (err) {
117634
+ AppStartup.logger.error(`Failed to register consumer for exchange "${exchange}" routingKey "${routingKey}": ${err.message}`);
117635
+ }
117636
+ continue;
117637
+ }
117638
+ if (!queue2) {
117639
+ AppStartup.logger.warn(`@RabbitSubscribe on ${providerClass.name}.${descriptor.methodName}() has neither 'queue' nor 'exchange'+'routingKey' \u2013 skipping.`);
117640
+ continue;
117641
+ }
117642
+ if (!queueMap.has(queue2))
117643
+ queueMap.set(queue2, []);
117644
+ const queueHandlers = queueMap.get(queue2);
117645
+ queueHandlers.push({
117646
+ instance,
117647
+ descriptor,
117648
+ noAck,
117649
+ providerName: providerClass.name
117650
+ });
117651
+ }
117652
+ }
117653
+ for (const [queue2, handlers] of queueMap.entries()) {
117654
+ const noAck = handlers.every((h3) => h3.noAck);
117655
+ const handlerList = handlers.map((h3) => `${h3.providerName}.${h3.descriptor.methodName}()`).join(", ");
117656
+ AppStartup.logger.log(`Registering RabbitMQ consumer for queue: "${queue2}" \u2192 [${handlerList}]`);
117657
+ try {
117658
+ const channel = await RabbitMQConnection.getConsumerChannel(queue2);
117659
+ await channel.consume(queue2, async (raw) => {
117660
+ if (!raw)
117661
+ return;
117662
+ const data = (() => {
117663
+ try {
117664
+ return JSON.parse(raw.content.toString());
117665
+ } catch {
117666
+ return raw.content.toString();
117667
+ }
117668
+ })();
117669
+ let settled = false;
117670
+ const settle = (fn3) => {
117671
+ if (!settled) {
117672
+ settled = true;
117673
+ fn3();
117674
+ }
117675
+ };
117676
+ const msg = {
117677
+ data,
117678
+ raw,
117679
+ ack: () => settle(() => channel.ack(raw)),
117680
+ nack: (requeue = true) => settle(() => channel.nack(raw, false, requeue)),
117681
+ reject: () => settle(() => channel.reject(raw, false))
117682
+ };
117683
+ for (const {
117684
+ instance,
117685
+ descriptor,
117686
+ noAck: handlerNoAck,
117687
+ providerName
117688
+ } of handlers) {
117603
117689
  try {
117604
117690
  await instance[descriptor.methodName](msg);
117605
117691
  } catch (err) {
117606
- AppStartup.logger.error(`Unhandled error in RabbitMQ handler ${providerClass.name}.${descriptor.methodName}() on queue "${queue2}": ${err.message}`);
117607
- if (!noAck) {
117608
- channel.nack(raw, false, true);
117692
+ AppStartup.logger.error(`Unhandled error in RabbitMQ handler ${providerName}.${descriptor.methodName}() on queue "${queue2}": ${err.message}`);
117693
+ if (!handlerNoAck && !settled) {
117694
+ settle(() => channel.nack(raw, false, true));
117609
117695
  }
117610
117696
  }
117611
- }, { noAck });
117612
- } catch (err) {
117613
- AppStartup.logger.error(`Failed to register consumer for queue "${queue2}": ${err.message}`);
117614
- }
117697
+ }
117698
+ }, { noAck });
117699
+ } catch (err) {
117700
+ AppStartup.logger.error(`Failed to register consumer for queue "${queue2}": ${err.message}`);
117615
117701
  }
117616
117702
  }
117617
117703
  })();
@@ -80,6 +80,14 @@ export declare class AppStartup {
80
80
  /**
81
81
  * Sets up RabbitMQ consumers for every provider that has `@RabbitSubscribe`
82
82
  * methods registered in the given module.
83
+ *
84
+ * Queue mode (fan-out): all handlers subscribed to the same named queue share a
85
+ * single AMQP consumer. Every message is delivered to ALL handlers in declaration
86
+ * order. A "settle guard" ensures ack/nack/reject is called only once per message
87
+ * regardless of how many handlers invoke it.
88
+ *
89
+ * Routing-key mode: each handler gets its own exclusive auto-delete queue bound
90
+ * to the exchange, so the broker itself handles fan-out.
83
91
  */
84
92
  private static registerRabbitMQConsumers;
85
93
  private static registerCqrsHandlers;
@@ -120,13 +120,51 @@ export interface RabbitPublishOptions {
120
120
  }
121
121
  /**
122
122
  * Options for the `@RabbitSubscribe` method decorator.
123
+ *
124
+ * Two usage modes:
125
+ *
126
+ * 1. **Direct queue** – set `queue` to consume from a named queue.
127
+ * 2. **Routing key** – set `exchange` + `routingKey` to subscribe to a topic/direct
128
+ * exchange with a specific routing key pattern. The lib creates an exclusive
129
+ * auto-delete queue per handler, so **every** handler bound to the same routing
130
+ * key receives its own copy of the message (fan-out per key).
131
+ *
132
+ * @example Queue mode
133
+ * ```typescript
134
+ * @RabbitSubscribe({ queue: 'orders.created' })
135
+ * async handle(msg: RabbitMessage<Order>) { msg.ack(); }
136
+ * ```
137
+ *
138
+ * @example Routing key mode
139
+ * ```typescript
140
+ * @RabbitSubscribe({ exchange: 'events', routingKey: 'article.published' })
141
+ * async onPublished(msg: RabbitMessage<Article>) { msg.ack(); }
142
+ * ```
123
143
  */
124
144
  export interface RabbitSubscribeOptions {
125
145
  /**
126
146
  * Queue to consume messages from.
127
147
  * The queue must be declared either via `RabbitMQModule.register({ queues: [...] })` or by the broker.
148
+ * Mutually exclusive with `exchange` + `routingKey`.
128
149
  */
129
- queue: string;
150
+ queue?: string;
151
+ /**
152
+ * Exchange name to bind to. Must be used together with `routingKey`.
153
+ * The lib automatically creates an exclusive auto-delete queue for each handler
154
+ * and binds it to this exchange, so all handlers for the same routing key
155
+ * receive a copy of every published message.
156
+ */
157
+ exchange?: string;
158
+ /**
159
+ * Routing key to subscribe to. Supports wildcards for topic exchanges:
160
+ * - `*` matches exactly one word
161
+ * - `#` matches zero or more words
162
+ *
163
+ * Examples: `article.published`, `article.*`, `article.#`
164
+ *
165
+ * Must be used together with `exchange`.
166
+ */
167
+ routingKey?: string;
130
168
  /**
131
169
  * When `true`, messages are automatically acknowledged as soon as they are delivered.
132
170
  * When `false` (default), you must call `msg.ack()` / `msg.nack()` manually.
@@ -27,6 +27,20 @@ export declare class RabbitMQConnection {
27
27
  * Each queue gets its own channel so that prefetch applies per-queue.
28
28
  */
29
29
  static getConsumerChannel(queue: string): Promise<Channel>;
30
+ /**
31
+ * Creates a **new** channel with an exclusive, auto-delete server-named queue
32
+ * bound to `exchange` with `routingKey`.
33
+ *
34
+ * Because each call creates an independent queue, every handler that subscribes
35
+ * to the same exchange + routing key receives its own copy of the message
36
+ * (fan-out behaviour per routing key).
37
+ *
38
+ * The channel and queue are **not** cached – each call returns a fresh pair.
39
+ */
40
+ static createRoutingKeyConsumerChannel(exchange: string, routingKey: string): Promise<{
41
+ channel: Channel;
42
+ queueName: string;
43
+ }>;
30
44
  /**
31
45
  * Initialises the connection, asserts all configured exchanges and queues,
32
46
  * then resolves. Safe to call multiple times – returns the same promise.
@@ -857,6 +857,14 @@ if (document.readyState === 'loading') {
857
857
  /**
858
858
  * Sets up RabbitMQ consumers for every provider that has `@RabbitSubscribe`
859
859
  * methods registered in the given module.
860
+ *
861
+ * Queue mode (fan-out): all handlers subscribed to the same named queue share a
862
+ * single AMQP consumer. Every message is delivered to ALL handlers in declaration
863
+ * order. A "settle guard" ensures ack/nack/reject is called only once per message
864
+ * regardless of how many handlers invoke it.
865
+ *
866
+ * Routing-key mode: each handler gets its own exclusive auto-delete queue bound
867
+ * to the exchange, so the broker itself handles fan-out.
860
868
  */
861
869
  private static registerRabbitMQConsumers(module: any): void {
862
870
  const providersRabbitMQ: Map<any, RabbitMQMethodDescriptor[]> | undefined =
@@ -871,6 +879,13 @@ if (document.readyState === 'loading') {
871
879
  module,
872
880
  );
873
881
 
882
+ type QueueHandler = {
883
+ instance: any;
884
+ descriptor: RabbitMQMethodDescriptor;
885
+ noAck: boolean;
886
+ providerName: string;
887
+ };
888
+
874
889
  // Fire-and-forget – connect asynchronously so startup is never blocked
875
890
  (async () => {
876
891
  try {
@@ -882,59 +897,170 @@ if (document.readyState === 'loading') {
882
897
  return;
883
898
  }
884
899
 
900
+ // ── Step 1: separate routing-key handlers from named-queue handlers ──
901
+ // Named-queue handlers are grouped by queue name so that a single AMQP
902
+ // consumer is created per queue and every message is fanned-out to all
903
+ // registered handlers in-process.
904
+ const queueMap = new Map<string, QueueHandler[]>();
905
+
885
906
  for (const [providerClass, descriptors] of providersRabbitMQ.entries()) {
886
907
  const instance = injectables?.get(providerClass) ?? new providerClass();
887
908
 
888
909
  for (const descriptor of descriptors) {
889
- const { queue, noAck = false } = descriptor.options;
910
+ const {
911
+ queue,
912
+ exchange,
913
+ routingKey,
914
+ noAck = false,
915
+ } = descriptor.options;
916
+
917
+ // ── Routing-key mode: exchange + routingKey ─────────────────────
918
+ if (exchange && routingKey) {
919
+ AppStartup.logger.log(
920
+ `Registering RabbitMQ consumer for exchange: "${exchange}" routingKey: "${routingKey}" → ${providerClass.name}.${descriptor.methodName}()`,
921
+ );
890
922
 
891
- AppStartup.logger.log(
892
- `Registering RabbitMQ consumer for queue: "${queue}" → ${providerClass.name}.${descriptor.methodName}()`,
893
- );
923
+ try {
924
+ const { channel, queueName } =
925
+ await RabbitMQConnection.createRoutingKeyConsumerChannel(
926
+ exchange,
927
+ routingKey,
928
+ );
894
929
 
895
- try {
896
- const channel = await RabbitMQConnection.getConsumerChannel(queue);
930
+ await channel.consume(
931
+ queueName,
932
+ async (raw) => {
933
+ if (!raw) return;
897
934
 
898
- await channel.consume(
899
- queue,
900
- async (raw) => {
901
- if (!raw) return; // consumer cancelled
935
+ const data = (() => {
936
+ try {
937
+ return JSON.parse(raw.content.toString());
938
+ } catch {
939
+ return raw.content.toString();
940
+ }
941
+ })();
942
+
943
+ const msg: RabbitMessage = {
944
+ data,
945
+ raw,
946
+ ack: () => channel.ack(raw),
947
+ nack: (requeue = true) => channel.nack(raw, false, requeue),
948
+ reject: () => channel.reject(raw, false),
949
+ };
902
950
 
903
- const data = (() => {
904
951
  try {
905
- return JSON.parse(raw.content.toString());
906
- } catch {
907
- return raw.content.toString();
952
+ await instance[descriptor.methodName](msg);
953
+ } catch (err: any) {
954
+ AppStartup.logger.error(
955
+ `Unhandled error in RabbitMQ handler ${providerClass.name}.${descriptor.methodName}() on exchange "${exchange}" routingKey "${routingKey}": ${err.message}`,
956
+ );
957
+ if (!noAck) {
958
+ channel.nack(raw, false, true);
959
+ }
908
960
  }
909
- })();
961
+ },
962
+ { noAck },
963
+ );
964
+ } catch (err: any) {
965
+ AppStartup.logger.error(
966
+ `Failed to register consumer for exchange "${exchange}" routingKey "${routingKey}": ${err.message}`,
967
+ );
968
+ }
969
+
970
+ continue;
971
+ }
972
+
973
+ // ── Queue mode: collect and group by queue name ─────────────────
974
+ if (!queue) {
975
+ AppStartup.logger.warn(
976
+ `@RabbitSubscribe on ${providerClass.name}.${descriptor.methodName}() has neither 'queue' nor 'exchange'+'routingKey' – skipping.`,
977
+ );
978
+ continue;
979
+ }
980
+
981
+ if (!queueMap.has(queue)) queueMap.set(queue, []);
982
+ const queueHandlers = queueMap.get(queue) as QueueHandler[];
983
+ queueHandlers.push({
984
+ instance,
985
+ descriptor,
986
+ noAck,
987
+ providerName: providerClass.name,
988
+ });
989
+ }
990
+ }
910
991
 
911
- const msg: RabbitMessage = {
912
- data,
913
- raw,
914
- ack: () => channel.ack(raw),
915
- nack: (requeue = true) => channel.nack(raw, false, requeue),
916
- reject: () => channel.reject(raw, false),
917
- };
992
+ // ── Step 2: one AMQP consumer per unique queue, fan-out in-process ──
993
+ for (const [queue, handlers] of queueMap.entries()) {
994
+ // Use noAck only when every handler opts in; otherwise manual ack.
995
+ const noAck = handlers.every((h) => h.noAck);
918
996
 
997
+ const handlerList = handlers
998
+ .map((h) => `${h.providerName}.${h.descriptor.methodName}()`)
999
+ .join(", ");
1000
+
1001
+ AppStartup.logger.log(
1002
+ `Registering RabbitMQ consumer for queue: "${queue}" → [${handlerList}]`,
1003
+ );
1004
+
1005
+ try {
1006
+ const channel = await RabbitMQConnection.getConsumerChannel(queue);
1007
+
1008
+ await channel.consume(
1009
+ queue,
1010
+ async (raw) => {
1011
+ if (!raw) return; // consumer cancelled
1012
+
1013
+ const data = (() => {
1014
+ try {
1015
+ return JSON.parse(raw.content.toString());
1016
+ } catch {
1017
+ return raw.content.toString();
1018
+ }
1019
+ })();
1020
+
1021
+ // Settle guard: ack/nack/reject may only be called once per
1022
+ // delivery tag regardless of how many handlers invoke it.
1023
+ let settled = false;
1024
+ const settle = (fn: () => void) => {
1025
+ if (!settled) {
1026
+ settled = true;
1027
+ fn();
1028
+ }
1029
+ };
1030
+
1031
+ const msg: RabbitMessage = {
1032
+ data,
1033
+ raw,
1034
+ ack: () => settle(() => channel.ack(raw)),
1035
+ nack: (requeue = true) =>
1036
+ settle(() => channel.nack(raw, false, requeue)),
1037
+ reject: () => settle(() => channel.reject(raw, false)),
1038
+ };
1039
+
1040
+ for (const {
1041
+ instance,
1042
+ descriptor,
1043
+ noAck: handlerNoAck,
1044
+ providerName,
1045
+ } of handlers) {
919
1046
  try {
920
1047
  await instance[descriptor.methodName](msg);
921
1048
  } catch (err: any) {
922
1049
  AppStartup.logger.error(
923
- `Unhandled error in RabbitMQ handler ${providerClass.name}.${descriptor.methodName}() on queue "${queue}": ${err.message}`,
1050
+ `Unhandled error in RabbitMQ handler ${providerName}.${descriptor.methodName}() on queue "${queue}": ${err.message}`,
924
1051
  );
925
- if (!noAck) {
926
- // Nack and requeue by default so the message isn't lost
927
- channel.nack(raw, false, true);
1052
+ if (!handlerNoAck && !settled) {
1053
+ settle(() => channel.nack(raw, false, true));
928
1054
  }
929
1055
  }
930
- },
931
- { noAck },
932
- );
933
- } catch (err: any) {
934
- AppStartup.logger.error(
935
- `Failed to register consumer for queue "${queue}": ${err.message}`,
936
- );
937
- }
1056
+ }
1057
+ },
1058
+ { noAck },
1059
+ );
1060
+ } catch (err: any) {
1061
+ AppStartup.logger.error(
1062
+ `Failed to register consumer for queue "${queue}": ${err.message}`,
1063
+ );
938
1064
  }
939
1065
  }
940
1066
  })();
@@ -134,13 +134,51 @@ export interface RabbitPublishOptions {
134
134
 
135
135
  /**
136
136
  * Options for the `@RabbitSubscribe` method decorator.
137
+ *
138
+ * Two usage modes:
139
+ *
140
+ * 1. **Direct queue** – set `queue` to consume from a named queue.
141
+ * 2. **Routing key** – set `exchange` + `routingKey` to subscribe to a topic/direct
142
+ * exchange with a specific routing key pattern. The lib creates an exclusive
143
+ * auto-delete queue per handler, so **every** handler bound to the same routing
144
+ * key receives its own copy of the message (fan-out per key).
145
+ *
146
+ * @example Queue mode
147
+ * ```typescript
148
+ * @RabbitSubscribe({ queue: 'orders.created' })
149
+ * async handle(msg: RabbitMessage<Order>) { msg.ack(); }
150
+ * ```
151
+ *
152
+ * @example Routing key mode
153
+ * ```typescript
154
+ * @RabbitSubscribe({ exchange: 'events', routingKey: 'article.published' })
155
+ * async onPublished(msg: RabbitMessage<Article>) { msg.ack(); }
156
+ * ```
137
157
  */
138
158
  export interface RabbitSubscribeOptions {
139
159
  /**
140
160
  * Queue to consume messages from.
141
161
  * The queue must be declared either via `RabbitMQModule.register({ queues: [...] })` or by the broker.
162
+ * Mutually exclusive with `exchange` + `routingKey`.
142
163
  */
143
- queue: string;
164
+ queue?: string;
165
+ /**
166
+ * Exchange name to bind to. Must be used together with `routingKey`.
167
+ * The lib automatically creates an exclusive auto-delete queue for each handler
168
+ * and binds it to this exchange, so all handlers for the same routing key
169
+ * receive a copy of every published message.
170
+ */
171
+ exchange?: string;
172
+ /**
173
+ * Routing key to subscribe to. Supports wildcards for topic exchanges:
174
+ * - `*` matches exactly one word
175
+ * - `#` matches zero or more words
176
+ *
177
+ * Examples: `article.published`, `article.*`, `article.#`
178
+ *
179
+ * Must be used together with `exchange`.
180
+ */
181
+ routingKey?: string;
144
182
  /**
145
183
  * When `true`, messages are automatically acknowledged as soon as they are delivered.
146
184
  * When `false` (default), you must call `msg.ack()` / `msg.nack()` manually.
@@ -70,6 +70,42 @@ export class RabbitMQConnection {
70
70
  return channel;
71
71
  }
72
72
 
73
+ /**
74
+ * Creates a **new** channel with an exclusive, auto-delete server-named queue
75
+ * bound to `exchange` with `routingKey`.
76
+ *
77
+ * Because each call creates an independent queue, every handler that subscribes
78
+ * to the same exchange + routing key receives its own copy of the message
79
+ * (fan-out behaviour per routing key).
80
+ *
81
+ * The channel and queue are **not** cached – each call returns a fresh pair.
82
+ */
83
+ static async createRoutingKeyConsumerChannel(
84
+ exchange: string,
85
+ routingKey: string,
86
+ ): Promise<{ channel: Channel; queueName: string }> {
87
+ const connection = await RabbitMQConnection.getConnection();
88
+ const channel = await connection.createChannel();
89
+
90
+ const prefetch = RabbitMQConnection.options?.prefetch ?? 10;
91
+ await channel.prefetch(prefetch);
92
+
93
+ // Server-generated name, exclusive so only this consumer uses it,
94
+ // autoDelete so it disappears when the consumer disconnects.
95
+ const { queue: queueName } = await channel.assertQueue("", {
96
+ exclusive: true,
97
+ autoDelete: true,
98
+ durable: false,
99
+ });
100
+
101
+ await channel.bindQueue(queueName, exchange, routingKey);
102
+ logger.log(
103
+ `Routing-key consumer queue "${queueName}" bound to exchange "${exchange}" with key "${routingKey}"`,
104
+ );
105
+
106
+ return { channel, queueName };
107
+ }
108
+
73
109
  /**
74
110
  * Initialises the connection, asserts all configured exchanges and queues,
75
111
  * then resolves. Safe to call multiple times – returns the same promise.
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "types": "./dist/*.d.ts"
14
14
  }
15
15
  },
16
- "version": "0.3.12",
16
+ "version": "0.4.1",
17
17
  "homepage": "https://bunstone.diario.one/",
18
18
  "repository": {
19
19
  "url": "https://github.com/diariodaregiao/bunstone.git",