@blokjs/trigger-pubsub 0.2.2 → 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 -4
- package/dist/PubSubTrigger.js +74 -21
- 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 +89 -24
- 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,18 +119,27 @@ 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>>;
|
|
114
141
|
protected abstract workflows: Record<string, HelperResponse>;
|
|
115
142
|
|
|
116
|
-
constructor() {
|
|
117
|
-
super();
|
|
118
|
-
this.loadNodes();
|
|
119
|
-
this.loadWorkflows();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
143
|
/**
|
|
123
144
|
* Load nodes into the node map
|
|
124
145
|
*/
|
|
@@ -143,11 +164,12 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
143
164
|
async listen(): Promise<number> {
|
|
144
165
|
const startTime = this.startCounter();
|
|
145
166
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
167
|
+
// Initialize nodes and workflows (called here because subclass properties
|
|
168
|
+
// aren't available in parent constructor)
|
|
169
|
+
this.loadNodes();
|
|
170
|
+
this.loadWorkflows();
|
|
150
171
|
|
|
172
|
+
try {
|
|
151
173
|
// Find all workflows with pub/sub triggers
|
|
152
174
|
const pubsubWorkflows = this.getPubSubWorkflows();
|
|
153
175
|
|
|
@@ -156,14 +178,17 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
156
178
|
return this.endCounter(startTime);
|
|
157
179
|
}
|
|
158
180
|
|
|
159
|
-
// 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).
|
|
160
184
|
for (const workflow of pubsubWorkflows) {
|
|
161
185
|
const config = workflow.config.trigger?.pubsub as PubSubTriggerOpts;
|
|
186
|
+
const adapter = await this.resolveAdapterForWorkflow(config);
|
|
162
187
|
this.logger.log(
|
|
163
|
-
`Subscribing to topic: ${config.topic}
|
|
188
|
+
`Subscribing to topic: ${config.topic} via ${adapter.provider} (subscription: ${config.subscription ?? "<auto>"}, group: ${config.consumerGroup ?? "<fan-out>"})`,
|
|
164
189
|
);
|
|
165
190
|
|
|
166
|
-
await
|
|
191
|
+
await adapter.subscribe(config, async (message) => {
|
|
167
192
|
await this.handleMessage(message, workflow, config);
|
|
168
193
|
});
|
|
169
194
|
}
|
|
@@ -183,13 +208,53 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
183
208
|
}
|
|
184
209
|
|
|
185
210
|
/**
|
|
186
|
-
* 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).
|
|
187
213
|
*/
|
|
188
214
|
async stop(): Promise<void> {
|
|
189
|
-
|
|
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();
|
|
190
223
|
this.logger.log("Pub/Sub trigger stopped");
|
|
191
224
|
}
|
|
192
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
|
+
|
|
193
258
|
protected override async onHmrWorkflowChange(): Promise<void> {
|
|
194
259
|
this.logger.log("[HMR] Pub/Sub workflow changed, reloading...");
|
|
195
260
|
await this.waitForInFlightRequests();
|
|
@@ -264,7 +329,7 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
264
329
|
|
|
265
330
|
// Store message metadata in context
|
|
266
331
|
if (!ctx.vars) ctx.vars = {};
|
|
267
|
-
ctx.vars
|
|
332
|
+
ctx.vars._pubsub_message = {
|
|
268
333
|
topic: message.topic,
|
|
269
334
|
subscription: message.subscription || "",
|
|
270
335
|
publishTime: message.publishTime?.toISOString() ?? "",
|
|
@@ -281,8 +346,8 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
281
346
|
span.setAttribute("success", true);
|
|
282
347
|
span.setAttribute("message_id", id);
|
|
283
348
|
span.setAttribute("topic", config.topic);
|
|
284
|
-
span.setAttribute("subscription", config.subscription);
|
|
285
|
-
span.setAttribute("provider", config.provider);
|
|
349
|
+
span.setAttribute("subscription", config.subscription ?? "<auto>");
|
|
350
|
+
span.setAttribute("provider", config.provider ?? "<default>");
|
|
286
351
|
span.setAttribute("elapsed_ms", end - start);
|
|
287
352
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
288
353
|
|
|
@@ -290,8 +355,8 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
290
355
|
pubsubMessages.add(1, {
|
|
291
356
|
env: process.env.NODE_ENV,
|
|
292
357
|
topic: config.topic,
|
|
293
|
-
subscription: config.subscription,
|
|
294
|
-
provider: config.provider,
|
|
358
|
+
subscription: config.subscription ?? "<auto>",
|
|
359
|
+
provider: config.provider ?? "<default>",
|
|
295
360
|
workflow_name: this.configuration.name,
|
|
296
361
|
success: "true",
|
|
297
362
|
});
|
|
@@ -315,8 +380,8 @@ export abstract class PubSubTrigger extends TriggerBase {
|
|
|
315
380
|
pubsubErrors.add(1, {
|
|
316
381
|
env: process.env.NODE_ENV,
|
|
317
382
|
topic: config.topic,
|
|
318
|
-
subscription: config.subscription,
|
|
319
|
-
provider: config.provider,
|
|
383
|
+
subscription: config.subscription ?? "<auto>",
|
|
384
|
+
provider: config.provider ?? "<default>",
|
|
320
385
|
workflow_name: this.configuration?.name || "unknown",
|
|
321
386
|
});
|
|
322
387
|
|