@kumologica/sdk 3.4.0 → 3.5.0-beta2

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.
Files changed (51) hide show
  1. package/cli/commands/create-commands/openapi.js +42 -0
  2. package/cli/commands/create.js +17 -8
  3. package/cli/commands/login.js +87 -0
  4. package/package.json +18 -7
  5. package/src/app/lib/ai/layout.js +75 -0
  6. package/src/app/lib/ai/openai.js +108 -0
  7. package/src/app/lib/ai/prompt.txt +583 -0
  8. package/src/app/lib/aws/ca-cloudwatch-api.js +2 -10
  9. package/src/app/lib/aws/ca-dynamodb-api.js +6 -10
  10. package/src/app/lib/aws/ca-elb-api.js +4 -24
  11. package/src/app/lib/aws/ca-events-api.js +5 -12
  12. package/src/app/lib/aws/ca-iot-api.js +3 -87
  13. package/src/app/lib/aws/ca-s3-api.js +17 -62
  14. package/src/app/lib/aws/ca-sns-api.js +6 -15
  15. package/src/app/lib/aws/ca-sqs-api.js +9 -6
  16. package/src/app/lib/aws/index.js +70 -86
  17. package/src/app/lib/aws/kl-apigw-api.js +40 -0
  18. package/src/app/lib/aws/kl-iam-api.js +5 -5
  19. package/src/app/lib/github/index.js +0 -17
  20. package/src/app/lib/serverless/index.js +1 -1
  21. package/src/app/lib/stores/settings-cloud-store.js +35 -2
  22. package/src/app/main.js +34 -32
  23. package/src/app/preload.js +36 -28
  24. package/src/app/ui/editor-client/public/red/red.js +924 -458
  25. package/src/app/ui/editor-client/public/red/red.min.js +2 -2
  26. package/src/app/ui/editor-client/public/red/style.min.css +1 -1
  27. package/src/app/ui/editor-client/src/js/nodes.js +19 -18
  28. package/src/app/ui/editor-client/src/js/red.js +6 -3
  29. package/src/app/ui/editor-client/src/js/ui/editor.js +70 -70
  30. package/src/app/ui/editor-client/src/js/ui/footer.js +143 -0
  31. package/src/app/ui/editor-client/src/js/ui/search.js +43 -34
  32. package/src/app/ui/editor-client/src/js/ui/sidebar.js +26 -24
  33. package/src/app/ui/editor-client/src/js/ui/signup.js +56 -0
  34. package/src/app/ui/editor-client/src/js/ui/tab-ai.js +210 -0
  35. package/src/app/ui/editor-client/src/js/ui/tab-awsDeploy.js +30 -5
  36. package/src/app/ui/editor-client/src/js/ui/tab-test.js +120 -99
  37. package/src/app/ui/editor-client/src/js/ui/update-panel.js +0 -1
  38. package/src/app/ui/editor-client/src/js/ui/view.js +201 -202
  39. package/src/app/ui/editor-client/src/sass/editor.scss +715 -645
  40. package/src/app/ui/editor-client/src/sass/sidebar.scss +21 -12
  41. package/src/app/ui/editor-client/src/sass/style.scss +101 -0
  42. package/src/app/ui/editor-client/src/sass/tab-ai.scss +68 -0
  43. package/src/app/ui/editor-client/src/sass/workspace.scss +12 -2
  44. package/src/app/ui/editor-client/templates/index.mst +41 -7
  45. package/src/server/DesignerServer.js +2 -1
  46. package/cli/.DS_Store +0 -0
  47. package/fixtures/.DS_Store +0 -0
  48. package/src/app/lib/aws/ca-apigw-api.js +0 -216
  49. package/src/app/lib/aws/ca-codecommit-api.js +0 -63
  50. package/src/app/lib/aws/kl-rekognition-api.js +0 -66
  51. package/src/app/lib/aws/kl-ssm-api.js +0 -24
@@ -0,0 +1,583 @@
1
+
2
+
3
+ As a software developer, your task is to produce a kumologica flow app implementation from a description given by the user at the end.
4
+ The specification of kumologica will be defined as a markdown in a series of rules enclosed by "---" delimiter as follows:
5
+
6
+ ---
7
+ # Specification
8
+
9
+
10
+
11
+ # FLOW RULES
12
+
13
+ - A kumologica flow app is implemented as a valid json document. Specifically is an array of nodes objects.
14
+ - A kumologica flow app consists of a number of flows, aka "api flows" or simply "api".
15
+ - An api is a collection of nodes connected to each other to form a logic DAG.
16
+ - An api is defined as one node acting as an entry point that will listen for an http request, and an ending node writing an http response. Between the entry and end node, there may be a number of connected nodes.
17
+ - The entry point node of an api is called EventListener, and the ending node is called EventListenerEnd.
18
+ - The EventListener node will filter an http request and it will output a kumologica message.
19
+ - The EventListenerEnd node will accept a kumologica message and it will write an http response.
20
+ - Any other node will accept and emit a kumologica message.
21
+ - A `msg` will visit one node and the message will be send to the node reference in the `wires` property.
22
+ - If not set otherwise, a node will have a maximum number of wires of 1.
23
+ - If more wires is required a `Switch` node must be used.
24
+ - If a node thrown an error, the error will be set in the msg object and send it to a `Catch` node.
25
+
26
+ # EXECUTION CONTEXT
27
+
28
+ - There are three context variables that are available to all nodes: `msg`, `vars`, and `env`. These are all mutable and can be used to store and retrieve temporary data by each node.
29
+ - These variables are encoded as json objects.
30
+ - The following is an example of a `msg` object. Specifically is the structure of the message that an EventListener node will send to the next node in the flow:
31
+
32
+ ```
33
+ {
34
+ "type": "object"
35
+ "properties": {
36
+ "_msgid": {
37
+ "type": "string",
38
+ "description": "Unique identifier for each execution of an api within a kumologica flow app"
39
+ },
40
+ "header": {
41
+ "type": "object",
42
+ "description": "An object encapsulating the triggering `event` and the `context`,
43
+ "properties": {
44
+ "event": {
45
+ "type": "object",
46
+ "properties": {
47
+ "Records": {
48
+ "type": "array",
49
+ "items": {
50
+ "type": "object",
51
+ "properties": {
52
+ "headers": {
53
+ "type": "object",
54
+ "description": "the key-value pairs of an standard http request from nodeJS"
55
+ },
56
+ "httpMethod": {
57
+ "type": "string"
58
+ },
59
+ "path": {
60
+ "type": "string"
61
+ },
62
+ "queryStringParameters": {
63
+ "type": "object"
64
+ }
65
+ },
66
+ "required": ["headers", "httpMethod", "path", "queryStringParameters"]
67
+ }
68
+ }
69
+ },
70
+ "required": ["Records"]
71
+ },
72
+ "context": {
73
+ "type": "object",
74
+ "description": "The execution context depending on the platform that runs the kumologica flow app"
75
+ }
76
+
77
+ }
78
+ },
79
+ "payload": {
80
+ "type": "object",
81
+ "description": "If available, it will contain the http request body"
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+
88
+ # NODES
89
+
90
+ - A node can be seen as a partial function, that is defined by a set of properties, and during runtime, it will take a `msg` as input and it will return a `msg` as output.
91
+
92
+ ## PROPERTIES
93
+
94
+ - Node properties can be of type string, number, array, or dynamic expression.
95
+ - A dynamic expression is a jsonata expression that takes the context variables: `msg`, `vars`, and `env` as bindings.
96
+ - Valid examples of dynamic expressions are: `msg.payload`, `'Hello ' & vars.name`
97
+
98
+ ## TABS
99
+
100
+ - Nodes are arranged in tabs when editing a flow. Each tab is a collection of nodes that are logically grouped together.
101
+ - A tab will be defined as a special element of the application flow, defined as:
102
+ ```
103
+
104
+ {
105
+ "type": "object",
106
+ "properties": {
107
+ "id": {
108
+ "type": "string",
109
+ "description": "Unique identifier for all nodes within this tab. If not specified use the default: "main.flow"
110
+ },
111
+ "type": {
112
+ "type": "string",
113
+ "description": "Identifies the node type. Value is "tab"
114
+ },
115
+ "label": {
116
+ "type": "string",
117
+ "description": "Human readable short label that references this tab and its purpose"
118
+ },
119
+ "disabled": {
120
+ "type": "boolean",
121
+ "description": "If true, the tab will be disabled. Default value is false"
122
+ },
123
+ "info": {
124
+ "type": "string",
125
+ "description": "Human readable description of the tab. Not used"
126
+ }
127
+ }
128
+ ```
129
+
130
+ - An example of a tab named main would be as follows:
131
+ ```
132
+
133
+ {
134
+ "id": "main.flow",
135
+ "type": "tab",
136
+ "label": "main",
137
+ "disabled": false,
138
+ "info": ""
139
+ }
140
+ ```
141
+
142
+ - All nodes in the flow within this tab, will be connected by setting the value of `z` to `main.flow`
143
+
144
+
145
+
146
+
147
+ ## SCHEMA
148
+
149
+ - The following is a common schema shared by all nodes:
150
+
151
+ ```
152
+ {
153
+ "type": "object",
154
+ "properties": {
155
+ "id": {
156
+ "type": "string",
157
+ "description": "Unique identifier for each instance of the node within a flow. This will be autogenerated using UUID".
158
+ },
159
+ "type": {
160
+ "type": "string",
161
+ "description": "Identifies the node type. It will be defined on each node schema"
162
+ },
163
+ "name": {
164
+ "type": "string",
165
+ "description": "Human readable short label that references this node and its purpose"
166
+ },
167
+ "z": {
168
+ "type": "string",
169
+ "description": "the id of the tab where this node is located. If not specified, it will be set to the default tab"
170
+ }
171
+ "wires: {
172
+ "type": "array",
173
+ "description": "Number of outputs of this node may have. If not specified, the maximum length of this array will be 1"
174
+ "items": {
175
+ "type": "array",
176
+ "items": {
177
+ "type": "string"
178
+ }
179
+ }
180
+ }
181
+ }
182
+ }
183
+ ```
184
+
185
+ - kumologica provides an out of the box set of nodes that form the core library.
186
+ - Kumologica allows to third party contributors to implement their own nodes. Each node is a npm project that will follow the convention: `{ account } /kumologica-contrib-{nodeName}`
187
+
188
+
189
+
190
+ # Node Library
191
+
192
+ Kumologica core library consist of the following nodes:
193
+
194
+ ## General
195
+
196
+ ```
197
+ [
198
+ {
199
+ "type": "object",
200
+ "description": "This node is responsible to listen to an API HTTP request, and filter the incoming event based on the 'method' and 'url' and transform the request into a kumologica message",
201
+ "properties": {
202
+ "type": "EventListener",
203
+ "provider": {
204
+ "type": "string",
205
+ "enum": [
206
+ "aws",
207
+ "nodejs"
208
+ ],
209
+ "description": "what target platform this flow will be deployed. Default: `nodejs`"
210
+ },
211
+ "napiMethod": {
212
+ "type": "string",
213
+ "enum": [
214
+ "any",
215
+ "get",
216
+ "post",
217
+ "delete",
218
+ "patch",
219
+ "put"
220
+ ],
221
+ "description": "The http method that will be implemented. This property is only applicable when provider is `nodejs`"
222
+ },
223
+ "apiMethod": {
224
+ "type": "string",
225
+ "enum": [
226
+ "any",
227
+ "get",
228
+ "post",
229
+ "delete",
230
+ "patch",
231
+ "put"
232
+ ],
233
+ "description": "The http method that will be implemented. This property is only applicable when provider is `aws`"
234
+ },
235
+ "apiUrl": {
236
+ "type": "string",
237
+ "description": "The path url that this flow will be listening to. This property is only applicable when provider is set to `aws`"
238
+ },
239
+ "napiUrl": {
240
+ "type": "string",
241
+ "description": "The path url that this flow will be listening to. This property is only applicable when provider is set to `nodejs`"
242
+ }
243
+ }
244
+ },
245
+ {
246
+ "type": "object",
247
+ "description": "This node is responsible to send a http response back to the caller.\n The `wires` property will be always set to []",
248
+ "properties": {
249
+ "type": "EventListener-End",
250
+ "statusCode": {
251
+ "type": "string",
252
+ "description": "A valid HTTP status code to indicate the outcome of the client's request. JSONata expression is acceptable"
253
+ },
254
+ "headers": {
255
+ "type": "object",
256
+ "description": "A key-value pair of strings that will be sent with the http response"
257
+ },
258
+ "payload": {
259
+ "type": "string",
260
+ "description": "this value corresponds with the body section of an http response, JSONata expression is acceptable, but not JS code"
261
+ }
262
+ }
263
+ }
264
+ ]
265
+ ```
266
+
267
+ ## Transformation
268
+
269
+ ```
270
+ [
271
+ {
272
+ "type": "object",
273
+ "description": "This node executes native nodejs code. Useful when no other node in the core library can be used to produce the output or step desired, or the complexity of configuring a node is too complex compare with js code",
274
+ "properties": {
275
+ "type": "Function",
276
+ "query": {
277
+ "type": "string",
278
+ "description": "\nJavascript (nodeJs) code that will be executed.It will take one input: `msg` object, and it will return a `msg` or it will throw an error.\nTo return a `msg` you can type: `node.send(msg)`, and to throw an error: `node.sendError(Error, msg)`;\nthe following variables will be available in the execution context: `msg` (the message received), `vars` (the variable context), and `env` (key-value pair of the environment variables)\nLogging can be added within this property by calling the methods: node.log(\"message\")\nYou can import external libraries with commonJS format.\nFor top level await, the following code needs to be included: \n`(async () => {\n function delay(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n try {\n await delay(2000);\n node.send(msg);\n } catch (error) {\n node.sendError(error, msg);\n }\n})(); `\n\nA call to node.sendError will follow the execution to a Catch node, otherwise the flow will terminate with an unhandled error\n\nIf external dependencies are used. Make sure in the final output, they are highlighted following the implementation of the kumologica flow app.\n",
279
+ "examples": [
280
+ "const currentTime = new Date();\n\n// Extract the time components\nconst hours = currentTime.getHours();\nconst minutes = currentTime.getMinutes();\nconst seconds = currentTime.getSeconds();\n\n// Format the time\nconst formattedTime = `${ hours }: ${ minutes }: ${ seconds }`;\n\nmsg.payload = formattedTime;\n\nnode.send(msg);\n"
281
+ ]
282
+ }
283
+ }
284
+ }
285
+ ]
286
+ ```
287
+
288
+ ## Validation
289
+
290
+ ```
291
+ [
292
+ {
293
+ "type": "object",
294
+ "description": "This node will validate a JSON object against a JSON schema. It uses the npm library Ajv. It will thrown an error `JSONSchemaValError` if the validation fails.\n Jumping the execution to a Catch node. This must have exactly one input and one output",
295
+ "properties": {
296
+ "type": "json-schema-validator",
297
+ "Property": {
298
+ "type": "string",
299
+ "description": "The json object that we want to validate. It supports a dynamic expression. Default value is \"msg.payload\""
300
+ },
301
+ "query": {
302
+ "type": "string",
303
+ "description": "The JSON schema used to validate the `Property` json object. \n AJV formats plugin is not included so any custom format must be implemented using the pattern property\n Example below check a property called `email` follows the format of a valid email address: \n \"{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"type\": \"object\",\n \"properties\": {\n \"email\": {\n \"type\": \"string\",\n \"pattern\": \"^\\S+@\\S+\\.\\S+$\"\n }\n },\n \"required\": [\"email\"]\n }\"\n "
304
+ }
305
+ }
306
+ }
307
+ ]
308
+ ```
309
+
310
+ ## Logging
311
+
312
+ ```
313
+ [
314
+ {
315
+ "type": "object",
316
+ "description": "This node writes a message into the console, useful for debugging purposes or setting some useful information on the console",
317
+ "properties": {
318
+ "type": "Logger",
319
+ "level": {
320
+ "type": "string",
321
+ "description": "The level of logging",
322
+ "enum": [
323
+ "INFO",
324
+ "ERROR",
325
+ "WARN",
326
+ "DEBUG",
327
+ "TRACE"
328
+ ],
329
+ "default": "INFO"
330
+ },
331
+ "message": {
332
+ "type": "string",
333
+ "description": "The message to print on the console. If follows a JSONata expression",
334
+ "examples": [
335
+ "$sum(msg.payload.Account.Order.Product.(Price * Quantity))"
336
+ ]
337
+ }
338
+ }
339
+ }
340
+ ]
341
+ ```
342
+
343
+ ## Web
344
+
345
+ ```
346
+ [
347
+ {
348
+ "type": "object",
349
+ "description": "This node can be used to execute external http requests, any error will be thrown as a HTTPClientError. The response received will be place in the msg as follows: `msg.http.statusCode` the result code; `msg.http.headers` the response headers; `msg.http.cookies` the response cookies, and `msg.payload` will be the response body",
350
+ "properties": {
351
+ "type": "HTTP Req",
352
+ "method": {
353
+ "type": "string",
354
+ "description": "A valid http method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS"
355
+ },
356
+ "url": {
357
+ "type": "string",
358
+ "description": "The target url expressed as a dynamic expression. Supports dynamic expression"
359
+ },
360
+ "ret": {
361
+ "type": "string",
362
+ "enum": [
363
+ "txt",
364
+ "bin",
365
+ "obj"
366
+ ],
367
+ "description": "\"txt\" to be used if response needs to be encoded as a UTF- 8 string(default ), \"bin\" to treat response as a binary buffer. \"obj\" to parsed the response as a JSON object\""
368
+ },
369
+ "responseTimeout": {
370
+ "type": "string",
371
+ "description": "Optional, timeout of the http request, before throwing error"
372
+ },
373
+ "followRedirect": {
374
+ "type": "boolean",
375
+ "description": "Optional. It determines whether the library should automatically follow HTTP redirects. True by default"
376
+ },
377
+ "maxRedirects": {
378
+ "type": "string",
379
+ "description": "Number of maximum redirects allow before throwing an error"
380
+ },
381
+ "headers": {
382
+ "type": "object",
383
+ "description": "A key value pair of standard http headers"
384
+ },
385
+ "authtype": {
386
+ "type": "string",
387
+ "enum": [
388
+ "none",
389
+ "basic",
390
+ "bearer"
391
+ ],
392
+ "description": "Type of authentication required. \"none\" no authentication required. \"basic\" basic auth required. \"bearer\" bearer token required"
393
+ },
394
+ "secUser": {
395
+ "type": "string",
396
+ "description": "the username to be used if \"basic\" authType is selected. Supports dynamic expression"
397
+ },
398
+ "secPassword": {
399
+ "type": "string",
400
+ "description": "the password ot be used if \"basic\" authType is selected. Supports dynamic expression"
401
+ },
402
+ "secToken": {
403
+ "type": "string",
404
+ "description": "the token to be used if \"bearer\" authType is selected. Supports dynamic expression"
405
+ }
406
+ }
407
+ }
408
+ ]
409
+ ```
410
+
411
+ ## Exception
412
+
413
+ ```
414
+ [
415
+ {
416
+ "type": "object",
417
+ "description": "This node will receive all errors thrown by all nodes defined in the `scope` property. Othewise, the error will be cause an early termination of the kumologica flow\n The process works as follows:\n - A node throws an error.\n - An error object is created with the following properties:\n - name: The error name\n - message: The error message\n - source: {\n - id: The id of the node that caused the error\n - type: The type of the node that caused the error\n - name: The name of the node that caused the error\n }\n An example of the msg with an error on it would be as follows:\n ```json\n {\n \"_msgid\": \"e8fb91dc.46c24\",\n \"header\": {},\n \"payload\": \"{}\",\n \"error: {\n \"name\": \"Error\",\n \"message\": \"Cannot read property 'name' of undefined\",\n \"source\": {\n \"id\": \"a2b2c3d4\",\n \"type\": \"function\",\n \"name\": \"Get Name\",\n \"count\": 1\n }\n }\n }\n\n ",
418
+ "properties": {
419
+ "type": "catch",
420
+ "scope": {
421
+ "type": "array",
422
+ "description": "The list of node ids that you want to catch the error from. \n if value is `null` the catch node will catch all errors thrown by nodes within the same tab, i.e. the same `z` property\"\n otherwise it will catch only errors thrown by nodes with an id that matches the value of any of the elements in the array"
423
+ }
424
+ }
425
+ }
426
+ ]
427
+ ```
428
+
429
+ ## Routing
430
+
431
+ ```
432
+ [
433
+ {
434
+ "type": "object",
435
+ "description": "This node will start an iteration over an array of items, each item will be placed on the `msg.payload` and it will be passed to the next node. The node will also add some useful metadata of the iteration to the `msg[\"_forEach\"]` let iterator = { id: App.util.generateId(), count: elements.length, index: i, type: 'array', break: false, skip: false } `msg[\"_forEach\"][iterator.id] = iterator; `msg[\"_forEach\"]['stack'].push(iterator.id);",
436
+ "properties": {
437
+ "type": "ForEach",
438
+ "array": {
439
+ "type": "string",
440
+ "description": "The array that you want to iterate. It supports dynamic expression. Default value is \"msg.payload\" log"
441
+ }
442
+ }
443
+ },
444
+ {
445
+ "type": "object",
446
+ "description": "This node will end the iteration over the forEach. Referring always to the last iterator in the stack. If all iterations have been completed, the node will pass in the msg.payload the array of all the msg.payload from each iteration. The following code will help to determine the current loop iterator: ```javascript let stack = msg[\"_foreach\"]['stack'] let latestIteratorId = stack[stack.length -1] return latestIteratorId; ```",
447
+ "properties": {
448
+ "type": "ForEachEnd"
449
+ }
450
+ },
451
+ {
452
+ "type": "object",
453
+ "description": "This node will be found always enclosed between a ForEach and a ForEachEnd node. When encounter the current iterator will be deleted and it will terminate the looping by passing the msg to its connected node. ",
454
+ "properties": {
455
+ "type": "ForEachBreak"
456
+ }
457
+ },
458
+ {
459
+ "type": "object",
460
+ "description": "This node will be used to create conditional routes, based on predicate. Unlike other nodes, the number of outputs (aka. wires) will depend on the number of different conditional routes defined",
461
+ "properties": {
462
+ "type": "Switch",
463
+ "outputs": {
464
+ "type": "number",
465
+ "description": "number of rules defined on the property `rules`"
466
+ },
467
+ "property": {
468
+ "type": "string",
469
+ "description": "The condition predicated encoded as a dynamic expression to be evaluated."
470
+ },
471
+ "rules": {
472
+ "type": "array",
473
+ "items": {
474
+ "type": "object",
475
+ "description": "Each item correspond with a possible route or condition that the predicate will be matched",
476
+ "properties": {
477
+ "t": {
478
+ "type": "string",
479
+ "enum": [
480
+ "eq",
481
+ "neq",
482
+ "lt",
483
+ "lte",
484
+ "gt",
485
+ "gte",
486
+ "btwn",
487
+ "cont",
488
+ "regex",
489
+ "true",
490
+ "false",
491
+ "null",
492
+ "nnull",
493
+ "isType",
494
+ "empty",
495
+ "nempty",
496
+ "else"
497
+ ],
498
+ "description": "\nThe predicate operators. Each one will be evaluated in a nodejs environment as per the following implementation: In all cases, `a` corresponds with the value of the evaluated expression of `property`, and `b`, if present, with the value of the rule property: `v` ```javascript eq: function(a, b) { return a === b; }, neq: function (a, b) { return a !== b; }, lt: function (a, b) { return a < b; }, lte: function (a, b) { return a <= b; }, gt: function (a, b) { return a > b; }, gte: function (a, b) { return a >= b; }, btwn: function (a, b, c) { return a >= b && a <= c; }, cont: function (a, b) { return (a + '').indexOf(b) != -1; }, regex: function (a, b, c, d) { return (a + '').match(new RegExp(b, d ? 'i' : '')); }, true: function (a) { return a === true; }, false: function (a) { return a === false; }, null: function (a) { return typeof a == 'undefined' || a === null; }, nnull: function (a) { return typeof a != 'undefined' && a !== null; }, empty: function (a) { return isEmpty(a); }, nempty: function (a) { return !isEmpty(a); }, istype: function (a, b) { \n if (b === 'array') { \n return Array.isArray(a); \n } else if (b === 'buffer') {\n return Buffer.isBuffer(a);\n } else if (b === 'json') {\n try {\n JSON.parse(a);\n return true;\n } catch (e) {\n // or maybe ??? a !== null; }\n return false;\n }\n } else if (b === 'null') {\n return a === null;\n } else {\n return (\n typeof a === b &&\n !Array.isArray(a) &&\n !Buffer.isBuffer(a) &&\n a !== null\n );\n }\n },\n else: function (a) { return a === true; }\n```\n"
499
+ },
500
+ "v": {
501
+ "type": "string",
502
+ "description": "The value that you want to compare in the predicate function"
503
+ },
504
+ "vt": {
505
+ "type": "string",
506
+ "enum": [
507
+ "str",
508
+ "num",
509
+ "camsg",
510
+ "cavars",
511
+ "caenv"
512
+ ],
513
+ "description": "the type of the value `v`. if `str` it will be treated as a string, if `num` it will be converted to a js number before executing the predicate, if `camsg`, `cavars`, or `caenv` it will interpolate first the value from the context variables: `msg`, `vars` and `env` respectively"
514
+ }
515
+ }
516
+ }
517
+ }
518
+ }
519
+ }
520
+ ]
521
+ ```
522
+
523
+ # Examples
524
+
525
+ For better understanding, here are some examples of how the flow should be implemented.
526
+
527
+ ```
528
+ [
529
+ {
530
+ "prompt": "Create a service that listens to /hello. and responds with a \"hello {user}\". Given user is passed as a query parameter.",
531
+ "completion": {
532
+ "flow": "[{\"id\":\"main.flow\",\"type\":\"tab\",\"label\":\"main\",\"disabled\":false,\"info\":\"\"},{\"id\":\"eacbb9ef.69d5c8\",\"type\":\"EventListener\",\"z\":\"main.flow\",\"name\":\"GET /hello\",\"provider\":\"aws\",\"eventSource\":\"api\",\"apiMethod\":\"get\",\"apiUrl\":\"/hello\",\"wires\":[[\"b5fc6ccd.17dd7\"]]},{\"id\":\"b5fc6ccd.17dd7\",\"type\":\"EventListener-End\",\"z\":\"main.flow\",\"name\":\"Success\",\"statusCode\":\"200\",\"responseType\":\"http\",\"headers\":{\"Content-Type\":\"text/plain \"},\"payload\":\"'Hello ' & msg.header.event.Records[0].queryStringParameters.name\",\"wires\":[]}]"
533
+ }
534
+ },
535
+ {
536
+ "prompt": "Create a service that listens to /uuid, and it returns a json with a random uuid in the property \"id\".",
537
+ "completion": {
538
+ "flow": "[{\"id\":\"main.flow\",\"type\":\"tab\",\"label\":\"main\",\"disabled\":false,\"info\":\"\"},{\"id\":\"eacbb9ef.69d5c8\",\"type\":\"EventListener\",\"z\":\"main.flow\",\"name\":\"GET /uuid\",\"provider\":\"nodejs\",\"neventSource\":\"napi\",\"napiMethod\":\"get\",\"napiUrl\":\"/uuid\",\"wires\":[[\"d15f2025.71a9c\"]]},{\"id\":\"d15f2025.71a9c\",\"type\":\"Function\",\"z\":\"main.flow\",\"name\":\"UUID Gen\",\"query\":\"\\\"\\\\nconst currentTime = new Date();\\\\n// Extract the time components\\\\nconst hours = currentTime.getHours();\\\\nconst minutes = currentTime.getMinutes();\\\\nconst seconds = currentTime.getSeconds();\\\\n\\\\n// Format the time\\\\nconst formattedTime = ${hours}: ${minutes}: ${seconds};\\\\nmsg.payload = formattedTime;\\\\nnode.send(msg);\\\\n\\\"\",\"wires\":[[\"b5fc6ccd.17dd7\"]]},{\"id\":\"b5fc6ccd.17dd7\",\"type\":\"EventListener-End\",\"z\":\"main.flow\",\"name\":\"Success\",\"statusCode\":\"200\",\"responseType\":\"http\",\"headers\":{\"Content-Type\":\"application/json\"},\"payload\":\"{ \\\"id\\\": msg.payload }\",\"wires\":[]}]"
539
+ }
540
+ },
541
+ {
542
+ "prompt": "Create an api that takes the body of a post request, compress it and returns it in the responses body",
543
+ "completion": {
544
+ "flow": "[{\"id\":\"main.flow\",\"type\":\"tab\",\"label\":\"main\",\"disabled\":false,\"info\":\"\"},{\"id\":\"eacbb9ef.69d5c8\",\"type\":\"EventListener\",\"z\":\"main.flow\",\"name\":\"POST /compress\",\"provider\":\"nodejs\",\"neventSource\":\"napi\",\"napiMethod\":\"post\",\"napiUrl\":\"/compress\",\"wires\":[[\"c5b3b6a8.edecf8\"]]},{\"id\":\"c5b3b6a8.edecf8\",\"type\":\"Function\",\"z\":\"main.flow\",\"name\":\"Compress\",\"query\":\"const zlib = require('zlib');\\n\\n// Compress the message\\nzlib.deflate(msg.payload, (err, buffer) => {\\n if (!err) {\\n node.payload(buffer.toString('base64'));\\n } else {\\n node.sendError(err, msg)\\n }\\n});\\n\\n\",\"wires\":[[\"b5fc6ccd.17dd7\"]]},{\"id\":\"b5fc6ccd.17dd7\",\"type\":\"EventListener-End\",\"z\":\"main.flow\",\"name\":\"Success\",\"statusCode\":\"200\",\"responseType\":\"http\",\"headers\":{\"Content-Type\":\"text/plain\"},\"payload\":\"msg.payload\",\"wires\":[]}]",
545
+ "dependencies": "zlib"
546
+ }
547
+ },
548
+ {
549
+ "prompt": "Create an API that may take an optional query parameter. If present returns the value in the body, otherwise return a 404 error message saying query parameter not present",
550
+ "completion": {
551
+ "flow": "[{\"id\":\"main.flow\",\"type\":\"tab\",\"label\":\"main\",\"disabled\":false,\"info\":\"\"},{\"id\":\"eacbb9ef.69d5c8\",\"type\":\"EventListener\",\"z\":\"main.flow\",\"name\":\"GET /exists\",\"provider\":\"nodejs\",\"neventSource\":\"napi\",\"napiMethod\":\"get\",\"napiUrl\":\"/exists\",\"wires\":[[\"c5b3b6a8.edecf8\"]]},{\"id\":\"c5b3b6a8.edecf8\",\"type\":\"Switch\",\"z\":\"main.flow\",\"name\":\"Check Query Param\",\"property\":\"msg.header.event.Records[0].queryStringParameters.name\",\"rules\":[{\"t\":\"nnull\"},{\"t\":\"else\"}],\"outputs\":2,\"wires\":[[\"b5fc6ccd.17dd7\"],[\"71be33d8.aaeccc\"]],\"caname\":\"switch\",\"category\":\"routing\"},{\"id\":\"b5fc6ccd.17dd7\",\"type\":\"EventListener-End\",\"z\":\"main.flow\",\"name\":\"Success\",\"statusCode\":\"200\",\"responseType\":\"http\",\"headers\":{\"Content-Type\":\"text/plain \"},\"payload\":\"msg.header.event.Records[0].queryStringParameters.name\",\"wires\":[]},{\"id\":\"71be33d8.aaeccc\",\"type\":\"EventListener-End\",\"z\":\"main.flow\",\"name\":\"Fail\",\"statusCode\":\"404\",\"responseType\":\"http\",\"headers\":{\"Content-Type\":\"text/plain \"},\"payload\":\"Query parameter not present\",\"wires\":[]}]"
552
+ }
553
+ },
554
+ {
555
+ "prompt": "create a lambda that takes a json object from the body with following mandatory properties: name, age and email. If any property is missing return a 404 saying validation error found, otherwise return ok saying all ok",
556
+ "completion": {
557
+ "flow": "[{\"id\":\"2f512264.34355e\",\"type\":\"EventListener\",\"z\":\"main.flow\",\"name\":\"POST validate\",\"provider\":\"aws\",\"eventSource\":\"api\",\"apiMethod\":\"post\",\"apiUrl\":\"/validate\",\"albMethod\":\"any\",\"wires\":[[\"9099c5aa.a663b8\"]]},{\"id\":\"9099c5aa.a663b8\",\"type\":\"json-schema-validator\",\"z\":\"main.flow\",\"name\":\"JSON Validator\",\"Property\":\"msg.payload\",\"query\":\"{\\n \\\"type\\\": \\\"object\\\",\\n \\\"required\\\": [\\\"name\\\", \\\"age\\\", \\\"email\\\"],\\n \\\"properties\\\": {\\n \\\"name\\\": {\\n \\\"type\\\": \\\"string\\\"\\n },\\n \\\"age\\\": {\\n \\\"type\\\": \\\"number\\\"\\n },\\n \\\"email\\\": {\\n \\\"type\\\": \\\"string\\\"\\n }\\n }\\n}\",\"wires\":[[\"b008d04a.5a375\"]]},{\"id\":\"5947f75.b3fa708\",\"type\":\"catch\",\"z\":\"main.flow\",\"name\":\"catch\",\"scope\":null,\"uncaught\":false,\"wires\":[[\"717c3f8a.50186\"]]},{\"id\":\"b008d04a.5a375\",\"type\":\"EventListener-End\",\"z\":\"main.flow\",\"name\":\"Return OK\",\"statusCode\":\"200\",\"responseType\":\"http\",\"headers\":{\"Content-Type\":\"text/plain \"},\"payload\":\"All ok\",\"eventType\":\"success\",\"wires\":[]},{\"id\":\"717c3f8a.50186\",\"type\":\"EventListener-End\",\"z\":\"main.flow\",\"name\":\"Return Error\",\"statusCode\":\"404\",\"responseType\":\"http\",\"headers\":{\"Content-Type\":\"text/plain \"},\"payload\":\"Validation error found\",\"eventPayload\":\"\",\"eventType\":\"success\",\"wires\":[]}]"
558
+ }
559
+ }
560
+ ]
561
+ ```
562
+
563
+ ---
564
+
565
+ Considering the above provided specification, generate a response with the following structure:
566
+ {
567
+ "type": "object",
568
+ "properties": {
569
+ "flow": {
570
+ "type": "string",
571
+ "description": 'kumologica flow app in valid json format. Do not escape new lines or quotes '
572
+ },
573
+ "dependencies": {
574
+ "type": "string",
575
+ "description": "Comma separated list of external dependencies used in the flow. Optional"
576
+ },
577
+ "explanation": {
578
+ "type": "string",
579
+ "description": "Used when user asked specifically for an explanation. Optional"
580
+ }
581
+ }
582
+ }
583
+
@@ -1,9 +1,7 @@
1
- const AWS = require('aws-sdk');
2
1
 
3
2
  class AWSCloudWatch {
4
3
 
5
- constructor(log) {
6
- this.cwLogs = new AWS.CloudWatchLogs();
4
+ constructor(config, log) {
7
5
  this.logger = log;
8
6
  }
9
7
 
@@ -66,13 +64,7 @@ class AWSCloudWatch {
66
64
  }, 900000);
67
65
  }
68
66
 
69
- async listLogGroups() {
70
- var logs = await this.cwLogs.describeLogGroups({}).promise();
71
-
72
- return logs.logGroups.map(function(v) {
73
- return {id: v.arn, name: v.logGroupName, arn: v.arn};
74
- });
75
- }
67
+
76
68
  }
77
69
 
78
70
  module.exports = AWSCloudWatch;
@@ -1,14 +1,9 @@
1
- const AWS = require('aws-sdk');
2
-
3
- /*
4
- * AWS JS API:
5
- * https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html
6
- */
7
1
  class CADynamoDb {
8
2
 
9
- constructor(log) {
3
+ constructor(config, log) {
10
4
  this.log = log;
11
- this.dynamodbstreams = new AWS.DynamoDBStreams();
5
+ const { DynamoDBStreamsClient } = require("@aws-sdk/client-dynamodb-streams");
6
+ this.dynamodbstreams = new DynamoDBStreamsClient(config);
12
7
  }
13
8
 
14
9
  /**
@@ -16,9 +11,10 @@ class CADynamoDb {
16
11
  */
17
12
  async listStreams() {
18
13
 
19
- const streams = await this.dynamodbstreams.listStreams({}).promise();
14
+ const { ListStreamsCommand } = require("@aws-sdk/client-dynamodb-streams");
15
+ const streams = await this.dynamodbstreams.send(new ListStreamsCommand({}));
20
16
 
21
- return streams.Streams.map(function(v) {
17
+ return streams.Streams.map(v => {
22
18
  return {id: v.StreamArn, name: v.TableName, arn: v.StreamArn};
23
19
  });
24
20
  }