@brika/blocks-builtin 0.2.1 → 0.3.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/locales/en/plugin.json +86 -15
- package/locales/fr/plugin.json +134 -63
- package/package.json +15 -5
- package/src/main.ts +95 -35
package/locales/en/plugin.json
CHANGED
|
@@ -161,23 +161,94 @@
|
|
|
161
161
|
"description": "Final data"
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
+
},
|
|
165
|
+
"spark-receiver": {
|
|
166
|
+
"name": "Spark Receiver",
|
|
167
|
+
"description": "Receives typed spark events from plugins",
|
|
168
|
+
"ports": {
|
|
169
|
+
"out": {
|
|
170
|
+
"name": "Payload",
|
|
171
|
+
"description": "The spark event payload"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
164
174
|
}
|
|
165
175
|
},
|
|
166
176
|
"fields": {
|
|
167
|
-
"field":
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
"
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
"
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
"field": {
|
|
178
|
+
"label": "Field",
|
|
179
|
+
"description": "Field path to check (e.g., \"value\", \"data.status\")"
|
|
180
|
+
},
|
|
181
|
+
"operator": {
|
|
182
|
+
"label": "Operator",
|
|
183
|
+
"description": "Comparison operator"
|
|
184
|
+
},
|
|
185
|
+
"value": {
|
|
186
|
+
"label": "Value",
|
|
187
|
+
"description": "Value to compare against"
|
|
188
|
+
},
|
|
189
|
+
"case1": {
|
|
190
|
+
"label": "Case 1",
|
|
191
|
+
"description": "Value for case 1"
|
|
192
|
+
},
|
|
193
|
+
"case2": {
|
|
194
|
+
"label": "Case 2",
|
|
195
|
+
"description": "Value for case 2"
|
|
196
|
+
},
|
|
197
|
+
"case3": {
|
|
198
|
+
"label": "Case 3",
|
|
199
|
+
"description": "Value for case 3"
|
|
200
|
+
},
|
|
201
|
+
"duration": {
|
|
202
|
+
"label": "Duration",
|
|
203
|
+
"description": "How long to wait"
|
|
204
|
+
},
|
|
205
|
+
"message": {
|
|
206
|
+
"label": "Message",
|
|
207
|
+
"description": "Message template with {{inputs.in.field}} expressions"
|
|
208
|
+
},
|
|
209
|
+
"level": {
|
|
210
|
+
"label": "Log Level",
|
|
211
|
+
"description": "Severity level for the log entry"
|
|
212
|
+
},
|
|
213
|
+
"status": {
|
|
214
|
+
"label": "Status",
|
|
215
|
+
"description": "End status of the workflow"
|
|
216
|
+
},
|
|
217
|
+
"template": {
|
|
218
|
+
"label": "Template",
|
|
219
|
+
"description": "Template to build output object"
|
|
220
|
+
},
|
|
221
|
+
"interval": {
|
|
222
|
+
"label": "Interval",
|
|
223
|
+
"description": "Time between ticks"
|
|
224
|
+
},
|
|
225
|
+
"emitOnStart": {
|
|
226
|
+
"label": "Emit on Start",
|
|
227
|
+
"description": "Emit an initial tick immediately when started"
|
|
228
|
+
},
|
|
229
|
+
"url": {
|
|
230
|
+
"label": "URL",
|
|
231
|
+
"description": "Request URL"
|
|
232
|
+
},
|
|
233
|
+
"method": {
|
|
234
|
+
"label": "Method",
|
|
235
|
+
"description": "HTTP method (GET, POST, etc.)"
|
|
236
|
+
},
|
|
237
|
+
"headers": {
|
|
238
|
+
"label": "Headers",
|
|
239
|
+
"description": "HTTP request headers"
|
|
240
|
+
},
|
|
241
|
+
"body": {
|
|
242
|
+
"label": "Body",
|
|
243
|
+
"description": "Request body (for POST/PUT/PATCH)"
|
|
244
|
+
},
|
|
245
|
+
"timeout": {
|
|
246
|
+
"label": "Timeout",
|
|
247
|
+
"description": "Request timeout"
|
|
248
|
+
},
|
|
249
|
+
"sparkType": {
|
|
250
|
+
"label": "Spark Type",
|
|
251
|
+
"description": "The spark type to listen for (e.g., timer:tick)"
|
|
252
|
+
}
|
|
182
253
|
}
|
|
183
254
|
}
|
package/locales/fr/plugin.json
CHANGED
|
@@ -3,181 +3,252 @@
|
|
|
3
3
|
"description": "Blocs de workflow de base pour les automatisations BRIKA",
|
|
4
4
|
"blocks": {
|
|
5
5
|
"clock": {
|
|
6
|
-
"name": "
|
|
6
|
+
"name": "Clock",
|
|
7
7
|
"description": "Émettre des ticks périodiques à un intervalle configurable",
|
|
8
8
|
"ports": {
|
|
9
9
|
"tick": {
|
|
10
10
|
"name": "Tick",
|
|
11
|
-
"description": "Émis à chaque intervalle avec compteur et
|
|
11
|
+
"description": "Émis à chaque intervalle avec compteur et timestamp"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"http-request": {
|
|
16
|
-
"name": "
|
|
16
|
+
"name": "HTTP Request",
|
|
17
17
|
"description": "Effectuer des requêtes HTTP vers des APIs externes",
|
|
18
18
|
"ports": {
|
|
19
19
|
"trigger": {
|
|
20
|
-
"name": "
|
|
20
|
+
"name": "Trigger",
|
|
21
21
|
"description": "Déclencher la requête HTTP"
|
|
22
22
|
},
|
|
23
23
|
"response": {
|
|
24
|
-
"name": "
|
|
25
|
-
"description": "Réponse HTTP avec
|
|
24
|
+
"name": "Response",
|
|
25
|
+
"description": "Réponse HTTP avec status, headers et body"
|
|
26
26
|
},
|
|
27
27
|
"error": {
|
|
28
|
-
"name": "
|
|
28
|
+
"name": "Error",
|
|
29
29
|
"description": "Détails de l'erreur si la requête échoue"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"condition": {
|
|
34
34
|
"name": "Condition",
|
|
35
|
-
"description": "Brancher selon une condition",
|
|
35
|
+
"description": "Brancher le flux selon une condition",
|
|
36
36
|
"ports": {
|
|
37
37
|
"in": {
|
|
38
|
-
"name": "
|
|
39
|
-
"description": "Valeur à
|
|
38
|
+
"name": "In",
|
|
39
|
+
"description": "Valeur à évaluer"
|
|
40
40
|
},
|
|
41
41
|
"then": {
|
|
42
|
-
"name": "
|
|
42
|
+
"name": "Then",
|
|
43
43
|
"description": "Sortie si la condition est vraie"
|
|
44
44
|
},
|
|
45
45
|
"else": {
|
|
46
|
-
"name": "
|
|
46
|
+
"name": "Else",
|
|
47
47
|
"description": "Sortie si la condition est fausse"
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"switch": {
|
|
52
|
-
"name": "
|
|
52
|
+
"name": "Switch",
|
|
53
53
|
"description": "Branchement multiple selon une valeur",
|
|
54
54
|
"ports": {
|
|
55
55
|
"in": {
|
|
56
|
-
"name": "
|
|
57
|
-
"description": "Valeur à
|
|
56
|
+
"name": "In",
|
|
57
|
+
"description": "Valeur à évaluer"
|
|
58
58
|
},
|
|
59
59
|
"case1": {
|
|
60
|
-
"name": "
|
|
60
|
+
"name": "Case 1",
|
|
61
61
|
"description": "Première sortie"
|
|
62
62
|
},
|
|
63
63
|
"case2": {
|
|
64
|
-
"name": "
|
|
64
|
+
"name": "Case 2",
|
|
65
65
|
"description": "Deuxième sortie"
|
|
66
66
|
},
|
|
67
67
|
"case3": {
|
|
68
|
-
"name": "
|
|
68
|
+
"name": "Case 3",
|
|
69
69
|
"description": "Troisième sortie"
|
|
70
70
|
},
|
|
71
71
|
"default": {
|
|
72
|
-
"name": "
|
|
73
|
-
"description": "Sortie si aucun cas ne correspond"
|
|
72
|
+
"name": "Default",
|
|
73
|
+
"description": "Sortie par défaut si aucun cas ne correspond"
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
},
|
|
77
77
|
"delay": {
|
|
78
|
-
"name": "
|
|
79
|
-
"description": "Attendre une durée spécifiée",
|
|
78
|
+
"name": "Delay",
|
|
79
|
+
"description": "Attendre une durée spécifiée avant de continuer",
|
|
80
80
|
"ports": {
|
|
81
81
|
"in": {
|
|
82
|
-
"name": "
|
|
82
|
+
"name": "In",
|
|
83
83
|
"description": "Données à retarder"
|
|
84
84
|
},
|
|
85
85
|
"out": {
|
|
86
|
-
"name": "
|
|
87
|
-
"description": "Données
|
|
86
|
+
"name": "Out",
|
|
87
|
+
"description": "Données après le délai"
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
91
|
"transform": {
|
|
92
|
-
"name": "
|
|
92
|
+
"name": "Transform",
|
|
93
93
|
"description": "Transformer ou extraire des données",
|
|
94
94
|
"ports": {
|
|
95
95
|
"in": {
|
|
96
|
-
"name": "
|
|
97
|
-
"description": "Données
|
|
96
|
+
"name": "In",
|
|
97
|
+
"description": "Données d'entrée"
|
|
98
98
|
},
|
|
99
99
|
"out": {
|
|
100
|
-
"name": "
|
|
100
|
+
"name": "Out",
|
|
101
101
|
"description": "Données transformées"
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
"log": {
|
|
106
|
-
"name": "
|
|
107
|
-
"description": "Enregistrer un message",
|
|
106
|
+
"name": "Log",
|
|
107
|
+
"description": "Enregistrer un message dans les logs",
|
|
108
108
|
"ports": {
|
|
109
109
|
"in": {
|
|
110
|
-
"name": "
|
|
111
|
-
"description": "Données à
|
|
110
|
+
"name": "In",
|
|
111
|
+
"description": "Données à logger"
|
|
112
112
|
},
|
|
113
113
|
"out": {
|
|
114
|
-
"name": "
|
|
115
|
-
"description": "Données
|
|
114
|
+
"name": "Out",
|
|
115
|
+
"description": "Données transmises sans modification"
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
119
|
"merge": {
|
|
120
|
-
"name": "
|
|
121
|
-
"description": "Attendre et
|
|
120
|
+
"name": "Merge",
|
|
121
|
+
"description": "Attendre et combiner plusieurs entrées",
|
|
122
122
|
"ports": {
|
|
123
123
|
"a": {
|
|
124
|
-
"name": "
|
|
124
|
+
"name": "Input A",
|
|
125
125
|
"description": "Première entrée"
|
|
126
126
|
},
|
|
127
127
|
"b": {
|
|
128
|
-
"name": "
|
|
128
|
+
"name": "Input B",
|
|
129
129
|
"description": "Deuxième entrée"
|
|
130
130
|
},
|
|
131
131
|
"out": {
|
|
132
|
-
"name": "
|
|
132
|
+
"name": "Out",
|
|
133
133
|
"description": "Entrées combinées"
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
"split": {
|
|
138
|
-
"name": "
|
|
139
|
-
"description": "Diviser
|
|
138
|
+
"name": "Split",
|
|
139
|
+
"description": "Diviser le flux en branches parallèles",
|
|
140
140
|
"ports": {
|
|
141
141
|
"in": {
|
|
142
|
-
"name": "
|
|
142
|
+
"name": "In",
|
|
143
143
|
"description": "Données à diviser"
|
|
144
144
|
},
|
|
145
145
|
"a": {
|
|
146
|
-
"name": "
|
|
146
|
+
"name": "Branch A",
|
|
147
147
|
"description": "Première branche"
|
|
148
148
|
},
|
|
149
149
|
"b": {
|
|
150
|
-
"name": "
|
|
150
|
+
"name": "Branch B",
|
|
151
151
|
"description": "Deuxième branche"
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
},
|
|
155
155
|
"end": {
|
|
156
|
-
"name": "
|
|
157
|
-
"description": "Terminer
|
|
156
|
+
"name": "End",
|
|
157
|
+
"description": "Terminer l'exécution du workflow",
|
|
158
158
|
"ports": {
|
|
159
159
|
"in": {
|
|
160
|
-
"name": "
|
|
160
|
+
"name": "In",
|
|
161
161
|
"description": "Données finales"
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
+
},
|
|
165
|
+
"spark-receiver": {
|
|
166
|
+
"name": "Récepteur Spark",
|
|
167
|
+
"description": "Reçoit des événements spark typés des plugins",
|
|
168
|
+
"ports": {
|
|
169
|
+
"out": {
|
|
170
|
+
"name": "Payload",
|
|
171
|
+
"description": "Le payload de l'événement spark"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
164
174
|
}
|
|
165
175
|
},
|
|
166
176
|
"fields": {
|
|
167
|
-
"field":
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
"
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
"
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
"field": {
|
|
178
|
+
"label": "Field",
|
|
179
|
+
"description": "Chemin du champ à évaluer (ex: \"value\", \"data.status\")"
|
|
180
|
+
},
|
|
181
|
+
"operator": {
|
|
182
|
+
"label": "Operator",
|
|
183
|
+
"description": "Opérateur de comparaison"
|
|
184
|
+
},
|
|
185
|
+
"value": {
|
|
186
|
+
"label": "Value",
|
|
187
|
+
"description": "Valeur à comparer"
|
|
188
|
+
},
|
|
189
|
+
"case1": {
|
|
190
|
+
"label": "Case 1",
|
|
191
|
+
"description": "Valeur pour le cas 1"
|
|
192
|
+
},
|
|
193
|
+
"case2": {
|
|
194
|
+
"label": "Case 2",
|
|
195
|
+
"description": "Valeur pour le cas 2"
|
|
196
|
+
},
|
|
197
|
+
"case3": {
|
|
198
|
+
"label": "Case 3",
|
|
199
|
+
"description": "Valeur pour le cas 3"
|
|
200
|
+
},
|
|
201
|
+
"duration": {
|
|
202
|
+
"label": "Duration",
|
|
203
|
+
"description": "Durée d'attente"
|
|
204
|
+
},
|
|
205
|
+
"message": {
|
|
206
|
+
"label": "Message",
|
|
207
|
+
"description": "Template du message avec expressions {{inputs.in.field}}"
|
|
208
|
+
},
|
|
209
|
+
"level": {
|
|
210
|
+
"label": "Level",
|
|
211
|
+
"description": "Niveau de log"
|
|
212
|
+
},
|
|
213
|
+
"status": {
|
|
214
|
+
"label": "Status",
|
|
215
|
+
"description": "Status de fin du workflow"
|
|
216
|
+
},
|
|
217
|
+
"template": {
|
|
218
|
+
"label": "Template",
|
|
219
|
+
"description": "Template pour construire l'objet de sortie"
|
|
220
|
+
},
|
|
221
|
+
"interval": {
|
|
222
|
+
"label": "Interval",
|
|
223
|
+
"description": "Temps entre les ticks"
|
|
224
|
+
},
|
|
225
|
+
"emitOnStart": {
|
|
226
|
+
"label": "Emit on Start",
|
|
227
|
+
"description": "Émettre un tick immédiatement au démarrage"
|
|
228
|
+
},
|
|
229
|
+
"url": {
|
|
230
|
+
"label": "URL",
|
|
231
|
+
"description": "URL de la requête"
|
|
232
|
+
},
|
|
233
|
+
"method": {
|
|
234
|
+
"label": "Method",
|
|
235
|
+
"description": "Méthode HTTP (GET, POST, PUT, PATCH, DELETE)"
|
|
236
|
+
},
|
|
237
|
+
"headers": {
|
|
238
|
+
"label": "Headers",
|
|
239
|
+
"description": "Headers HTTP de la requête"
|
|
240
|
+
},
|
|
241
|
+
"body": {
|
|
242
|
+
"label": "Body",
|
|
243
|
+
"description": "Corps de la requête (pour POST/PUT/PATCH)"
|
|
244
|
+
},
|
|
245
|
+
"timeout": {
|
|
246
|
+
"label": "Timeout",
|
|
247
|
+
"description": "Délai d'expiration de la requête"
|
|
248
|
+
},
|
|
249
|
+
"sparkType": {
|
|
250
|
+
"label": "Type de Spark",
|
|
251
|
+
"description": "Le type de spark à écouter (ex: timer:tick)"
|
|
252
|
+
}
|
|
182
253
|
}
|
|
183
254
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://schema.brika.dev/plugin.schema.json",
|
|
3
3
|
"name": "@brika/blocks-builtin",
|
|
4
|
-
"
|
|
4
|
+
"displayName": "Core Blocks",
|
|
5
|
+
"version": "0.3.0",
|
|
5
6
|
"description": "Core workflow blocks for BRIKA automations",
|
|
6
7
|
"author": "BRIKA Team",
|
|
7
8
|
"license": "MIT",
|
|
@@ -23,10 +24,11 @@
|
|
|
23
24
|
"condition",
|
|
24
25
|
"delay",
|
|
25
26
|
"home-automation",
|
|
26
|
-
"visual-programming"
|
|
27
|
+
"visual-programming",
|
|
28
|
+
"brika-plugin"
|
|
27
29
|
],
|
|
28
30
|
"engines": {
|
|
29
|
-
"brika": "^0.
|
|
31
|
+
"brika": "^0.3.0"
|
|
30
32
|
},
|
|
31
33
|
"type": "module",
|
|
32
34
|
"main": "./src/main.ts",
|
|
@@ -42,7 +44,7 @@
|
|
|
42
44
|
"scripts": {
|
|
43
45
|
"link": "bun link",
|
|
44
46
|
"tsc": "bunx --biome tsc --noEmit",
|
|
45
|
-
"prepublishOnly": "
|
|
47
|
+
"prepublishOnly": "brika-verify-plugin"
|
|
46
48
|
},
|
|
47
49
|
"blocks": [
|
|
48
50
|
{
|
|
@@ -124,10 +126,18 @@
|
|
|
124
126
|
"category": "action",
|
|
125
127
|
"icon": "square",
|
|
126
128
|
"color": "#dc2626"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": "spark-receiver",
|
|
132
|
+
"name": "Spark Receiver",
|
|
133
|
+
"description": "Receives typed spark events",
|
|
134
|
+
"category": "trigger",
|
|
135
|
+
"icon": "zap",
|
|
136
|
+
"color": "#f59e0b"
|
|
127
137
|
}
|
|
128
138
|
],
|
|
129
139
|
"dependencies": {
|
|
130
|
-
"@brika/sdk": "0.
|
|
140
|
+
"@brika/sdk": "0.3.0",
|
|
131
141
|
"zod": "^4.3.4"
|
|
132
142
|
}
|
|
133
143
|
}
|
package/src/main.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
log,
|
|
15
15
|
map,
|
|
16
16
|
output,
|
|
17
|
-
|
|
17
|
+
subscribeSpark,
|
|
18
18
|
z,
|
|
19
19
|
} from '@brika/sdk';
|
|
20
20
|
|
|
@@ -52,16 +52,25 @@ export const httpRequest = defineReactiveBlock(
|
|
|
52
52
|
body: z.string().optional().describe('Request body (for POST/PUT/PATCH)'),
|
|
53
53
|
}),
|
|
54
54
|
},
|
|
55
|
-
({ inputs, outputs, config
|
|
55
|
+
({ inputs, outputs, config }) => {
|
|
56
56
|
inputs.trigger.on(async () => {
|
|
57
|
-
log(
|
|
57
|
+
log.debug(`HTTP ${config.method ?? 'GET'} ${config.url}`);
|
|
58
58
|
try {
|
|
59
59
|
const res = await fetch(config.url, {
|
|
60
60
|
method: config.method ?? 'GET',
|
|
61
61
|
headers: config.headers,
|
|
62
62
|
body: config.body,
|
|
63
63
|
});
|
|
64
|
-
|
|
64
|
+
|
|
65
|
+
// Read body as text first, then try to parse as JSON
|
|
66
|
+
const text = await res.text();
|
|
67
|
+
let body: unknown;
|
|
68
|
+
try {
|
|
69
|
+
body = JSON.parse(text);
|
|
70
|
+
} catch {
|
|
71
|
+
body = text;
|
|
72
|
+
}
|
|
73
|
+
|
|
65
74
|
outputs.response.emit({
|
|
66
75
|
status: res.status,
|
|
67
76
|
statusText: res.statusText,
|
|
@@ -69,7 +78,7 @@ export const httpRequest = defineReactiveBlock(
|
|
|
69
78
|
body,
|
|
70
79
|
});
|
|
71
80
|
} catch (err) {
|
|
72
|
-
log(
|
|
81
|
+
log.error(`HTTP request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
73
82
|
outputs.error.emit({ message: String(err) });
|
|
74
83
|
}
|
|
75
84
|
});
|
|
@@ -92,8 +101,8 @@ export const condition = defineReactiveBlock(
|
|
|
92
101
|
in: input(z.generic(), { name: 'Input' }),
|
|
93
102
|
},
|
|
94
103
|
outputs: {
|
|
95
|
-
|
|
96
|
-
|
|
104
|
+
pass: output(z.passthrough('in'), { name: 'Then' }),
|
|
105
|
+
fail: output(z.passthrough('in'), { name: 'Else' }),
|
|
97
106
|
},
|
|
98
107
|
config: z.object({
|
|
99
108
|
field: z.string().describe('Field path to check (e.g., "value", "data.status")'),
|
|
@@ -103,16 +112,16 @@ export const condition = defineReactiveBlock(
|
|
|
103
112
|
value: z.any().optional().describe('Value to compare against'),
|
|
104
113
|
}),
|
|
105
114
|
},
|
|
106
|
-
({ inputs, outputs, config
|
|
115
|
+
({ inputs, outputs, config }) => {
|
|
107
116
|
inputs.in.on((data) => {
|
|
108
117
|
const fieldValue = getFieldValue(data, config.field);
|
|
109
118
|
const result = evaluate(fieldValue, config.operator, config.value);
|
|
110
|
-
log(
|
|
119
|
+
log.debug(`Condition: ${config.field} ${config.operator} ${JSON.stringify(config.value)} = ${result}`);
|
|
111
120
|
|
|
112
121
|
if (result) {
|
|
113
|
-
outputs.
|
|
122
|
+
outputs.pass.emit(data);
|
|
114
123
|
} else {
|
|
115
|
-
outputs.
|
|
124
|
+
outputs.fail.emit(data);
|
|
116
125
|
}
|
|
117
126
|
});
|
|
118
127
|
}
|
|
@@ -181,10 +190,10 @@ export const switchBlock = defineReactiveBlock(
|
|
|
181
190
|
case3: z.any().optional().describe('Value for case 3'),
|
|
182
191
|
}),
|
|
183
192
|
},
|
|
184
|
-
({ inputs, outputs, config
|
|
193
|
+
({ inputs, outputs, config }) => {
|
|
185
194
|
inputs.in.on((data) => {
|
|
186
195
|
const value = getFieldValue(data, config.field);
|
|
187
|
-
log(
|
|
196
|
+
log.debug(`Switch value: ${JSON.stringify(value)}`);
|
|
188
197
|
|
|
189
198
|
if (value === config.case1) {
|
|
190
199
|
outputs.case1.emit(data);
|
|
@@ -221,8 +230,8 @@ export const delay = defineReactiveBlock(
|
|
|
221
230
|
duration: z.duration(undefined, 'Duration to wait'),
|
|
222
231
|
}),
|
|
223
232
|
},
|
|
224
|
-
({ inputs, outputs, config
|
|
225
|
-
log(
|
|
233
|
+
({ inputs, outputs, config }) => {
|
|
234
|
+
log.debug(`Delay configured: ${config.duration}ms`);
|
|
226
235
|
|
|
227
236
|
// Use delay operator to wait before emitting
|
|
228
237
|
inputs.in.pipe(delayOp(config.duration)).to(outputs.out);
|
|
@@ -249,7 +258,7 @@ export const clock = defineReactiveBlock(
|
|
|
249
258
|
interval: z.duration(undefined, 'Interval between ticks'),
|
|
250
259
|
}),
|
|
251
260
|
},
|
|
252
|
-
({ outputs, config,
|
|
261
|
+
({ outputs, config, start }) => {
|
|
253
262
|
start(interval(config.interval))
|
|
254
263
|
.pipe(
|
|
255
264
|
map((count) => {
|
|
@@ -257,7 +266,7 @@ export const clock = defineReactiveBlock(
|
|
|
257
266
|
})
|
|
258
267
|
)
|
|
259
268
|
.to(outputs.tick);
|
|
260
|
-
log(
|
|
269
|
+
log.info(`Clock started with interval: ${config.interval}ms`);
|
|
261
270
|
}
|
|
262
271
|
);
|
|
263
272
|
|
|
@@ -284,7 +293,7 @@ export const transform = defineReactiveBlock(
|
|
|
284
293
|
template: z.record(z.string(), z.string()).optional().describe('Template to build output'),
|
|
285
294
|
}),
|
|
286
295
|
},
|
|
287
|
-
({ inputs, outputs, config
|
|
296
|
+
({ inputs, outputs, config }) => {
|
|
288
297
|
inputs.in
|
|
289
298
|
.pipe(
|
|
290
299
|
map((data) => {
|
|
@@ -294,14 +303,14 @@ export const transform = defineReactiveBlock(
|
|
|
294
303
|
for (const [key, path] of Object.entries(config.template)) {
|
|
295
304
|
result[key] = getFieldValue(data, path);
|
|
296
305
|
}
|
|
297
|
-
log(
|
|
306
|
+
log.debug(`Transformed with template: ${JSON.stringify(result)}`);
|
|
298
307
|
return result;
|
|
299
308
|
}
|
|
300
309
|
|
|
301
310
|
// If field is provided, extract it
|
|
302
311
|
if (config.field) {
|
|
303
312
|
const value = getFieldValue(data, config.field);
|
|
304
|
-
log(
|
|
313
|
+
log.debug(`Extracted field ${config.field}: ${JSON.stringify(value)}`);
|
|
305
314
|
return value;
|
|
306
315
|
}
|
|
307
316
|
|
|
@@ -327,7 +336,7 @@ function interpolate(
|
|
|
327
336
|
template: string,
|
|
328
337
|
context: { inputs: Record<string, unknown>; config: Record<string, unknown> }
|
|
329
338
|
): string {
|
|
330
|
-
return template.
|
|
339
|
+
return template.replaceAll(/\{\{([^{}]+)}}/g, (_, expr: string) => {
|
|
331
340
|
const path = expr.trim().split('.');
|
|
332
341
|
let value: unknown = context;
|
|
333
342
|
|
|
@@ -339,7 +348,8 @@ function interpolate(
|
|
|
339
348
|
|
|
340
349
|
if (value === undefined || value === null) return '';
|
|
341
350
|
if (typeof value === 'object') return JSON.stringify(value);
|
|
342
|
-
|
|
351
|
+
if (typeof value === 'string') return value;
|
|
352
|
+
return JSON.stringify(value);
|
|
343
353
|
});
|
|
344
354
|
}
|
|
345
355
|
|
|
@@ -366,18 +376,18 @@ export const logBlock = defineReactiveBlock(
|
|
|
366
376
|
level: z.enum(['debug', 'info', 'warn', 'error']).default('info').describe('Log level'),
|
|
367
377
|
}),
|
|
368
378
|
},
|
|
369
|
-
({ inputs, outputs, config
|
|
379
|
+
({ inputs, outputs, config }) => {
|
|
370
380
|
inputs.in.on((data) => {
|
|
371
|
-
const
|
|
381
|
+
const c = {
|
|
372
382
|
inputs: { in: data },
|
|
373
|
-
config
|
|
383
|
+
config,
|
|
374
384
|
};
|
|
375
385
|
|
|
376
386
|
const message = config.message
|
|
377
|
-
? interpolate(config.message,
|
|
387
|
+
? interpolate(config.message, c)
|
|
378
388
|
: JSON.stringify(data);
|
|
379
389
|
|
|
380
|
-
log
|
|
390
|
+
log[config.level](message);
|
|
381
391
|
outputs.out.emit(data);
|
|
382
392
|
});
|
|
383
393
|
}
|
|
@@ -410,12 +420,12 @@ export const merge = defineReactiveBlock(
|
|
|
410
420
|
},
|
|
411
421
|
config: z.object({}),
|
|
412
422
|
},
|
|
413
|
-
({ inputs, outputs
|
|
423
|
+
({ inputs, outputs }) => {
|
|
414
424
|
// Combine waits for both inputs to have values
|
|
415
425
|
combine(inputs.a, inputs.b)
|
|
416
426
|
.pipe(
|
|
417
427
|
map(([a, b]) => {
|
|
418
|
-
log('
|
|
428
|
+
log.debug('Merged inputs');
|
|
419
429
|
return { a, b };
|
|
420
430
|
})
|
|
421
431
|
)
|
|
@@ -444,9 +454,9 @@ export const split = defineReactiveBlock(
|
|
|
444
454
|
},
|
|
445
455
|
config: z.object({}),
|
|
446
456
|
},
|
|
447
|
-
({ inputs, outputs
|
|
457
|
+
({ inputs, outputs }) => {
|
|
448
458
|
inputs.in.on((data) => {
|
|
449
|
-
log('
|
|
459
|
+
log.debug('Splitting to parallel branches');
|
|
450
460
|
outputs.a.emit(data);
|
|
451
461
|
outputs.b.emit(data);
|
|
452
462
|
});
|
|
@@ -473,14 +483,64 @@ export const end = defineReactiveBlock(
|
|
|
473
483
|
status: z.enum(['success', 'failure']).default('success').describe('End status'),
|
|
474
484
|
}),
|
|
475
485
|
},
|
|
476
|
-
({ inputs, config
|
|
486
|
+
({ inputs, config }) => {
|
|
477
487
|
inputs.in.on((data) => {
|
|
478
|
-
log(
|
|
479
|
-
log(
|
|
488
|
+
log.info(`Workflow ended with status: ${config.status}`);
|
|
489
|
+
log.debug(`Final data: ${JSON.stringify(data)}`);
|
|
480
490
|
});
|
|
481
491
|
}
|
|
482
492
|
);
|
|
483
493
|
|
|
494
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
495
|
+
// Spark Receiver Block - Receive typed events
|
|
496
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Spark Receiver Block
|
|
500
|
+
*
|
|
501
|
+
* This is a trigger block that receives typed spark events from the hub.
|
|
502
|
+
* The hub subscribes to the configured spark type and emits data directly
|
|
503
|
+
* to the output port via blockEmit IPC.
|
|
504
|
+
*
|
|
505
|
+
* Configuration:
|
|
506
|
+
* - sparkType: Full spark type to listen for (e.g., "timer:timer-started")
|
|
507
|
+
*
|
|
508
|
+
* The output type is resolved dynamically from the selected spark's schema
|
|
509
|
+
* using the z.resolved() type marker.
|
|
510
|
+
*/
|
|
511
|
+
export const sparkReceiver = defineReactiveBlock(
|
|
512
|
+
{
|
|
513
|
+
id: 'spark-receiver',
|
|
514
|
+
name: 'Spark Receiver',
|
|
515
|
+
description: 'Receives typed spark events',
|
|
516
|
+
category: 'trigger',
|
|
517
|
+
icon: 'zap',
|
|
518
|
+
color: '#f59e0b',
|
|
519
|
+
inputs: {},
|
|
520
|
+
outputs: {
|
|
521
|
+
// Output type is resolved from spark's schema via config.sparkType
|
|
522
|
+
out: output(z.resolved('spark', 'sparkType'), { name: 'Payload' }),
|
|
523
|
+
},
|
|
524
|
+
config: z.object({
|
|
525
|
+
sparkType: z.sparkType('Spark type to listen for'),
|
|
526
|
+
}),
|
|
527
|
+
},
|
|
528
|
+
({ config, outputs, start }) => {
|
|
529
|
+
if (!config.sparkType) {
|
|
530
|
+
log.warn('No spark type configured');
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
log.info(`Subscribing to spark: ${config.sparkType}`);
|
|
535
|
+
|
|
536
|
+
// Subscribe to sparks and emit payload to output
|
|
537
|
+
// Cleanup is automatic when block stops (via flow system)
|
|
538
|
+
start(subscribeSpark(config.sparkType))
|
|
539
|
+
.pipe(map((event) => event.payload))
|
|
540
|
+
.to(outputs.out);
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
|
|
484
544
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
485
545
|
|
|
486
|
-
log('
|
|
546
|
+
log.info('Built-in blocks plugin loaded');
|