@mastra/google-cloud-pubsub 1.0.2-alpha.0 → 1.0.3-alpha.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @mastra/inngest
2
2
 
3
+ ## 1.0.3-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Add `nack` support and `deliveryAttempt` tracking on the subscriber callback, and enable exactly-once delivery on grouped subscriptions. ([#15307](https://github.com/mastra-ai/mastra/pull/15307))
8
+
9
+ - Updated dependencies [[`d63ffdb`](https://github.com/mastra-ai/mastra/commit/d63ffdbb2c11e76fe5ea45faab44bc15460f010c)]:
10
+ - @mastra/core@1.25.1-alpha.0
11
+
12
+ ## 1.0.2
13
+
14
+ ### Patch Changes
15
+
16
+ - dependencies updates: ([#13013](https://github.com/mastra-ai/mastra/pull/13013))
17
+ - Updated dependency [`@inngest/realtime@^0.4.6` ↗︎](https://www.npmjs.com/package/@inngest/realtime/v/0.4.6) (from `^0.4.5`, in `dependencies`)
18
+
19
+ - dependencies updates: ([#13101](https://github.com/mastra-ai/mastra/pull/13101))
20
+ - Updated dependency [`@google-cloud/pubsub@^5.2.3` ↗︎](https://www.npmjs.com/package/@google-cloud/pubsub/v/5.2.3) (from `^5.2.2`, in `dependencies`)
21
+ - Updated dependencies [[`252580a`](https://github.com/mastra-ai/mastra/commit/252580a71feb0e46d0ccab04a70a79ff6a2ee0ab), [`f8e819f`](https://github.com/mastra-ai/mastra/commit/f8e819fabdfdc43d2da546a3ad81ba23685f603d), [`5c75261`](https://github.com/mastra-ai/mastra/commit/5c7526120d936757d4ffb7b82232e1641ebd45cb), [`e27d832`](https://github.com/mastra-ai/mastra/commit/e27d83281b5e166fd63a13969689e928d8605944), [`e37ef84`](https://github.com/mastra-ai/mastra/commit/e37ef8404043c94ca0c8e35ecdedb093b8087878), [`6fdd3d4`](https://github.com/mastra-ai/mastra/commit/6fdd3d451a07a8e7e216c62ac364f8dd8e36c2af), [`10cf521`](https://github.com/mastra-ai/mastra/commit/10cf52183344743a0d7babe24cd24fd78870c354), [`efdb682`](https://github.com/mastra-ai/mastra/commit/efdb682887f6522149769383908f9790c188ab88), [`0dee7a0`](https://github.com/mastra-ai/mastra/commit/0dee7a0ff4c2507e6eb6e6ee5f9738877ebd4ad1), [`04c2c8e`](https://github.com/mastra-ai/mastra/commit/04c2c8e888984364194131aecb490a3d6e920e61), [`02dc07a`](https://github.com/mastra-ai/mastra/commit/02dc07acc4ad42d93335825e3308f5b42266eba2), [`bb7262b`](https://github.com/mastra-ai/mastra/commit/bb7262b7c0ca76320d985b40510b6ffbbb936582), [`cf1c6e7`](https://github.com/mastra-ai/mastra/commit/cf1c6e789b131f55638fed52183a89d5078b4876), [`5ffadfe`](https://github.com/mastra-ai/mastra/commit/5ffadfefb1468ac2612b20bb84d24c39de6961c0), [`1e1339c`](https://github.com/mastra-ai/mastra/commit/1e1339cc276e571a48cfff5014487877086bfe68), [`d03df73`](https://github.com/mastra-ai/mastra/commit/d03df73f8fe9496064a33e1c3b74ba0479bf9ee6), [`79b8f45`](https://github.com/mastra-ai/mastra/commit/79b8f45a6767e1a5c3d56cd3c5b1214326b81661), [`9bbf08e`](https://github.com/mastra-ai/mastra/commit/9bbf08e3c20731c79dea13a765895b9fcf29cbf1), [`0a25952`](https://github.com/mastra-ai/mastra/commit/0a259526b5e1ac11e6efa53db1f140272962af2d), [`ffa5468`](https://github.com/mastra-ai/mastra/commit/ffa546857fc4821753979b3a34e13b4d76fbbcd4), [`3264a04`](https://github.com/mastra-ai/mastra/commit/3264a04e30340c3c5447433300a035ea0878df85), [`6fdd3d4`](https://github.com/mastra-ai/mastra/commit/6fdd3d451a07a8e7e216c62ac364f8dd8e36c2af), [`088d9ba`](https://github.com/mastra-ai/mastra/commit/088d9ba2577518703c52b0dccd617178d9ee6b0d), [`74fbebd`](https://github.com/mastra-ai/mastra/commit/74fbebd918a03832a2864965a8bea59bf617d3a2), [`aea6217`](https://github.com/mastra-ai/mastra/commit/aea621790bfb2291431b08da0cc5e6e150303ae7), [`b6a855e`](https://github.com/mastra-ai/mastra/commit/b6a855edc056e088279075506442ba1d6fa6def9), [`ae408ea`](https://github.com/mastra-ai/mastra/commit/ae408ea7128f0d2710b78d8623185198e7cb19c1), [`17e942e`](https://github.com/mastra-ai/mastra/commit/17e942eee2ba44985b1f807e6208cdde672f82f9), [`2015cf9`](https://github.com/mastra-ai/mastra/commit/2015cf921649f44c3f5bcd32a2c052335f8e49b4), [`7ef454e`](https://github.com/mastra-ai/mastra/commit/7ef454eaf9dcec6de60021c8f42192052dd490d6), [`2be1d99`](https://github.com/mastra-ai/mastra/commit/2be1d99564ce79acc4846071082bff353035a87a), [`2708fa1`](https://github.com/mastra-ai/mastra/commit/2708fa1055ac91c03e08b598869f6b8fb51fa37f), [`ba74aef`](https://github.com/mastra-ai/mastra/commit/ba74aef5716142dbbe931351f5243c9c6e4128a9), [`ba74aef`](https://github.com/mastra-ai/mastra/commit/ba74aef5716142dbbe931351f5243c9c6e4128a9), [`ec53e89`](https://github.com/mastra-ai/mastra/commit/ec53e8939c76c638991e21af762e51378eff7543), [`9b5a8cb`](https://github.com/mastra-ai/mastra/commit/9b5a8cb13e120811b0bf14140ada314f1c067894), [`607e66b`](https://github.com/mastra-ai/mastra/commit/607e66b02dc7f531ee37799f3456aa2dc0ca7ac5), [`a215d06`](https://github.com/mastra-ai/mastra/commit/a215d06758dcf590eabfe0b7afd4ae39bdbf082c), [`6909c74`](https://github.com/mastra-ai/mastra/commit/6909c74a7781e0447d475e9dbc1dc871b700f426), [`192438f`](https://github.com/mastra-ai/mastra/commit/192438f8a90c4f375e955f8ff179bf8dc6821a83)]:
22
+ - @mastra/core@1.5.0
23
+
3
24
  ## 1.0.2-alpha.0
4
25
 
5
26
  ### Patch Changes
package/LICENSE.md CHANGED
@@ -1,3 +1,18 @@
1
+ Portions of this software are licensed as follows:
2
+
3
+ - All content that resides under any directory named "ee/" within this
4
+ repository, including but not limited to:
5
+ - `packages/core/src/auth/ee/`
6
+ - `packages/server/src/server/auth/ee/`
7
+ is licensed under the license defined in `ee/LICENSE`.
8
+
9
+ - All third-party components incorporated into the Mastra Software are
10
+ licensed under the original license provided by the owner of the
11
+ applicable component.
12
+
13
+ - Content outside of the above-mentioned directories or restrictions is
14
+ available under the "Apache License 2.0" as defined below.
15
+
1
16
  # Apache License 2.0
2
17
 
3
18
  Copyright (c) 2025 Kepler Software, Inc.
package/dist/index.cjs CHANGED
@@ -10,12 +10,18 @@ var GoogleCloudPubSub = class extends events.PubSub {
10
10
  ackBuffer = {};
11
11
  activeSubscriptions = {};
12
12
  activeCbs = {};
13
+ // Tracks the actual anonymous message listener registered on each subscription,
14
+ // so we can remove it cleanly on the final unsubscribe.
15
+ messageListeners = {};
13
16
  constructor(config) {
14
17
  super();
15
18
  this.pubsub = new pubsub.PubSub(config);
16
19
  this.instanceId = crypto.randomUUID();
17
20
  }
18
- getSubscriptionName(topic) {
21
+ getSubscriptionName(topic, group) {
22
+ if (group) {
23
+ return `${topic}-${group}`;
24
+ }
19
25
  return `${topic}-${this.instanceId}`;
20
26
  }
21
27
  async ackMessage(topic, message) {
@@ -29,19 +35,29 @@ var GoogleCloudPubSub = class extends events.PubSub {
29
35
  console.error("Error acking message", e);
30
36
  }
31
37
  }
32
- async init(topicName) {
38
+ async init(topicName, group) {
33
39
  try {
34
40
  await this.pubsub.createTopic(topicName);
35
41
  } catch {
36
42
  }
43
+ const subscriptionName = this.getSubscriptionName(topicName, group);
44
+ const subscriptionKey = group ? `${topicName}:${group}` : topicName;
37
45
  try {
38
- const [sub] = await this.pubsub.topic(topicName).createSubscription(this.getSubscriptionName(topicName), {
46
+ const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {
39
47
  enableMessageOrdering: true,
40
- enableExactlyOnceDelivery: topicName === "workflows" ? true : false
48
+ enableExactlyOnceDelivery: topicName === "workflows" || !!group
41
49
  });
42
- this.activeSubscriptions[topicName] = sub;
50
+ this.activeSubscriptions[subscriptionKey] = sub;
43
51
  return sub;
44
52
  } catch {
53
+ if (group) {
54
+ try {
55
+ const sub = this.pubsub.subscription(subscriptionName);
56
+ this.activeSubscriptions[subscriptionKey] = sub;
57
+ return sub;
58
+ } catch {
59
+ }
60
+ }
45
61
  }
46
62
  return void 0;
47
63
  }
@@ -77,7 +93,7 @@ var GoogleCloudPubSub = class extends events.PubSub {
77
93
  }
78
94
  }
79
95
  }
80
- async subscribe(topic, cb) {
96
+ async subscribe(topic, cb, options) {
81
97
  if (topic.startsWith("workflow.events.")) {
82
98
  const parts = topic.split(".");
83
99
  if (parts[parts.length - 2] === "v2") {
@@ -86,48 +102,79 @@ var GoogleCloudPubSub = class extends events.PubSub {
86
102
  topic = "workflow.events.v1";
87
103
  }
88
104
  }
89
- const subscription = this.activeSubscriptions[topic] ?? await this.init(topic);
105
+ const group = options?.group;
106
+ const subscriptionKey = group ? `${topic}:${group}` : topic;
107
+ const subscription = this.activeSubscriptions[subscriptionKey] ?? await this.init(topic, group);
90
108
  if (!subscription) {
91
109
  throw new Error(`Failed to subscribe to topic: ${topic}`);
92
110
  }
93
- this.activeSubscriptions[topic] = subscription;
94
- const activeCbs = this.activeCbs[topic] ?? /* @__PURE__ */ new Set();
111
+ this.activeSubscriptions[subscriptionKey] = subscription;
112
+ const activeCbs = this.activeCbs[subscriptionKey] ?? /* @__PURE__ */ new Set();
95
113
  activeCbs.add(cb);
96
- this.activeCbs[topic] = activeCbs;
114
+ this.activeCbs[subscriptionKey] = activeCbs;
97
115
  if (subscription.isOpen) {
98
116
  return;
99
117
  }
100
- subscription.on("message", async (message) => {
118
+ const messageListener = async (message) => {
101
119
  const event = JSON.parse(message.data.toString());
102
120
  event.id = message.id;
103
121
  event.createdAt = message.publishTime;
122
+ event.deliveryAttempt = message.deliveryAttempt ?? 1;
104
123
  try {
105
- const activeCbs2 = this.activeCbs[topic] ?? [];
124
+ const activeCbs2 = this.activeCbs[subscriptionKey] ?? [];
106
125
  for (const cb2 of activeCbs2) {
107
- cb2(event, async () => {
108
- try {
109
- await this.ackMessage(topic, message);
110
- } catch (e) {
111
- console.error("Error acking message", e);
126
+ cb2(
127
+ event,
128
+ async () => {
129
+ try {
130
+ await this.ackMessage(subscriptionKey, message);
131
+ } catch (e) {
132
+ console.error("Error acking message", e);
133
+ }
134
+ },
135
+ async () => {
136
+ try {
137
+ message.nack();
138
+ } catch (e) {
139
+ console.error("Error nacking message", e);
140
+ }
112
141
  }
113
- });
142
+ );
114
143
  }
115
144
  } catch (error) {
116
145
  console.error("Error processing event", error);
117
146
  }
118
- });
147
+ };
148
+ this.messageListeners[subscriptionKey] = messageListener;
149
+ subscription.on("message", messageListener);
119
150
  subscription.on("error", async (error) => {
120
151
  console.error("subscription error", error);
121
152
  });
122
153
  }
123
154
  async unsubscribe(topic, cb) {
124
- const subscription = this.activeSubscriptions[topic] ?? this.pubsub.subscription(this.getSubscriptionName(topic));
125
- const activeCbs = this.activeCbs[topic] ?? /* @__PURE__ */ new Set();
126
- activeCbs.delete(cb);
127
- this.activeCbs[topic] = activeCbs;
128
- if (activeCbs.size === 0) {
129
- subscription.removeListener("message", cb);
130
- await subscription.close();
155
+ const keysToCheck = [topic];
156
+ for (const key of Object.keys(this.activeCbs)) {
157
+ if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {
158
+ keysToCheck.push(key);
159
+ }
160
+ }
161
+ for (const subscriptionKey of keysToCheck) {
162
+ const activeCbs = this.activeCbs[subscriptionKey];
163
+ if (activeCbs?.has(cb)) {
164
+ activeCbs.delete(cb);
165
+ if (activeCbs.size === 0) {
166
+ const subscription = this.activeSubscriptions[subscriptionKey];
167
+ const listener = this.messageListeners[subscriptionKey];
168
+ if (subscription) {
169
+ if (listener) subscription.removeListener("message", listener);
170
+ await subscription.close();
171
+ }
172
+ delete this.activeSubscriptions[subscriptionKey];
173
+ delete this.activeCbs[subscriptionKey];
174
+ delete this.messageListeners[subscriptionKey];
175
+ }
176
+ return;
177
+ }
131
178
  }
132
179
  }
133
180
  async flush() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["PubSub","PubSubClient","activeCbs","cb"],"mappings":"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","file":"index.cjs","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<(event: Event, ack: () => Promise<void>) => void>> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string) {\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string) {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(this.getSubscriptionName(topicName), {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' ? true : false,\n });\n this.activeSubscriptions[topicName] = sub;\n return sub;\n } catch {\n // no-op\n }\n\n return undefined;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: (event: Event, ack?: () => Promise<void>) => void): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[topic] ?? (await this.init(topic));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[topic] = subscription;\n\n const activeCbs = this.activeCbs[topic] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[topic] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n subscription.on('message', async message => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n\n try {\n const activeCbs = this.activeCbs[topic] ?? [];\n for (const cb of activeCbs) {\n cb(event, async () => {\n try {\n await this.ackMessage(topic, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n });\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n });\n\n subscription.on('error', async error => {\n // if (error.code === 5) {\n // await this.init(topic);\n // } else {\n // // TODO: determine if other errors require re-subscription\n // // console.error('subscription error, retrying in 5 seconds', error);\n // // await new Promise(resolve => setTimeout(resolve, 5000));\n // // await this.subscribe(topic, cb);\n // console.error('subscription error', error);\n // }\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: (event: Event, ack?: () => Promise<void>) => void): Promise<void> {\n const subscription = this.activeSubscriptions[topic] ?? this.pubsub.subscription(this.getSubscriptionName(topic));\n const activeCbs = this.activeCbs[topic] ?? new Set();\n activeCbs.delete(cb);\n this.activeCbs[topic] = activeCbs;\n\n if (activeCbs.size === 0) {\n subscription.removeListener('message', cb);\n await subscription.close();\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["PubSub","PubSubClient","activeCbs","cb"],"mappings":"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","file":"index.cjs","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, SubscribeOptions } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<EventCallback>> = {};\n // Tracks the actual anonymous message listener registered on each subscription,\n // so we can remove it cleanly on the final unsubscribe.\n private messageListeners: Record<string, (message: Message) => void> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string, group?: string) {\n if (group) {\n return `${topic}-${group}`;\n }\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string, group?: string) {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // Subscription may already exist (e.g. shared group subscription created by another process).\n // Get the existing subscription instead.\n if (group) {\n try {\n const sub = this.pubsub.subscription(subscriptionName);\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // no-op\n }\n }\n }\n\n return undefined;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n const group = options?.group;\n // Use a composite key when group is set so grouped and non-grouped subscriptions\n // on the same topic don't collide\n const subscriptionKey = group ? `${topic}:${group}` : topic;\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[subscriptionKey] ?? (await this.init(topic, group));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[subscriptionKey] = subscription;\n\n const activeCbs = this.activeCbs[subscriptionKey] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[subscriptionKey] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n const messageListener = async (message: Message) => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n event.deliveryAttempt = message.deliveryAttempt ?? 1;\n\n try {\n const activeCbs = this.activeCbs[subscriptionKey] ?? [];\n for (const cb of activeCbs) {\n cb(\n event,\n async () => {\n try {\n await this.ackMessage(subscriptionKey, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n },\n async () => {\n try {\n message.nack();\n } catch (e) {\n console.error('Error nacking message', e);\n }\n },\n );\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n };\n\n this.messageListeners[subscriptionKey] = messageListener;\n subscription.on('message', messageListener);\n\n subscription.on('error', async error => {\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n // Check both grouped and non-grouped subscription keys for this callback\n const keysToCheck = [topic];\n for (const key of Object.keys(this.activeCbs)) {\n if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {\n keysToCheck.push(key);\n }\n }\n\n for (const subscriptionKey of keysToCheck) {\n const activeCbs = this.activeCbs[subscriptionKey];\n if (activeCbs?.has(cb)) {\n activeCbs.delete(cb);\n\n if (activeCbs.size === 0) {\n const subscription = this.activeSubscriptions[subscriptionKey];\n const listener = this.messageListeners[subscriptionKey];\n if (subscription) {\n if (listener) subscription.removeListener('message', listener);\n await subscription.close();\n }\n delete this.activeSubscriptions[subscriptionKey];\n delete this.activeCbs[subscriptionKey];\n delete this.messageListeners[subscriptionKey];\n }\n return;\n }\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,20 +1,21 @@
1
1
  import type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';
2
2
  import { PubSub } from '@mastra/core/events';
3
- import type { Event } from '@mastra/core/events';
3
+ import type { Event, EventCallback, SubscribeOptions } from '@mastra/core/events';
4
4
  export declare class GoogleCloudPubSub extends PubSub {
5
5
  private instanceId;
6
6
  private pubsub;
7
7
  private ackBuffer;
8
8
  private activeSubscriptions;
9
9
  private activeCbs;
10
+ private messageListeners;
10
11
  constructor(config: ClientConfig);
11
- getSubscriptionName(topic: string): string;
12
+ getSubscriptionName(topic: string, group?: string): string;
12
13
  ackMessage(topic: string, message: Message): Promise<void>;
13
- init(topicName: string): Promise<Subscription | undefined>;
14
+ init(topicName: string, group?: string): Promise<Subscription | undefined>;
14
15
  destroy(topicName: string): Promise<void>;
15
16
  publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void>;
16
- subscribe(topic: string, cb: (event: Event, ack?: () => Promise<void>) => void): Promise<void>;
17
- unsubscribe(topic: string, cb: (event: Event, ack?: () => Promise<void>) => void): Promise<void>;
17
+ subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void>;
18
+ unsubscribe(topic: string, cb: EventCallback): Promise<void>;
18
19
  flush(): Promise<void>;
19
20
  }
20
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,SAAS,CAA6E;gBAElF,MAAM,EAAE,YAAY;IAMhC,mBAAmB,CAAC,KAAK,EAAE,MAAM;IAI3B,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAW1C,IAAI,CAAC,SAAS,EAAE,MAAM;IAoBtB,OAAO,CAAC,SAAS,EAAE,MAAM;IASzB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BjF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA6D9F,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAYhG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAElF,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,SAAS,CAA0C;IAG3D,OAAO,CAAC,gBAAgB,CAAkD;gBAE9D,MAAM,EAAE,YAAY;IAMhC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAO3C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAW1C,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAgCtC,OAAO,CAAC,SAAS,EAAE,MAAM;IASzB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BjF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuEtF,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
package/dist/index.js CHANGED
@@ -8,12 +8,18 @@ var GoogleCloudPubSub = class extends PubSub {
8
8
  ackBuffer = {};
9
9
  activeSubscriptions = {};
10
10
  activeCbs = {};
11
+ // Tracks the actual anonymous message listener registered on each subscription,
12
+ // so we can remove it cleanly on the final unsubscribe.
13
+ messageListeners = {};
11
14
  constructor(config) {
12
15
  super();
13
16
  this.pubsub = new PubSub$1(config);
14
17
  this.instanceId = crypto.randomUUID();
15
18
  }
16
- getSubscriptionName(topic) {
19
+ getSubscriptionName(topic, group) {
20
+ if (group) {
21
+ return `${topic}-${group}`;
22
+ }
17
23
  return `${topic}-${this.instanceId}`;
18
24
  }
19
25
  async ackMessage(topic, message) {
@@ -27,19 +33,29 @@ var GoogleCloudPubSub = class extends PubSub {
27
33
  console.error("Error acking message", e);
28
34
  }
29
35
  }
30
- async init(topicName) {
36
+ async init(topicName, group) {
31
37
  try {
32
38
  await this.pubsub.createTopic(topicName);
33
39
  } catch {
34
40
  }
41
+ const subscriptionName = this.getSubscriptionName(topicName, group);
42
+ const subscriptionKey = group ? `${topicName}:${group}` : topicName;
35
43
  try {
36
- const [sub] = await this.pubsub.topic(topicName).createSubscription(this.getSubscriptionName(topicName), {
44
+ const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {
37
45
  enableMessageOrdering: true,
38
- enableExactlyOnceDelivery: topicName === "workflows" ? true : false
46
+ enableExactlyOnceDelivery: topicName === "workflows" || !!group
39
47
  });
40
- this.activeSubscriptions[topicName] = sub;
48
+ this.activeSubscriptions[subscriptionKey] = sub;
41
49
  return sub;
42
50
  } catch {
51
+ if (group) {
52
+ try {
53
+ const sub = this.pubsub.subscription(subscriptionName);
54
+ this.activeSubscriptions[subscriptionKey] = sub;
55
+ return sub;
56
+ } catch {
57
+ }
58
+ }
43
59
  }
44
60
  return void 0;
45
61
  }
@@ -75,7 +91,7 @@ var GoogleCloudPubSub = class extends PubSub {
75
91
  }
76
92
  }
77
93
  }
78
- async subscribe(topic, cb) {
94
+ async subscribe(topic, cb, options) {
79
95
  if (topic.startsWith("workflow.events.")) {
80
96
  const parts = topic.split(".");
81
97
  if (parts[parts.length - 2] === "v2") {
@@ -84,48 +100,79 @@ var GoogleCloudPubSub = class extends PubSub {
84
100
  topic = "workflow.events.v1";
85
101
  }
86
102
  }
87
- const subscription = this.activeSubscriptions[topic] ?? await this.init(topic);
103
+ const group = options?.group;
104
+ const subscriptionKey = group ? `${topic}:${group}` : topic;
105
+ const subscription = this.activeSubscriptions[subscriptionKey] ?? await this.init(topic, group);
88
106
  if (!subscription) {
89
107
  throw new Error(`Failed to subscribe to topic: ${topic}`);
90
108
  }
91
- this.activeSubscriptions[topic] = subscription;
92
- const activeCbs = this.activeCbs[topic] ?? /* @__PURE__ */ new Set();
109
+ this.activeSubscriptions[subscriptionKey] = subscription;
110
+ const activeCbs = this.activeCbs[subscriptionKey] ?? /* @__PURE__ */ new Set();
93
111
  activeCbs.add(cb);
94
- this.activeCbs[topic] = activeCbs;
112
+ this.activeCbs[subscriptionKey] = activeCbs;
95
113
  if (subscription.isOpen) {
96
114
  return;
97
115
  }
98
- subscription.on("message", async (message) => {
116
+ const messageListener = async (message) => {
99
117
  const event = JSON.parse(message.data.toString());
100
118
  event.id = message.id;
101
119
  event.createdAt = message.publishTime;
120
+ event.deliveryAttempt = message.deliveryAttempt ?? 1;
102
121
  try {
103
- const activeCbs2 = this.activeCbs[topic] ?? [];
122
+ const activeCbs2 = this.activeCbs[subscriptionKey] ?? [];
104
123
  for (const cb2 of activeCbs2) {
105
- cb2(event, async () => {
106
- try {
107
- await this.ackMessage(topic, message);
108
- } catch (e) {
109
- console.error("Error acking message", e);
124
+ cb2(
125
+ event,
126
+ async () => {
127
+ try {
128
+ await this.ackMessage(subscriptionKey, message);
129
+ } catch (e) {
130
+ console.error("Error acking message", e);
131
+ }
132
+ },
133
+ async () => {
134
+ try {
135
+ message.nack();
136
+ } catch (e) {
137
+ console.error("Error nacking message", e);
138
+ }
110
139
  }
111
- });
140
+ );
112
141
  }
113
142
  } catch (error) {
114
143
  console.error("Error processing event", error);
115
144
  }
116
- });
145
+ };
146
+ this.messageListeners[subscriptionKey] = messageListener;
147
+ subscription.on("message", messageListener);
117
148
  subscription.on("error", async (error) => {
118
149
  console.error("subscription error", error);
119
150
  });
120
151
  }
121
152
  async unsubscribe(topic, cb) {
122
- const subscription = this.activeSubscriptions[topic] ?? this.pubsub.subscription(this.getSubscriptionName(topic));
123
- const activeCbs = this.activeCbs[topic] ?? /* @__PURE__ */ new Set();
124
- activeCbs.delete(cb);
125
- this.activeCbs[topic] = activeCbs;
126
- if (activeCbs.size === 0) {
127
- subscription.removeListener("message", cb);
128
- await subscription.close();
153
+ const keysToCheck = [topic];
154
+ for (const key of Object.keys(this.activeCbs)) {
155
+ if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {
156
+ keysToCheck.push(key);
157
+ }
158
+ }
159
+ for (const subscriptionKey of keysToCheck) {
160
+ const activeCbs = this.activeCbs[subscriptionKey];
161
+ if (activeCbs?.has(cb)) {
162
+ activeCbs.delete(cb);
163
+ if (activeCbs.size === 0) {
164
+ const subscription = this.activeSubscriptions[subscriptionKey];
165
+ const listener = this.messageListeners[subscriptionKey];
166
+ if (subscription) {
167
+ if (listener) subscription.removeListener("message", listener);
168
+ await subscription.close();
169
+ }
170
+ delete this.activeSubscriptions[subscriptionKey];
171
+ delete this.activeCbs[subscriptionKey];
172
+ delete this.messageListeners[subscriptionKey];
173
+ }
174
+ return;
175
+ }
129
176
  }
130
177
  }
131
178
  async flush() {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["PubSubClient","activeCbs","cb"],"mappings":"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","file":"index.js","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<(event: Event, ack: () => Promise<void>) => void>> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string) {\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string) {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(this.getSubscriptionName(topicName), {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' ? true : false,\n });\n this.activeSubscriptions[topicName] = sub;\n return sub;\n } catch {\n // no-op\n }\n\n return undefined;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: (event: Event, ack?: () => Promise<void>) => void): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[topic] ?? (await this.init(topic));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[topic] = subscription;\n\n const activeCbs = this.activeCbs[topic] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[topic] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n subscription.on('message', async message => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n\n try {\n const activeCbs = this.activeCbs[topic] ?? [];\n for (const cb of activeCbs) {\n cb(event, async () => {\n try {\n await this.ackMessage(topic, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n });\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n });\n\n subscription.on('error', async error => {\n // if (error.code === 5) {\n // await this.init(topic);\n // } else {\n // // TODO: determine if other errors require re-subscription\n // // console.error('subscription error, retrying in 5 seconds', error);\n // // await new Promise(resolve => setTimeout(resolve, 5000));\n // // await this.subscribe(topic, cb);\n // console.error('subscription error', error);\n // }\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: (event: Event, ack?: () => Promise<void>) => void): Promise<void> {\n const subscription = this.activeSubscriptions[topic] ?? this.pubsub.subscription(this.getSubscriptionName(topic));\n const activeCbs = this.activeCbs[topic] ?? new Set();\n activeCbs.delete(cb);\n this.activeCbs[topic] = activeCbs;\n\n if (activeCbs.size === 0) {\n subscription.removeListener('message', cb);\n await subscription.close();\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["PubSubClient","activeCbs","cb"],"mappings":";;;;AAKO,IAAM,iBAAA,GAAN,cAAgC,MAAA,CAAO;AAAA,EACpC,UAAA;AAAA,EACA,MAAA;AAAA,EACA,YAA0C,EAAC;AAAA,EAC3C,sBAAoD,EAAC;AAAA,EACrD,YAAgD,EAAC;AAAA;AAAA;AAAA,EAGjD,mBAA+D,EAAC;AAAA,EAExE,YAAY,MAAA,EAAsB;AAChC,IAAA,KAAA,EAAM;AACN,IAAA,IAAA,CAAK,MAAA,GAAS,IAAIA,QAAA,CAAa,MAAM,CAAA;AACrC,IAAA,IAAA,CAAK,UAAA,GAAa,OAAO,UAAA,EAAW;AAAA,EACtC;AAAA,EAEA,mBAAA,CAAoB,OAAe,KAAA,EAAgB;AACjD,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,IAC1B;AACA,IAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,UAAU,CAAA,CAAA;AAAA,EACpC;AAAA,EAEA,MAAM,UAAA,CAAW,KAAA,EAAe,OAAA,EAAkB;AAChD,IAAA,IAAI;AACF,MAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,IAAA,CAAK,CAAC,QAAQ,eAAA,EAAgB,EAAG,IAAI,OAAA,CAAQ,aAAW,UAAA,CAAW,OAAA,EAAS,GAAI,CAAC,CAAC,CAAC,CAAA;AAC/G,MAAA,IAAA,CAAK,SAAA,CAAU,QAAQ,GAAA,GAAM,OAAA,CAAQ,EAAE,CAAA,GAAI,WAAA,CAAY,MAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AACrE,MAAA,MAAM,WAAA;AACN,MAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAA,GAAQ,GAAA,GAAM,QAAQ,EAAE,CAAA;AAAA,IAChD,SAAS,CAAA,EAAG;AACV,MAAA,OAAA,CAAQ,KAAA,CAAM,wBAAwB,CAAC,CAAA;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,IAAA,CAAK,SAAA,EAAmB,KAAA,EAAgB;AAC5C,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,SAAS,CAAA;AAAA,IACzC,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,mBAAA,CAAoB,SAAA,EAAW,KAAK,CAAA;AAClE,IAAA,MAAM,kBAAkB,KAAA,GAAQ,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,SAAA;AAC1D,IAAA,IAAI;AACF,MAAA,MAAM,CAAC,GAAG,CAAA,GAAI,MAAM,IAAA,CAAK,OAAO,KAAA,CAAM,SAAS,CAAA,CAAE,kBAAA,CAAmB,gBAAA,EAAkB;AAAA,QACpF,qBAAA,EAAuB,IAAA;AAAA,QACvB,yBAAA,EAA2B,SAAA,KAAc,WAAA,IAAe,CAAC,CAAC;AAAA,OAC3D,CAAA;AACD,MAAA,IAAA,CAAK,mBAAA,CAAoB,eAAe,CAAA,GAAI,GAAA;AAC5C,MAAA,OAAO,GAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AAGN,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,IAAI;AACF,UAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,gBAAgB,CAAA;AACrD,UAAA,IAAA,CAAK,mBAAA,CAAoB,eAAe,CAAA,GAAI,GAAA;AAC5C,UAAA,OAAO,GAAA;AAAA,QACT,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,SAAA,EAAmB;AAC/B,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,mBAAA,CAAoB,SAAS,CAAA;AAClD,IAAA,OAAO,IAAA,CAAK,oBAAoB,SAAS,CAAA;AACzC,IAAA,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,OAAO,CAAA,CAAE,kBAAA,EAAmB;AACrD,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,OAAO,EAAE,KAAA,EAAM;AAC9C,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,OAAO,EAAE,MAAA,EAAO;AAC/C,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,SAAS,EAAE,MAAA,EAAO;AAAA,EAC5C;AAAA,EAEA,MAAM,OAAA,CAAQ,SAAA,EAAmB,KAAA,EAAuD;AACtF,IAAA,IAAI,SAAA,CAAU,UAAA,CAAW,kBAAkB,CAAA,EAAG;AAC5C,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,GAAG,CAAA;AACjC,MAAA,IAAI,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,MAAM,IAAA,EAAM;AACpC,QAAA,SAAA,GAAY,oBAAA;AAAA,MACd,CAAA,MAAO;AACL,QAAA,SAAA,GAAY,oBAAA;AAAA,MACd;AAAA,IACF;AAEA,IAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA;AAEvC,IAAA,IAAI;AACF,MAAA,MAAM,MAAM,cAAA,CAAe;AAAA,QACzB,MAAM,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,QACvC,WAAA,EAAa;AAAA,OACd,CAAA;AAAA,IACH,SAAS,CAAA,EAAQ;AACf,MAAA,IAAI,CAAA,CAAE,SAAS,CAAA,EAAG;AAChB,QAAA,MAAM,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,SAAS,CAAA;AACvC,QAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,KAAK,CAAA;AAAA,MACrC,CAAA,MAAO;AACL,QAAA,MAAM,CAAA;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,SAAA,CAAU,KAAA,EAAe,EAAA,EAAmB,OAAA,EAA2C;AAC3F,IAAA,IAAI,KAAA,CAAM,UAAA,CAAW,kBAAkB,CAAA,EAAG;AACxC,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,MAAA,IAAI,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,MAAM,IAAA,EAAM;AACpC,QAAA,KAAA,GAAQ,oBAAA;AAAA,MACV,CAAA,MAAO;AACL,QAAA,KAAA,GAAQ,oBAAA;AAAA,MACV;AAAA,IACF;AAEA,IAAA,MAAM,QAAQ,OAAA,EAAS,KAAA;AAGvB,IAAA,MAAM,kBAAkB,KAAA,GAAQ,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,KAAA;AAGtD,IAAA,MAAM,YAAA,GAAe,KAAK,mBAAA,CAAoB,eAAe,KAAM,MAAM,IAAA,CAAK,IAAA,CAAK,KAAA,EAAO,KAAK,CAAA;AAC/F,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8BAAA,EAAiC,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1D;AAEA,IAAA,IAAA,CAAK,mBAAA,CAAoB,eAAe,CAAA,GAAI,YAAA;AAE5C,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA,CAAU,eAAe,CAAA,wBAAS,GAAA,EAAI;AAC7D,IAAA,SAAA,CAAU,IAAI,EAAE,CAAA;AAChB,IAAA,IAAA,CAAK,SAAA,CAAU,eAAe,CAAA,GAAI,SAAA;AAElC,IAAA,IAAI,aAAa,MAAA,EAAQ;AACvB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,eAAA,GAAkB,OAAO,OAAA,KAAqB;AAClD,MAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,UAAU,CAAA;AAChD,MAAA,KAAA,CAAM,KAAK,OAAA,CAAQ,EAAA;AACnB,MAAA,KAAA,CAAM,YAAY,OAAA,CAAQ,WAAA;AAC1B,MAAA,KAAA,CAAM,eAAA,GAAkB,QAAQ,eAAA,IAAmB,CAAA;AAEnD,MAAA,IAAI;AACF,QAAA,MAAMC,UAAAA,GAAY,IAAA,CAAK,SAAA,CAAU,eAAe,KAAK,EAAC;AACtD,QAAA,KAAA,MAAWC,OAAMD,UAAAA,EAAW;AAC1B,UAAAC,GAAAA;AAAA,YACE,KAAA;AAAA,YACA,YAAY;AACV,cAAA,IAAI;AACF,gBAAA,MAAM,IAAA,CAAK,UAAA,CAAW,eAAA,EAAiB,OAAO,CAAA;AAAA,cAChD,SAAS,CAAA,EAAG;AACV,gBAAA,OAAA,CAAQ,KAAA,CAAM,wBAAwB,CAAC,CAAA;AAAA,cACzC;AAAA,YACF,CAAA;AAAA,YACA,YAAY;AACV,cAAA,IAAI;AACF,gBAAA,OAAA,CAAQ,IAAA,EAAK;AAAA,cACf,SAAS,CAAA,EAAG;AACV,gBAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,CAAC,CAAA;AAAA,cAC1C;AAAA,YACF;AAAA,WACF;AAAA,QACF;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,0BAA0B,KAAK,CAAA;AAAA,MAC/C;AAAA,IACF,CAAA;AAEA,IAAA,IAAA,CAAK,gBAAA,CAAiB,eAAe,CAAA,GAAI,eAAA;AACzC,IAAA,YAAA,CAAa,EAAA,CAAG,WAAW,eAAe,CAAA;AAE1C,IAAA,YAAA,CAAa,EAAA,CAAG,OAAA,EAAS,OAAM,KAAA,KAAS;AACtC,MAAA,OAAA,CAAQ,KAAA,CAAM,sBAAsB,KAAK,CAAA;AAAA,IAC3C,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,WAAA,CAAY,KAAA,EAAe,EAAA,EAAkC;AAEjE,IAAA,MAAM,WAAA,GAAc,CAAC,KAAK,CAAA;AAC1B,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA,EAAG;AAC7C,MAAA,IAAI,GAAA,CAAI,UAAA,CAAW,CAAA,EAAG,KAAK,CAAA,CAAA,CAAG,KAAK,CAAC,WAAA,CAAY,QAAA,CAAS,GAAG,CAAA,EAAG;AAC7D,QAAA,WAAA,CAAY,KAAK,GAAG,CAAA;AAAA,MACtB;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,mBAAmB,WAAA,EAAa;AACzC,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,eAAe,CAAA;AAChD,MAAA,IAAI,SAAA,EAAW,GAAA,CAAI,EAAE,CAAA,EAAG;AACtB,QAAA,SAAA,CAAU,OAAO,EAAE,CAAA;AAEnB,QAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG;AACxB,UAAA,MAAM,YAAA,GAAe,IAAA,CAAK,mBAAA,CAAoB,eAAe,CAAA;AAC7D,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,gBAAA,CAAiB,eAAe,CAAA;AACtD,UAAA,IAAI,YAAA,EAAc;AAChB,YAAA,IAAI,QAAA,EAAU,YAAA,CAAa,cAAA,CAAe,SAAA,EAAW,QAAQ,CAAA;AAC7D,YAAA,MAAM,aAAa,KAAA,EAAM;AAAA,UAC3B;AACA,UAAA,OAAO,IAAA,CAAK,oBAAoB,eAAe,CAAA;AAC/C,UAAA,OAAO,IAAA,CAAK,UAAU,eAAe,CAAA;AACrC,UAAA,OAAO,IAAA,CAAK,iBAAiB,eAAe,CAAA;AAAA,QAC9C;AACA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,QAAQ,GAAA,CAAI,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,SAAS,CAAC,CAAA;AAAA,EACjD;AACF","file":"index.js","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, SubscribeOptions } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<EventCallback>> = {};\n // Tracks the actual anonymous message listener registered on each subscription,\n // so we can remove it cleanly on the final unsubscribe.\n private messageListeners: Record<string, (message: Message) => void> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string, group?: string) {\n if (group) {\n return `${topic}-${group}`;\n }\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string, group?: string) {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // Subscription may already exist (e.g. shared group subscription created by another process).\n // Get the existing subscription instead.\n if (group) {\n try {\n const sub = this.pubsub.subscription(subscriptionName);\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // no-op\n }\n }\n }\n\n return undefined;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n const group = options?.group;\n // Use a composite key when group is set so grouped and non-grouped subscriptions\n // on the same topic don't collide\n const subscriptionKey = group ? `${topic}:${group}` : topic;\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[subscriptionKey] ?? (await this.init(topic, group));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[subscriptionKey] = subscription;\n\n const activeCbs = this.activeCbs[subscriptionKey] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[subscriptionKey] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n const messageListener = async (message: Message) => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n event.deliveryAttempt = message.deliveryAttempt ?? 1;\n\n try {\n const activeCbs = this.activeCbs[subscriptionKey] ?? [];\n for (const cb of activeCbs) {\n cb(\n event,\n async () => {\n try {\n await this.ackMessage(subscriptionKey, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n },\n async () => {\n try {\n message.nack();\n } catch (e) {\n console.error('Error nacking message', e);\n }\n },\n );\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n };\n\n this.messageListeners[subscriptionKey] = messageListener;\n subscription.on('message', messageListener);\n\n subscription.on('error', async error => {\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n // Check both grouped and non-grouped subscription keys for this callback\n const keysToCheck = [topic];\n for (const key of Object.keys(this.activeCbs)) {\n if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {\n keysToCheck.push(key);\n }\n }\n\n for (const subscriptionKey of keysToCheck) {\n const activeCbs = this.activeCbs[subscriptionKey];\n if (activeCbs?.has(cb)) {\n activeCbs.delete(cb);\n\n if (activeCbs.size === 0) {\n const subscription = this.activeSubscriptions[subscriptionKey];\n const listener = this.messageListeners[subscriptionKey];\n if (subscription) {\n if (listener) subscription.removeListener('message', listener);\n await subscription.close();\n }\n delete this.activeSubscriptions[subscriptionKey];\n delete this.activeCbs[subscriptionKey];\n delete this.messageListeners[subscriptionKey];\n }\n return;\n }\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/google-cloud-pubsub",
3
- "version": "1.0.2-alpha.0",
3
+ "version": "1.0.3-alpha.0",
4
4
  "description": "Mastra Google Cloud PubSub integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -23,26 +23,26 @@
23
23
  "./package.json": "./package.json"
24
24
  },
25
25
  "dependencies": {
26
- "@google-cloud/pubsub": "^5.2.3",
26
+ "@google-cloud/pubsub": "^5.3.0",
27
27
  "@inngest/realtime": "^0.4.6",
28
28
  "@opentelemetry/api": "^1.9.0",
29
- "inngest": "^3.44.2",
30
- "zod": "^3.25.76"
29
+ "inngest": "^3.52.6",
30
+ "zod": "^4.3.6"
31
31
  },
32
32
  "devDependencies": {
33
- "@types/node": "22.19.7",
34
- "@vitest/coverage-v8": "4.0.12",
35
- "@vitest/ui": "4.0.12",
36
- "ai": "^4.3.16",
37
- "eslint": "^9.37.0",
33
+ "@types/node": "22.19.15",
34
+ "@vitest/coverage-v8": "4.0.18",
35
+ "@vitest/ui": "4.0.18",
36
+ "ai": "^4.3.19",
37
+ "eslint": "^9.39.4",
38
38
  "tsup": "^8.5.1",
39
39
  "typescript": "^5.9.3",
40
- "vitest": "4.0.16",
41
- "@internal/lint": "0.0.59",
42
- "@mastra/deployer": "1.5.0-alpha.0",
43
- "@internal/types-builder": "0.0.34",
44
- "@mastra/libsql": "1.5.0-alpha.0",
45
- "@mastra/core": "1.5.0-alpha.0"
40
+ "vitest": "4.0.18",
41
+ "@mastra/deployer": "1.25.1-alpha.0",
42
+ "@mastra/libsql": "1.8.2-alpha.0",
43
+ "@internal/lint": "0.0.83",
44
+ "@internal/types-builder": "0.0.58",
45
+ "@mastra/core": "1.25.1-alpha.0"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@mastra/core": ">=1.0.0-0 <2.0.0-0"