@onlineapps/conn-orch-cookbook 2.0.0

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ONLINE APPS s.r.o.; info@onlineapps.cz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,281 @@
1
+ # @onlineapps/connector-cookbook
2
+
3
+ > Complete cookbook toolkit for ALL services - unified wrapper including core, executor, transformer, and router functionality
4
+
5
+ ## 🚀 Version 2.0 - Major Update
6
+
7
+ The `connector-cookbook` package (v2.0) is now a complete toolkit that combines all cookbook functionality in one unified package. This ensures architectural consistency across ALL services including infrastructure components like workflow_launcher.
8
+
9
+ ### What's New in v2.0
10
+
11
+ - **Modular architecture** - Four specialized modules combined
12
+ - **Backward compatibility** - All v1.x APIs still work
13
+ - **Unified approach** - Same package for ALL services (infrastructure and business)
14
+ - **Complete toolkit** - Parsing, execution, transformation, and routing
15
+
16
+ ### Why Unified Approach?
17
+
18
+ Per architectural decision, ALL services including workflow_launcher use this single package to ensure:
19
+ - **Consistency** - Same API everywhere
20
+ - **Predictability** - No special cases
21
+ - **Maintainability** - Single source of truth
22
+ - **Simplicity** - One package to learn
23
+
24
+ ## 📦 Installation
25
+
26
+ ```bash
27
+ npm install @onlineapps/connector-cookbook
28
+ # or
29
+ yarn add @onlineapps/connector-cookbook
30
+ ```
31
+
32
+ ## 🔧 Quick Start
33
+
34
+ ### Backward Compatible (v1.x style)
35
+
36
+ ```javascript
37
+ const {
38
+ parseCookbookFromFile,
39
+ validateCookbook
40
+ } = require('@onlineapps/connector-cookbook');
41
+
42
+ // Works exactly as before
43
+ const cookbook = await parseCookbookFromFile('./workflow.json');
44
+ validateCookbook(cookbook);
45
+ ```
46
+
47
+ ### New Modular Approach (v2.0)
48
+
49
+ ```javascript
50
+ const cookbook = require('@onlineapps/connector-cookbook');
51
+
52
+ // Use specific modules
53
+ const { CookbookExecutor } = cookbook.executor;
54
+ const { CookbookRouter } = cookbook.router;
55
+ const { CookbookGenerator } = cookbook.transformer;
56
+
57
+ // Or use factory functions
58
+ const processor = cookbook.createProcessor({
59
+ cookbook: myCookbook,
60
+ maxRetries: 3
61
+ });
62
+ ```
63
+
64
+ ## 📚 Included Modules
65
+
66
+ ### 1. Core Module (@onlineapps/cookbook-core)
67
+ - JSON Schema validation
68
+ - Recursive step validation
69
+ - Parsing from file/object
70
+ - Lightweight (~50KB)
71
+
72
+ ### 2. Executor Module (@onlineapps/cookbook-executor)
73
+ - Workflow execution engine
74
+ - Context management
75
+ - Variable resolution ($api_input, $steps)
76
+ - Step processing for all types
77
+
78
+ ### 3. Transformer Module (@onlineapps/cookbook-transformer)
79
+ - OpenAPI to cookbook generation
80
+ - API spec analysis
81
+ - Response mapping
82
+ - JSONPath transformations
83
+
84
+ ### 4. Router Module (@onlineapps/cookbook-router)
85
+ - Service discovery
86
+ - Queue management
87
+ - Retry with exponential backoff
88
+ - Dead letter queue handling
89
+
90
+ ## 🎯 Usage Examples
91
+
92
+ ### Complete Service Implementation
93
+
94
+ ```javascript
95
+ const cookbook = require('@onlineapps/connector-cookbook');
96
+ const MQClient = require('@onlineapps/connector-mq-client');
97
+ const RegistryClient = require('@onlineapps/connector-registry-client');
98
+
99
+ class MyService {
100
+ constructor() {
101
+ // Initialize clients
102
+ this.mqClient = new MQClient(mqConfig);
103
+ this.registryClient = new RegistryClient(registryConfig);
104
+
105
+ // Create router for message handling
106
+ this.router = cookbook.createRouter(
107
+ this.mqClient,
108
+ this.registryClient
109
+ );
110
+ }
111
+
112
+ async processWorkflow(message) {
113
+ // Parse and validate
114
+ const workflowDef = cookbook.parseCookbookFromObject(message.cookbook);
115
+
116
+ // Create executor
117
+ const executor = new cookbook.CookbookExecutor(workflowDef);
118
+
119
+ // Execute workflow
120
+ const result = await executor.execute(message.context);
121
+
122
+ // Route to next service
123
+ await this.router.routeToNextService(
124
+ workflowDef,
125
+ result,
126
+ message.current_step
127
+ );
128
+ }
129
+ }
130
+ ```
131
+
132
+ ### Infrastructure Service (workflow_launcher)
133
+
134
+ ```javascript
135
+ // workflow_launcher uses the SAME package
136
+ const cookbook = require('@onlineapps/connector-cookbook');
137
+
138
+ class WorkflowLauncher {
139
+ async handleWorkflowInit(message) {
140
+ // Validate cookbook
141
+ cookbook.validateCookbook(message.cookbook);
142
+
143
+ // Route to first service
144
+ await this.router.routeWorkflow(
145
+ message.cookbook,
146
+ message.context
147
+ );
148
+ }
149
+ }
150
+ ```
151
+
152
+ ### OpenAPI Integration
153
+
154
+ ```javascript
155
+ const { CookbookGenerator } = require('@onlineapps/connector-cookbook');
156
+
157
+ const generator = new CookbookGenerator({
158
+ defaultTimeout: 10000,
159
+ defaultRetry: { maxAttempts: 3, delayMs: 2000 }
160
+ });
161
+
162
+ // Generate cookbook from OpenAPI spec
163
+ const openApiSpec = require('./api-spec.json');
164
+ const cookbook = generator.generate(openApiSpec);
165
+ ```
166
+
167
+ ## 📖 Cookbook Structure
168
+
169
+ ### Basic Example
170
+ ```json
171
+ {
172
+ "version": "1.0.0",
173
+ "api_input": {
174
+ "customer": "ACME Corp",
175
+ "amount": 1000
176
+ },
177
+ "steps": [
178
+ {
179
+ "id": "invoice_step",
180
+ "type": "task",
181
+ "service": "invoice_service",
182
+ "input": {
183
+ "customer": "$api_input.customer",
184
+ "amount": "$api_input.amount"
185
+ },
186
+ "output": {
187
+ "invoice_id": "$.invoice_id"
188
+ },
189
+ "retry": {
190
+ "maxAttempts": 3,
191
+ "delayMs": 2000
192
+ }
193
+ }
194
+ ]
195
+ }
196
+ ```
197
+
198
+ ## 📚 Step Types
199
+
200
+ All 7 step types are fully supported:
201
+
202
+ - **task** - Service operation execution
203
+ - **foreach** - Iteration over arrays
204
+ - **fork_join** - Parallel execution
205
+ - **switch** - Conditional branching
206
+ - **sub_workflow** - Nested workflows
207
+ - **wait** - Time delays
208
+ - **dispatch** - Webhook dispatching
209
+
210
+ ## 🔄 Migration from v1.x
211
+
212
+ Version 2.0 maintains full backward compatibility. Existing code continues to work without changes:
213
+
214
+ ```javascript
215
+ // This still works exactly as before
216
+ const { parseCookbookFromFile } = require('@onlineapps/connector-cookbook');
217
+ const cookbook = await parseCookbookFromFile('./workflow.json');
218
+ ```
219
+
220
+ To access new features, use the modular exports:
221
+
222
+ ```javascript
223
+ // New modular approach
224
+ const { executor, router, transformer } = require('@onlineapps/connector-cookbook');
225
+ ```
226
+
227
+ ## 📋 API Reference
228
+
229
+ ### Legacy Exports (v1.x compatible)
230
+ - `parseCookbookFromFile(path)` - Parse from file
231
+ - `parseCookbookFromObject(obj)` - Parse from object
232
+ - `validateCookbook(cookbook)` - Validate structure
233
+ - `CookbookValidationError` - Error class
234
+
235
+ ### New Modular Exports (v2.0)
236
+ - `core` - Core parsing and validation
237
+ - `executor` - Workflow execution
238
+ - `transformer` - OpenAPI transformation
239
+ - `router` - Message routing
240
+ - `createProcessor(options)` - Factory for complete processor
241
+ - `createRouter(mqClient, registryClient, options)` - Factory for router
242
+
243
+ ## 🧪 Testing
244
+
245
+ ```bash
246
+ npm test # Run all tests
247
+ npm run test:unit # Unit tests only
248
+ npm run test:integration # Integration tests
249
+ ```
250
+
251
+ ## ⚠️ Important Notes
252
+
253
+ ### Schema Validation Strictness
254
+ The current schema validation is very strict. See [Schema Audit Report](/shared/cookbook/cookbook-core/docs/SCHEMA_AUDIT.md) for detailed analysis and recommendations.
255
+
256
+ **Known Issues:**
257
+ - All step types incorrectly require `service`, `input`, and `output` fields
258
+ - `type` field should be required but isn't
259
+ - Some control flow steps (foreach, switch) have unnecessary field requirements
260
+
261
+ **Workaround:** Until schema is updated, include all required fields even if not used:
262
+ ```javascript
263
+ {
264
+ type: 'foreach',
265
+ service: 'dummy-service', // Not actually used
266
+ input: {}, // Not actually used
267
+ output: {}, // Optional but may be required by schema
268
+ // ... actual foreach fields
269
+ }
270
+ ```
271
+
272
+ ## 📄 License
273
+
274
+ PROPRIETARY - All rights reserved
275
+
276
+ ## 🤝 Contributing
277
+
278
+ Internal package - contributions via internal GitLab only.
279
+
280
+ ---
281
+ *For detailed documentation on individual modules, see their respective README files in the shared/ directory.*
@@ -0,0 +1,84 @@
1
+ /**
2
+ * basicUsage.js
3
+ *
4
+ * Example demonstrating full lifecycle of ServiceRegistryClient:
5
+ * 1. Load environment variables
6
+ * 2. Instantiate client
7
+ * 3. Initialize (setup queues and start listening for requests)
8
+ * 4. Register event listeners (apiDescriptionRequest, heartbeatSent, apiDescriptionSent, error)
9
+ * 5. Start heartbeat loop
10
+ * 6. Graceful shutdown on process signals
11
+ */
12
+
13
+ // Load environment variables from .env file
14
+ require('dotenv').config();
15
+
16
+ const { ServiceRegistryClient, EVENTS } = require('agent-registry-client');
17
+
18
+ // Step 1: Create a new ServiceRegistryClient instance
19
+ const registryClient = new ServiceRegistryClient({
20
+ amqpUrl: process.env.AMQP_URL,
21
+ serviceName: process.env.SERVICE_NAME || 'invoicing',
22
+ version: process.env.SERVICE_VERSION || '1.0.0',
23
+ heartbeatInterval: parseInt(process.env.HEARTBEAT_INTERVAL, 10) || 10000,
24
+ apiQueue: process.env.API_QUEUE,
25
+ registryQueue: process.env.REGISTRY_QUEUE
26
+ });
27
+
28
+ // Step 2: Register event listeners
29
+ registryClient.on(EVENTS.HEARTBEAT_SENT, (msg) => {
30
+ console.log(`[Heartbeat] Sent at ${msg.timestamp} for ${msg.serviceName}@${msg.version}`);
31
+ });
32
+
33
+ registryClient.on(EVENTS.API_DESCRIPTION_REQUEST, async (payload) => {
34
+ console.log(`[API Description Request] for ${payload.serviceName}@${payload.version}`);
35
+ // Load local API description (from file or in-memory)
36
+ const apiDesc = await loadLocalApiDescription();
37
+ await registryClient.sendApiDescription(apiDesc);
38
+ });
39
+
40
+ registryClient.on(EVENTS.API_DESCRIPTION_SENT, (msg) => {
41
+ console.log(`[API Description Sent] at ${msg.timestamp} for ${msg.serviceName}@${msg.version}`);
42
+ });
43
+
44
+ registryClient.on(EVENTS.ERROR, (err) => {
45
+ console.error('[RegistryClient Error]', err);
46
+ });
47
+
48
+ (async () => {
49
+ try {
50
+ // Step 3: Initialize client (setup queues and listeners)
51
+ await registryClient.init();
52
+ console.log('RegistryClient initialized: queues are ready.');
53
+
54
+ // Step 4: Start heartbeat loop
55
+ registryClient.startHeartbeat();
56
+ console.log('Heartbeat loop started.');
57
+
58
+ // Step 5: Graceful shutdown on SIGINT/SIGTERM
59
+ const shutdown = async () => {
60
+ console.log('Shutting down RegistryClient...');
61
+ await registryClient.close();
62
+ process.exit(0);
63
+ };
64
+ process.on('SIGINT', shutdown);
65
+ process.on('SIGTERM', shutdown);
66
+ } catch (err) {
67
+ console.error('Failed to initialize RegistryClient', err);
68
+ process.exit(1);
69
+ }
70
+ })();
71
+
72
+ /**
73
+ * Helper: Load local API description
74
+ * In a real application, this could read from a JSON file,
75
+ * introspect OpenAPI spec, or build dynamically.
76
+ */
77
+ async function loadLocalApiDescription() {
78
+ return {
79
+ endpoints: [
80
+ { path: '/invoices', method: 'POST', description: 'Create a new invoice' },
81
+ { path: '/invoices/:id', method: 'GET', description: 'Retrieve invoice by ID' }
82
+ ]
83
+ };
84
+ }
@@ -0,0 +1,169 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "api_input": {
4
+ "customer": "ACME Corp.",
5
+ "amount": 1000,
6
+ "currency": "USD",
7
+ "requested_formats": ["html", "pdf"],
8
+ "items": [
9
+ { "sku": "A1", "qty": 2 },
10
+ { "sku": "B2", "qty": 1 }
11
+ ],
12
+ "priority": "high",
13
+ "order_details": {
14
+ "order_id": "ORD-123",
15
+ "date": "2025-06-01"
16
+ }
17
+ },
18
+ "workflow_steps": [
19
+ {
20
+ "step": "1",
21
+ "type": "task",
22
+ "service": "invoice_service",
23
+ "queue": "invoice.process",
24
+ "input_mapping": {
25
+ "customer": "api_input.customer",
26
+ "amount": "api_input.amount",
27
+ "currency": "api_input.currency"
28
+ },
29
+ "output_schema": {
30
+ "invoice_id": "invoice_service.invoice_id",
31
+ "total_amount": "invoice_service.total_amount"
32
+ },
33
+ "retry": {
34
+ "max_attempts": 3,
35
+ "delay": 2000
36
+ },
37
+ "timeout": 10000
38
+ },
39
+ {
40
+ "step": "2",
41
+ "type": "foreach",
42
+ "iterator": "api_input.items",
43
+ "steps": [
44
+ {
45
+ "step": "2.1",
46
+ "type": "task",
47
+ "service": "item_processing_service",
48
+ "queue": "item.process",
49
+ "input_mapping": {
50
+ "invoice_id": "workflow_steps[0].result.invoice_id",
51
+ "item": "foreach.item"
52
+ },
53
+ "output_schema": {
54
+ "processed_item": "item_processing_service.result"
55
+ }
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ "step": "3",
61
+ "type": "fork_join",
62
+ "fork": [
63
+ {
64
+ "service": "template_service",
65
+ "queue": "template.generate",
66
+ "input_mapping": {
67
+ "invoice_id": "workflow_steps[0].result.invoice_id",
68
+ "customer": "api_input.customer"
69
+ },
70
+ "output_schema": {
71
+ "generated_html": "template_service.generated_html"
72
+ }
73
+ },
74
+ {
75
+ "service": "analytics_service",
76
+ "queue": "analytics.process",
77
+ "input_mapping": {
78
+ "invoice_id": "workflow_steps[0].result.invoice_id",
79
+ "amount": "workflow_steps[0].result.total_amount"
80
+ },
81
+ "output_schema": {
82
+ "analytics_report": "analytics_service.report"
83
+ }
84
+ }
85
+ ],
86
+ "join": {
87
+ "strategy": "merge",
88
+ "result_mapping": {
89
+ "combined_html": ["fork[0].generated_html"],
90
+ "analytics": ["fork[1].analytics_report"]
91
+ }
92
+ }
93
+ },
94
+ {
95
+ "step": "4",
96
+ "type": "switch",
97
+ "expression": "api_input.priority",
98
+ "cases": {
99
+ "high": {
100
+ "service": "priority_service",
101
+ "queue": "priority.process",
102
+ "input_mapping": {
103
+ "invoice_id": "workflow_steps[0].result.invoice_id",
104
+ "priority_flag": "api_input.priority"
105
+ },
106
+ "output_schema": {
107
+ "priority_result": "priority_service.result"
108
+ }
109
+ },
110
+ "low": {
111
+ "service": "standard_service",
112
+ "queue": "standard.process",
113
+ "input_mapping": {
114
+ "invoice_id": "workflow_steps[0].result.invoice_id"
115
+ },
116
+ "output_schema": {
117
+ "standard_result": "standard_service.result"
118
+ }
119
+ }
120
+ },
121
+ "default": {
122
+ "service": "fallback_service",
123
+ "queue": "fallback.process",
124
+ "input_mapping": {
125
+ "invoice_id": "workflow_steps[0].result.invoice_id"
126
+ },
127
+ "output_schema": {
128
+ "fallback_result": "fallback_service.result"
129
+ }
130
+ }
131
+ },
132
+ {
133
+ "step": "5",
134
+ "type": "sub_workflow",
135
+ "workflow_id": "generate_invoice_pdf",
136
+ "parameters": {
137
+ "invoice_id": "workflow_steps[0].result.invoice_id",
138
+ "html_content": "workflow_steps[3].result.combined_html"
139
+ }
140
+ },
141
+ {
142
+ "step": "6",
143
+ "type": "wait",
144
+ "duration": 30000,
145
+ "message": "Čekání 30 s než se vygeneruje PDF na úložišti"
146
+ },
147
+ {
148
+ "step": "7",
149
+ "type": "task",
150
+ "service": "pdf_service",
151
+ "queue": "pdf.convert",
152
+ "input_mapping": {
153
+ "html": "workflow_steps[3].result.combined_html",
154
+ "invoice_id": "workflow_steps[0].result.invoice_id"
155
+ },
156
+ "output_schema": {
157
+ "pdf_url": "pdf_service.pdf_url"
158
+ },
159
+ "retry": {
160
+ "max_attempts": 2,
161
+ "delay": 1000
162
+ }
163
+ }
164
+ ],
165
+ "final_delivery": {
166
+ "method": "webhook",
167
+ "target": "https://client.example.com/webhook"
168
+ }
169
+ }
@@ -0,0 +1,180 @@
1
+ {
2
+ "version": "1.0.0", # Version of the workflow schema X.X.X
3
+ "api_input": { # Input parameters for the API call
4
+ "customer": "ACME Corp.",
5
+ "amount": 1000,
6
+ "currency": "USD",
7
+ "requested_formats": ["html", "pdf"],
8
+ "items": [
9
+ { "sku": "A1", "qty": 2 },
10
+ { "sku": "B2", "qty": 1 }
11
+ ],
12
+ "priority": "high",
13
+ "order_details": {
14
+ "order_id": "ORD-123",
15
+ "date": "2025-06-01"
16
+ }
17
+ },
18
+ "general_workflow": [ # Steps in the workflow
19
+ { # typical step structure
20
+ "step": "1", # Unique identifier for the step ("1", "A", etc.)
21
+ "type": "task", # Type of the step (task, foreach, fork_join, sub_workflow, switch, wait, dispatch)
22
+ "service": "invoice_service", # Service and its queue to be called
23
+ "input_mapping": { # Mapping of input parameters to the service
24
+ "customer": "api_input.customer",
25
+ "amount": "api_input.amount",
26
+ "currency": "api_input.currency"
27
+ },
28
+ "output_schema": { # Schema of the output from the service
29
+ "invoice_id": "this.invoice_id", # Reference to the output field, "this" refers to the current step's output
30
+ "total_amount": "this.total_amount"
31
+ },
32
+ "retry": { # Retry configuration for the step
33
+ "max_attempts": 3, # Maximum number of retry attempts
34
+ "delay": 2000 # Delay between retries in milliseconds
35
+ },
36
+ "timeout": 10000 # Timeout for the step in milliseconds
37
+ },
38
+ { # Foreach step to process each item in the input array
39
+ "step": "B",
40
+ "type": "foreach",
41
+ "input_iterator": "api_input.items", # Input for the foreach loop, in case of an array
42
+ "workflow": [
43
+ {
44
+ "step": "2.1",
45
+ "type": "task",
46
+ "service": "item_processing_service",
47
+ "input_mapping": {
48
+ "invoice_id": "parent.previous.result.invoice_id", # Reference to the parent and previous step's output
49
+ "item": "foreach.item" # Reference to the current item in the foreach loop
50
+ },
51
+ "output_schema": {
52
+ "processed_item": "this.result"
53
+ }
54
+ }
55
+ ],
56
+ "output_mapping": {
57
+ "items": "foreach.processed_item" # Output schema for the foreach step}
58
+ },
59
+ {
60
+ "step": "3X",
61
+ "type": "fork_join",
62
+ "fork": [
63
+ {
64
+ "service": "template_service",
65
+ "queue": "template.generate",
66
+ "input_mapping": {
67
+ "invoice_id": "workflow_steps[0].result.invoice_id",
68
+ "customer": "api_input.customer"
69
+ },
70
+ "output_schema": {
71
+ "generated_html": "template_service.generated_html"
72
+ }
73
+ },
74
+ {
75
+ "service": "analytics_service",
76
+ "queue": "analytics.process",
77
+ "input_mapping": {
78
+ "invoice_id": "workflow_steps[0].result.invoice_id",
79
+ "amount": "workflow_steps[0].result.total_amount"
80
+ },
81
+ "output_schema": {
82
+ "analytics_report": "analytics_service.report"
83
+ }
84
+ }
85
+ ],
86
+ "join": {
87
+ "strategy": "merge",
88
+ "result_mapping": {
89
+ "combined_html": ["fork[0].generated_html"],
90
+ "analytics": ["fork[1].analytics_report"]
91
+ }
92
+ }
93
+ },
94
+ {
95
+ "step": "4",
96
+ "type": "switch",
97
+ "expression": "api_input.priority",
98
+ "cases": {
99
+ "high": {
100
+ "service": "priority_service",
101
+ "queue": "priority.process",
102
+ "input_mapping": {
103
+ "invoice_id": "workflow_steps[0].result.invoice_id",
104
+ "priority_flag": "api_input.priority"
105
+ },
106
+ "output_schema": {
107
+ "priority_result": "priority_service.result"
108
+ }
109
+ },
110
+ "low": {
111
+ "service": "standard_service",
112
+ "queue": "standard.process",
113
+ "input_mapping": {
114
+ "invoice_id": "workflow_steps[0].result.invoice_id"
115
+ },
116
+ "output_schema": {
117
+ "standard_result": "standard_service.result"
118
+ }
119
+ }
120
+ },
121
+ "default": {
122
+ "service": "fallback_service",
123
+ "queue": "fallback.process",
124
+ "input_mapping": {
125
+ "invoice_id": "workflow_steps[0].result.invoice_id"
126
+ },
127
+ "output_schema": {
128
+ "fallback_result": "fallback_service.result"
129
+ }
130
+ }
131
+ },
132
+ {
133
+ "step": "5",
134
+ "type": "sub_workflow",
135
+ "workflow_id": "generate_invoice_pdf",
136
+ "parameters": {
137
+ "invoice_id": "workflow_steps[0].result.invoice_id",
138
+ "html_content": "workflow_steps[3].result.combined_html"
139
+ }
140
+ },
141
+ {
142
+ "step": "6",
143
+ "type": "wait",
144
+ "duration": 30000,
145
+ "message": "Čekání 30 s než se vygeneruje PDF na úložišti"
146
+ },
147
+ {
148
+ "step": "7",
149
+ "type": "task",
150
+ "service": "pdf_service",
151
+ "queue": "pdf.convert",
152
+ "input_mapping": {
153
+ "html": "workflow_steps[3].result.combined_html",
154
+ "invoice_id": "workflow_steps[0].result.invoice_id"
155
+ },
156
+ "output_schema": {
157
+ "pdf_url": "pdf_service.pdf_url"
158
+ },
159
+ "retry": {
160
+ "max_attempts": 2,
161
+ "delay": 1000
162
+ }
163
+ },
164
+ {
165
+ "step": "7",
166
+ "type": "dispatch",
167
+ "method": "webhook",
168
+ "target": "https://client.example.com/webhook",
169
+ "input_mapping": {
170
+ "html": "workflow_steps[3].result.combined_html",
171
+ "invoice_id": "workflow_steps[0].result.invoice_id"
172
+ },
173
+ "retry": {
174
+ "max_attempts": 2,
175
+ "delay": 1000
176
+ }
177
+ }
178
+ ]
179
+ }
180
+
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@onlineapps/conn-orch-cookbook",
3
+ "version": "2.0.0",
4
+ "description": "Complete cookbook toolkit for all services - unified wrapper including core, executor, transformer, and router functionality",
5
+ "main": "src/index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/onlineapps/connector-cookbook.git"
9
+ },
10
+ "files": [
11
+ "src/",
12
+ "docs/",
13
+ "examples/",
14
+ "README.md",
15
+ "LICENSE",
16
+ "CHANGELOG.md"
17
+ ],
18
+ "scripts": {
19
+ "test": "jest --coverage",
20
+ "test:unit": "jest --testPathPattern=unit --coverage",
21
+ "test:component": "jest --testPathPattern=component --coverage",
22
+ "test:integration": "jest --testPathPattern=integration --coverage",
23
+ "test:fixtures": "jest test/integration/cookbook-fixtures.test.js",
24
+ "test:smoke": "jest test/smoke.test.js",
25
+ "test:watch": "jest --watch",
26
+ "test:coverage": "jest --coverage --coverageReporters=text-lcov html",
27
+ "lint": "eslint \"src/**/*.js\" \"tests/**/*.js\"",
28
+ "prettier:check": "prettier --check \"src/**/*.js\" \"tests/**/*.js\"",
29
+ "prettier:fix": "prettier --write \"src/**/*.js\" \"tests/**/*.js\"",
30
+ "docs": "jsdoc2md --files src/**/*.js > API.md"
31
+ },
32
+ "keywords": [
33
+ "connector",
34
+ "cookbook",
35
+ "workflow",
36
+ "orchestration",
37
+ "microservice",
38
+ "parser",
39
+ "validator",
40
+ "json-schema"
41
+ ],
42
+ "author": "OnlineApps Team <dev@onlineapps.io>",
43
+ "license": "MIT",
44
+ "bugs": {
45
+ "url": "https://github.com/onlineapps/connector-cookbook/issues"
46
+ },
47
+ "homepage": "https://github.com/onlineapps/connector-cookbook#readme",
48
+ "dependencies": {},
49
+ "devDependencies": {
50
+ "eslint": "^8.30.0",
51
+ "eslint-config-prettier": "^8.5.0",
52
+ "jest": "^29.5.0",
53
+ "prettier": "^2.8.0"
54
+ },
55
+ "engines": {
56
+ "node": ">=12"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public"
60
+ }
61
+ }
package/src/index.js ADDED
@@ -0,0 +1,230 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @module @onlineapps/conn-orch-cookbook
5
+ * @description Unified cookbook connector for service-wrapper integration.
6
+ * This is a THIN WRAPPER around cookbook-* modules, providing a single
7
+ * unified interface for all cookbook functionality.
8
+ *
9
+ * NO DUPLICATION: All implementation is in cookbook-* modules.
10
+ * This connector only re-exports and provides compatibility layer.
11
+ *
12
+ * @see {@link https://github.com/onlineapps/oa-drive/tree/main/shared/connector/conn-orch-cookbook|GitHub Repository}
13
+ * @author OA Drive Team
14
+ * @license MIT
15
+ * @since 2.0.0
16
+ */
17
+
18
+ // Import from shared cookbook modules - NO LOCAL IMPLEMENTATIONS!
19
+ const cookbookCore = require('../../../cookbook/cookbook-core');
20
+ const cookbookExecutor = require('../../../cookbook/cookbook-executor');
21
+ const cookbookTransformer = require('../../../cookbook/cookbook-transformer');
22
+ const cookbookRouter = require('../../../cookbook/cookbook-router');
23
+
24
+ // Re-export all from cookbook-core (parser and validator)
25
+ const {
26
+ parseCookbookFromFile,
27
+ parseCookbookFromFileSync,
28
+ parseCookbookFromObject,
29
+ validateCookbook,
30
+ validateStep,
31
+ CookbookValidationError,
32
+ validateAllReferences,
33
+ validateDependsOnReferences,
34
+ validateVariableReferences,
35
+ validateErrorHandlerReferences,
36
+ CookbookSchema,
37
+ loadSchema
38
+ } = cookbookCore;
39
+
40
+ // Re-export all from cookbook-executor
41
+ const {
42
+ CookbookExecutor,
43
+ ContextManager,
44
+ StepProcessor,
45
+ VariableResolver
46
+ } = cookbookExecutor;
47
+
48
+ // Re-export all from cookbook-transformer
49
+ const {
50
+ CookbookGenerator,
51
+ ApiSpecAnalyzer,
52
+ StepTranslator,
53
+ ResponseMapper,
54
+ createTransformer
55
+ } = cookbookTransformer;
56
+
57
+ // Re-export all from cookbook-router
58
+ const {
59
+ CookbookRouter,
60
+ ServiceDiscovery,
61
+ QueueManager,
62
+ RetryHandler,
63
+ createRouter
64
+ } = cookbookRouter;
65
+
66
+
67
+ /**
68
+ * Create a cookbook processor with all capabilities
69
+ * Factory function that creates a processor with parser, validator, executor, and router
70
+ *
71
+ * @function createProcessor
72
+ * @param {Object} [config={}] - Processor configuration
73
+ * @param {Object} [config.executor] - Executor configuration
74
+ * @param {Object} [config.router] - Router configuration
75
+ * @param {Object} [config.transformer] - Transformer configuration
76
+ * @param {Object} [config.mqClient] - Message queue client for router
77
+ * @param {Object} [config.registryClient] - Registry client for router
78
+ * @returns {Object} Processor instance with process method
79
+ *
80
+ * @example
81
+ * const processor = createProcessor({
82
+ * executor: { timeout: 30000 },
83
+ * router: { baseUrl: "http://api.example.com" },
84
+ * mqClient: mqConnector,
85
+ * registryClient: registryConnector
86
+ * });
87
+ *
88
+ * const result = await processor.process(cookbook);
89
+ */
90
+ function createProcessor(config = {}) {
91
+ const executor = new CookbookExecutor(config.executor);
92
+ const router = config.mqClient && config.registryClient
93
+ ? createRouter(config.mqClient, config.registryClient, config.router)
94
+ : null;
95
+ const transformer = createTransformer(config.transformer);
96
+ const mapper = new ResponseMapper(config.transformer);
97
+
98
+ return {
99
+ /**
100
+ * Process a cookbook through the full pipeline
101
+ * @param {Object|string} cookbook - Cookbook object or file path
102
+ * @param {Object} [context={}] - Execution context
103
+ * @returns {Promise<Object>} Execution result
104
+ */
105
+ async process(cookbook, context = {}) {
106
+ // Parse if string (file path)
107
+ if (typeof cookbook === 'string') {
108
+ cookbook = await parseCookbookFromFile(cookbook);
109
+ }
110
+
111
+ // Validate
112
+ validateCookbook(cookbook);
113
+
114
+ // Validate all references
115
+ validateAllReferences(cookbook);
116
+
117
+ // Execute with routing and transformation
118
+ const executionContext = {
119
+ ...context,
120
+ router,
121
+ transformer,
122
+ mapper
123
+ };
124
+
125
+ return executor.execute(cookbook, executionContext);
126
+ },
127
+
128
+ // Expose components for direct access
129
+ executor,
130
+ router,
131
+ transformer,
132
+ mapper
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Helper function to execute a single step
138
+ * Convenience wrapper around CookbookExecutor
139
+ *
140
+ * @function executeStep
141
+ * @param {Object} step - Step to execute
142
+ * @param {Object} [context={}] - Execution context
143
+ * @returns {Promise<Object>} Step execution result
144
+ *
145
+ * @example
146
+ * const result = await executeStep({
147
+ * id: "step1",
148
+ * type: "task",
149
+ * service: "api",
150
+ * action: "GET",
151
+ * endpoint: "/users"
152
+ * });
153
+ */
154
+ async function executeStep(step, context = {}) {
155
+ const executor = new CookbookExecutor();
156
+ return executor.executeStep(step, context);
157
+ }
158
+
159
+ /**
160
+ * Helper function to execute a complete workflow
161
+ * Convenience wrapper around CookbookExecutor
162
+ *
163
+ * @function executeWorkflow
164
+ * @param {Object} cookbook - Cookbook to execute
165
+ * @param {Object} [context={}] - Execution context
166
+ * @returns {Promise<Object>} Workflow execution result
167
+ *
168
+ * @example
169
+ * const result = await executeWorkflow(cookbook, {
170
+ * variables: { userId: 123 }
171
+ * });
172
+ */
173
+ async function executeWorkflow(cookbook, context = {}) {
174
+ const executor = new CookbookExecutor();
175
+ return executor.execute(cookbook, context);
176
+ }
177
+
178
+ // Export everything as unified interface
179
+ module.exports = {
180
+ // Parser functions (from cookbook-core)
181
+ parseCookbookFromFile,
182
+ parseCookbookFromFileSync,
183
+ parseCookbookFromObject,
184
+
185
+ // Validator functions (from cookbook-core)
186
+ validateCookbook,
187
+ validateStep,
188
+ CookbookValidationError,
189
+
190
+ // Reference validators (from cookbook-core)
191
+ validateAllReferences,
192
+ validateDependsOnReferences,
193
+ validateVariableReferences,
194
+ validateErrorHandlerReferences,
195
+
196
+ // Schema (from cookbook-core)
197
+ CookbookSchema,
198
+ loadSchema,
199
+
200
+ // Executor classes (from cookbook-executor)
201
+ CookbookExecutor,
202
+ ContextManager,
203
+ StepProcessor,
204
+ VariableResolver,
205
+
206
+ // Transformer classes (from cookbook-transformer)
207
+ CookbookGenerator,
208
+ ApiSpecAnalyzer,
209
+ StepTranslator,
210
+ ResponseMapper,
211
+ createTransformer,
212
+
213
+ // Router classes (from cookbook-router)
214
+ CookbookRouter,
215
+ ServiceDiscovery,
216
+ QueueManager,
217
+ RetryHandler,
218
+ createRouter,
219
+
220
+
221
+ // Factory and helper functions
222
+ createProcessor,
223
+ executeStep,
224
+ executeWorkflow,
225
+
226
+ // Version info
227
+ VERSION: '2.0.0',
228
+ COMPATIBLE_CORE_VERSION: cookbookCore.VERSION,
229
+ COMPATIBLE_SCHEMA_VERSION: cookbookCore.SCHEMA_VERSION
230
+ };