@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,88 @@
|
|
|
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
|
+
|
|
18
|
+
import type { PubSubProvider } from "@blokjs/helper";
|
|
19
|
+
import type { PubSubAdapter } from "../PubSubTrigger";
|
|
20
|
+
import { AWSSNSAdapter } from "./AWSSNSAdapter";
|
|
21
|
+
import { AzureServiceBusAdapter } from "./AzureServiceBusAdapter";
|
|
22
|
+
import { GCPPubSubAdapter } from "./GCPPubSubAdapter";
|
|
23
|
+
import { KafkaPubSubAdapter } from "./KafkaPubSubAdapter";
|
|
24
|
+
import { NATSPubSubAdapter } from "./NATSPubSubAdapter";
|
|
25
|
+
import { RedisStreamsPubSubAdapter } from "./RedisStreamsPubSubAdapter";
|
|
26
|
+
|
|
27
|
+
export function resolveProvider(provider?: PubSubProvider): PubSubProvider {
|
|
28
|
+
if (provider) return provider;
|
|
29
|
+
const envValue = process.env.BLOK_PUBSUB_ADAPTER;
|
|
30
|
+
if (envValue && isPubSubProvider(envValue)) return envValue;
|
|
31
|
+
return "nats";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isPubSubProvider(value: string): value is PubSubProvider {
|
|
35
|
+
return (
|
|
36
|
+
value === "nats" ||
|
|
37
|
+
value === "redis-streams" ||
|
|
38
|
+
value === "kafka" ||
|
|
39
|
+
value === "gcp" ||
|
|
40
|
+
value === "aws" ||
|
|
41
|
+
value === "azure"
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function createPubSubAdapter(provider: PubSubProvider): PubSubAdapter {
|
|
46
|
+
switch (provider) {
|
|
47
|
+
case "nats":
|
|
48
|
+
return new NATSPubSubAdapter();
|
|
49
|
+
case "redis-streams":
|
|
50
|
+
return new RedisStreamsPubSubAdapter();
|
|
51
|
+
case "kafka":
|
|
52
|
+
return new KafkaPubSubAdapter();
|
|
53
|
+
case "gcp":
|
|
54
|
+
return new GCPPubSubAdapter();
|
|
55
|
+
case "aws":
|
|
56
|
+
return new AWSSNSAdapter();
|
|
57
|
+
case "azure":
|
|
58
|
+
return new AzureServiceBusAdapter();
|
|
59
|
+
default: {
|
|
60
|
+
const exhaustive: never = provider;
|
|
61
|
+
throw new Error(`[blok][pubsub] unknown provider "${exhaustive as string}". Check PubSubProviderSchema.`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Process-singleton adapter pool — one instance per provider. The
|
|
68
|
+
* trigger calls `getOrCreateAdapter("nats")` once per workflow, and
|
|
69
|
+
* subsequent workflows on the same provider share the broker
|
|
70
|
+
* connection.
|
|
71
|
+
*/
|
|
72
|
+
const pool: Map<PubSubProvider, PubSubAdapter> = new Map();
|
|
73
|
+
|
|
74
|
+
export function getOrCreateAdapter(provider: PubSubProvider): PubSubAdapter {
|
|
75
|
+
let adapter = pool.get(provider);
|
|
76
|
+
if (!adapter) {
|
|
77
|
+
adapter = createPubSubAdapter(provider);
|
|
78
|
+
pool.set(provider, adapter);
|
|
79
|
+
}
|
|
80
|
+
return adapter;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function _resetAdapterPoolForTests(): void {
|
|
84
|
+
for (const adapter of pool.values()) {
|
|
85
|
+
void adapter.disconnect?.().catch(() => {});
|
|
86
|
+
}
|
|
87
|
+
pool.clear();
|
|
88
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smoke tests for the v0.7 PR 6 pub/sub adapters (NATS, Redis
|
|
3
|
+
* Streams, Kafka) plus the v0.7 publish() backfill on the existing
|
|
4
|
+
* 3 (GCP, AWS, Azure). Boundary-only — constructor, provider name,
|
|
5
|
+
* initial state, `disconnect()` before connect.
|
|
6
|
+
*
|
|
7
|
+
* Live broker round-trips need docker-compose CI (see PR 6 plan,
|
|
8
|
+
* deferred to follow-up).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
|
|
13
|
+
import { AWSSNSAdapter } from "./AWSSNSAdapter";
|
|
14
|
+
import { AzureServiceBusAdapter } from "./AzureServiceBusAdapter";
|
|
15
|
+
import { GCPPubSubAdapter } from "./GCPPubSubAdapter";
|
|
16
|
+
import { KafkaPubSubAdapter } from "./KafkaPubSubAdapter";
|
|
17
|
+
import { NATSPubSubAdapter } from "./NATSPubSubAdapter";
|
|
18
|
+
import { RedisStreamsPubSubAdapter } from "./RedisStreamsPubSubAdapter";
|
|
19
|
+
|
|
20
|
+
describe("NATSPubSubAdapter — v0.7 PR 6", () => {
|
|
21
|
+
it("reports provider 'nats'", () => {
|
|
22
|
+
expect(new NATSPubSubAdapter().provider).toBe("nats");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("is not connected before connect()", () => {
|
|
26
|
+
expect(new NATSPubSubAdapter().isConnected()).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("disconnect() before connect is a no-op", async () => {
|
|
30
|
+
await expect(new NATSPubSubAdapter().disconnect()).resolves.toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("reads server list from NATS_SERVERS env var", () => {
|
|
34
|
+
process.env.NATS_SERVERS = "nats-a:4222,nats-b:4222";
|
|
35
|
+
const adapter = new NATSPubSubAdapter();
|
|
36
|
+
expect((adapter as unknown as { config: { servers: string[] } }).config.servers).toEqual([
|
|
37
|
+
"nats-a:4222",
|
|
38
|
+
"nats-b:4222",
|
|
39
|
+
]);
|
|
40
|
+
process.env.NATS_SERVERS = undefined;
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("RedisStreamsPubSubAdapter — v0.7 PR 6", () => {
|
|
45
|
+
it("reports provider 'redis-streams'", () => {
|
|
46
|
+
expect(new RedisStreamsPubSubAdapter().provider).toBe("redis-streams");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("is not connected before connect()", () => {
|
|
50
|
+
expect(new RedisStreamsPubSubAdapter().isConnected()).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("disconnect() before connect is a no-op", async () => {
|
|
54
|
+
await expect(new RedisStreamsPubSubAdapter().disconnect()).resolves.toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("generates a unique consumer name per instance (fan-out isolation)", () => {
|
|
58
|
+
const a = new RedisStreamsPubSubAdapter();
|
|
59
|
+
const b = new RedisStreamsPubSubAdapter();
|
|
60
|
+
expect((a as unknown as { consumerName: string }).consumerName).not.toBe(
|
|
61
|
+
(b as unknown as { consumerName: string }).consumerName,
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("KafkaPubSubAdapter — v0.7 PR 6", () => {
|
|
67
|
+
it("reports provider 'kafka'", () => {
|
|
68
|
+
expect(new KafkaPubSubAdapter().provider).toBe("kafka");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("is not connected before connect()", () => {
|
|
72
|
+
expect(new KafkaPubSubAdapter().isConnected()).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("disconnect() before connect is a no-op", async () => {
|
|
76
|
+
await expect(new KafkaPubSubAdapter().disconnect()).resolves.toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("honors the explicit broker list override", () => {
|
|
80
|
+
const adapter = new KafkaPubSubAdapter({ brokers: ["kafka-prod:9092"] });
|
|
81
|
+
expect((adapter as unknown as { config: { brokers: string[] } }).config.brokers).toEqual(["kafka-prod:9092"]);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe("Existing adapters — provider names + publish() surface (v0.7 PR 6 backfill)", () => {
|
|
86
|
+
it("GCPPubSubAdapter reports provider 'gcp'", () => {
|
|
87
|
+
expect(new GCPPubSubAdapter().provider).toBe("gcp");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("AWSSNSAdapter reports provider 'aws'", () => {
|
|
91
|
+
expect(new AWSSNSAdapter().provider).toBe("aws");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("AzureServiceBusAdapter reports provider 'azure'", () => {
|
|
95
|
+
const adapter = new AzureServiceBusAdapter({
|
|
96
|
+
connectionString: "Endpoint=sb://example.servicebus.windows.net/;...",
|
|
97
|
+
});
|
|
98
|
+
expect(adapter.provider).toBe("azure");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("all three now expose a publish() method (added in PR 6)", () => {
|
|
102
|
+
expect(typeof new GCPPubSubAdapter().publish).toBe("function");
|
|
103
|
+
expect(typeof new AWSSNSAdapter().publish).toBe("function");
|
|
104
|
+
expect(
|
|
105
|
+
typeof new AzureServiceBusAdapter({ connectionString: "Endpoint=sb://x.servicebus.windows.net/;Y" }).publish,
|
|
106
|
+
).toBe("function");
|
|
107
|
+
});
|
|
108
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,50 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @blokjs/trigger-pubsub
|
|
3
3
|
*
|
|
4
|
-
* Pub/Sub-based trigger for Blok workflows.
|
|
5
|
-
* Supports multiple pub/sub providers:
|
|
6
|
-
* - Google Cloud Pub/Sub
|
|
7
|
-
* - AWS SNS/SQS
|
|
8
|
-
* - Azure Service Bus
|
|
4
|
+
* Pub/Sub-based trigger for Blok workflows. Supports 6 providers:
|
|
9
5
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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.
|
|
13
12
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* const trigger = new MyPubSubTrigger();
|
|
24
|
-
* await trigger.listen();
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* @example AWS SNS/SQS
|
|
28
|
-
* ```typescript
|
|
29
|
-
* import { PubSubTrigger, AWSSNSAdapter } from "@blokjs/trigger-pubsub";
|
|
30
|
-
*
|
|
31
|
-
* class MyPubSubTrigger extends PubSubTrigger {
|
|
32
|
-
* protected adapter = new AWSSNSAdapter({
|
|
33
|
-
* region: "us-east-1",
|
|
34
|
-
* });
|
|
35
|
-
* // ...
|
|
36
|
-
* }
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* @example Azure Service Bus
|
|
40
|
-
* ```typescript
|
|
41
|
-
* import { PubSubTrigger, AzureServiceBusAdapter } from "@blokjs/trigger-pubsub";
|
|
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.
|
|
42
21
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
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
|
*/
|
|
@@ -57,9 +44,21 @@ export {
|
|
|
57
44
|
} from "./PubSubTrigger";
|
|
58
45
|
|
|
59
46
|
// Adapters
|
|
60
|
-
export { GCPPubSubAdapter, type GCPPubSubConfig } from "./adapters/GCPPubSubAdapter";
|
|
61
47
|
export { AWSSNSAdapter, type AWSSNSConfig } from "./adapters/AWSSNSAdapter";
|
|
62
48
|
export { AzureServiceBusAdapter, type AzureServiceBusConfig } from "./adapters/AzureServiceBusAdapter";
|
|
49
|
+
export { GCPPubSubAdapter, type GCPPubSubConfig } from "./adapters/GCPPubSubAdapter";
|
|
50
|
+
export { KafkaPubSubAdapter, type KafkaPubSubConfig } from "./adapters/KafkaPubSubAdapter";
|
|
51
|
+
export { NATSPubSubAdapter, type NATSPubSubConfig } from "./adapters/NATSPubSubAdapter";
|
|
52
|
+
export { RedisStreamsPubSubAdapter, type RedisStreamsPubSubConfig } from "./adapters/RedisStreamsPubSubAdapter";
|
|
53
|
+
|
|
54
|
+
// v0.7 PR 6 — factory + pool used by PubSubTrigger and exposed for
|
|
55
|
+
// helper nodes (`@blokjs/pubsub-publish`).
|
|
56
|
+
export {
|
|
57
|
+
_resetAdapterPoolForTests,
|
|
58
|
+
createPubSubAdapter,
|
|
59
|
+
getOrCreateAdapter,
|
|
60
|
+
resolveProvider,
|
|
61
|
+
} from "./adapters/factory";
|
|
63
62
|
|
|
64
63
|
// Re-export types from helper for convenience
|
|
65
64
|
export type {
|
package/template/package.json
CHANGED
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"vitest": "^4.0.18"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@blokjs/api-call": "^0.
|
|
29
|
-
"@blokjs/helper": "^0.
|
|
30
|
-
"@blokjs/if-else": "^0.
|
|
31
|
-
"@blokjs/runner": "^0.
|
|
32
|
-
"@blokjs/shared": "^0.
|
|
33
|
-
"@blokjs/trigger-pubsub": "^0.
|
|
28
|
+
"@blokjs/api-call": "^0.6.1",
|
|
29
|
+
"@blokjs/helper": "^0.6.1",
|
|
30
|
+
"@blokjs/if-else": "^0.6.1",
|
|
31
|
+
"@blokjs/runner": "^0.6.1",
|
|
32
|
+
"@blokjs/shared": "^0.6.1",
|
|
33
|
+
"@blokjs/trigger-pubsub": "^0.6.1",
|
|
34
34
|
"@opentelemetry/api": "^1.9.0",
|
|
35
35
|
"@opentelemetry/exporter-prometheus": "^0.57.2",
|
|
36
36
|
"@opentelemetry/resources": "^1.30.1",
|
|
@@ -34,6 +34,6 @@ export default class PubSubServer extends PubSubTrigger {
|
|
|
34
34
|
projectId: process.env.GCP_PROJECT_ID || "my-project",
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
protected nodes = nodes;
|
|
38
|
-
protected workflows = workflows;
|
|
37
|
+
protected nodes: Record<string, import("@blokjs/runner").BlokService<unknown>> = nodes;
|
|
38
|
+
protected workflows: Record<string, import("@blokjs/helper").HelperResponse> = workflows;
|
|
39
39
|
}
|
|
@@ -1,44 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { workflow } from "@blokjs/helper";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Example Pub/Sub workflow
|
|
4
|
+
* Example Pub/Sub workflow — fires when a message arrives on a subscription.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* Message payload + metadata on ctx.request:
|
|
7
|
+
* - ctx.request.body — the message payload
|
|
8
|
+
* - ctx.request.headers — message attributes
|
|
9
|
+
* - ctx.request.params.topic — topic name
|
|
10
|
+
* - ctx.request.params.subscription — subscription name
|
|
11
|
+
* - ctx.request.params.messageId — unique message ID
|
|
12
|
+
* - ctx.vars._pubsub_message — full broker metadata
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* Pick a provider in the trigger config:
|
|
15
|
+
* provider: "gcp" | "aws" | "azure"
|
|
16
|
+
*
|
|
17
|
+
* v2 reliability knobs available on each step (uncomment to use):
|
|
18
|
+
* idempotencyKey: "$.req.params.messageId" — at-most-once delivery semantics
|
|
19
|
+
* retry: { maxAttempts: 3 } — retry on transient failures
|
|
18
20
|
*/
|
|
19
|
-
|
|
21
|
+
export default workflow({
|
|
20
22
|
name: "On Pub/Sub Message",
|
|
21
23
|
version: "1.0.0",
|
|
22
24
|
description: "Handles incoming Pub/Sub messages",
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
trigger: {
|
|
26
|
+
pubsub: {
|
|
27
|
+
provider: "gcp",
|
|
28
|
+
topic: "my-topic",
|
|
29
|
+
subscription: "my-subscription",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
steps: [
|
|
33
|
+
{
|
|
34
|
+
id: "log-message",
|
|
35
|
+
use: "@blokjs/api-call",
|
|
36
|
+
type: "module",
|
|
37
|
+
inputs: {
|
|
38
|
+
url: "https://httpbin.org/post",
|
|
39
|
+
method: "POST",
|
|
40
|
+
body: {
|
|
41
|
+
message: "js/ctx.request.body",
|
|
42
|
+
topic: "js/ctx.request.params.topic",
|
|
43
|
+
messageId: "js/ctx.request.params.messageId",
|
|
44
|
+
},
|
|
40
45
|
},
|
|
41
46
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export default step;
|
|
47
|
+
],
|
|
48
|
+
});
|