@ductape/mcp 0.1.40 → 0.1.42
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/dist/index.js +77 -43
- package/package.json +1 -1
- package/src/index.ts +74 -40
package/dist/index.js
CHANGED
|
@@ -249,21 +249,46 @@ CONTROLLER DECORATORS:
|
|
|
249
249
|
@Webhook.Register(...) — register a webhook consumer URL
|
|
250
250
|
@Webhook.Consumer(...) — mark inbound handler for forwarded webhook payloads
|
|
251
251
|
|
|
252
|
-
FOR MESSAGING (events.produce / events.consume):
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
event: 'broker-tag:topic-tag'
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
252
|
+
FOR MESSAGING (events.produce / events.consume / events.dispatch):
|
|
253
|
+
|
|
254
|
+
In @ductape/nestjs, inject DuctapeContextService (not raw Ductape):
|
|
255
|
+
constructor(private readonly ductape: DuctapeContextService) {}
|
|
256
|
+
|
|
257
|
+
Produce immediately (method decorator — returns payload as message):
|
|
258
|
+
@Events.Produce({ event: 'broker-tag:topic-tag' })
|
|
259
|
+
emitOrderCreated(payload: { orderId: string }) { return payload; }
|
|
260
|
+
|
|
261
|
+
Dispatch (scheduled or immediate) — static schedule in decorator:
|
|
262
|
+
@Events.Dispatch({ broker: 'order-events', event: 'order-events:order-created', schedule: { every: 60000 } })
|
|
263
|
+
dispatchHeartbeat(payload: { message: { ping: boolean } }) { return payload; }
|
|
264
|
+
|
|
265
|
+
Dispatch with dynamic schedule — method returns { message, schedule?, retries? }:
|
|
266
|
+
@Events.Dispatch({ broker: 'statecraft-events', event: 'statecraft-events:boundary-due' })
|
|
267
|
+
scheduleBoundary(match: MatchLifecycle) {
|
|
268
|
+
return {
|
|
269
|
+
message: buildBoundaryCommand(match),
|
|
270
|
+
schedule: { start_at: match.nextBoundaryAt },
|
|
271
|
+
retries: 5,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
// method return takes precedence over decorator schedule; use sdk.events.dispatch() directly
|
|
275
|
+
// when even the broker/event must vary at call time.
|
|
276
|
+
|
|
277
|
+
Consume (method decorator — method is called for each incoming message):
|
|
278
|
+
@Events.Consumer({ event: 'order-events:order-created' })
|
|
279
|
+
async onOrderCreated(message: { orderId: string; total: number }) {
|
|
280
|
+
await this.processOrder(message);
|
|
281
|
+
// return to ack; throw to nack
|
|
282
|
+
}
|
|
283
|
+
// DuctapeEventsConsumerService wires this up automatically at module init.
|
|
284
|
+
// No manual onModuleInit needed when using the decorator.
|
|
285
|
+
|
|
286
|
+
Low-level SDK access (for produce only — not needed for consume with the decorator):
|
|
287
|
+
await this.ductape.sdk.events.produce({
|
|
288
|
+
product: 'my-product', env: 'prd',
|
|
289
|
+
event: 'broker-tag:topic-tag',
|
|
290
|
+
message: { ... },
|
|
291
|
+
});
|
|
267
292
|
|
|
268
293
|
SPECIALIZED MODULES (for injecting handles directly without @InjectContext):
|
|
269
294
|
|
|
@@ -1072,6 +1097,7 @@ const ADMIN_SUBCOMMANDS = [
|
|
|
1072
1097
|
'link', 'unlink', 'init',
|
|
1073
1098
|
'products', 'apps',
|
|
1074
1099
|
'resources',
|
|
1100
|
+
'events',
|
|
1075
1101
|
'cloud',
|
|
1076
1102
|
'secrets',
|
|
1077
1103
|
'generate',
|
|
@@ -2476,16 +2502,30 @@ Import (register an EXISTING cloud resource):
|
|
|
2476
2502
|
idempotencyTtl?: 86400, // seconds; default 86400 (24h)
|
|
2477
2503
|
});
|
|
2478
2504
|
|
|
2479
|
-
NESTJS — method
|
|
2505
|
+
NESTJS — method decorators:
|
|
2480
2506
|
import { Events } from '@ductape/nestjs';
|
|
2481
2507
|
@Injectable() export class OrdersService {
|
|
2508
|
+
// Immediate produce — method returns the message payload:
|
|
2482
2509
|
@Events.Produce({ event: 'order-events:order-created' })
|
|
2483
2510
|
emitOrderCreated(payload: { orderId: string; total: number }) { return payload; }
|
|
2484
2511
|
|
|
2485
|
-
//
|
|
2486
|
-
@Events.Dispatch({ broker: 'order-events', event: 'order-events:
|
|
2487
|
-
|
|
2488
|
-
|
|
2512
|
+
// Dispatch with static schedule (known at deploy time):
|
|
2513
|
+
@Events.Dispatch({ broker: 'order-events', event: 'order-events:reminder-due',
|
|
2514
|
+
schedule: { every: 86400000 } })
|
|
2515
|
+
scheduleReminder(payload: { message: { orderId: string } }) { return payload; }
|
|
2516
|
+
|
|
2517
|
+
// Dispatch with dynamic schedule (known at call time) — method returns { message, schedule?, retries? }:
|
|
2518
|
+
@Events.Dispatch({ broker: 'order-events', event: 'order-events:fulfillment-due' })
|
|
2519
|
+
scheduleFulfillment(order: Order) {
|
|
2520
|
+
return {
|
|
2521
|
+
message: { orderId: order.id, items: order.items },
|
|
2522
|
+
schedule: { start_at: order.expectedAt },
|
|
2523
|
+
retries: 3,
|
|
2524
|
+
};
|
|
2525
|
+
}
|
|
2526
|
+
// Called as: await this.ordersService.scheduleFulfillment(order);
|
|
2527
|
+
// When method return has a 'message' key, schedule/retries from return take precedence over decorator config.
|
|
2528
|
+
// For even more control (dynamic broker/event), use sdk.events.dispatch() directly.
|
|
2489
2529
|
}
|
|
2490
2530
|
|
|
2491
2531
|
CLIENT-SIDE (browser — publishable key):
|
|
@@ -2522,11 +2562,6 @@ Import (register an EXISTING cloud resource):
|
|
|
2522
2562
|
|
|
2523
2563
|
━━━ STEP 4: CONSUME — WRITTEN IN APPLICATION CODE ━━━
|
|
2524
2564
|
|
|
2525
|
-
Consumers are auto-registered by the SDK on first consume call.
|
|
2526
|
-
Consumer registration options (all optional — used for tracking in Workbench):
|
|
2527
|
-
consumer?: { tag?: string, name?: string, description?: string }
|
|
2528
|
-
If tag is omitted, Ductape generates one: "consumer-<brokerTag>-<topicTag>".
|
|
2529
|
-
|
|
2530
2565
|
ACK BEHAVIOR (automatic):
|
|
2531
2566
|
- Callback returns successfully → message is acknowledged (ack)
|
|
2532
2567
|
- Callback throws → message is tracked as failed; broker nacks/retries per provider behavior
|
|
@@ -2545,34 +2580,32 @@ Import (register an EXISTING cloud resource):
|
|
|
2545
2580
|
Run multiple instances of your service to scale consumption.
|
|
2546
2581
|
|
|
2547
2582
|
GENERAL BACKEND (TypeScript/Node.js — not NestJS):
|
|
2548
|
-
Start consuming in your module init or service startup:
|
|
2549
2583
|
await ductape.events.consume({
|
|
2550
2584
|
product: "my-product",
|
|
2551
2585
|
env: "prd",
|
|
2552
|
-
event: "order-events:order-created",
|
|
2586
|
+
event: "order-events:order-created", // ALWAYS "broker-tag:topic-tag"
|
|
2553
2587
|
callback: async (message) => {
|
|
2554
|
-
// All real processing logic goes here.
|
|
2555
2588
|
// Throw to nack. Return to ack.
|
|
2556
2589
|
await processOrder(message as { orderId: string; total: number });
|
|
2557
2590
|
},
|
|
2558
|
-
consumer?: { tag: "order-processor", name: "Order Processor" },
|
|
2559
2591
|
});
|
|
2560
2592
|
|
|
2561
|
-
NESTJS — use
|
|
2593
|
+
NESTJS — use @Events.Consumer decorator (preferred):
|
|
2594
|
+
import { Events } from '@ductape/nestjs';
|
|
2562
2595
|
@Injectable()
|
|
2563
|
-
export class OrderConsumerService
|
|
2564
|
-
|
|
2565
|
-
async
|
|
2566
|
-
await this.
|
|
2567
|
-
|
|
2568
|
-
env: process.env.DUCTAPE_ENV || 'prd',
|
|
2569
|
-
event: "order-events:order-created",
|
|
2570
|
-
callback: async (message) => { await this.handle(message); },
|
|
2571
|
-
consumer: { tag: "order-consumer", name: "Order Consumer" },
|
|
2572
|
-
});
|
|
2596
|
+
export class OrderConsumerService {
|
|
2597
|
+
@Events.Consumer({ event: 'order-events:order-created' })
|
|
2598
|
+
async onOrderCreated(message: { orderId: string; total: number }) {
|
|
2599
|
+
await this.processOrder(message);
|
|
2600
|
+
// return to ack; throw to nack
|
|
2573
2601
|
}
|
|
2574
|
-
private async
|
|
2602
|
+
private async processOrder(msg: { orderId: string; total: number }) { /* ... */ }
|
|
2575
2603
|
}
|
|
2604
|
+
// DuctapeEventsConsumerService (auto-registered by DuctapeModule) wires this up at startup.
|
|
2605
|
+
// No manual onModuleInit needed.
|
|
2606
|
+
|
|
2607
|
+
// If you need to override product/env for a specific consumer:
|
|
2608
|
+
@Events.Consumer({ event: 'order-events:order-created', product: 'my-product', env: 'prd' })
|
|
2576
2609
|
|
|
2577
2610
|
CLIENT-SIDE: Clients CANNOT consume. Event consumption is always server-side only.
|
|
2578
2611
|
This is the key distinction between server topics (produce + consume) and client-observable
|
|
@@ -3191,9 +3224,10 @@ const cliInputSchema = z.object({
|
|
|
3191
3224
|
command: z.string().describe('The ductape CLI command to run, without the leading "ductape" word. ' +
|
|
3192
3225
|
'Examples: "products list", "products create --name \\"My Product\\" --tag my-product", ' +
|
|
3193
3226
|
'"apps list", "apps create -f app.json", "resources storage list", ' +
|
|
3227
|
+
'"events topics create -f topic.json", "events topics list --tag broker-tag", ' +
|
|
3194
3228
|
'"cloud connections list", "link --product my-product --env dev".\n\n' +
|
|
3195
3229
|
'Use this tool for administrative operations: creating or updating products, apps, ' +
|
|
3196
|
-
'resources (databases, storage, caches…), cloud connections, secrets, ' +
|
|
3230
|
+
'resources (databases, storage, caches…), event broker topics, cloud connections, secrets, ' +
|
|
3197
3231
|
'and for apply/migrate workflows.\n\n' +
|
|
3198
3232
|
'Note: environments, app actions, features, quotas, fallbacks, and jobs are configured ' +
|
|
3199
3233
|
'in the Workbench UI — there are no CLI commands for them.\n\n' +
|
|
@@ -3531,7 +3565,7 @@ async function main() {
|
|
|
3531
3565
|
' "product":"my-product","component":"core-db","env":"prd","resource":"Cluster0","dbName":"myapp_prd"}]\n' +
|
|
3532
3566
|
' - Message broker / event broker import:\n' +
|
|
3533
3567
|
' CLI accepts these aliases for the messageBrokers module: events, event, broker, brokers, message-brokers.\n' +
|
|
3534
|
-
' List existing brokers: ductape_cli("resources events list
|
|
3568
|
+
' List existing brokers: ductape_cli("resources events list --json")\n' +
|
|
3535
3569
|
' GCP Pub/Sub service identifier is "pubsub". AWS SQS is "sqs". Azure Service Bus is "servicebus".\n' +
|
|
3536
3570
|
' Message brokers are import-only (no provision-persist). Import flow is the same as storage.\n' +
|
|
3537
3571
|
' type field = "messageBrokers" (not "messagebrokers" or "events").\n' +
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -260,21 +260,46 @@ CONTROLLER DECORATORS:
|
|
|
260
260
|
@Webhook.Register(...) — register a webhook consumer URL
|
|
261
261
|
@Webhook.Consumer(...) — mark inbound handler for forwarded webhook payloads
|
|
262
262
|
|
|
263
|
-
FOR MESSAGING (events.produce / events.consume):
|
|
263
|
+
FOR MESSAGING (events.produce / events.consume / events.dispatch):
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
In @ductape/nestjs, inject DuctapeContextService (not raw Ductape):
|
|
266
|
+
constructor(private readonly ductape: DuctapeContextService) {}
|
|
266
267
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
message: { ... },
|
|
271
|
-
});
|
|
268
|
+
Produce immediately (method decorator — returns payload as message):
|
|
269
|
+
@Events.Produce({ event: 'broker-tag:topic-tag' })
|
|
270
|
+
emitOrderCreated(payload: { orderId: string }) { return payload; }
|
|
272
271
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
272
|
+
Dispatch (scheduled or immediate) — static schedule in decorator:
|
|
273
|
+
@Events.Dispatch({ broker: 'order-events', event: 'order-events:order-created', schedule: { every: 60000 } })
|
|
274
|
+
dispatchHeartbeat(payload: { message: { ping: boolean } }) { return payload; }
|
|
275
|
+
|
|
276
|
+
Dispatch with dynamic schedule — method returns { message, schedule?, retries? }:
|
|
277
|
+
@Events.Dispatch({ broker: 'statecraft-events', event: 'statecraft-events:boundary-due' })
|
|
278
|
+
scheduleBoundary(match: MatchLifecycle) {
|
|
279
|
+
return {
|
|
280
|
+
message: buildBoundaryCommand(match),
|
|
281
|
+
schedule: { start_at: match.nextBoundaryAt },
|
|
282
|
+
retries: 5,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
// method return takes precedence over decorator schedule; use sdk.events.dispatch() directly
|
|
286
|
+
// when even the broker/event must vary at call time.
|
|
287
|
+
|
|
288
|
+
Consume (method decorator — method is called for each incoming message):
|
|
289
|
+
@Events.Consumer({ event: 'order-events:order-created' })
|
|
290
|
+
async onOrderCreated(message: { orderId: string; total: number }) {
|
|
291
|
+
await this.processOrder(message);
|
|
292
|
+
// return to ack; throw to nack
|
|
293
|
+
}
|
|
294
|
+
// DuctapeEventsConsumerService wires this up automatically at module init.
|
|
295
|
+
// No manual onModuleInit needed when using the decorator.
|
|
296
|
+
|
|
297
|
+
Low-level SDK access (for produce only — not needed for consume with the decorator):
|
|
298
|
+
await this.ductape.sdk.events.produce({
|
|
299
|
+
product: 'my-product', env: 'prd',
|
|
300
|
+
event: 'broker-tag:topic-tag',
|
|
301
|
+
message: { ... },
|
|
302
|
+
});
|
|
278
303
|
|
|
279
304
|
SPECIALIZED MODULES (for injecting handles directly without @InjectContext):
|
|
280
305
|
|
|
@@ -1121,6 +1146,7 @@ const ADMIN_SUBCOMMANDS = [
|
|
|
1121
1146
|
'link', 'unlink', 'init',
|
|
1122
1147
|
'products', 'apps',
|
|
1123
1148
|
'resources',
|
|
1149
|
+
'events',
|
|
1124
1150
|
'cloud',
|
|
1125
1151
|
'secrets',
|
|
1126
1152
|
'generate',
|
|
@@ -2549,16 +2575,30 @@ Import (register an EXISTING cloud resource):
|
|
|
2549
2575
|
idempotencyTtl?: 86400, // seconds; default 86400 (24h)
|
|
2550
2576
|
});
|
|
2551
2577
|
|
|
2552
|
-
NESTJS — method
|
|
2578
|
+
NESTJS — method decorators:
|
|
2553
2579
|
import { Events } from '@ductape/nestjs';
|
|
2554
2580
|
@Injectable() export class OrdersService {
|
|
2581
|
+
// Immediate produce — method returns the message payload:
|
|
2555
2582
|
@Events.Produce({ event: 'order-events:order-created' })
|
|
2556
2583
|
emitOrderCreated(payload: { orderId: string; total: number }) { return payload; }
|
|
2557
2584
|
|
|
2558
|
-
//
|
|
2559
|
-
@Events.Dispatch({ broker: 'order-events', event: 'order-events:
|
|
2560
|
-
|
|
2561
|
-
|
|
2585
|
+
// Dispatch with static schedule (known at deploy time):
|
|
2586
|
+
@Events.Dispatch({ broker: 'order-events', event: 'order-events:reminder-due',
|
|
2587
|
+
schedule: { every: 86400000 } })
|
|
2588
|
+
scheduleReminder(payload: { message: { orderId: string } }) { return payload; }
|
|
2589
|
+
|
|
2590
|
+
// Dispatch with dynamic schedule (known at call time) — method returns { message, schedule?, retries? }:
|
|
2591
|
+
@Events.Dispatch({ broker: 'order-events', event: 'order-events:fulfillment-due' })
|
|
2592
|
+
scheduleFulfillment(order: Order) {
|
|
2593
|
+
return {
|
|
2594
|
+
message: { orderId: order.id, items: order.items },
|
|
2595
|
+
schedule: { start_at: order.expectedAt },
|
|
2596
|
+
retries: 3,
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
// Called as: await this.ordersService.scheduleFulfillment(order);
|
|
2600
|
+
// When method return has a 'message' key, schedule/retries from return take precedence over decorator config.
|
|
2601
|
+
// For even more control (dynamic broker/event), use sdk.events.dispatch() directly.
|
|
2562
2602
|
}
|
|
2563
2603
|
|
|
2564
2604
|
CLIENT-SIDE (browser — publishable key):
|
|
@@ -2595,11 +2635,6 @@ Import (register an EXISTING cloud resource):
|
|
|
2595
2635
|
|
|
2596
2636
|
━━━ STEP 4: CONSUME — WRITTEN IN APPLICATION CODE ━━━
|
|
2597
2637
|
|
|
2598
|
-
Consumers are auto-registered by the SDK on first consume call.
|
|
2599
|
-
Consumer registration options (all optional — used for tracking in Workbench):
|
|
2600
|
-
consumer?: { tag?: string, name?: string, description?: string }
|
|
2601
|
-
If tag is omitted, Ductape generates one: "consumer-<brokerTag>-<topicTag>".
|
|
2602
|
-
|
|
2603
2638
|
ACK BEHAVIOR (automatic):
|
|
2604
2639
|
- Callback returns successfully → message is acknowledged (ack)
|
|
2605
2640
|
- Callback throws → message is tracked as failed; broker nacks/retries per provider behavior
|
|
@@ -2618,34 +2653,32 @@ Import (register an EXISTING cloud resource):
|
|
|
2618
2653
|
Run multiple instances of your service to scale consumption.
|
|
2619
2654
|
|
|
2620
2655
|
GENERAL BACKEND (TypeScript/Node.js — not NestJS):
|
|
2621
|
-
Start consuming in your module init or service startup:
|
|
2622
2656
|
await ductape.events.consume({
|
|
2623
2657
|
product: "my-product",
|
|
2624
2658
|
env: "prd",
|
|
2625
|
-
event: "order-events:order-created",
|
|
2659
|
+
event: "order-events:order-created", // ALWAYS "broker-tag:topic-tag"
|
|
2626
2660
|
callback: async (message) => {
|
|
2627
|
-
// All real processing logic goes here.
|
|
2628
2661
|
// Throw to nack. Return to ack.
|
|
2629
2662
|
await processOrder(message as { orderId: string; total: number });
|
|
2630
2663
|
},
|
|
2631
|
-
consumer?: { tag: "order-processor", name: "Order Processor" },
|
|
2632
2664
|
});
|
|
2633
2665
|
|
|
2634
|
-
NESTJS — use
|
|
2666
|
+
NESTJS — use @Events.Consumer decorator (preferred):
|
|
2667
|
+
import { Events } from '@ductape/nestjs';
|
|
2635
2668
|
@Injectable()
|
|
2636
|
-
export class OrderConsumerService
|
|
2637
|
-
|
|
2638
|
-
async
|
|
2639
|
-
await this.
|
|
2640
|
-
|
|
2641
|
-
env: process.env.DUCTAPE_ENV || 'prd',
|
|
2642
|
-
event: "order-events:order-created",
|
|
2643
|
-
callback: async (message) => { await this.handle(message); },
|
|
2644
|
-
consumer: { tag: "order-consumer", name: "Order Consumer" },
|
|
2645
|
-
});
|
|
2669
|
+
export class OrderConsumerService {
|
|
2670
|
+
@Events.Consumer({ event: 'order-events:order-created' })
|
|
2671
|
+
async onOrderCreated(message: { orderId: string; total: number }) {
|
|
2672
|
+
await this.processOrder(message);
|
|
2673
|
+
// return to ack; throw to nack
|
|
2646
2674
|
}
|
|
2647
|
-
private async
|
|
2675
|
+
private async processOrder(msg: { orderId: string; total: number }) { /* ... */ }
|
|
2648
2676
|
}
|
|
2677
|
+
// DuctapeEventsConsumerService (auto-registered by DuctapeModule) wires this up at startup.
|
|
2678
|
+
// No manual onModuleInit needed.
|
|
2679
|
+
|
|
2680
|
+
// If you need to override product/env for a specific consumer:
|
|
2681
|
+
@Events.Consumer({ event: 'order-events:order-created', product: 'my-product', env: 'prd' })
|
|
2649
2682
|
|
|
2650
2683
|
CLIENT-SIDE: Clients CANNOT consume. Event consumption is always server-side only.
|
|
2651
2684
|
This is the key distinction between server topics (produce + consume) and client-observable
|
|
@@ -3271,9 +3304,10 @@ const cliInputSchema = z.object({
|
|
|
3271
3304
|
'The ductape CLI command to run, without the leading "ductape" word. ' +
|
|
3272
3305
|
'Examples: "products list", "products create --name \\"My Product\\" --tag my-product", ' +
|
|
3273
3306
|
'"apps list", "apps create -f app.json", "resources storage list", ' +
|
|
3307
|
+
'"events topics create -f topic.json", "events topics list --tag broker-tag", ' +
|
|
3274
3308
|
'"cloud connections list", "link --product my-product --env dev".\n\n' +
|
|
3275
3309
|
'Use this tool for administrative operations: creating or updating products, apps, ' +
|
|
3276
|
-
'resources (databases, storage, caches…), cloud connections, secrets, ' +
|
|
3310
|
+
'resources (databases, storage, caches…), event broker topics, cloud connections, secrets, ' +
|
|
3277
3311
|
'and for apply/migrate workflows.\n\n' +
|
|
3278
3312
|
'Note: environments, app actions, features, quotas, fallbacks, and jobs are configured ' +
|
|
3279
3313
|
'in the Workbench UI — there are no CLI commands for them.\n\n' +
|
|
@@ -3667,7 +3701,7 @@ async function main() {
|
|
|
3667
3701
|
' "product":"my-product","component":"core-db","env":"prd","resource":"Cluster0","dbName":"myapp_prd"}]\n' +
|
|
3668
3702
|
' - Message broker / event broker import:\n' +
|
|
3669
3703
|
' CLI accepts these aliases for the messageBrokers module: events, event, broker, brokers, message-brokers.\n' +
|
|
3670
|
-
' List existing brokers: ductape_cli("resources events list
|
|
3704
|
+
' List existing brokers: ductape_cli("resources events list --json")\n' +
|
|
3671
3705
|
' GCP Pub/Sub service identifier is "pubsub". AWS SQS is "sqs". Azure Service Bus is "servicebus".\n' +
|
|
3672
3706
|
' Message brokers are import-only (no provision-persist). Import flow is the same as storage.\n' +
|
|
3673
3707
|
' type field = "messageBrokers" (not "messagebrokers" or "events").\n' +
|