@hostwebhook/node-types 1.70.0 → 1.71.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bucket-operations.d.ts +88 -0
- package/dist/bucket-operations.js +140 -0
- package/dist/connections.js +1 -0
- package/dist/dispatch.js +1 -0
- package/dist/esm/bucket-operations.d.ts +88 -0
- package/dist/esm/bucket-operations.js +136 -0
- package/dist/esm/connections.js +1 -0
- package/dist/esm/dispatch.js +1 -0
- package/dist/esm/github-operations.js +67 -67
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/jira-operations.js +47 -47
- package/dist/esm/registry.d.ts +4 -4
- package/dist/esm/registry.js +540 -210
- package/dist/esm/types.d.ts +1 -1
- package/dist/esm/ui.js +2 -0
- package/dist/github-operations.js +67 -67
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -2
- package/dist/jira-operations.js +47 -47
- package/dist/registry.d.ts +4 -4
- package/dist/registry.js +540 -210
- package/dist/types.d.ts +1 -1
- package/dist/ui.js +2 -0
- package/package.json +1 -1
package/dist/esm/registry.js
CHANGED
|
@@ -8,151 +8,289 @@
|
|
|
8
8
|
export const NODE_REGISTRY = {
|
|
9
9
|
// ── Sources ──
|
|
10
10
|
webhook: {
|
|
11
|
-
type:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
type: "webhook",
|
|
12
|
+
prefix: "wh",
|
|
13
|
+
label: "Webhook",
|
|
14
|
+
group: "Sources",
|
|
15
|
+
detailPath: "/dashboard/webhooks",
|
|
16
|
+
apiPath: "/webhooks",
|
|
17
|
+
stateKey: "webhooks",
|
|
18
|
+
allStateKey: "allWebhooks",
|
|
19
|
+
color: "#a78bfa",
|
|
20
|
+
testable: false,
|
|
15
21
|
},
|
|
16
22
|
scheduledWorkflow: {
|
|
17
|
-
type:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
type: "scheduledWorkflow",
|
|
24
|
+
prefix: "swf",
|
|
25
|
+
label: "Scheduled Workflow",
|
|
26
|
+
group: "Sources",
|
|
27
|
+
detailPath: "/dashboard/scheduled-workflows",
|
|
28
|
+
apiPath: "/scheduled-workflows",
|
|
29
|
+
stateKey: "scheduledWorkflows",
|
|
30
|
+
allStateKey: "allScheduledWorkflows",
|
|
31
|
+
color: "#2dd4bf",
|
|
32
|
+
testable: true,
|
|
21
33
|
},
|
|
22
34
|
chatTrigger: {
|
|
23
|
-
type:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
type: "chatTrigger",
|
|
36
|
+
prefix: "chat",
|
|
37
|
+
label: "Chat Trigger",
|
|
38
|
+
group: "Sources",
|
|
39
|
+
detailPath: "/dashboard/chat-triggers",
|
|
40
|
+
apiPath: "/chat-triggers",
|
|
41
|
+
stateKey: "chatTriggers",
|
|
42
|
+
allStateKey: "allChatTriggers",
|
|
43
|
+
color: "#06b6d4",
|
|
44
|
+
testable: false,
|
|
27
45
|
},
|
|
28
46
|
trigger: {
|
|
29
|
-
type:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
47
|
+
type: "trigger",
|
|
48
|
+
prefix: "trg",
|
|
49
|
+
label: "Trigger",
|
|
50
|
+
group: "Sources",
|
|
51
|
+
detailPath: "/dashboard/triggers",
|
|
52
|
+
apiPath: "/triggers",
|
|
53
|
+
stateKey: "triggers",
|
|
54
|
+
allStateKey: "allTriggers",
|
|
55
|
+
color: "#ef4444",
|
|
56
|
+
testable: false,
|
|
33
57
|
},
|
|
34
58
|
voiceAgent: {
|
|
35
|
-
type:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
59
|
+
type: "voiceAgent",
|
|
60
|
+
prefix: "va",
|
|
61
|
+
label: "Voice Agent",
|
|
62
|
+
group: "Sources",
|
|
63
|
+
detailPath: "/dashboard/voice-agents",
|
|
64
|
+
apiPath: "/voice-agents",
|
|
65
|
+
stateKey: "voiceAgents",
|
|
66
|
+
allStateKey: "allVoiceAgents",
|
|
67
|
+
color: "#a855f7",
|
|
68
|
+
testable: false,
|
|
39
69
|
},
|
|
40
70
|
// ── Flow Control ──
|
|
41
71
|
filter: {
|
|
42
|
-
type:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
type: "filter",
|
|
73
|
+
prefix: "fi",
|
|
74
|
+
label: "Filter",
|
|
75
|
+
group: "Flow Control",
|
|
76
|
+
detailPath: "/dashboard/filter-nodes",
|
|
77
|
+
apiPath: "/filter-nodes",
|
|
78
|
+
stateKey: "filterNodes",
|
|
79
|
+
allStateKey: "allFilterNodes",
|
|
80
|
+
color: "#facc15",
|
|
81
|
+
testable: true,
|
|
46
82
|
},
|
|
47
83
|
transform: {
|
|
48
|
-
type:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
84
|
+
type: "transform",
|
|
85
|
+
prefix: "tr",
|
|
86
|
+
label: "Transform",
|
|
87
|
+
group: "Flow Control",
|
|
88
|
+
detailPath: "/dashboard/transform-nodes",
|
|
89
|
+
apiPath: "/transform-nodes",
|
|
90
|
+
stateKey: "transformNodes",
|
|
91
|
+
allStateKey: "allTransformNodes",
|
|
92
|
+
color: "#fbbf24",
|
|
93
|
+
testable: true,
|
|
52
94
|
},
|
|
53
95
|
schemaValidator: {
|
|
54
|
-
type:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
96
|
+
type: "schemaValidator",
|
|
97
|
+
prefix: "sv",
|
|
98
|
+
label: "Schema Validator",
|
|
99
|
+
group: "Flow Control",
|
|
100
|
+
detailPath: "/dashboard/schema-validators",
|
|
101
|
+
apiPath: "/schema-validators",
|
|
102
|
+
stateKey: "schemaValidators",
|
|
103
|
+
allStateKey: "allSchemaValidators",
|
|
104
|
+
color: "#818cf8",
|
|
105
|
+
testable: true,
|
|
58
106
|
},
|
|
59
107
|
conditional: {
|
|
60
|
-
type:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
108
|
+
type: "conditional",
|
|
109
|
+
prefix: "cond",
|
|
110
|
+
label: "Conditional",
|
|
111
|
+
group: "Flow Control",
|
|
112
|
+
detailPath: "/dashboard/conditional-nodes",
|
|
113
|
+
apiPath: "/conditional-nodes",
|
|
114
|
+
stateKey: "conditionalNodes",
|
|
115
|
+
allStateKey: "allConditionalNodes",
|
|
116
|
+
color: "#c084fc",
|
|
117
|
+
testable: true,
|
|
64
118
|
},
|
|
65
119
|
delay: {
|
|
66
|
-
type:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
120
|
+
type: "delay",
|
|
121
|
+
prefix: "delay",
|
|
122
|
+
label: "Delay",
|
|
123
|
+
group: "Flow Control",
|
|
124
|
+
detailPath: "/dashboard/delay-nodes",
|
|
125
|
+
apiPath: "/delay-nodes",
|
|
126
|
+
stateKey: "delayNodes",
|
|
127
|
+
allStateKey: "allDelayNodes",
|
|
128
|
+
color: "#94a3b8",
|
|
129
|
+
testable: true,
|
|
70
130
|
},
|
|
71
131
|
rateLimiter: {
|
|
72
|
-
type:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
132
|
+
type: "rateLimiter",
|
|
133
|
+
prefix: "rl",
|
|
134
|
+
label: "Rate Limiter",
|
|
135
|
+
group: "Flow Control",
|
|
136
|
+
detailPath: "/dashboard/rate-limiter-nodes",
|
|
137
|
+
apiPath: "/rate-limiter-nodes",
|
|
138
|
+
stateKey: "rateLimiterNodes",
|
|
139
|
+
allStateKey: "allRateLimiterNodes",
|
|
140
|
+
color: "#f97316",
|
|
141
|
+
testable: false,
|
|
76
142
|
},
|
|
77
143
|
aggregator: {
|
|
78
|
-
type:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
144
|
+
type: "aggregator",
|
|
145
|
+
prefix: "agg",
|
|
146
|
+
label: "Aggregator",
|
|
147
|
+
group: "Flow Control",
|
|
148
|
+
detailPath: "/dashboard/aggregator-nodes",
|
|
149
|
+
apiPath: "/aggregator-nodes",
|
|
150
|
+
stateKey: "aggregatorNodes",
|
|
151
|
+
allStateKey: "allAggregatorNodes",
|
|
152
|
+
color: "#84cc16",
|
|
153
|
+
testable: true,
|
|
82
154
|
},
|
|
83
155
|
cache: {
|
|
84
|
-
type:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
156
|
+
type: "cache",
|
|
157
|
+
prefix: "cache",
|
|
158
|
+
label: "Cache",
|
|
159
|
+
group: "Flow Control",
|
|
160
|
+
detailPath: "/dashboard/cache-nodes",
|
|
161
|
+
apiPath: "/cache-nodes",
|
|
162
|
+
stateKey: "cacheNodes",
|
|
163
|
+
allStateKey: "allCacheNodes",
|
|
164
|
+
color: "#d946ef",
|
|
165
|
+
testable: true,
|
|
88
166
|
},
|
|
89
167
|
code: {
|
|
90
|
-
type:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
168
|
+
type: "code",
|
|
169
|
+
prefix: "code",
|
|
170
|
+
label: "Code",
|
|
171
|
+
group: "Flow Control",
|
|
172
|
+
detailPath: "/dashboard/code-nodes",
|
|
173
|
+
apiPath: "/code-nodes",
|
|
174
|
+
stateKey: "codeNodes",
|
|
175
|
+
allStateKey: "allCodeNodes",
|
|
176
|
+
color: "#a855f7",
|
|
177
|
+
testable: true,
|
|
94
178
|
},
|
|
95
179
|
ai: {
|
|
96
|
-
type:
|
|
180
|
+
type: "ai",
|
|
181
|
+
prefix: "ai",
|
|
182
|
+
label: "AI",
|
|
97
183
|
/* 'Actions' y no 'Flow Control': un nodo de IA no encamina ni retiene un
|
|
98
184
|
evento —eso es control de flujo— sino que HACE algo con él y devuelve un
|
|
99
185
|
resultado, igual que enviar un correo o escribir en una hoja. Además es
|
|
100
186
|
lo que decide qué se ofrece como acción en el flujo guiado del primer
|
|
101
187
|
flujo (`FIRST_FLOW_ACTIONS` en el dashboard), y ahí tiene que estar. */
|
|
102
|
-
group:
|
|
103
|
-
|
|
104
|
-
|
|
188
|
+
group: "Actions",
|
|
189
|
+
detailPath: "/dashboard/ai-nodes",
|
|
190
|
+
apiPath: "/ai-nodes",
|
|
191
|
+
stateKey: "aiNodes",
|
|
192
|
+
allStateKey: "allAiNodes",
|
|
193
|
+
color: "#d946ef",
|
|
194
|
+
testable: true,
|
|
105
195
|
},
|
|
106
196
|
split: {
|
|
107
|
-
type:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
197
|
+
type: "split",
|
|
198
|
+
prefix: "split",
|
|
199
|
+
label: "Split",
|
|
200
|
+
group: "Flow Control",
|
|
201
|
+
detailPath: "/dashboard/split-nodes",
|
|
202
|
+
apiPath: "/split-nodes",
|
|
203
|
+
stateKey: "splitNodes",
|
|
204
|
+
allStateKey: "allSplitNodes",
|
|
205
|
+
color: "#38bdf8",
|
|
206
|
+
testable: true,
|
|
111
207
|
},
|
|
112
208
|
merge: {
|
|
113
|
-
type:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
209
|
+
type: "merge",
|
|
210
|
+
prefix: "merge",
|
|
211
|
+
label: "Merge",
|
|
212
|
+
group: "Flow Control",
|
|
213
|
+
detailPath: "/dashboard/merge-nodes",
|
|
214
|
+
apiPath: "/merge-nodes",
|
|
215
|
+
stateKey: "mergeNodes",
|
|
216
|
+
allStateKey: "allMergeNodes",
|
|
217
|
+
color: "#94a3b8",
|
|
218
|
+
testable: false,
|
|
117
219
|
},
|
|
118
220
|
approval: {
|
|
119
|
-
type:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
221
|
+
type: "approval",
|
|
222
|
+
prefix: "appr",
|
|
223
|
+
label: "Approval",
|
|
224
|
+
group: "Flow Control",
|
|
225
|
+
detailPath: "/dashboard/approval-nodes",
|
|
226
|
+
apiPath: "/approval-nodes",
|
|
227
|
+
stateKey: "approvalNodes",
|
|
228
|
+
allStateKey: "allApprovalNodes",
|
|
229
|
+
color: "#94a3b8",
|
|
230
|
+
testable: true,
|
|
123
231
|
},
|
|
124
232
|
loop: {
|
|
125
|
-
type:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
233
|
+
type: "loop",
|
|
234
|
+
prefix: "loop",
|
|
235
|
+
label: "Loop",
|
|
236
|
+
group: "Flow Control",
|
|
237
|
+
detailPath: "/dashboard/loop-nodes",
|
|
238
|
+
apiPath: "/loop-nodes",
|
|
239
|
+
stateKey: "loopNodes",
|
|
240
|
+
allStateKey: "allLoopNodes",
|
|
241
|
+
color: "#f59e0b",
|
|
242
|
+
testable: true,
|
|
129
243
|
},
|
|
130
244
|
markdown: {
|
|
131
|
-
type:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
245
|
+
type: "markdown",
|
|
246
|
+
prefix: "md",
|
|
247
|
+
label: "Markdown",
|
|
248
|
+
group: "Flow Control",
|
|
249
|
+
detailPath: "/dashboard/markdown-nodes",
|
|
250
|
+
apiPath: "/markdown-nodes",
|
|
251
|
+
stateKey: "markdownNodes",
|
|
252
|
+
allStateKey: "allMarkdownNodes",
|
|
253
|
+
color: "#6366f1",
|
|
254
|
+
testable: true,
|
|
135
255
|
},
|
|
136
256
|
fileTransform: {
|
|
137
|
-
type:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
257
|
+
type: "fileTransform",
|
|
258
|
+
prefix: "ft",
|
|
259
|
+
label: "File Transform",
|
|
260
|
+
group: "Flow Control",
|
|
261
|
+
detailPath: "/dashboard/file-transform-nodes",
|
|
262
|
+
apiPath: "/file-transform-nodes",
|
|
263
|
+
stateKey: "fileTransformNodes",
|
|
264
|
+
allStateKey: "allFileTransformNodes",
|
|
265
|
+
color: "#f97316",
|
|
266
|
+
testable: true,
|
|
141
267
|
},
|
|
142
268
|
limit: {
|
|
143
|
-
type:
|
|
144
|
-
|
|
145
|
-
|
|
269
|
+
type: "limit",
|
|
270
|
+
prefix: "lim",
|
|
271
|
+
label: "Limit",
|
|
272
|
+
group: "Flow Control",
|
|
273
|
+
detailPath: "/dashboard/limit-nodes",
|
|
274
|
+
apiPath: "/limit-nodes",
|
|
275
|
+
stateKey: "limitNodes",
|
|
276
|
+
allStateKey: "allLimitNodes",
|
|
146
277
|
// Amber matches filter / aggregator family — visually groups
|
|
147
278
|
// "array-shape transformations" together on the canvas.
|
|
148
|
-
color:
|
|
279
|
+
color: "#fbbf24",
|
|
280
|
+
testable: true,
|
|
149
281
|
},
|
|
150
282
|
// ── Routing ──
|
|
151
283
|
router: {
|
|
152
|
-
type:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
284
|
+
type: "router",
|
|
285
|
+
prefix: "ro",
|
|
286
|
+
label: "Router",
|
|
287
|
+
group: "Flow Control",
|
|
288
|
+
detailPath: "/dashboard/routers",
|
|
289
|
+
apiPath: "/routers",
|
|
290
|
+
stateKey: "routers",
|
|
291
|
+
allStateKey: "allRouters",
|
|
292
|
+
color: "#38bdf8",
|
|
293
|
+
testable: true,
|
|
156
294
|
},
|
|
157
295
|
// ── Actions ──
|
|
158
296
|
/**
|
|
@@ -164,10 +302,16 @@ export const NODE_REGISTRY = {
|
|
|
164
302
|
* el modo de IA no tiene dieciséis herramientas que ofrecer.
|
|
165
303
|
*/
|
|
166
304
|
emailAction: {
|
|
167
|
-
type:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
305
|
+
type: "emailAction",
|
|
306
|
+
prefix: "ea",
|
|
307
|
+
label: "Email Action",
|
|
308
|
+
group: "Actions",
|
|
309
|
+
detailPath: "/dashboard/email-actions",
|
|
310
|
+
apiPath: "/email-actions",
|
|
311
|
+
stateKey: "emailActions",
|
|
312
|
+
allStateKey: "allEmailActions",
|
|
313
|
+
color: "#f472b6",
|
|
314
|
+
testable: true,
|
|
171
315
|
/**
|
|
172
316
|
* Sigue siendo herramienta: hay una ruta native + aiEnabled donde el nodo
|
|
173
317
|
* AI genera el correo y este lo manda por Resend —en produccion existe un
|
|
@@ -186,96 +330,173 @@ export const NODE_REGISTRY = {
|
|
|
186
330
|
* solo y el de Email vuelve a caber en una pantalla.
|
|
187
331
|
*/
|
|
188
332
|
gmailAction: {
|
|
189
|
-
type:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
333
|
+
type: "gmailAction",
|
|
334
|
+
prefix: "gm",
|
|
335
|
+
label: "Gmail",
|
|
336
|
+
group: "Actions",
|
|
337
|
+
detailPath: "/dashboard/gmail-actions",
|
|
338
|
+
apiPath: "/gmail-actions",
|
|
339
|
+
stateKey: "gmailActions",
|
|
340
|
+
allStateKey: "allGmailActions",
|
|
341
|
+
color: "#ea4335",
|
|
342
|
+
testable: true,
|
|
193
343
|
// El toolkit de IA se vino con Gmail: son sus dieciseis operaciones las
|
|
194
344
|
// que el LLM llama, no las dos de Resend. Ver el comentario de arriba.
|
|
195
345
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
196
346
|
},
|
|
197
347
|
httpAction: {
|
|
198
|
-
type:
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
348
|
+
type: "httpAction",
|
|
349
|
+
prefix: "ha",
|
|
350
|
+
label: "HTTP Action",
|
|
351
|
+
group: "Actions",
|
|
352
|
+
detailPath: "/dashboard/http-actions",
|
|
353
|
+
apiPath: "/http-actions",
|
|
354
|
+
stateKey: "httpActions",
|
|
355
|
+
allStateKey: "allHttpActions",
|
|
356
|
+
color: "#3b82f6",
|
|
357
|
+
testable: true,
|
|
202
358
|
},
|
|
203
359
|
mongoAction: {
|
|
204
|
-
type:
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
360
|
+
type: "mongoAction",
|
|
361
|
+
prefix: "ma",
|
|
362
|
+
label: "MongoDB Action",
|
|
363
|
+
group: "Actions",
|
|
364
|
+
detailPath: "/dashboard/mongo-actions",
|
|
365
|
+
apiPath: "/mongo-actions",
|
|
366
|
+
stateKey: "mongoActions",
|
|
367
|
+
allStateKey: "allMongoActions",
|
|
368
|
+
color: "#34d399",
|
|
369
|
+
testable: true,
|
|
208
370
|
},
|
|
209
371
|
postgresAction: {
|
|
210
|
-
type:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
372
|
+
type: "postgresAction",
|
|
373
|
+
prefix: "pg",
|
|
374
|
+
label: "Postgres Action",
|
|
375
|
+
group: "Actions",
|
|
376
|
+
detailPath: "/dashboard/postgres-actions",
|
|
377
|
+
apiPath: "/postgres-actions",
|
|
378
|
+
stateKey: "postgresActions",
|
|
379
|
+
allStateKey: "allPostgresActions",
|
|
380
|
+
color: "#336791",
|
|
381
|
+
testable: true,
|
|
214
382
|
},
|
|
215
383
|
notificationAction: {
|
|
216
|
-
type:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
384
|
+
type: "notificationAction",
|
|
385
|
+
prefix: "na",
|
|
386
|
+
label: "Notification",
|
|
387
|
+
group: "Actions",
|
|
388
|
+
detailPath: "/dashboard/notification-actions",
|
|
389
|
+
apiPath: "/notification-actions",
|
|
390
|
+
stateKey: "notificationActions",
|
|
391
|
+
allStateKey: "allNotificationActions",
|
|
392
|
+
color: "#f472b6",
|
|
393
|
+
testable: true,
|
|
220
394
|
},
|
|
221
395
|
sheetsAction: {
|
|
222
|
-
type:
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
396
|
+
type: "sheetsAction",
|
|
397
|
+
prefix: "sheet",
|
|
398
|
+
label: "Google Sheets Action",
|
|
399
|
+
group: "Actions",
|
|
400
|
+
detailPath: "/dashboard/sheets-actions",
|
|
401
|
+
apiPath: "/sheets-actions",
|
|
402
|
+
stateKey: "sheetsActions",
|
|
403
|
+
allStateKey: "allSheetsActions",
|
|
404
|
+
color: "#34d399",
|
|
405
|
+
testable: true,
|
|
226
406
|
},
|
|
227
407
|
calendarAction: {
|
|
228
|
-
type:
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
408
|
+
type: "calendarAction",
|
|
409
|
+
prefix: "cal",
|
|
410
|
+
label: "Google Calendar Action",
|
|
411
|
+
group: "Actions",
|
|
412
|
+
detailPath: "/dashboard/calendar-actions",
|
|
413
|
+
apiPath: "/calendar-actions",
|
|
414
|
+
stateKey: "calendarActions",
|
|
415
|
+
allStateKey: "allCalendarActions",
|
|
416
|
+
color: "#60a5fa",
|
|
417
|
+
testable: true,
|
|
232
418
|
// AI Toolkit mode wires the node through the upstream AI Node's
|
|
233
419
|
// tools[] list, not via canvas edges — same pattern as emailAction.
|
|
234
420
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
235
421
|
},
|
|
236
422
|
docsAction: {
|
|
237
|
-
type:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
423
|
+
type: "docsAction",
|
|
424
|
+
prefix: "doc",
|
|
425
|
+
label: "Google Docs",
|
|
426
|
+
group: "Actions",
|
|
427
|
+
detailPath: "/dashboard/docs-actions",
|
|
428
|
+
apiPath: "/docs-actions",
|
|
429
|
+
stateKey: "docsActions",
|
|
430
|
+
allStateKey: "allDocsActions",
|
|
431
|
+
color: "#4285F4",
|
|
432
|
+
testable: true,
|
|
241
433
|
},
|
|
242
434
|
driveAction: {
|
|
243
|
-
type:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
435
|
+
type: "driveAction",
|
|
436
|
+
prefix: "drv",
|
|
437
|
+
label: "Google Drive",
|
|
438
|
+
group: "Actions",
|
|
439
|
+
detailPath: "/dashboard/drive-actions",
|
|
440
|
+
apiPath: "/drive-actions",
|
|
441
|
+
stateKey: "driveActions",
|
|
442
|
+
allStateKey: "allDriveActions",
|
|
443
|
+
color: "#22c55e",
|
|
444
|
+
testable: true,
|
|
247
445
|
// AI Toolkit mode wires the node through the upstream AI Node's
|
|
248
446
|
// tools[] list, not via canvas edges — same pattern as emailAction.
|
|
249
447
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
250
448
|
},
|
|
251
449
|
firecrawlAction: {
|
|
252
|
-
type:
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
450
|
+
type: "firecrawlAction",
|
|
451
|
+
prefix: "fc",
|
|
452
|
+
label: "Firecrawl",
|
|
453
|
+
group: "Actions",
|
|
454
|
+
detailPath: "/dashboard/firecrawl-actions",
|
|
455
|
+
apiPath: "/firecrawl-actions",
|
|
456
|
+
stateKey: "firecrawlActions",
|
|
457
|
+
allStateKey: "allFirecrawlActions",
|
|
458
|
+
color: "#f97316",
|
|
459
|
+
testable: true,
|
|
256
460
|
},
|
|
257
461
|
mailchimpAction: {
|
|
258
|
-
type:
|
|
259
|
-
|
|
260
|
-
|
|
462
|
+
type: "mailchimpAction",
|
|
463
|
+
prefix: "mc",
|
|
464
|
+
label: "Mailchimp",
|
|
465
|
+
group: "Actions",
|
|
466
|
+
detailPath: "/dashboard/mailchimp-actions",
|
|
467
|
+
apiPath: "/mailchimp-actions",
|
|
468
|
+
stateKey: "mailchimpActions",
|
|
469
|
+
allStateKey: "allMailchimpActions",
|
|
261
470
|
// Mailchimp's Cavendish yellow, darkened until it holds contrast on a
|
|
262
471
|
// light canvas. The brand value (#ffe01b) reads as a highlighter there.
|
|
263
|
-
color:
|
|
472
|
+
color: "#c9a227",
|
|
473
|
+
testable: true,
|
|
264
474
|
},
|
|
265
475
|
shopifyAction: {
|
|
266
|
-
type:
|
|
267
|
-
|
|
268
|
-
|
|
476
|
+
type: "shopifyAction",
|
|
477
|
+
prefix: "shp",
|
|
478
|
+
label: "Shopify",
|
|
479
|
+
group: "Actions",
|
|
480
|
+
detailPath: "/dashboard/shopify-actions",
|
|
481
|
+
apiPath: "/shopify-actions",
|
|
482
|
+
stateKey: "shopifyActions",
|
|
483
|
+
allStateKey: "allShopifyActions",
|
|
269
484
|
// Shopify's green, abierto un punto. El de marca (#008060) es más oscuro
|
|
270
485
|
// que cualquier otro color de este registro y se hunde contra el lienzo
|
|
271
486
|
// en modo oscuro; éste sigue leyéndose como Shopify y aguanta en los dos
|
|
272
487
|
// temas. Mismo criterio que el amarillo de Mailchimp, al revés.
|
|
273
|
-
color:
|
|
488
|
+
color: "#0a9e70",
|
|
489
|
+
testable: true,
|
|
274
490
|
},
|
|
275
491
|
githubAction: {
|
|
276
|
-
type:
|
|
277
|
-
|
|
278
|
-
|
|
492
|
+
type: "githubAction",
|
|
493
|
+
prefix: "gh",
|
|
494
|
+
label: "GitHub",
|
|
495
|
+
group: "Actions",
|
|
496
|
+
detailPath: "/dashboard/github-actions",
|
|
497
|
+
apiPath: "/github-actions",
|
|
498
|
+
stateKey: "githubActions",
|
|
499
|
+
allStateKey: "allGithubActions",
|
|
279
500
|
// El morado de "merged" de GitHub. Su marca real es acromática, y ahí no
|
|
280
501
|
// hay elección posible: en el minimapa lo único que distingue a un nodo es
|
|
281
502
|
// el color, el gris cálido ya lo ocupa Notion y el frío lo llevan tres.
|
|
@@ -285,15 +506,21 @@ export const NODE_REGISTRY = {
|
|
|
285
506
|
// color que de verdad dice GitHub, pero **la decisión se cierra mirando el
|
|
286
507
|
// minimapa**, no leyendo este comentario. Si choca, el plan B es un
|
|
287
508
|
// grafito claro, sabiendo que compite con Notion.
|
|
288
|
-
color:
|
|
509
|
+
color: "#8957e5",
|
|
510
|
+
testable: true,
|
|
289
511
|
/* Sin isToolOnly: la v1 no trae modo toolkit de IA, y aquí pesa más que en
|
|
290
512
|
ningún otro nodo — el MCP oficial de GitHub ya cubre ese caso dentro del
|
|
291
513
|
AI Node. Los rieles son este nodo; la improvisación es el MCP. */
|
|
292
514
|
},
|
|
293
515
|
jiraAction: {
|
|
294
|
-
type:
|
|
295
|
-
|
|
296
|
-
|
|
516
|
+
type: "jiraAction",
|
|
517
|
+
prefix: "jr",
|
|
518
|
+
label: "Jira",
|
|
519
|
+
group: "Actions",
|
|
520
|
+
detailPath: "/dashboard/jira-actions",
|
|
521
|
+
apiPath: "/jira-actions",
|
|
522
|
+
stateKey: "jiraActions",
|
|
523
|
+
allStateKey: "allJiraActions",
|
|
297
524
|
// El azul de marca de Jira, y estaba libre. La banda azul es la segunda
|
|
298
525
|
// mas poblada de este registro —nueve nodos— pero ninguno tan profundo:
|
|
299
526
|
// #3b82f6 y #60a5fa son claramente mas claros, y el #336791 de Postgres es
|
|
@@ -301,7 +528,8 @@ export const NODE_REGISTRY = {
|
|
|
301
528
|
//
|
|
302
529
|
// Sigue valiendo lo que escribio GitHub aqui al lado: **la decision se
|
|
303
530
|
// cierra mirando el minimapa**, no leyendo este comentario.
|
|
304
|
-
color:
|
|
531
|
+
color: "#0052CC",
|
|
532
|
+
testable: true,
|
|
305
533
|
/* Sin isToolOnly: la v1 no trae modo toolkit de IA. Cada toolkit vive dos
|
|
306
534
|
veces —specs del dashboard para el AI Node y specs de la api para MCP— y
|
|
307
535
|
esa duplicacion no se paga antes de ver el nodo en pantalla. Ademas
|
|
@@ -309,11 +537,44 @@ export const NODE_REGISTRY = {
|
|
|
309
537
|
`MCP_OAUTH_PRESETS.atlassian`, que cubre la cola larga dentro del AI
|
|
310
538
|
Node. Los rieles son este nodo. */
|
|
311
539
|
},
|
|
540
|
+
bucketAction: {
|
|
541
|
+
type: "bucketAction",
|
|
542
|
+
prefix: "bkt",
|
|
543
|
+
label: "Bucket",
|
|
544
|
+
group: "Actions",
|
|
545
|
+
detailPath: "/dashboard/bucket-actions",
|
|
546
|
+
apiPath: "/bucket-actions",
|
|
547
|
+
stateKey: "bucketActions",
|
|
548
|
+
allStateKey: "allBucketActions",
|
|
549
|
+
// Teal profundo, y la banda estaba VACIA por abajo. Los cuatro vecinos de
|
|
550
|
+
// esa familia son claramente mas claros: `#2dd4bf` y `#34d399` son pasteles,
|
|
551
|
+
// `#06b6d4` tira a cian brillante y `#0a9e70` es verde. En el minimapa este
|
|
552
|
+
// es el unico oscuro de la banda, y eso lo distingue.
|
|
553
|
+
//
|
|
554
|
+
// Se eligio neutro a proposito y no un color de marca: el nodo no es de
|
|
555
|
+
// Cloudflare. Pintarlo del naranja de R2 seria mentir en cuanto alguien lo
|
|
556
|
+
// apunte a AWS, a MinIO o a Backblaze — que es justo para lo que se llama
|
|
557
|
+
// `bucketAction` y no `r2Action`.
|
|
558
|
+
//
|
|
559
|
+
// Vale lo que escribieron GitHub y Jira aqui al lado: **la decision se
|
|
560
|
+
// cierra mirando el minimapa**, no leyendo este comentario.
|
|
561
|
+
color: "#0f766e",
|
|
562
|
+
testable: true,
|
|
563
|
+
/* Sin `isToolOnly`: la v1 no trae modo toolkit de IA. Cada toolkit vive dos
|
|
564
|
+
veces —specs del dashboard para el AI Node y specs de la api para MCP— y
|
|
565
|
+
esa duplicacion no se paga antes de ver el nodo en pantalla. */
|
|
566
|
+
},
|
|
312
567
|
telegramAction: {
|
|
313
|
-
type:
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
568
|
+
type: "telegramAction",
|
|
569
|
+
prefix: "tg",
|
|
570
|
+
label: "Telegram Action",
|
|
571
|
+
group: "Actions",
|
|
572
|
+
detailPath: "/dashboard/telegram-actions",
|
|
573
|
+
apiPath: "/telegram-actions",
|
|
574
|
+
stateKey: "telegramActions",
|
|
575
|
+
allStateKey: "allTelegramActions",
|
|
576
|
+
color: "#0ea5e9",
|
|
577
|
+
testable: true,
|
|
317
578
|
// AI Toolkit mode — same pattern as emailAction. One aiEnabled
|
|
318
579
|
// telegramAction expands into N MCP tools (one per operation) in
|
|
319
580
|
// the upstream AI Node's tool list, so we hide canvas handles to
|
|
@@ -322,11 +583,17 @@ export const NODE_REGISTRY = {
|
|
|
322
583
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
323
584
|
},
|
|
324
585
|
whatsappAction: {
|
|
325
|
-
type:
|
|
326
|
-
|
|
327
|
-
|
|
586
|
+
type: "whatsappAction",
|
|
587
|
+
prefix: "wa",
|
|
588
|
+
label: "WhatsApp Action",
|
|
589
|
+
group: "Actions",
|
|
590
|
+
detailPath: "/dashboard/whatsapp-actions",
|
|
591
|
+
apiPath: "/whatsapp-actions",
|
|
592
|
+
stateKey: "whatsappActions",
|
|
593
|
+
allStateKey: "allWhatsappActions",
|
|
328
594
|
// WhatsApp brand green (#25d366) — instantly recognisable on the canvas.
|
|
329
|
-
color:
|
|
595
|
+
color: "#25d366",
|
|
596
|
+
testable: true,
|
|
330
597
|
// Same toolkit pattern as telegramAction — when aiEnabled the
|
|
331
598
|
// entity stops being a manually-wired single-op action and becomes
|
|
332
599
|
// a multi-op tool surface for an upstream AI Node. Hide canvas
|
|
@@ -335,24 +602,36 @@ export const NODE_REGISTRY = {
|
|
|
335
602
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
336
603
|
},
|
|
337
604
|
discordAction: {
|
|
338
|
-
type:
|
|
339
|
-
|
|
340
|
-
|
|
605
|
+
type: "discordAction",
|
|
606
|
+
prefix: "dc",
|
|
607
|
+
label: "Discord Action",
|
|
608
|
+
group: "Actions",
|
|
609
|
+
detailPath: "/dashboard/discord-actions",
|
|
610
|
+
apiPath: "/discord-actions",
|
|
611
|
+
stateKey: "discordActions",
|
|
612
|
+
allStateKey: "allDiscordActions",
|
|
341
613
|
// Discord brand "Blurple" (#5865F2).
|
|
342
|
-
color:
|
|
614
|
+
color: "#5865F2",
|
|
615
|
+
testable: true,
|
|
343
616
|
// Same toolkit pattern as telegramAction / whatsappAction. Hide
|
|
344
617
|
// canvas handles when aiEnabled so the user can't manually wire a
|
|
345
618
|
// multi-op tool surface — the LLM picks the operation per call.
|
|
346
619
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
347
620
|
},
|
|
348
621
|
slackAction: {
|
|
349
|
-
type:
|
|
350
|
-
|
|
351
|
-
|
|
622
|
+
type: "slackAction",
|
|
623
|
+
prefix: "sl",
|
|
624
|
+
label: "Slack Action",
|
|
625
|
+
group: "Actions",
|
|
626
|
+
detailPath: "/dashboard/slack-actions",
|
|
627
|
+
apiPath: "/slack-actions",
|
|
628
|
+
stateKey: "slackActions",
|
|
629
|
+
allStateKey: "allSlackActions",
|
|
352
630
|
// Slack brand purple ("aubergine"-derived family). Matches the
|
|
353
631
|
// accent color used by SlackConfigSection / ServiceTriggerNode for
|
|
354
632
|
// visual continuity across Slack-related nodes.
|
|
355
|
-
color:
|
|
633
|
+
color: "#7c3aed",
|
|
634
|
+
testable: true,
|
|
356
635
|
// Same AI-tool gating as Telegram/Discord/WhatsApp/Email/Calendar/
|
|
357
636
|
// Contacts. When aiEnabled the node fans out into 16 MCP tools
|
|
358
637
|
// (one per SLACK_OPERATIONS entry); hide canvas handles to prevent
|
|
@@ -360,11 +639,17 @@ export const NODE_REGISTRY = {
|
|
|
360
639
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
361
640
|
},
|
|
362
641
|
googleContactsAction: {
|
|
363
|
-
type:
|
|
364
|
-
|
|
365
|
-
|
|
642
|
+
type: "googleContactsAction",
|
|
643
|
+
prefix: "gc",
|
|
644
|
+
label: "Google Contacts",
|
|
645
|
+
group: "Actions",
|
|
646
|
+
detailPath: "/dashboard/google-contacts-actions",
|
|
647
|
+
apiPath: "/google-contacts-actions",
|
|
648
|
+
stateKey: "googleContactsActions",
|
|
649
|
+
allStateKey: "allGoogleContactsActions",
|
|
366
650
|
// Google "blue" used by Google Drive / Docs (#4285F4) — same family.
|
|
367
|
-
color:
|
|
651
|
+
color: "#4285F4",
|
|
652
|
+
testable: true,
|
|
368
653
|
// AI toolkit mode mirrors emailAction / calendarAction — when
|
|
369
654
|
// aiEnabled the node expands into N MCP tools (one per People API
|
|
370
655
|
// operation) in the upstream AI Node's tool list. Hide canvas
|
|
@@ -372,54 +657,84 @@ export const NODE_REGISTRY = {
|
|
|
372
657
|
isToolOnly: (e) => e.aiEnabled === true,
|
|
373
658
|
},
|
|
374
659
|
googleAnalyticsAction: {
|
|
375
|
-
type:
|
|
376
|
-
|
|
377
|
-
|
|
660
|
+
type: "googleAnalyticsAction",
|
|
661
|
+
prefix: "gaa",
|
|
662
|
+
label: "Google Analytics",
|
|
663
|
+
group: "Actions",
|
|
664
|
+
detailPath: "/dashboard/google-analytics-actions",
|
|
665
|
+
apiPath: "/google-analytics-actions",
|
|
666
|
+
stateKey: "googleAnalyticsActions",
|
|
667
|
+
allStateKey: "allGoogleAnalyticsActions",
|
|
378
668
|
// Naranja de marca de Google Analytics (#E37400). No reutiliza el
|
|
379
669
|
// #ff9933 de RSS ni el orange-500 de Tailwind que ya llevan tres nodos:
|
|
380
670
|
// en el minimapa lo unico que distingue a un nodo es el color.
|
|
381
|
-
color:
|
|
671
|
+
color: "#E37400",
|
|
672
|
+
testable: true,
|
|
382
673
|
/* Sin isToolOnly: la v1 no trae modo toolkit de IA. Cada toolkit vive
|
|
383
674
|
dos veces --specs del dashboard para el AI Node y specs de la api para
|
|
384
675
|
MCP, sin nada que las ate-- y esa duplicacion no se paga antes de ver
|
|
385
676
|
el nodo funcionando en pantalla. */
|
|
386
677
|
},
|
|
387
678
|
notionAction: {
|
|
388
|
-
type:
|
|
389
|
-
|
|
390
|
-
|
|
679
|
+
type: "notionAction",
|
|
680
|
+
prefix: "ntn",
|
|
681
|
+
label: "Notion",
|
|
682
|
+
group: "Actions",
|
|
683
|
+
detailPath: "/dashboard/notion-actions",
|
|
684
|
+
apiPath: "/notion-actions",
|
|
685
|
+
stateKey: "notionActions",
|
|
686
|
+
allStateKey: "allNotionActions",
|
|
391
687
|
// Notion es monocromo de marca (su negro es #37352F), y un punto negro
|
|
392
688
|
// en el minimapa desaparece en modo oscuro. Este stone-500 es el gris
|
|
393
689
|
// CÁLIDO más cercano a esa marca, y no choca con el #94a3b8 (slate, gris
|
|
394
690
|
// frío) que ya llevan tres nodos: en el minimapa lo único que distingue
|
|
395
691
|
// a un nodo es el color.
|
|
396
|
-
color:
|
|
692
|
+
color: "#78716c",
|
|
693
|
+
testable: true,
|
|
397
694
|
/* Sin isToolOnly: la v1 no trae modo toolkit de IA. Cada toolkit vive dos
|
|
398
695
|
veces --specs del dashboard para el AI Node y specs de la api para
|
|
399
696
|
MCP-- y esa duplicación no se paga antes de ver el nodo en pantalla. */
|
|
400
697
|
},
|
|
401
698
|
vectorStore: {
|
|
402
|
-
type:
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
699
|
+
type: "vectorStore",
|
|
700
|
+
prefix: "vs",
|
|
701
|
+
label: "Vector Store",
|
|
702
|
+
group: "Actions",
|
|
703
|
+
detailPath: "/dashboard/vector-store-nodes",
|
|
704
|
+
apiPath: "/vector-store-nodes",
|
|
705
|
+
stateKey: "vectorStoreNodes",
|
|
706
|
+
allStateKey: "allVectorStoreNodes",
|
|
707
|
+
color: "#06b6d4",
|
|
708
|
+
testable: true,
|
|
406
709
|
},
|
|
407
710
|
rssAction: {
|
|
408
|
-
type:
|
|
409
|
-
|
|
410
|
-
|
|
711
|
+
type: "rssAction",
|
|
712
|
+
prefix: "rssa",
|
|
713
|
+
label: "RSS Fetch",
|
|
714
|
+
group: "Actions",
|
|
715
|
+
detailPath: "/dashboard/rss-actions",
|
|
716
|
+
apiPath: "/rss-actions",
|
|
717
|
+
stateKey: "rssActions",
|
|
718
|
+
allStateKey: "allRssActions",
|
|
411
719
|
// Classic RSS feed orange (#ff9933) — distinguishes from rateLimiter /
|
|
412
720
|
// fileTransform / firecrawl which sit on Tailwind orange-500.
|
|
413
|
-
color:
|
|
721
|
+
color: "#ff9933",
|
|
722
|
+
testable: true,
|
|
414
723
|
},
|
|
415
724
|
socialMediaAction: {
|
|
416
|
-
type:
|
|
417
|
-
|
|
418
|
-
|
|
725
|
+
type: "socialMediaAction",
|
|
726
|
+
prefix: "sm",
|
|
727
|
+
label: "Social Media",
|
|
728
|
+
group: "Actions",
|
|
729
|
+
detailPath: "/dashboard/social-media-actions",
|
|
730
|
+
apiPath: "/social-media-actions",
|
|
731
|
+
stateKey: "socialMediaActions",
|
|
732
|
+
allStateKey: "allSocialMediaActions",
|
|
419
733
|
// Pink/magenta (#ec4899) — neutral default; the canvas card overrides
|
|
420
734
|
// with the picked provider's brandColor at render time so each
|
|
421
735
|
// platform reads at a glance (Bluesky #0085ff, Mastodon #6364ff, ...).
|
|
422
|
-
color:
|
|
736
|
+
color: "#ec4899",
|
|
737
|
+
testable: true,
|
|
423
738
|
// AI toolkit mode (Sprint 4) wires through tools[] like the other
|
|
424
739
|
// toolkit-capable actions. Manual + toolkit modes share the same
|
|
425
740
|
// detail page; the segmented control hides ops-config when toolkit.
|
|
@@ -427,10 +742,16 @@ export const NODE_REGISTRY = {
|
|
|
427
742
|
},
|
|
428
743
|
// ── Annotations ──
|
|
429
744
|
stickyNote: {
|
|
430
|
-
type:
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
745
|
+
type: "stickyNote",
|
|
746
|
+
prefix: "note",
|
|
747
|
+
label: "Sticky Note",
|
|
748
|
+
group: "Annotations",
|
|
749
|
+
detailPath: "",
|
|
750
|
+
apiPath: "/sticky-notes",
|
|
751
|
+
stateKey: "stickyNotes",
|
|
752
|
+
allStateKey: "allStickyNotes",
|
|
753
|
+
color: "#fbbf24",
|
|
754
|
+
testable: false,
|
|
434
755
|
},
|
|
435
756
|
};
|
|
436
757
|
// ── Derived helpers ──
|
|
@@ -439,15 +760,20 @@ export function getNodeRegistryEntry(type) {
|
|
|
439
760
|
return NODE_REGISTRY[type];
|
|
440
761
|
}
|
|
441
762
|
/** type → detail page path */
|
|
442
|
-
export const NODE_DETAIL_PATHS = Object.fromEntries(Object.values(NODE_REGISTRY)
|
|
763
|
+
export const NODE_DETAIL_PATHS = Object.fromEntries(Object.values(NODE_REGISTRY)
|
|
764
|
+
.filter((n) => n.detailPath)
|
|
765
|
+
.map((n) => [n.type, n.detailPath]));
|
|
443
766
|
/** type → minimap color */
|
|
444
|
-
export const NODE_COLORS = Object.fromEntries(Object.values(NODE_REGISTRY).map(n => [n.type, n.color]));
|
|
767
|
+
export const NODE_COLORS = Object.fromEntries(Object.values(NODE_REGISTRY).map((n) => [n.type, n.color]));
|
|
445
768
|
/** type → [stateKey, allStateKey] */
|
|
446
|
-
export const NODE_STATE_KEYS = Object.fromEntries(Object.values(NODE_REGISTRY).map(n => [
|
|
769
|
+
export const NODE_STATE_KEYS = Object.fromEntries(Object.values(NODE_REGISTRY).map((n) => [
|
|
770
|
+
n.type,
|
|
771
|
+
[n.stateKey, n.allStateKey],
|
|
772
|
+
]));
|
|
447
773
|
/** prefix → type */
|
|
448
|
-
export const PREFIX_TO_NODE_TYPE = Object.fromEntries(Object.values(NODE_REGISTRY).map(n => [n.prefix, n.type]));
|
|
774
|
+
export const PREFIX_TO_NODE_TYPE = Object.fromEntries(Object.values(NODE_REGISTRY).map((n) => [n.prefix, n.type]));
|
|
449
775
|
/** type → prefix */
|
|
450
|
-
export const NODE_TYPE_TO_PREFIX = Object.fromEntries(Object.values(NODE_REGISTRY).map(n => [n.type, n.prefix]));
|
|
776
|
+
export const NODE_TYPE_TO_PREFIX = Object.fromEntries(Object.values(NODE_REGISTRY).map((n) => [n.type, n.prefix]));
|
|
451
777
|
function specsFor(type, catalog) {
|
|
452
778
|
return catalog[type]?.versions;
|
|
453
779
|
}
|
|
@@ -467,7 +793,7 @@ export function versionsOf(type, catalog = NODE_REGISTRY) {
|
|
|
467
793
|
}
|
|
468
794
|
/** One version's spec, or undefined when the type or the number is unknown. */
|
|
469
795
|
export function versionSpec(type, v, catalog = NODE_REGISTRY) {
|
|
470
|
-
return specsFor(type, catalog)?.find(s => s.v === v);
|
|
796
|
+
return specsFor(type, catalog)?.find((s) => s.v === v);
|
|
471
797
|
}
|
|
472
798
|
/**
|
|
473
799
|
* The version a new node of this type is born on.
|
|
@@ -478,7 +804,7 @@ export function versionSpec(type, v, catalog = NODE_REGISTRY) {
|
|
|
478
804
|
* is not a convention — it is the truth.
|
|
479
805
|
*/
|
|
480
806
|
export function currentVersion(type, catalog = NODE_REGISTRY) {
|
|
481
|
-
const current = specsFor(type, catalog)?.find(s => s.status ===
|
|
807
|
+
const current = specsFor(type, catalog)?.find((s) => s.status === "current");
|
|
482
808
|
return current?.v ?? 1;
|
|
483
809
|
}
|
|
484
810
|
/**
|
|
@@ -516,7 +842,7 @@ export function fieldsLost(from, to) {
|
|
|
516
842
|
if (to.cleanBreak)
|
|
517
843
|
return [...from.fields];
|
|
518
844
|
const kept = new Set(to.fields);
|
|
519
|
-
return from.fields.filter(f => !kept.has(f));
|
|
845
|
+
return from.fields.filter((f) => !kept.has(f));
|
|
520
846
|
}
|
|
521
847
|
/**
|
|
522
848
|
* Declaration mistakes in the version catalogs, as readable lines.
|
|
@@ -536,18 +862,22 @@ export function versionCatalogErrors(catalog = NODE_REGISTRY) {
|
|
|
536
862
|
errors.push(`${entry.type}: declares an empty versions array — omit the field instead`);
|
|
537
863
|
continue;
|
|
538
864
|
}
|
|
539
|
-
const numbers = versions.map(s => s.v);
|
|
540
|
-
const repeatedNumbers = [
|
|
865
|
+
const numbers = versions.map((s) => s.v);
|
|
866
|
+
const repeatedNumbers = [
|
|
867
|
+
...new Set(numbers.filter((n, i) => numbers.indexOf(n) !== i)),
|
|
868
|
+
];
|
|
541
869
|
if (repeatedNumbers.length)
|
|
542
|
-
errors.push(`${entry.type}: repeated version number ${repeatedNumbers.join(
|
|
870
|
+
errors.push(`${entry.type}: repeated version number ${repeatedNumbers.join(", ")}`);
|
|
543
871
|
for (const spec of versions) {
|
|
544
872
|
if (!Number.isInteger(spec.v) || spec.v < 1)
|
|
545
873
|
errors.push(`${entry.type}: version "${spec.v}" is not a positive integer`);
|
|
546
|
-
const repeatedFields = [
|
|
874
|
+
const repeatedFields = [
|
|
875
|
+
...new Set(spec.fields.filter((f, i) => spec.fields.indexOf(f) !== i)),
|
|
876
|
+
];
|
|
547
877
|
if (repeatedFields.length)
|
|
548
|
-
errors.push(`${entry.type} v${spec.v}: repeated field ${repeatedFields.join(
|
|
878
|
+
errors.push(`${entry.type} v${spec.v}: repeated field ${repeatedFields.join(", ")}`);
|
|
549
879
|
}
|
|
550
|
-
const current = versions.filter(s => s.status ===
|
|
880
|
+
const current = versions.filter((s) => s.status === "current");
|
|
551
881
|
if (current.length !== 1)
|
|
552
882
|
errors.push(`${entry.type}: needs exactly one version with status "current", found ${current.length}`);
|
|
553
883
|
}
|