@mastra/google-cloud-pubsub 1.1.1-alpha.0 → 1.1.1-alpha.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/CHANGELOG.md +11 -0
- package/dist/index.cjs +55 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -1
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @mastra/inngest
|
|
2
2
|
|
|
3
|
+
## 1.1.1-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Honor the `localOnly` publish option so in-process subscribers can receive events without round-tripping through the broker. ([#17836](https://github.com/mastra-ai/mastra/pull/17836))
|
|
8
|
+
|
|
9
|
+
This matches the contract already implemented by `UnixSocketPubSub` in `@mastra/core`: when `Mastra` tags an internal workflow event as `localOnly`, the payload is delivered by reference to local subscribers and the broker is skipped entirely. Live runtime values like `MastraModelOutput` instances now keep their prototypes when the evented agent loop runs against a Redis Streams or Google Cloud Pub/Sub broker, fixing `output.consumeStream is not a function` style failures.
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`5c4e9a4`](https://github.com/mastra-ai/mastra/commit/5c4e9a4cfb2216bb3ea7f8988ad3727f3b92bb3a), [`25961e3`](https://github.com/mastra-ai/mastra/commit/25961e3260ff3b1464637af8fcdb36210551c39f), [`7b29f33`](https://github.com/mastra-ai/mastra/commit/7b29f332a357a83e555f29e718e5f2fab9979943), [`24912b1`](https://github.com/mastra-ai/mastra/commit/24912b1f855d29ec36af4ef4bde1f7417e20cdf5), [`7686216`](https://github.com/mastra-ai/mastra/commit/7686216f37e74568feddec17cef3c3d24e10e60a), [`975c59a`](https://github.com/mastra-ai/mastra/commit/975c59ae363ee275fc55062392e1ffd2cbccbd53), [`d95f394`](https://github.com/mastra-ai/mastra/commit/d95f394fd24c8411886930d727679c4d5252aa26), [`f3f0c9d`](https://github.com/mastra-ai/mastra/commit/f3f0c9d7c878db5a13177871ce3523a14f14b311)]:
|
|
12
|
+
- @mastra/core@1.46.0-alpha.4
|
|
13
|
+
|
|
3
14
|
## 1.1.1-alpha.0
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -10,6 +10,10 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
10
10
|
ackBuffer = {};
|
|
11
11
|
activeSubscriptions = {};
|
|
12
12
|
activeCbs = {};
|
|
13
|
+
// `localOnly` publishes never touch Google Cloud — they are delivered to
|
|
14
|
+
// same-process subscribers only. Tracks live callbacks per (normalized) topic
|
|
15
|
+
// so we can fan out without going through PubSub.
|
|
16
|
+
localCallbacks = /* @__PURE__ */ new Map();
|
|
13
17
|
// Coalesces concurrent init() calls for the same subscription so racing
|
|
14
18
|
// subscribers (e.g. a producer stream and a consumer observe on the same
|
|
15
19
|
// run topic) share a single createTopic/createSubscription attempt.
|
|
@@ -83,7 +87,7 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
83
87
|
await this.pubsub.subscription(subName).delete();
|
|
84
88
|
await this.pubsub.topic(topicName).delete();
|
|
85
89
|
}
|
|
86
|
-
async publish(topicName, event) {
|
|
90
|
+
async publish(topicName, event, options) {
|
|
87
91
|
if (topicName.startsWith("workflow.events.")) {
|
|
88
92
|
const parts = topicName.split(".");
|
|
89
93
|
if (parts[parts.length - 2] === "v2") {
|
|
@@ -92,6 +96,10 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
92
96
|
topicName = "workflow.events.v1";
|
|
93
97
|
}
|
|
94
98
|
}
|
|
99
|
+
if (options?.localOnly) {
|
|
100
|
+
await this.deliverLocal(topicName, event);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
95
103
|
let topic = this.pubsub.topic(topicName);
|
|
96
104
|
try {
|
|
97
105
|
await topic.publishMessage({
|
|
@@ -118,6 +126,12 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
118
126
|
}
|
|
119
127
|
const group = options?.group;
|
|
120
128
|
const subscriptionKey = group ? `${topic}:${group}` : topic;
|
|
129
|
+
let localSet = this.localCallbacks.get(topic);
|
|
130
|
+
if (!localSet) {
|
|
131
|
+
localSet = /* @__PURE__ */ new Set();
|
|
132
|
+
this.localCallbacks.set(topic, localSet);
|
|
133
|
+
}
|
|
134
|
+
localSet.add(cb);
|
|
121
135
|
const subscription = this.activeSubscriptions[subscriptionKey] ?? await this.init(topic, group);
|
|
122
136
|
if (!subscription) {
|
|
123
137
|
throw new Error(`Failed to subscribe to topic: ${topic}`);
|
|
@@ -166,6 +180,18 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
166
180
|
});
|
|
167
181
|
}
|
|
168
182
|
async unsubscribe(topic, cb) {
|
|
183
|
+
if (topic.startsWith("workflow.events.")) {
|
|
184
|
+
const parts = topic.split(".");
|
|
185
|
+
if (parts[parts.length - 2] === "v2") {
|
|
186
|
+
topic = "workflow.events.v2";
|
|
187
|
+
} else {
|
|
188
|
+
topic = "workflow.events.v1";
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const localSet = this.localCallbacks.get(topic);
|
|
192
|
+
if (localSet?.delete(cb) && localSet.size === 0) {
|
|
193
|
+
this.localCallbacks.delete(topic);
|
|
194
|
+
}
|
|
169
195
|
const keysToCheck = [topic];
|
|
170
196
|
for (const key of Object.keys(this.activeCbs)) {
|
|
171
197
|
if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {
|
|
@@ -194,6 +220,34 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
194
220
|
async flush() {
|
|
195
221
|
await Promise.all(Object.values(this.ackBuffer));
|
|
196
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Fan a `localOnly` event out to in-process subscribers without going through
|
|
225
|
+
* Google Cloud. The payload is delivered by reference, so live class instances
|
|
226
|
+
* and functions on the event survive intact.
|
|
227
|
+
*/
|
|
228
|
+
async deliverLocal(topicName, event) {
|
|
229
|
+
const callbacks = this.localCallbacks.get(topicName);
|
|
230
|
+
if (!callbacks || callbacks.size === 0) return;
|
|
231
|
+
const localEvent = {
|
|
232
|
+
...event,
|
|
233
|
+
id: crypto.randomUUID(),
|
|
234
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
235
|
+
deliveryAttempt: 1
|
|
236
|
+
};
|
|
237
|
+
for (const cb of [...callbacks]) {
|
|
238
|
+
try {
|
|
239
|
+
cb(
|
|
240
|
+
localEvent,
|
|
241
|
+
async () => {
|
|
242
|
+
},
|
|
243
|
+
async () => {
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.error("Error delivering local event", error);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
197
251
|
};
|
|
198
252
|
|
|
199
253
|
exports.GoogleCloudPubSub = GoogleCloudPubSub;
|
package/dist/index.cjs.map
CHANGED
|
@@ -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, 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 // Coalesces concurrent init() calls for the same subscription so racing\n // subscribers (e.g. a producer stream and a consumer observe on the same\n // run topic) share a single createTopic/createSubscription attempt.\n private inFlightInit: Record<string, Promise<Subscription | undefined>> = {};\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): Promise<Subscription | undefined> {\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n\n // Reuse an in-flight init so concurrent subscribers don't race to create the\n // same subscription. The promise is registered synchronously below (before any\n // await), so a second caller arriving during the create window reuses it.\n if (this.inFlightInit[subscriptionKey]) {\n return this.inFlightInit[subscriptionKey];\n }\n\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const initPromise = (async (): Promise<Subscription | undefined> => {\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(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch (error) {\n // The subscription may already exist: created concurrently by a racing\n // subscriber (ALREADY_EXISTS / gRPC code 6), shared by another process via\n // a group, or surviving a previous process. In all of these cases attach to\n // the existing subscription instead of failing. Ungrouped subscriptions hit\n // this on the concurrent-create race, so we must not gate it on `group`.\n const alreadyExists = (error as { code?: number } | undefined)?.code === 6;\n if (alreadyExists || 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 return undefined;\n })().finally(() => {\n delete this.inFlightInit[subscriptionKey];\n });\n\n this.inFlightInit[subscriptionKey] = initPromise;\n return initPromise;\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"]}
|
|
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 // `localOnly` publishes never touch Google Cloud — they are delivered to\n // same-process subscribers only. Tracks live callbacks per (normalized) topic\n // so we can fan out without going through PubSub.\n private localCallbacks: Map<string, Set<EventCallback>> = new Map();\n // Coalesces concurrent init() calls for the same subscription so racing\n // subscribers (e.g. a producer stream and a consumer observe on the same\n // run topic) share a single createTopic/createSubscription attempt.\n private inFlightInit: Record<string, Promise<Subscription | undefined>> = {};\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): Promise<Subscription | undefined> {\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n\n // Reuse an in-flight init so concurrent subscribers don't race to create the\n // same subscription. The promise is registered synchronously below (before any\n // await), so a second caller arriving during the create window reuses it.\n if (this.inFlightInit[subscriptionKey]) {\n return this.inFlightInit[subscriptionKey];\n }\n\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const initPromise = (async (): Promise<Subscription | undefined> => {\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(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch (error) {\n // The subscription may already exist: created concurrently by a racing\n // subscriber (ALREADY_EXISTS / gRPC code 6), shared by another process via\n // a group, or surviving a previous process. In all of these cases attach to\n // the existing subscription instead of failing. Ungrouped subscriptions hit\n // this on the concurrent-create race, so we must not gate it on `group`.\n const alreadyExists = (error as { code?: number } | undefined)?.code === 6;\n if (alreadyExists || 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 return undefined;\n })().finally(() => {\n delete this.inFlightInit[subscriptionKey];\n });\n\n this.inFlightInit[subscriptionKey] = initPromise;\n return initPromise;\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(\n topicName: string,\n event: Omit<Event, 'id' | 'createdAt'>,\n options?: { localOnly?: boolean },\n ): 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 // `localOnly` events stay entirely within the publishing process. They are\n // never serialized through Google Cloud, so live methods on payload values\n // (e.g. `MastraModelOutput.getFullOutput`) survive intact. The agent's\n // execution-workflow relies on this: the run result is delivered via\n // `workflows-finish` and includes the `MastraModelOutput` instance —\n // round-tripping it through Pub/Sub would strip its methods.\n if (options?.localOnly) {\n await this.deliverLocal(topicName, event);\n return;\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 // Register callback for `localOnly` delivery. Local delivery bypasses Google\n // Cloud entirely so live class instances on the payload (e.g. Date, Map,\n // Error, MastraModelOutput) keep their prototypes.\n let localSet = this.localCallbacks.get(topic);\n if (!localSet) {\n localSet = new Set();\n this.localCallbacks.set(topic, localSet);\n }\n localSet.add(cb);\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 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 // Drop from the local-delivery set; if nobody is left, tear down the bucket.\n const localSet = this.localCallbacks.get(topic);\n if (localSet?.delete(cb) && localSet.size === 0) {\n this.localCallbacks.delete(topic);\n }\n\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 /**\n * Fan a `localOnly` event out to in-process subscribers without going through\n * Google Cloud. The payload is delivered by reference, so live class instances\n * and functions on the event survive intact.\n */\n private async deliverLocal(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n const callbacks = this.localCallbacks.get(topicName);\n if (!callbacks || callbacks.size === 0) return;\n\n const localEvent: Event = {\n ...event,\n id: crypto.randomUUID(),\n createdAt: new Date(),\n deliveryAttempt: 1,\n };\n\n for (const cb of [...callbacks]) {\n try {\n cb(\n localEvent,\n async () => {},\n async () => {},\n );\n } catch (error) {\n console.error('Error delivering local event', error);\n }\n }\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare class GoogleCloudPubSub extends PubSub {
|
|
|
7
7
|
private ackBuffer;
|
|
8
8
|
private activeSubscriptions;
|
|
9
9
|
private activeCbs;
|
|
10
|
+
private localCallbacks;
|
|
10
11
|
private inFlightInit;
|
|
11
12
|
private messageListeners;
|
|
12
13
|
constructor(config: ClientConfig);
|
|
@@ -14,9 +15,17 @@ export declare class GoogleCloudPubSub extends PubSub {
|
|
|
14
15
|
ackMessage(topic: string, message: Message): Promise<void>;
|
|
15
16
|
init(topicName: string, group?: string): Promise<Subscription | undefined>;
|
|
16
17
|
destroy(topicName: string): Promise<void>;
|
|
17
|
-
publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'
|
|
18
|
+
publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>, options?: {
|
|
19
|
+
localOnly?: boolean;
|
|
20
|
+
}): Promise<void>;
|
|
18
21
|
subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void>;
|
|
19
22
|
unsubscribe(topic: string, cb: EventCallback): Promise<void>;
|
|
20
23
|
flush(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Fan a `localOnly` event out to in-process subscribers without going through
|
|
26
|
+
* Google Cloud. The payload is delivered by reference, so live class instances
|
|
27
|
+
* and functions on the event survive intact.
|
|
28
|
+
*/
|
|
29
|
+
private deliverLocal;
|
|
21
30
|
}
|
|
22
31
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,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;IAI3D,OAAO,CAAC,YAAY,CAAyD;IAG7E,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,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAkD1E,OAAO,CAAC,SAAS,EAAE,MAAM;IASzB,OAAO,
|
|
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;IAI3D,OAAO,CAAC,cAAc,CAA8C;IAIpE,OAAO,CAAC,YAAY,CAAyD;IAG7E,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,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAkD1E,OAAO,CAAC,SAAS,EAAE,MAAM;IASzB,OAAO,CACX,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,WAAW,CAAC,EACtC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAChC,OAAO,CAAC,IAAI,CAAC;IAsCV,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiFtF,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA6C5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;OAIG;YACW,YAAY;CAuB3B"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,10 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
8
8
|
ackBuffer = {};
|
|
9
9
|
activeSubscriptions = {};
|
|
10
10
|
activeCbs = {};
|
|
11
|
+
// `localOnly` publishes never touch Google Cloud — they are delivered to
|
|
12
|
+
// same-process subscribers only. Tracks live callbacks per (normalized) topic
|
|
13
|
+
// so we can fan out without going through PubSub.
|
|
14
|
+
localCallbacks = /* @__PURE__ */ new Map();
|
|
11
15
|
// Coalesces concurrent init() calls for the same subscription so racing
|
|
12
16
|
// subscribers (e.g. a producer stream and a consumer observe on the same
|
|
13
17
|
// run topic) share a single createTopic/createSubscription attempt.
|
|
@@ -81,7 +85,7 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
81
85
|
await this.pubsub.subscription(subName).delete();
|
|
82
86
|
await this.pubsub.topic(topicName).delete();
|
|
83
87
|
}
|
|
84
|
-
async publish(topicName, event) {
|
|
88
|
+
async publish(topicName, event, options) {
|
|
85
89
|
if (topicName.startsWith("workflow.events.")) {
|
|
86
90
|
const parts = topicName.split(".");
|
|
87
91
|
if (parts[parts.length - 2] === "v2") {
|
|
@@ -90,6 +94,10 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
90
94
|
topicName = "workflow.events.v1";
|
|
91
95
|
}
|
|
92
96
|
}
|
|
97
|
+
if (options?.localOnly) {
|
|
98
|
+
await this.deliverLocal(topicName, event);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
93
101
|
let topic = this.pubsub.topic(topicName);
|
|
94
102
|
try {
|
|
95
103
|
await topic.publishMessage({
|
|
@@ -116,6 +124,12 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
116
124
|
}
|
|
117
125
|
const group = options?.group;
|
|
118
126
|
const subscriptionKey = group ? `${topic}:${group}` : topic;
|
|
127
|
+
let localSet = this.localCallbacks.get(topic);
|
|
128
|
+
if (!localSet) {
|
|
129
|
+
localSet = /* @__PURE__ */ new Set();
|
|
130
|
+
this.localCallbacks.set(topic, localSet);
|
|
131
|
+
}
|
|
132
|
+
localSet.add(cb);
|
|
119
133
|
const subscription = this.activeSubscriptions[subscriptionKey] ?? await this.init(topic, group);
|
|
120
134
|
if (!subscription) {
|
|
121
135
|
throw new Error(`Failed to subscribe to topic: ${topic}`);
|
|
@@ -164,6 +178,18 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
164
178
|
});
|
|
165
179
|
}
|
|
166
180
|
async unsubscribe(topic, cb) {
|
|
181
|
+
if (topic.startsWith("workflow.events.")) {
|
|
182
|
+
const parts = topic.split(".");
|
|
183
|
+
if (parts[parts.length - 2] === "v2") {
|
|
184
|
+
topic = "workflow.events.v2";
|
|
185
|
+
} else {
|
|
186
|
+
topic = "workflow.events.v1";
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const localSet = this.localCallbacks.get(topic);
|
|
190
|
+
if (localSet?.delete(cb) && localSet.size === 0) {
|
|
191
|
+
this.localCallbacks.delete(topic);
|
|
192
|
+
}
|
|
167
193
|
const keysToCheck = [topic];
|
|
168
194
|
for (const key of Object.keys(this.activeCbs)) {
|
|
169
195
|
if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {
|
|
@@ -192,6 +218,34 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
192
218
|
async flush() {
|
|
193
219
|
await Promise.all(Object.values(this.ackBuffer));
|
|
194
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Fan a `localOnly` event out to in-process subscribers without going through
|
|
223
|
+
* Google Cloud. The payload is delivered by reference, so live class instances
|
|
224
|
+
* and functions on the event survive intact.
|
|
225
|
+
*/
|
|
226
|
+
async deliverLocal(topicName, event) {
|
|
227
|
+
const callbacks = this.localCallbacks.get(topicName);
|
|
228
|
+
if (!callbacks || callbacks.size === 0) return;
|
|
229
|
+
const localEvent = {
|
|
230
|
+
...event,
|
|
231
|
+
id: crypto.randomUUID(),
|
|
232
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
233
|
+
deliveryAttempt: 1
|
|
234
|
+
};
|
|
235
|
+
for (const cb of [...callbacks]) {
|
|
236
|
+
try {
|
|
237
|
+
cb(
|
|
238
|
+
localEvent,
|
|
239
|
+
async () => {
|
|
240
|
+
},
|
|
241
|
+
async () => {
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error("Error delivering local event", error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
195
249
|
};
|
|
196
250
|
|
|
197
251
|
export { GoogleCloudPubSub };
|
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, 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 // Coalesces concurrent init() calls for the same subscription so racing\n // subscribers (e.g. a producer stream and a consumer observe on the same\n // run topic) share a single createTopic/createSubscription attempt.\n private inFlightInit: Record<string, Promise<Subscription | undefined>> = {};\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): Promise<Subscription | undefined> {\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n\n // Reuse an in-flight init so concurrent subscribers don't race to create the\n // same subscription. The promise is registered synchronously below (before any\n // await), so a second caller arriving during the create window reuses it.\n if (this.inFlightInit[subscriptionKey]) {\n return this.inFlightInit[subscriptionKey];\n }\n\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const initPromise = (async (): Promise<Subscription | undefined> => {\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(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch (error) {\n // The subscription may already exist: created concurrently by a racing\n // subscriber (ALREADY_EXISTS / gRPC code 6), shared by another process via\n // a group, or surviving a previous process. In all of these cases attach to\n // the existing subscription instead of failing. Ungrouped subscriptions hit\n // this on the concurrent-create race, so we must not gate it on `group`.\n const alreadyExists = (error as { code?: number } | undefined)?.code === 6;\n if (alreadyExists || 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 return undefined;\n })().finally(() => {\n delete this.inFlightInit[subscriptionKey];\n });\n\n this.inFlightInit[subscriptionKey] = initPromise;\n return initPromise;\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"]}
|
|
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;AAAA,EAIjD,cAAA,uBAAsD,GAAA,EAAI;AAAA;AAAA;AAAA;AAAA,EAI1D,eAAkE,EAAC;AAAA;AAAA;AAAA,EAGnE,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,EAAmD;AAC/E,IAAA,MAAM,kBAAkB,KAAA,GAAQ,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,SAAA;AAK1D,IAAA,IAAI,IAAA,CAAK,YAAA,CAAa,eAAe,CAAA,EAAG;AACtC,MAAA,OAAO,IAAA,CAAK,aAAa,eAAe,CAAA;AAAA,IAC1C;AAEA,IAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,mBAAA,CAAoB,SAAA,EAAW,KAAK,CAAA;AAClE,IAAA,MAAM,eAAe,YAA+C;AAClE,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,SAAS,CAAA;AAAA,MACzC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,IAAI;AACF,QAAA,MAAM,CAAC,GAAG,CAAA,GAAI,MAAM,IAAA,CAAK,OAAO,KAAA,CAAM,SAAS,CAAA,CAAE,kBAAA,CAAmB,gBAAA,EAAkB;AAAA,UACpF,qBAAA,EAAuB,IAAA;AAAA,UACvB,yBAAA,EAA2B,SAAA,KAAc,WAAA,IAAe,CAAC,CAAC;AAAA,SAC3D,CAAA;AACD,QAAA,IAAA,CAAK,mBAAA,CAAoB,eAAe,CAAA,GAAI,GAAA;AAC5C,QAAA,OAAO,GAAA;AAAA,MACT,SAAS,KAAA,EAAO;AAMd,QAAA,MAAM,aAAA,GAAiB,OAAyC,IAAA,KAAS,CAAA;AACzE,QAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,UAAA,IAAI;AACF,YAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,gBAAgB,CAAA;AACrD,YAAA,IAAA,CAAK,mBAAA,CAAoB,eAAe,CAAA,GAAI,GAAA;AAC5C,YAAA,OAAO,GAAA;AAAA,UACT,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AACA,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,GAAG,CAAE,OAAA,CAAQ,MAAM;AACjB,MAAA,OAAO,IAAA,CAAK,aAAa,eAAe,CAAA;AAAA,IAC1C,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,YAAA,CAAa,eAAe,CAAA,GAAI,WAAA;AACrC,IAAA,OAAO,WAAA;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,CACJ,SAAA,EACA,KAAA,EACA,OAAA,EACe;AACf,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;AAQA,IAAA,IAAI,SAAS,SAAA,EAAW;AACtB,MAAA,MAAM,IAAA,CAAK,YAAA,CAAa,SAAA,EAAW,KAAK,CAAA;AACxC,MAAA;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;AAKtD,IAAA,IAAI,QAAA,GAAW,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,KAAK,CAAA;AAC5C,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,QAAA,uBAAe,GAAA,EAAI;AACnB,MAAA,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,KAAA,EAAO,QAAQ,CAAA;AAAA,IACzC;AACA,IAAA,QAAA,CAAS,IAAI,EAAE,CAAA;AAGf,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;AACjE,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;AAGA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,KAAK,CAAA;AAC9C,IAAA,IAAI,UAAU,MAAA,CAAO,EAAE,CAAA,IAAK,QAAA,CAAS,SAAS,CAAA,EAAG;AAC/C,MAAA,IAAA,CAAK,cAAA,CAAe,OAAO,KAAK,CAAA;AAAA,IAClC;AAGA,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,YAAA,CAAa,SAAA,EAAmB,KAAA,EAAuD;AACnG,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,SAAS,CAAA;AACnD,IAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,IAAA,KAAS,CAAA,EAAG;AAExC,IAAA,MAAM,UAAA,GAAoB;AAAA,MACxB,GAAG,KAAA;AAAA,MACH,EAAA,EAAI,OAAO,UAAA,EAAW;AAAA,MACtB,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,eAAA,EAAiB;AAAA,KACnB;AAEA,IAAA,KAAA,MAAW,EAAA,IAAM,CAAC,GAAG,SAAS,CAAA,EAAG;AAC/B,MAAA,IAAI;AACF,QAAA,EAAA;AAAA,UACE,UAAA;AAAA,UACA,YAAY;AAAA,UAAC,CAAA;AAAA,UACb,YAAY;AAAA,UAAC;AAAA,SACf;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,gCAAgC,KAAK,CAAA;AAAA,MACrD;AAAA,IACF;AAAA,EACF;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 // `localOnly` publishes never touch Google Cloud — they are delivered to\n // same-process subscribers only. Tracks live callbacks per (normalized) topic\n // so we can fan out without going through PubSub.\n private localCallbacks: Map<string, Set<EventCallback>> = new Map();\n // Coalesces concurrent init() calls for the same subscription so racing\n // subscribers (e.g. a producer stream and a consumer observe on the same\n // run topic) share a single createTopic/createSubscription attempt.\n private inFlightInit: Record<string, Promise<Subscription | undefined>> = {};\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): Promise<Subscription | undefined> {\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n\n // Reuse an in-flight init so concurrent subscribers don't race to create the\n // same subscription. The promise is registered synchronously below (before any\n // await), so a second caller arriving during the create window reuses it.\n if (this.inFlightInit[subscriptionKey]) {\n return this.inFlightInit[subscriptionKey];\n }\n\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const initPromise = (async (): Promise<Subscription | undefined> => {\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(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch (error) {\n // The subscription may already exist: created concurrently by a racing\n // subscriber (ALREADY_EXISTS / gRPC code 6), shared by another process via\n // a group, or surviving a previous process. In all of these cases attach to\n // the existing subscription instead of failing. Ungrouped subscriptions hit\n // this on the concurrent-create race, so we must not gate it on `group`.\n const alreadyExists = (error as { code?: number } | undefined)?.code === 6;\n if (alreadyExists || 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 return undefined;\n })().finally(() => {\n delete this.inFlightInit[subscriptionKey];\n });\n\n this.inFlightInit[subscriptionKey] = initPromise;\n return initPromise;\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(\n topicName: string,\n event: Omit<Event, 'id' | 'createdAt'>,\n options?: { localOnly?: boolean },\n ): 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 // `localOnly` events stay entirely within the publishing process. They are\n // never serialized through Google Cloud, so live methods on payload values\n // (e.g. `MastraModelOutput.getFullOutput`) survive intact. The agent's\n // execution-workflow relies on this: the run result is delivered via\n // `workflows-finish` and includes the `MastraModelOutput` instance —\n // round-tripping it through Pub/Sub would strip its methods.\n if (options?.localOnly) {\n await this.deliverLocal(topicName, event);\n return;\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 // Register callback for `localOnly` delivery. Local delivery bypasses Google\n // Cloud entirely so live class instances on the payload (e.g. Date, Map,\n // Error, MastraModelOutput) keep their prototypes.\n let localSet = this.localCallbacks.get(topic);\n if (!localSet) {\n localSet = new Set();\n this.localCallbacks.set(topic, localSet);\n }\n localSet.add(cb);\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 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 // Drop from the local-delivery set; if nobody is left, tear down the bucket.\n const localSet = this.localCallbacks.get(topic);\n if (localSet?.delete(cb) && localSet.size === 0) {\n this.localCallbacks.delete(topic);\n }\n\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 /**\n * Fan a `localOnly` event out to in-process subscribers without going through\n * Google Cloud. The payload is delivered by reference, so live class instances\n * and functions on the event survive intact.\n */\n private async deliverLocal(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n const callbacks = this.localCallbacks.get(topicName);\n if (!callbacks || callbacks.size === 0) return;\n\n const localEvent: Event = {\n ...event,\n id: crypto.randomUUID(),\n createdAt: new Date(),\n deliveryAttempt: 1,\n };\n\n for (const cb of [...callbacks]) {\n try {\n cb(\n localEvent,\n async () => {},\n async () => {},\n );\n } catch (error) {\n console.error('Error delivering local event', error);\n }\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/google-cloud-pubsub",
|
|
3
|
-
"version": "1.1.1-alpha.
|
|
3
|
+
"version": "1.1.1-alpha.1",
|
|
4
4
|
"description": "Mastra Google Cloud PubSub integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
"zod": "^4.4.3"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
+
"@ai-sdk/openai-v5": "npm:@ai-sdk/openai@2.0.106",
|
|
34
|
+
"@copilotkit/aimock": "^1.29.0",
|
|
33
35
|
"@types/node": "22.19.21",
|
|
34
36
|
"@vitest/coverage-v8": "4.1.8",
|
|
35
37
|
"@vitest/ui": "4.1.8",
|
|
@@ -38,11 +40,12 @@
|
|
|
38
40
|
"tsup": "^8.5.1",
|
|
39
41
|
"typescript": "^6.0.3",
|
|
40
42
|
"vitest": "4.1.8",
|
|
41
|
-
"@internal/
|
|
43
|
+
"@internal/ai-sdk-v5": "0.0.54",
|
|
42
44
|
"@internal/types-builder": "0.0.82",
|
|
43
|
-
"@
|
|
44
|
-
"@mastra/
|
|
45
|
-
"@mastra/libsql": "1.14.
|
|
45
|
+
"@internal/lint": "0.0.107",
|
|
46
|
+
"@mastra/core": "1.46.0-alpha.4",
|
|
47
|
+
"@mastra/libsql": "1.14.1-alpha.1",
|
|
48
|
+
"@mastra/deployer": "1.46.0-alpha.4"
|
|
46
49
|
},
|
|
47
50
|
"peerDependencies": {
|
|
48
51
|
"@mastra/core": ">=1.13.2-0 <2.0.0-0"
|