@blokjs/trigger-pubsub 0.2.3 → 0.6.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/__tests__/integration/gcp-pubsub.real-emulator.test.ts +235 -0
- package/__tests__/integration/kafka-pubsub.real-kafka.test.ts +269 -0
- package/__tests__/integration/nats-pubsub.real-nats.test.ts +138 -0
- package/dist/PubSubTrigger.d.ts +43 -3
- package/dist/PubSubTrigger.js +70 -16
- package/dist/adapters/AWSSNSAdapter.d.ts +16 -0
- package/dist/adapters/AWSSNSAdapter.js +52 -9
- package/dist/adapters/AzureServiceBusAdapter.d.ts +15 -0
- package/dist/adapters/AzureServiceBusAdapter.js +44 -11
- package/dist/adapters/GCPPubSubAdapter.d.ts +16 -0
- package/dist/adapters/GCPPubSubAdapter.js +42 -8
- package/dist/adapters/KafkaPubSubAdapter.d.ts +53 -0
- package/dist/adapters/KafkaPubSubAdapter.js +168 -0
- package/dist/adapters/NATSPubSubAdapter.d.ts +52 -0
- package/dist/adapters/NATSPubSubAdapter.js +260 -0
- package/dist/adapters/RedisStreamsPubSubAdapter.d.ts +49 -0
- package/dist/adapters/RedisStreamsPubSubAdapter.js +193 -0
- package/dist/adapters/factory.d.ts +22 -0
- package/dist/adapters/factory.js +80 -0
- package/dist/index.d.ts +36 -45
- package/dist/index.js +39 -46
- package/package.json +22 -10
- package/src/PubSubTrigger.ts +84 -18
- package/src/adapters/AWSSNSAdapter.ts +76 -12
- package/src/adapters/AzureServiceBusAdapter.ts +57 -14
- package/src/adapters/GCPPubSubAdapter.ts +50 -10
- package/src/adapters/KafkaPubSubAdapter.ts +194 -0
- package/src/adapters/NATSPubSubAdapter.ts +326 -0
- package/src/adapters/RedisStreamsPubSubAdapter.ts +225 -0
- package/src/adapters/factory.test.ts +87 -0
- package/src/adapters/factory.ts +88 -0
- package/src/adapters/new-adapters.test.ts +108 -0
- package/src/index.ts +40 -41
- package/template/package.json +6 -6
- package/template/src/runner/PubSubServer.ts +2 -2
- package/template/src/workflows/messages/on-message.ts +38 -34
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.7 PR 6 — pub/sub adapter factory.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a `provider` string to a concrete `PubSubAdapter` instance.
|
|
5
|
+
* Used by `PubSubTrigger` (per-workflow provider dispatch) and by the
|
|
6
|
+
* `@blokjs/pubsub-publish` helper.
|
|
7
|
+
*
|
|
8
|
+
* Provider resolution order:
|
|
9
|
+
* 1. Explicit `provider` field on the workflow.
|
|
10
|
+
* 2. `BLOK_PUBSUB_ADAPTER` env var.
|
|
11
|
+
* 3. `"nats"` fallback (cheapest infra; matches the v0.7 plan's
|
|
12
|
+
* "default for pub/sub" recommendation).
|
|
13
|
+
*
|
|
14
|
+
* Each adapter lazy-imports its broker SDK on first use; workflows
|
|
15
|
+
* that don't use a given provider don't pay the install cost.
|
|
16
|
+
*/
|
|
17
|
+
import { AWSSNSAdapter } from "./AWSSNSAdapter";
|
|
18
|
+
import { AzureServiceBusAdapter } from "./AzureServiceBusAdapter";
|
|
19
|
+
import { GCPPubSubAdapter } from "./GCPPubSubAdapter";
|
|
20
|
+
import { KafkaPubSubAdapter } from "./KafkaPubSubAdapter";
|
|
21
|
+
import { NATSPubSubAdapter } from "./NATSPubSubAdapter";
|
|
22
|
+
import { RedisStreamsPubSubAdapter } from "./RedisStreamsPubSubAdapter";
|
|
23
|
+
export function resolveProvider(provider) {
|
|
24
|
+
if (provider)
|
|
25
|
+
return provider;
|
|
26
|
+
const envValue = process.env.BLOK_PUBSUB_ADAPTER;
|
|
27
|
+
if (envValue && isPubSubProvider(envValue))
|
|
28
|
+
return envValue;
|
|
29
|
+
return "nats";
|
|
30
|
+
}
|
|
31
|
+
function isPubSubProvider(value) {
|
|
32
|
+
return (value === "nats" ||
|
|
33
|
+
value === "redis-streams" ||
|
|
34
|
+
value === "kafka" ||
|
|
35
|
+
value === "gcp" ||
|
|
36
|
+
value === "aws" ||
|
|
37
|
+
value === "azure");
|
|
38
|
+
}
|
|
39
|
+
export function createPubSubAdapter(provider) {
|
|
40
|
+
switch (provider) {
|
|
41
|
+
case "nats":
|
|
42
|
+
return new NATSPubSubAdapter();
|
|
43
|
+
case "redis-streams":
|
|
44
|
+
return new RedisStreamsPubSubAdapter();
|
|
45
|
+
case "kafka":
|
|
46
|
+
return new KafkaPubSubAdapter();
|
|
47
|
+
case "gcp":
|
|
48
|
+
return new GCPPubSubAdapter();
|
|
49
|
+
case "aws":
|
|
50
|
+
return new AWSSNSAdapter();
|
|
51
|
+
case "azure":
|
|
52
|
+
return new AzureServiceBusAdapter();
|
|
53
|
+
default: {
|
|
54
|
+
const exhaustive = provider;
|
|
55
|
+
throw new Error(`[blok][pubsub] unknown provider "${exhaustive}". Check PubSubProviderSchema.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Process-singleton adapter pool — one instance per provider. The
|
|
61
|
+
* trigger calls `getOrCreateAdapter("nats")` once per workflow, and
|
|
62
|
+
* subsequent workflows on the same provider share the broker
|
|
63
|
+
* connection.
|
|
64
|
+
*/
|
|
65
|
+
const pool = new Map();
|
|
66
|
+
export function getOrCreateAdapter(provider) {
|
|
67
|
+
let adapter = pool.get(provider);
|
|
68
|
+
if (!adapter) {
|
|
69
|
+
adapter = createPubSubAdapter(provider);
|
|
70
|
+
pool.set(provider, adapter);
|
|
71
|
+
}
|
|
72
|
+
return adapter;
|
|
73
|
+
}
|
|
74
|
+
export function _resetAdapterPoolForTests() {
|
|
75
|
+
for (const adapter of pool.values()) {
|
|
76
|
+
void adapter.disconnect?.().catch(() => { });
|
|
77
|
+
}
|
|
78
|
+
pool.clear();
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVycy9mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUlILE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUV4RSxNQUFNLFVBQVUsZUFBZSxDQUFDLFFBQXlCO0lBQ3hELElBQUksUUFBUTtRQUFFLE9BQU8sUUFBUSxDQUFDO0lBQzlCLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLENBQUM7SUFDakQsSUFBSSxRQUFRLElBQUksZ0JBQWdCLENBQUMsUUFBUSxDQUFDO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFDNUQsT0FBTyxNQUFNLENBQUM7QUFDZixDQUFDO0FBRUQsU0FBUyxnQkFBZ0IsQ0FBQyxLQUFhO0lBQ3RDLE9BQU8sQ0FDTixLQUFLLEtBQUssTUFBTTtRQUNoQixLQUFLLEtBQUssZUFBZTtRQUN6QixLQUFLLEtBQUssT0FBTztRQUNqQixLQUFLLEtBQUssS0FBSztRQUNmLEtBQUssS0FBSyxLQUFLO1FBQ2YsS0FBSyxLQUFLLE9BQU8sQ0FDakIsQ0FBQztBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsbUJBQW1CLENBQUMsUUFBd0I7SUFDM0QsUUFBUSxRQUFRLEVBQUUsQ0FBQztRQUNsQixLQUFLLE1BQU07WUFDVixPQUFPLElBQUksaUJBQWlCLEVBQUUsQ0FBQztRQUNoQyxLQUFLLGVBQWU7WUFDbkIsT0FBTyxJQUFJLHlCQUF5QixFQUFFLENBQUM7UUFDeEMsS0FBSyxPQUFPO1lBQ1gsT0FBTyxJQUFJLGtCQUFrQixFQUFFLENBQUM7UUFDakMsS0FBSyxLQUFLO1lBQ1QsT0FBTyxJQUFJLGdCQUFnQixFQUFFLENBQUM7UUFDL0IsS0FBSyxLQUFLO1lBQ1QsT0FBTyxJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQzVCLEtBQUssT0FBTztZQUNYLE9BQU8sSUFBSSxzQkFBc0IsRUFBRSxDQUFDO1FBQ3JDLE9BQU8sQ0FBQyxDQUFDLENBQUM7WUFDVCxNQUFNLFVBQVUsR0FBVSxRQUFRLENBQUM7WUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQ0FBb0MsVUFBb0IsZ0NBQWdDLENBQUMsQ0FBQztRQUMzRyxDQUFDO0lBQ0YsQ0FBQztBQUNGLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sSUFBSSxHQUF1QyxJQUFJLEdBQUcsRUFBRSxDQUFDO0FBRTNELE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxRQUF3QjtJQUMxRCxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNkLE9BQU8sR0FBRyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDaEIsQ0FBQztBQUVELE1BQU0sVUFBVSx5QkFBeUI7SUFDeEMsS0FBSyxNQUFNLE9BQU8sSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQztRQUNyQyxLQUFLLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBQ0QsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQ2QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogdjAuNyBQUiA2IOKAlCBwdWIvc3ViIGFkYXB0ZXIgZmFjdG9yeS5cbiAqXG4gKiBSZXNvbHZlcyBhIGBwcm92aWRlcmAgc3RyaW5nIHRvIGEgY29uY3JldGUgYFB1YlN1YkFkYXB0ZXJgIGluc3RhbmNlLlxuICogVXNlZCBieSBgUHViU3ViVHJpZ2dlcmAgKHBlci13b3JrZmxvdyBwcm92aWRlciBkaXNwYXRjaCkgYW5kIGJ5IHRoZVxuICogYEBibG9ranMvcHVic3ViLXB1Ymxpc2hgIGhlbHBlci5cbiAqXG4gKiBQcm92aWRlciByZXNvbHV0aW9uIG9yZGVyOlxuICogICAxLiBFeHBsaWNpdCBgcHJvdmlkZXJgIGZpZWxkIG9uIHRoZSB3b3JrZmxvdy5cbiAqICAgMi4gYEJMT0tfUFVCU1VCX0FEQVBURVJgIGVudiB2YXIuXG4gKiAgIDMuIGBcIm5hdHNcImAgZmFsbGJhY2sgKGNoZWFwZXN0IGluZnJhOyBtYXRjaGVzIHRoZSB2MC43IHBsYW4nc1xuICogICAgICBcImRlZmF1bHQgZm9yIHB1Yi9zdWJcIiByZWNvbW1lbmRhdGlvbikuXG4gKlxuICogRWFjaCBhZGFwdGVyIGxhenktaW1wb3J0cyBpdHMgYnJva2VyIFNESyBvbiBmaXJzdCB1c2U7IHdvcmtmbG93c1xuICogdGhhdCBkb24ndCB1c2UgYSBnaXZlbiBwcm92aWRlciBkb24ndCBwYXkgdGhlIGluc3RhbGwgY29zdC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFB1YlN1YlByb3ZpZGVyIH0gZnJvbSBcIkBibG9ranMvaGVscGVyXCI7XG5pbXBvcnQgdHlwZSB7IFB1YlN1YkFkYXB0ZXIgfSBmcm9tIFwiLi4vUHViU3ViVHJpZ2dlclwiO1xuaW1wb3J0IHsgQVdTU05TQWRhcHRlciB9IGZyb20gXCIuL0FXU1NOU0FkYXB0ZXJcIjtcbmltcG9ydCB7IEF6dXJlU2VydmljZUJ1c0FkYXB0ZXIgfSBmcm9tIFwiLi9BenVyZVNlcnZpY2VCdXNBZGFwdGVyXCI7XG5pbXBvcnQgeyBHQ1BQdWJTdWJBZGFwdGVyIH0gZnJvbSBcIi4vR0NQUHViU3ViQWRhcHRlclwiO1xuaW1wb3J0IHsgS2Fma2FQdWJTdWJBZGFwdGVyIH0gZnJvbSBcIi4vS2Fma2FQdWJTdWJBZGFwdGVyXCI7XG5pbXBvcnQgeyBOQVRTUHViU3ViQWRhcHRlciB9IGZyb20gXCIuL05BVFNQdWJTdWJBZGFwdGVyXCI7XG5pbXBvcnQgeyBSZWRpc1N0cmVhbXNQdWJTdWJBZGFwdGVyIH0gZnJvbSBcIi4vUmVkaXNTdHJlYW1zUHViU3ViQWRhcHRlclwiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVByb3ZpZGVyKHByb3ZpZGVyPzogUHViU3ViUHJvdmlkZXIpOiBQdWJTdWJQcm92aWRlciB7XG5cdGlmIChwcm92aWRlcikgcmV0dXJuIHByb3ZpZGVyO1xuXHRjb25zdCBlbnZWYWx1ZSA9IHByb2Nlc3MuZW52LkJMT0tfUFVCU1VCX0FEQVBURVI7XG5cdGlmIChlbnZWYWx1ZSAmJiBpc1B1YlN1YlByb3ZpZGVyKGVudlZhbHVlKSkgcmV0dXJuIGVudlZhbHVlO1xuXHRyZXR1cm4gXCJuYXRzXCI7XG59XG5cbmZ1bmN0aW9uIGlzUHViU3ViUHJvdmlkZXIodmFsdWU6IHN0cmluZyk6IHZhbHVlIGlzIFB1YlN1YlByb3ZpZGVyIHtcblx0cmV0dXJuIChcblx0XHR2YWx1ZSA9PT0gXCJuYXRzXCIgfHxcblx0XHR2YWx1ZSA9PT0gXCJyZWRpcy1zdHJlYW1zXCIgfHxcblx0XHR2YWx1ZSA9PT0gXCJrYWZrYVwiIHx8XG5cdFx0dmFsdWUgPT09IFwiZ2NwXCIgfHxcblx0XHR2YWx1ZSA9PT0gXCJhd3NcIiB8fFxuXHRcdHZhbHVlID09PSBcImF6dXJlXCJcblx0KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVB1YlN1YkFkYXB0ZXIocHJvdmlkZXI6IFB1YlN1YlByb3ZpZGVyKTogUHViU3ViQWRhcHRlciB7XG5cdHN3aXRjaCAocHJvdmlkZXIpIHtcblx0XHRjYXNlIFwibmF0c1wiOlxuXHRcdFx0cmV0dXJuIG5ldyBOQVRTUHViU3ViQWRhcHRlcigpO1xuXHRcdGNhc2UgXCJyZWRpcy1zdHJlYW1zXCI6XG5cdFx0XHRyZXR1cm4gbmV3IFJlZGlzU3RyZWFtc1B1YlN1YkFkYXB0ZXIoKTtcblx0XHRjYXNlIFwia2Fma2FcIjpcblx0XHRcdHJldHVybiBuZXcgS2Fma2FQdWJTdWJBZGFwdGVyKCk7XG5cdFx0Y2FzZSBcImdjcFwiOlxuXHRcdFx0cmV0dXJuIG5ldyBHQ1BQdWJTdWJBZGFwdGVyKCk7XG5cdFx0Y2FzZSBcImF3c1wiOlxuXHRcdFx0cmV0dXJuIG5ldyBBV1NTTlNBZGFwdGVyKCk7XG5cdFx0Y2FzZSBcImF6dXJlXCI6XG5cdFx0XHRyZXR1cm4gbmV3IEF6dXJlU2VydmljZUJ1c0FkYXB0ZXIoKTtcblx0XHRkZWZhdWx0OiB7XG5cdFx0XHRjb25zdCBleGhhdXN0aXZlOiBuZXZlciA9IHByb3ZpZGVyO1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBbYmxva11bcHVic3ViXSB1bmtub3duIHByb3ZpZGVyIFwiJHtleGhhdXN0aXZlIGFzIHN0cmluZ31cIi4gQ2hlY2sgUHViU3ViUHJvdmlkZXJTY2hlbWEuYCk7XG5cdFx0fVxuXHR9XG59XG5cbi8qKlxuICogUHJvY2Vzcy1zaW5nbGV0b24gYWRhcHRlciBwb29sIOKAlCBvbmUgaW5zdGFuY2UgcGVyIHByb3ZpZGVyLiBUaGVcbiAqIHRyaWdnZXIgY2FsbHMgYGdldE9yQ3JlYXRlQWRhcHRlcihcIm5hdHNcIilgIG9uY2UgcGVyIHdvcmtmbG93LCBhbmRcbiAqIHN1YnNlcXVlbnQgd29ya2Zsb3dzIG9uIHRoZSBzYW1lIHByb3ZpZGVyIHNoYXJlIHRoZSBicm9rZXJcbiAqIGNvbm5lY3Rpb24uXG4gKi9cbmNvbnN0IHBvb2w6IE1hcDxQdWJTdWJQcm92aWRlciwgUHViU3ViQWRhcHRlcj4gPSBuZXcgTWFwKCk7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRPckNyZWF0ZUFkYXB0ZXIocHJvdmlkZXI6IFB1YlN1YlByb3ZpZGVyKTogUHViU3ViQWRhcHRlciB7XG5cdGxldCBhZGFwdGVyID0gcG9vbC5nZXQocHJvdmlkZXIpO1xuXHRpZiAoIWFkYXB0ZXIpIHtcblx0XHRhZGFwdGVyID0gY3JlYXRlUHViU3ViQWRhcHRlcihwcm92aWRlcik7XG5cdFx0cG9vbC5zZXQocHJvdmlkZXIsIGFkYXB0ZXIpO1xuXHR9XG5cdHJldHVybiBhZGFwdGVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gX3Jlc2V0QWRhcHRlclBvb2xGb3JUZXN0cygpOiB2b2lkIHtcblx0Zm9yIChjb25zdCBhZGFwdGVyIG9mIHBvb2wudmFsdWVzKCkpIHtcblx0XHR2b2lkIGFkYXB0ZXIuZGlzY29ubmVjdD8uKCkuY2F0Y2goKCkgPT4ge30pO1xuXHR9XG5cdHBvb2wuY2xlYXIoKTtcbn1cbiJdfQ==
|
package/dist/index.d.ts
CHANGED
|
@@ -1,55 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @blokjs/trigger-pubsub
|
|
3
3
|
*
|
|
4
|
-
* Pub/Sub-based trigger for Blok workflows.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* // ...
|
|
36
|
-
* }
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* @example Azure Service Bus
|
|
40
|
-
* ```typescript
|
|
41
|
-
* import { PubSubTrigger, AzureServiceBusAdapter } from "@blokjs/trigger-pubsub";
|
|
42
|
-
*
|
|
43
|
-
* class MyPubSubTrigger extends PubSubTrigger {
|
|
44
|
-
* protected adapter = new AzureServiceBusAdapter({
|
|
45
|
-
* connectionString: process.env.AZURE_SERVICE_BUS_CONNECTION_STRING,
|
|
46
|
-
* });
|
|
47
|
-
* // ...
|
|
4
|
+
* Pub/Sub-based trigger for Blok workflows. Supports 6 providers:
|
|
5
|
+
*
|
|
6
|
+
* - **NATS** (Core + JetStream) — cheapest infra; subject wildcards.
|
|
7
|
+
* - **Redis Streams** — when Redis is already in stack.
|
|
8
|
+
* - **Kafka** — high-throughput streaming.
|
|
9
|
+
* - **GCP Pub/Sub** — Google Cloud-locked.
|
|
10
|
+
* - **AWS SNS+SQS** — SNS fan-out → SQS queueing.
|
|
11
|
+
* - **Azure Service Bus** — Azure Service Bus.
|
|
12
|
+
*
|
|
13
|
+
* v0.7+ — pick the adapter per workflow via `trigger.pubsub.provider`.
|
|
14
|
+
* `BLOK_PUBSUB_ADAPTER` env var sets the default (falls back to NATS).
|
|
15
|
+
* Subclasses can still set `protected adapter` directly for back-
|
|
16
|
+
* compat with the pre-v0.7 single-adapter pattern.
|
|
17
|
+
*
|
|
18
|
+
* **Fan-out vs competing-consumer**: omit `consumerGroup` for fan-out
|
|
19
|
+
* (every subscriber sees every message); set it for competing-consumer
|
|
20
|
+
* (1 of N within group). One field disambiguates the two semantics.
|
|
21
|
+
*
|
|
22
|
+
* @example v0.7 — NATS subject hierarchy with JSON workflow
|
|
23
|
+
* ```json
|
|
24
|
+
* {
|
|
25
|
+
* "name": "audit-all-order-events",
|
|
26
|
+
* "trigger": {
|
|
27
|
+
* "pubsub": {
|
|
28
|
+
* "provider": "nats",
|
|
29
|
+
* "topic": "orders.>",
|
|
30
|
+
* "durable": true,
|
|
31
|
+
* "startFrom": "earliest"
|
|
32
|
+
* }
|
|
33
|
+
* },
|
|
34
|
+
* "steps": [...]
|
|
48
35
|
* }
|
|
49
36
|
* ```
|
|
50
37
|
*/
|
|
51
38
|
export { PubSubTrigger, type PubSubAdapter, type PubSubMessage, } from "./PubSubTrigger";
|
|
52
|
-
export { GCPPubSubAdapter, type GCPPubSubConfig } from "./adapters/GCPPubSubAdapter";
|
|
53
39
|
export { AWSSNSAdapter, type AWSSNSConfig } from "./adapters/AWSSNSAdapter";
|
|
54
40
|
export { AzureServiceBusAdapter, type AzureServiceBusConfig } from "./adapters/AzureServiceBusAdapter";
|
|
41
|
+
export { GCPPubSubAdapter, type GCPPubSubConfig } from "./adapters/GCPPubSubAdapter";
|
|
42
|
+
export { KafkaPubSubAdapter, type KafkaPubSubConfig } from "./adapters/KafkaPubSubAdapter";
|
|
43
|
+
export { NATSPubSubAdapter, type NATSPubSubConfig } from "./adapters/NATSPubSubAdapter";
|
|
44
|
+
export { RedisStreamsPubSubAdapter, type RedisStreamsPubSubConfig } from "./adapters/RedisStreamsPubSubAdapter";
|
|
45
|
+
export { _resetAdapterPoolForTests, createPubSubAdapter, getOrCreateAdapter, resolveProvider, } from "./adapters/factory";
|
|
55
46
|
export type { PubSubProvider, PubSubTriggerOpts, } from "@blokjs/helper";
|
package/dist/index.js
CHANGED
|
@@ -1,57 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @blokjs/trigger-pubsub
|
|
3
3
|
*
|
|
4
|
-
* Pub/Sub-based trigger for Blok workflows.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* // ...
|
|
36
|
-
* }
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* @example Azure Service Bus
|
|
40
|
-
* ```typescript
|
|
41
|
-
* import { PubSubTrigger, AzureServiceBusAdapter } from "@blokjs/trigger-pubsub";
|
|
42
|
-
*
|
|
43
|
-
* class MyPubSubTrigger extends PubSubTrigger {
|
|
44
|
-
* protected adapter = new AzureServiceBusAdapter({
|
|
45
|
-
* connectionString: process.env.AZURE_SERVICE_BUS_CONNECTION_STRING,
|
|
46
|
-
* });
|
|
47
|
-
* // ...
|
|
4
|
+
* Pub/Sub-based trigger for Blok workflows. Supports 6 providers:
|
|
5
|
+
*
|
|
6
|
+
* - **NATS** (Core + JetStream) — cheapest infra; subject wildcards.
|
|
7
|
+
* - **Redis Streams** — when Redis is already in stack.
|
|
8
|
+
* - **Kafka** — high-throughput streaming.
|
|
9
|
+
* - **GCP Pub/Sub** — Google Cloud-locked.
|
|
10
|
+
* - **AWS SNS+SQS** — SNS fan-out → SQS queueing.
|
|
11
|
+
* - **Azure Service Bus** — Azure Service Bus.
|
|
12
|
+
*
|
|
13
|
+
* v0.7+ — pick the adapter per workflow via `trigger.pubsub.provider`.
|
|
14
|
+
* `BLOK_PUBSUB_ADAPTER` env var sets the default (falls back to NATS).
|
|
15
|
+
* Subclasses can still set `protected adapter` directly for back-
|
|
16
|
+
* compat with the pre-v0.7 single-adapter pattern.
|
|
17
|
+
*
|
|
18
|
+
* **Fan-out vs competing-consumer**: omit `consumerGroup` for fan-out
|
|
19
|
+
* (every subscriber sees every message); set it for competing-consumer
|
|
20
|
+
* (1 of N within group). One field disambiguates the two semantics.
|
|
21
|
+
*
|
|
22
|
+
* @example v0.7 — NATS subject hierarchy with JSON workflow
|
|
23
|
+
* ```json
|
|
24
|
+
* {
|
|
25
|
+
* "name": "audit-all-order-events",
|
|
26
|
+
* "trigger": {
|
|
27
|
+
* "pubsub": {
|
|
28
|
+
* "provider": "nats",
|
|
29
|
+
* "topic": "orders.>",
|
|
30
|
+
* "durable": true,
|
|
31
|
+
* "startFrom": "earliest"
|
|
32
|
+
* }
|
|
33
|
+
* },
|
|
34
|
+
* "steps": [...]
|
|
48
35
|
* }
|
|
49
36
|
* ```
|
|
50
37
|
*/
|
|
51
38
|
// Core exports
|
|
52
39
|
export { PubSubTrigger, } from "./PubSubTrigger";
|
|
53
40
|
// Adapters
|
|
54
|
-
export { GCPPubSubAdapter } from "./adapters/GCPPubSubAdapter";
|
|
55
41
|
export { AWSSNSAdapter } from "./adapters/AWSSNSAdapter";
|
|
56
42
|
export { AzureServiceBusAdapter } from "./adapters/AzureServiceBusAdapter";
|
|
57
|
-
|
|
43
|
+
export { GCPPubSubAdapter } from "./adapters/GCPPubSubAdapter";
|
|
44
|
+
export { KafkaPubSubAdapter } from "./adapters/KafkaPubSubAdapter";
|
|
45
|
+
export { NATSPubSubAdapter } from "./adapters/NATSPubSubAdapter";
|
|
46
|
+
export { RedisStreamsPubSubAdapter } from "./adapters/RedisStreamsPubSubAdapter";
|
|
47
|
+
// v0.7 PR 6 — factory + pool used by PubSubTrigger and exposed for
|
|
48
|
+
// helper nodes (`@blokjs/pubsub-publish`).
|
|
49
|
+
export { _resetAdapterPoolForTests, createPubSubAdapter, getOrCreateAdapter, resolveProvider, } from "./adapters/factory";
|
|
50
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9DRztBQUVILGVBQWU7QUFDZixPQUFPLEVBQ04sYUFBYSxHQUdiLE1BQU0saUJBQWlCLENBQUM7QUFFekIsV0FBVztBQUNYLE9BQU8sRUFBRSxhQUFhLEVBQXFCLE1BQU0sMEJBQTBCLENBQUM7QUFDNUUsT0FBTyxFQUFFLHNCQUFzQixFQUE4QixNQUFNLG1DQUFtQyxDQUFDO0FBQ3ZHLE9BQU8sRUFBRSxnQkFBZ0IsRUFBd0IsTUFBTSw2QkFBNkIsQ0FBQztBQUNyRixPQUFPLEVBQUUsa0JBQWtCLEVBQTBCLE1BQU0sK0JBQStCLENBQUM7QUFDM0YsT0FBTyxFQUFFLGlCQUFpQixFQUF5QixNQUFNLDhCQUE4QixDQUFDO0FBQ3hGLE9BQU8sRUFBRSx5QkFBeUIsRUFBaUMsTUFBTSxzQ0FBc0MsQ0FBQztBQUVoSCxtRUFBbUU7QUFDbkUsMkNBQTJDO0FBQzNDLE9BQU8sRUFDTix5QkFBeUIsRUFDekIsbUJBQW1CLEVBQ25CLGtCQUFrQixFQUNsQixlQUFlLEdBQ2YsTUFBTSxvQkFBb0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGJsb2tqcy90cmlnZ2VyLXB1YnN1YlxuICpcbiAqIFB1Yi9TdWItYmFzZWQgdHJpZ2dlciBmb3IgQmxvayB3b3JrZmxvd3MuIFN1cHBvcnRzIDYgcHJvdmlkZXJzOlxuICpcbiAqICAgLSAqKk5BVFMqKiAoQ29yZSArIEpldFN0cmVhbSkg4oCUIGNoZWFwZXN0IGluZnJhOyBzdWJqZWN0IHdpbGRjYXJkcy5cbiAqICAgLSAqKlJlZGlzIFN0cmVhbXMqKiAgICAgICAgICAg4oCUIHdoZW4gUmVkaXMgaXMgYWxyZWFkeSBpbiBzdGFjay5cbiAqICAgLSAqKkthZmthKiogICAgICAgICAgICAgICAgICAg4oCUIGhpZ2gtdGhyb3VnaHB1dCBzdHJlYW1pbmcuXG4gKiAgIC0gKipHQ1AgUHViL1N1YioqICAgICAgICAgICAgIOKAlCBHb29nbGUgQ2xvdWQtbG9ja2VkLlxuICogICAtICoqQVdTIFNOUytTUVMqKiAgICAgICAgICAgICDigJQgU05TIGZhbi1vdXQg4oaSIFNRUyBxdWV1ZWluZy5cbiAqICAgLSAqKkF6dXJlIFNlcnZpY2UgQnVzKiogICAgICAg4oCUIEF6dXJlIFNlcnZpY2UgQnVzLlxuICpcbiAqIHYwLjcrIOKAlCBwaWNrIHRoZSBhZGFwdGVyIHBlciB3b3JrZmxvdyB2aWEgYHRyaWdnZXIucHVic3ViLnByb3ZpZGVyYC5cbiAqIGBCTE9LX1BVQlNVQl9BREFQVEVSYCBlbnYgdmFyIHNldHMgdGhlIGRlZmF1bHQgKGZhbGxzIGJhY2sgdG8gTkFUUykuXG4gKiBTdWJjbGFzc2VzIGNhbiBzdGlsbCBzZXQgYHByb3RlY3RlZCBhZGFwdGVyYCBkaXJlY3RseSBmb3IgYmFjay1cbiAqIGNvbXBhdCB3aXRoIHRoZSBwcmUtdjAuNyBzaW5nbGUtYWRhcHRlciBwYXR0ZXJuLlxuICpcbiAqICoqRmFuLW91dCB2cyBjb21wZXRpbmctY29uc3VtZXIqKjogb21pdCBgY29uc3VtZXJHcm91cGAgZm9yIGZhbi1vdXRcbiAqIChldmVyeSBzdWJzY3JpYmVyIHNlZXMgZXZlcnkgbWVzc2FnZSk7IHNldCBpdCBmb3IgY29tcGV0aW5nLWNvbnN1bWVyXG4gKiAoMSBvZiBOIHdpdGhpbiBncm91cCkuIE9uZSBmaWVsZCBkaXNhbWJpZ3VhdGVzIHRoZSB0d28gc2VtYW50aWNzLlxuICpcbiAqIEBleGFtcGxlIHYwLjcg4oCUIE5BVFMgc3ViamVjdCBoaWVyYXJjaHkgd2l0aCBKU09OIHdvcmtmbG93XG4gKiBgYGBqc29uXG4gKiB7XG4gKiAgIFwibmFtZVwiOiBcImF1ZGl0LWFsbC1vcmRlci1ldmVudHNcIixcbiAqICAgXCJ0cmlnZ2VyXCI6IHtcbiAqICAgICBcInB1YnN1YlwiOiB7XG4gKiAgICAgICBcInByb3ZpZGVyXCI6IFwibmF0c1wiLFxuICogICAgICAgXCJ0b3BpY1wiOiBcIm9yZGVycy4+XCIsXG4gKiAgICAgICBcImR1cmFibGVcIjogdHJ1ZSxcbiAqICAgICAgIFwic3RhcnRGcm9tXCI6IFwiZWFybGllc3RcIlxuICogICAgIH1cbiAqICAgfSxcbiAqICAgXCJzdGVwc1wiOiBbLi4uXVxuICogfVxuICogYGBgXG4gKi9cblxuLy8gQ29yZSBleHBvcnRzXG5leHBvcnQge1xuXHRQdWJTdWJUcmlnZ2VyLFxuXHR0eXBlIFB1YlN1YkFkYXB0ZXIsXG5cdHR5cGUgUHViU3ViTWVzc2FnZSxcbn0gZnJvbSBcIi4vUHViU3ViVHJpZ2dlclwiO1xuXG4vLyBBZGFwdGVyc1xuZXhwb3J0IHsgQVdTU05TQWRhcHRlciwgdHlwZSBBV1NTTlNDb25maWcgfSBmcm9tIFwiLi9hZGFwdGVycy9BV1NTTlNBZGFwdGVyXCI7XG5leHBvcnQgeyBBenVyZVNlcnZpY2VCdXNBZGFwdGVyLCB0eXBlIEF6dXJlU2VydmljZUJ1c0NvbmZpZyB9IGZyb20gXCIuL2FkYXB0ZXJzL0F6dXJlU2VydmljZUJ1c0FkYXB0ZXJcIjtcbmV4cG9ydCB7IEdDUFB1YlN1YkFkYXB0ZXIsIHR5cGUgR0NQUHViU3ViQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvR0NQUHViU3ViQWRhcHRlclwiO1xuZXhwb3J0IHsgS2Fma2FQdWJTdWJBZGFwdGVyLCB0eXBlIEthZmthUHViU3ViQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvS2Fma2FQdWJTdWJBZGFwdGVyXCI7XG5leHBvcnQgeyBOQVRTUHViU3ViQWRhcHRlciwgdHlwZSBOQVRTUHViU3ViQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvTkFUU1B1YlN1YkFkYXB0ZXJcIjtcbmV4cG9ydCB7IFJlZGlzU3RyZWFtc1B1YlN1YkFkYXB0ZXIsIHR5cGUgUmVkaXNTdHJlYW1zUHViU3ViQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvUmVkaXNTdHJlYW1zUHViU3ViQWRhcHRlclwiO1xuXG4vLyB2MC43IFBSIDYg4oCUIGZhY3RvcnkgKyBwb29sIHVzZWQgYnkgUHViU3ViVHJpZ2dlciBhbmQgZXhwb3NlZCBmb3Jcbi8vIGhlbHBlciBub2RlcyAoYEBibG9ranMvcHVic3ViLXB1Ymxpc2hgKS5cbmV4cG9ydCB7XG5cdF9yZXNldEFkYXB0ZXJQb29sRm9yVGVzdHMsXG5cdGNyZWF0ZVB1YlN1YkFkYXB0ZXIsXG5cdGdldE9yQ3JlYXRlQWRhcHRlcixcblx0cmVzb2x2ZVByb3ZpZGVyLFxufSBmcm9tIFwiLi9hZGFwdGVycy9mYWN0b3J5XCI7XG5cbi8vIFJlLWV4cG9ydCB0eXBlcyBmcm9tIGhlbHBlciBmb3IgY29udmVuaWVuY2VcbmV4cG9ydCB0eXBlIHtcblx0UHViU3ViUHJvdmlkZXIsXG5cdFB1YlN1YlRyaWdnZXJPcHRzLFxufSBmcm9tIFwiQGJsb2tqcy9oZWxwZXJcIjtcbiJdfQ==
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blokjs/trigger-pubsub",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Pub/Sub
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "Pub/Sub trigger for Blok workflows — supports NATS (Core + JetStream), Redis Streams, Kafka, GCP Pub/Sub, AWS SNS+SQS, and Azure Service Bus.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"author": "Deskree Technologies Inc.",
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@blokjs/helper": "^0.
|
|
18
|
-
"@blokjs/runner": "^0.
|
|
19
|
-
"@blokjs/shared": "^0.
|
|
17
|
+
"@blokjs/helper": "^0.6.1",
|
|
18
|
+
"@blokjs/runner": "^0.6.1",
|
|
19
|
+
"@blokjs/shared": "^0.6.1",
|
|
20
20
|
"@opentelemetry/api": "^1.9.0",
|
|
21
21
|
"uuid": "^11.1.0"
|
|
22
22
|
},
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"vitest": "^4.0.18"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@google-cloud/pubsub": "^5.0.0",
|
|
31
30
|
"@aws-sdk/client-sns": "^3.980.0",
|
|
32
31
|
"@aws-sdk/client-sqs": "^3.980.0",
|
|
33
|
-
"@azure/service-bus": "^7.9.5"
|
|
32
|
+
"@azure/service-bus": "^7.9.5",
|
|
33
|
+
"@google-cloud/pubsub": "^5.0.0",
|
|
34
|
+
"ioredis": "^5.9.2",
|
|
35
|
+
"kafkajs": "^2.2.0",
|
|
36
|
+
"nats": "^2.29.0"
|
|
34
37
|
},
|
|
35
38
|
"peerDependenciesMeta": {
|
|
36
|
-
"@google-cloud/pubsub": {
|
|
37
|
-
"optional": true
|
|
38
|
-
},
|
|
39
39
|
"@aws-sdk/client-sns": {
|
|
40
40
|
"optional": true
|
|
41
41
|
},
|
|
@@ -44,6 +44,18 @@
|
|
|
44
44
|
},
|
|
45
45
|
"@azure/service-bus": {
|
|
46
46
|
"optional": true
|
|
47
|
+
},
|
|
48
|
+
"@google-cloud/pubsub": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"ioredis": {
|
|
52
|
+
"optional": true
|
|
53
|
+
},
|
|
54
|
+
"kafkajs": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"nats": {
|
|
58
|
+
"optional": true
|
|
47
59
|
}
|
|
48
60
|
},
|
|
49
61
|
"private": false,
|
package/src/PubSubTrigger.ts
CHANGED
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
import type { HelperResponse, PubSubProvider, PubSubTriggerOpts } from "@blokjs/helper";
|
|
22
22
|
import {
|
|
23
|
+
type BlokService,
|
|
23
24
|
DefaultLogger,
|
|
24
25
|
type GlobalOptions,
|
|
25
|
-
type BlokService,
|
|
26
26
|
NodeMap,
|
|
27
27
|
TriggerBase,
|
|
28
28
|
type TriggerResponse,
|
|
@@ -74,6 +74,18 @@ export interface PubSubAdapter {
|
|
|
74
74
|
/** Unsubscribe from a topic */
|
|
75
75
|
unsubscribe(subscription: string): Promise<void>;
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* v0.7 PR 6 — publish a single message to a topic. Used by the
|
|
79
|
+
* `@blokjs/pubsub-publish` helper and any workflow that fan-outs
|
|
80
|
+
* events to subscribers. Provider-portable: each adapter wraps its
|
|
81
|
+
* native producer client.
|
|
82
|
+
*
|
|
83
|
+
* Optional `partitionKey` / `orderingKey` is honored by providers
|
|
84
|
+
* that support per-key ordering (Kafka, GCP Pub/Sub ordered
|
|
85
|
+
* delivery). Ignored otherwise.
|
|
86
|
+
*/
|
|
87
|
+
publish(topic: string, payload: unknown, opts?: { partitionKey?: string; orderingKey?: string }): Promise<void>;
|
|
88
|
+
|
|
77
89
|
/** Check if connected */
|
|
78
90
|
isConnected(): boolean;
|
|
79
91
|
|
|
@@ -107,7 +119,22 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
107
119
|
process.env.PROJECT_VERSION || "0.0.1",
|
|
108
120
|
);
|
|
109
121
|
protected readonly logger = new DefaultLogger();
|
|
110
|
-
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* v0.7 PR 6 — back-compat default adapter. When subclasses set
|
|
125
|
+
* `protected adapter = new GCPPubSubAdapter()` (pre-v0.7 pattern),
|
|
126
|
+
* ALL workflows route through it regardless of their `provider`
|
|
127
|
+
* field. When unset, each workflow's `provider` is resolved via
|
|
128
|
+
* the factory.
|
|
129
|
+
*/
|
|
130
|
+
protected adapter?: PubSubAdapter;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* v0.7 PR 6 — adapter pool, keyed by provider. Populated lazily in
|
|
134
|
+
* `listen()` as workflows are matched to providers. Drained in
|
|
135
|
+
* `stop()`. One adapter (one broker connection) per provider.
|
|
136
|
+
*/
|
|
137
|
+
protected adapterPool: Map<string, PubSubAdapter> = new Map();
|
|
111
138
|
|
|
112
139
|
// Subclasses provide these
|
|
113
140
|
protected abstract nodes: Record<string, BlokService<unknown>>;
|
|
@@ -143,10 +170,6 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
143
170
|
this.loadWorkflows();
|
|
144
171
|
|
|
145
172
|
try {
|
|
146
|
-
// Connect to pub/sub system
|
|
147
|
-
await this.adapter.connect();
|
|
148
|
-
this.logger.log(`Connected to ${this.adapter.provider} pub/sub system`);
|
|
149
|
-
|
|
150
173
|
// Find all workflows with pub/sub triggers
|
|
151
174
|
const pubsubWorkflows = this.getPubSubWorkflows();
|
|
152
175
|
|
|
@@ -155,14 +178,17 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
155
178
|
return this.endCounter(startTime);
|
|
156
179
|
}
|
|
157
180
|
|
|
158
|
-
// Subscribe to each topic
|
|
181
|
+
// Subscribe to each topic via the adapter that owns its
|
|
182
|
+
// provider. Per-workflow `provider` field with subclass-
|
|
183
|
+
// adapter back-compat (handled in resolveAdapterForWorkflow).
|
|
159
184
|
for (const workflow of pubsubWorkflows) {
|
|
160
185
|
const config = workflow.config.trigger?.pubsub as PubSubTriggerOpts;
|
|
186
|
+
const adapter = await this.resolveAdapterForWorkflow(config);
|
|
161
187
|
this.logger.log(
|
|
162
|
-
`Subscribing to topic: ${config.topic}
|
|
188
|
+
`Subscribing to topic: ${config.topic} via ${adapter.provider} (subscription: ${config.subscription ?? "<auto>"}, group: ${config.consumerGroup ?? "<fan-out>"})`,
|
|
163
189
|
);
|
|
164
190
|
|
|
165
|
-
await
|
|
191
|
+
await adapter.subscribe(config, async (message) => {
|
|
166
192
|
await this.handleMessage(message, workflow, config);
|
|
167
193
|
});
|
|
168
194
|
}
|
|
@@ -182,13 +208,53 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
182
208
|
}
|
|
183
209
|
|
|
184
210
|
/**
|
|
185
|
-
* Stop the pub/sub subscriber
|
|
211
|
+
* Stop the pub/sub subscriber — drains every adapter in the pool
|
|
212
|
+
* plus the subclass-set adapter (if any).
|
|
186
213
|
*/
|
|
187
214
|
async stop(): Promise<void> {
|
|
188
|
-
|
|
215
|
+
for (const adapter of this.adapterPool.values()) {
|
|
216
|
+
try {
|
|
217
|
+
await adapter.disconnect();
|
|
218
|
+
} catch (err) {
|
|
219
|
+
this.logger.error(`[blok][pubsub] disconnect failed: ${(err as Error).message}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
this.adapterPool.clear();
|
|
189
223
|
this.logger.log("Pub/Sub trigger stopped");
|
|
190
224
|
}
|
|
191
225
|
|
|
226
|
+
/**
|
|
227
|
+
* v0.7 PR 6 — pick the adapter for a workflow's `provider` field.
|
|
228
|
+
*
|
|
229
|
+
* Resolution order:
|
|
230
|
+
* 1. Subclass-set `this.adapter` (back-compat).
|
|
231
|
+
* 2. Per-workflow `provider` field via the factory.
|
|
232
|
+
* 3. `BLOK_PUBSUB_ADAPTER` env var.
|
|
233
|
+
* 4. `"nats"` fallback.
|
|
234
|
+
*
|
|
235
|
+
* Adapters are connected on first use and pooled per provider.
|
|
236
|
+
*/
|
|
237
|
+
protected async resolveAdapterForWorkflow(config: PubSubTriggerOpts): Promise<PubSubAdapter> {
|
|
238
|
+
if (this.adapter) {
|
|
239
|
+
if (!this.adapter.isConnected()) {
|
|
240
|
+
await this.adapter.connect();
|
|
241
|
+
this.logger.log(`Connected to ${this.adapter.provider} pub/sub system (subclass adapter)`);
|
|
242
|
+
}
|
|
243
|
+
this.adapterPool.set(this.adapter.provider, this.adapter);
|
|
244
|
+
return this.adapter;
|
|
245
|
+
}
|
|
246
|
+
const { resolveProvider, createPubSubAdapter } = await import("./adapters/factory");
|
|
247
|
+
const provider = resolveProvider(config.provider);
|
|
248
|
+
let adapter = this.adapterPool.get(provider);
|
|
249
|
+
if (!adapter) {
|
|
250
|
+
adapter = createPubSubAdapter(provider);
|
|
251
|
+
await adapter.connect();
|
|
252
|
+
this.logger.log(`Connected to ${adapter.provider} pub/sub system`);
|
|
253
|
+
this.adapterPool.set(provider, adapter);
|
|
254
|
+
}
|
|
255
|
+
return adapter;
|
|
256
|
+
}
|
|
257
|
+
|
|
192
258
|
protected override async onHmrWorkflowChange(): Promise<void> {
|
|
193
259
|
this.logger.log("[HMR] Pub/Sub workflow changed, reloading...");
|
|
194
260
|
await this.waitForInFlightRequests();
|
|
@@ -263,7 +329,7 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
263
329
|
|
|
264
330
|
// Store message metadata in context
|
|
265
331
|
if (!ctx.vars) ctx.vars = {};
|
|
266
|
-
ctx.vars
|
|
332
|
+
ctx.vars._pubsub_message = {
|
|
267
333
|
topic: message.topic,
|
|
268
334
|
subscription: message.subscription || "",
|
|
269
335
|
publishTime: message.publishTime?.toISOString() ?? "",
|
|
@@ -280,8 +346,8 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
280
346
|
span.setAttribute("success", true);
|
|
281
347
|
span.setAttribute("message_id", id);
|
|
282
348
|
span.setAttribute("topic", config.topic);
|
|
283
|
-
span.setAttribute("subscription", config.subscription);
|
|
284
|
-
span.setAttribute("provider", config.provider);
|
|
349
|
+
span.setAttribute("subscription", config.subscription ?? "<auto>");
|
|
350
|
+
span.setAttribute("provider", config.provider ?? "<default>");
|
|
285
351
|
span.setAttribute("elapsed_ms", end - start);
|
|
286
352
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
287
353
|
|
|
@@ -289,8 +355,8 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
289
355
|
pubsubMessages.add(1, {
|
|
290
356
|
env: process.env.NODE_ENV,
|
|
291
357
|
topic: config.topic,
|
|
292
|
-
subscription: config.subscription,
|
|
293
|
-
provider: config.provider,
|
|
358
|
+
subscription: config.subscription ?? "<auto>",
|
|
359
|
+
provider: config.provider ?? "<default>",
|
|
294
360
|
workflow_name: this.configuration.name,
|
|
295
361
|
success: "true",
|
|
296
362
|
});
|
|
@@ -314,8 +380,8 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
314
380
|
pubsubErrors.add(1, {
|
|
315
381
|
env: process.env.NODE_ENV,
|
|
316
382
|
topic: config.topic,
|
|
317
|
-
subscription: config.subscription,
|
|
318
|
-
provider: config.provider,
|
|
383
|
+
subscription: config.subscription ?? "<auto>",
|
|
384
|
+
provider: config.provider ?? "<default>",
|
|
319
385
|
workflow_name: this.configuration?.name || "unknown",
|
|
320
386
|
});
|
|
321
387
|
|